Implements a getting started page, and an option to set the extension as default password manager.

This commit is contained in:
varjolintu 2024-12-23 19:54:11 +02:00 committed by varjolintu
parent dac9ceceff
commit 0eb4564098
13 changed files with 290 additions and 3 deletions

View file

@ -181,7 +181,8 @@
"statusResponse": "readonly",
"Tests": "readonly",
"tr": "readonly",
"trimURL": "readonly"
"trimURL": "readonly",
"updateDefaultPasswordManager": "readonly"
},
"overrides": [
{

View file

@ -33,6 +33,7 @@ KeePassXC-Browser extension requests the following permissions:
| `nativeMessaging` | Allows communication with KeePassXC application |
| `notifications` | To show browser notifications |
| `offscreen` | For accessing system theme when setting icon colors (Chrome only) |
| `privacy` | For setting the extension as default password manager |
| `storage` | For storing extension settings (always stored locally in the browser, they are never synced) |
| `tabs` | To request tab URL's and other info |
| `webNavigation` | To show browser notifications on install or update |

View file

@ -162,6 +162,7 @@
"nativeMessaging",
"notifications",
"offscreen",
"privacy",
"storage",
"tabs",
"webNavigation",

View file

@ -166,6 +166,7 @@
"cookies",
"nativeMessaging",
"notifications",
"privacy",
"storage",
"tabs",
"webNavigation",

View file

@ -626,6 +626,14 @@
"message": "Dismiss and show the default authentication dialog",
"description": "Dismiss button text when in HTTP Authentication popup."
},
"optionsDefaultSettingsTitle": {
"message": "Default settings",
"description": "Default settings title for Getting Started page."
},
"optionsWelcomeTitle": {
"message": "KeePassXC-Browser",
"description": "Main card title for Getting Started page."
},
"optionsTitle": {
"message": "Settings | KeePassXC-Browser",
"description": "Options page title."
@ -818,6 +826,14 @@
"message": "Show a banner on the page when new credentials can be saved to the database",
"description": "Show login notifications checkbox text."
},
"optionsDefaultPasswordManager": {
"message": "Set as default password manager",
"description": "Default password manager checkbox text."
},
"optionsDefaultPasswordManagerHelpText": {
"message": "Sets KeePassXC-Browser as the default password manager for the browser.",
"description": "Default password manager help text."
},
"optionsRedirectAllowance": {
"message": "Number of allowed redirects: $1",
"description": "Redirect allowance range input text."
@ -1377,5 +1393,33 @@
"lockDatabase": {
"message": "Lock database",
"description": "Lock database button title text."
},
"welcomeText": {
"message": "Welcome to KeePassXC-Browser!",
"description": "Main title of Getting Started page."
},
"documentationGettingStarted": {
"message": "Our Getting Started Guide will get you up and running quickly.",
"description": "Getting Started document text."
},
"documentationUserGuide": {
"message": "Looking for more comprehensive documentation? Our User Guide is there to help.",
"description": "User Guide text."
},
"documentationTroubleshootingGuide": {
"message": "Need help troubleshooting the browser integration? Check the Troubleshooting Guide.",
"description": "Troubleshooting Guide text."
},
"gettingStartedWelcomeText": {
"message": "Welcome to KeePassXC-Browser, the official browser extension for KeePassXC.",
"description": "Welcome to KeePassXC-Browser, the official browser extension for KeePassXC."
},
"gettingStartedSecondWelcomeText": {
"message": "Please go through the default settings and check all your preferred options.",
"description": "Please go through the default settings and check all your preferred options."
},
"gettingStartedNewUser": {
"message": "Are you a new user? Check links to our documentation.",
"description": "Are you a new user? Check links to our documentation."
}
}

View file

@ -149,6 +149,15 @@ const initListeners = async function() {
logError(err);
});
});
// Show getting started page after first install
browser.runtime.onInstalled.addListener((details) => {
if (details?.reason === 'install') {
browser.tabs.create({
url: 'options/getting_started.html',
});
}
});
};
const initContextMenuItems = async function() {

View file

@ -7,3 +7,15 @@ HTMLElement.prototype.show = function() {
HTMLElement.prototype.hide = function() {
this.style.display = 'none';
};
// Disables the browser's internal password manager and let the extension take the control
const updateDefaultPasswordManager = async function() {
const passwordSavingEnabled = await browser.privacy.services.passwordSavingEnabled.get({});
if ((passwordSavingEnabled?.levelOfControl === 'controlled_by_this_extension'
|| passwordSavingEnabled?.levelOfControl === 'controllable_by_this_extension')
) {
await browser.privacy.services.passwordSavingEnabled.set({
value: !passwordSavingEnabled.value,
});
}
};

View file

@ -162,6 +162,7 @@
"nativeMessaging",
"notifications",
"offscreen",
"privacy",
"storage",
"tabs",
"webNavigation",

View file

@ -0,0 +1,19 @@
body {
display: flex;
justify-content: center;
max-width: 100% !important;
width: 100% !important;
}
.card {
width: 100%;
}
.tab {
align-self: center;
align-items: center;
display: flex;
flex-direction: column;
justify-content: center;
width: 50%;
}

View file

@ -0,0 +1,114 @@
<!DOCTYPE html>
<html>
<head>
<title data-i18n="welcomeText"></title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<link rel="stylesheet" href="../css/colors.css">
<link rel="stylesheet" href="../bootstrap/bootstrap.min.css">
<link rel="stylesheet" href="../fonts/fork-awesome.min.css">
<link rel="stylesheet" href="options.css">
<link rel="stylesheet" href="getting_started.css">
<link rel="icon" type="image/png" href="../icons/keepassxc_32x32.png" sizes="32x32">
<link rel="icon" type="image/png" href="../icons/keepassxc_64x64.png" sizes="64x64">
<link rel="icon" type="image/png" href="../icons/keepassxc_96x96.png" sizes="96x96">
<script src="../common/browser-polyfill.min.js"></script>
<script src="../common/global_ui.js"></script>
<script src="../bootstrap/bootstrap.min.js"></script>
<script src="getting_started.js"></script>
<script src="../common/translate.js" defer></script>
</head>
<body class="pt-3 pb-5">
<!-- Header -->
<div class="tab" id="tab-getting-started">
<h2 class="pb-3 mt-0" data-i18n="welcomeText"></h2>
<!-- Help text-->
<div class="card my-4 shadow">
<div class="card-header h6 rounded-0">
<i class="fa fa-desktop" aria-hidden="true"></i>
<span data-i18n="optionsWelcomeTitle"></span>
</div>
<div class="card-body">
<p>
<span data-i18n="gettingStartedWelcomeText"></span>
<br>
<span data-i18n="gettingStartedSecondWelcomeText"></span>
</p>
<hr class="mt-0">
<p><span data-i18n="gettingStartedNewUser"></span></p>
<p>
<a target="_blank" href="https://keepassxc.org/docs/KeePassXC_GettingStarted#_browser_integration" data-i18n="[title]openNewTab">
<span data-i18n="documentationGettingStarted"></span>
</a>
<br>
<a target="_blank" href="https://keepassxc.org/docs/KeePassXC_UserGuide" data-i18n="[title]openNewTab">
<span data-i18n="documentationUserGuide"></span>
</a>
<br>
<a target="_blank" href="https://github.com/keepassxreboot/keepassxc-browser/wiki/Troubleshooting-guide" data-i18n="[title]openNewTab">
<span data-i18n="documentationTroubleshootingGuide"></span>
</a>
</p>
</div>
</div>
<!-- Default settings -->
<div class="card my-4 shadow">
<div class="card-header h6 rounded-0">
<i class="fa fa-television" aria-hidden="true"></i>
<span data-i18n="optionsDefaultSettingsTitle"></span>
</div>
<div class="card-body">
<!-- Color theme -->
<div class="form-group col-sm-3 pb-4">
<label for="colorTheme" class="form-label" data-i18n="optionsThemeSelectionHeader"></label>
<select class="form-select form-select-sm col-md-3 col-lg-2" id="colorTheme" data-i18n="[title]optionsThemeSelection">
<option value="system" data-i18n="optionsThemeSystem"></option>
<option value="dark" data-i18n="optionsThemeDark"></option>
<option value="light" data-i18n="optionsThemeLight"></option>
</select>
</div>
<!-- Default password manager -->
<div class="form-group pb-1">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" name="defaultPasswordManager" id="defaultPasswordManager" value="true" />
<label class="form-check-label" for="defaultPasswordManager" data-i18n="optionsDefaultPasswordManager"></label>
<div class="form-text" data-i18n="optionsDefaultPasswordManagerHelpText"></div>
</div>
</div>
<!-- Enable Passkeys -->
<div class="form-group pb-1">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" name="passkeys" id="passkeys" value="true" />
<label class="form-check-label" for="passkeys" data-i18n="optionsPasskeysEnable"></label>
<div class="form-text" data-i18n="optionsPasskeysEnableHelpText"></div>
</div>
</div>
<!-- Autofill HTTP Auth dialogs -->
<div class="form-group pb-1">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" name="autoFillAndSend" id="autoFillAndSend" value="true">
<label class="form-check-label" for="autoFillAndSend" data-i18n="optionsCheckboxAutoFillAndSend"></label>
<div class="form-text" data-i18n="optionsAutoFillAndSendHelpText"></div>
</div>
</div>
<!-- Debug logging -->
<div class="form-group mt-2 pb-1">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" name="debugLogging" id="debugLogging" value="false">
<label class="form-check-label" for="debugLogging" data-i18n="optionsDebugLogging"></label>
<div class="form-text" data-i18n="optionsDebugLoggingHelpText"></div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>

View file

@ -0,0 +1,67 @@
'use strict';
const options = {};
const $ = function(elem) {
return document.querySelector(elem);
};
const initPage = async function() {
const changeCheckboxValue = async function(e) {
const name = e.currentTarget.name;
const isChecked = e.currentTarget.checked;
if (name === 'defaultPasswordManager') {
await updateDefaultPasswordManager();
return;
}
options.settings[name] = isChecked;
await saveSettings();
};
// Switch/checkboxes
const checkboxes = document.querySelectorAll('#tab-getting-started input[type=checkbox]');
for (const checkbox of checkboxes) {
if (checkbox.name === 'defaultPasswordManager') {
const passwordSavingEnabled = await browser.privacy.services.passwordSavingEnabled.get({});
checkbox.checked = (passwordSavingEnabled?.levelOfControl === 'controlled_by_this_extension'
&& !passwordSavingEnabled.value) || false;
} else {
checkbox.checked = options.settings[checkbox.name];
}
checkbox.addEventListener('click', changeCheckboxValue);
}
// Color theme
$('#tab-getting-started select#colorTheme').addEventListener('change', async function(e) {
options.settings['colorTheme'] = e.currentTarget.value;
await saveSettings();
updateTheme(options.settings['colorTheme']);
});
};
const saveSettings = async function() {
await browser.storage.local.set({ 'settings': options.settings });
};
const updateTheme = function(theme) {
if (theme === 'system') {
theme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
}
document.documentElement.setAttribute('data-bs-theme', theme);
};
(async() => {
try {
updateTheme('system');
const settings = await browser.runtime.sendMessage({ action: 'load_settings' });
options.settings = settings;
await initPage();
} catch (err) {
console.log('Error loading getting started page: ' + err);
}
})();

View file

@ -351,11 +351,20 @@
</div>
<!-- Number of allowed redirects -->
<div class="form-group w-50">
<div class="form-group w-50 pb-2">
<label id="redirectAllowanceLabel" class="font-weight-normal" for="redirectAllowance" data-i18n="optionsRedirectAllowance" data-i18n-placeholder="1"></label>
<input type="range" class="form-range" id="redirectAllowance" name="redirectAllowance" min="1" max="11" step="1" value="1">
<div class="form-text help-text" data-i18n="optionsRedirectAllowanceHelpText"></div>
</div>
<!-- Default password manager -->
<div class="form-group pb-1">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" name="defaultPasswordManager" id="defaultPasswordManager" value="true" />
<label class="form-check-label" for="defaultPasswordManager" data-i18n="optionsDefaultPasswordManager"></label>
<div class="form-text" data-i18n="optionsDefaultPasswordManagerHelpText"></div>
</div>
</div>
</div>
</div>

View file

@ -78,6 +78,8 @@ options.initGeneralSettings = async function() {
$('#passkeysFallback').disabled = !isChecked;
} else if (name === 'useMonochromeToolbarIcon') {
browser.runtime.sendMessage({ action: 'update_popup' });
} else if (name === 'defaultPasswordManager') {
await updateDefaultPasswordManager();
}
};
@ -90,7 +92,13 @@ options.initGeneralSettings = async function() {
const generalSettingsCheckboxes = document.querySelectorAll('#tab-general-settings input[type=checkbox]');
for (const checkbox of generalSettingsCheckboxes) {
checkbox.checked = options.settings[checkbox.name];
if (checkbox.name === 'defaultPasswordManager') {
const passwordSavingEnabled = await browser.privacy.services.passwordSavingEnabled.get({});
checkbox.checked = (passwordSavingEnabled?.levelOfControl === 'controlled_by_this_extension'
&& !passwordSavingEnabled.value) || false;
} else {
checkbox.checked = options.settings[checkbox.name];
}
if (checkbox.name === 'defaultGroupAlwaysAsk' && checkbox.checked) {
$('#defaultGroup').disabled = true;