diff --git a/.eslintrc b/.eslintrc index 5ddc93e..68baaa4 100644 --- a/.eslintrc +++ b/.eslintrc @@ -181,7 +181,8 @@ "statusResponse": "readonly", "Tests": "readonly", "tr": "readonly", - "trimURL": "readonly" + "trimURL": "readonly", + "updateDefaultPasswordManager": "readonly" }, "overrides": [ { diff --git a/README.md b/README.md index a3dadb9..b6ec5fe 100644 --- a/README.md +++ b/README.md @@ -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 | diff --git a/dist/manifest_chromium.json b/dist/manifest_chromium.json index 25990f3..f90819b 100755 --- a/dist/manifest_chromium.json +++ b/dist/manifest_chromium.json @@ -162,6 +162,7 @@ "nativeMessaging", "notifications", "offscreen", + "privacy", "storage", "tabs", "webNavigation", diff --git a/dist/manifest_firefox.json b/dist/manifest_firefox.json index 9e90477..4a3d876 100644 --- a/dist/manifest_firefox.json +++ b/dist/manifest_firefox.json @@ -166,6 +166,7 @@ "cookies", "nativeMessaging", "notifications", + "privacy", "storage", "tabs", "webNavigation", diff --git a/keepassxc-browser/_locales/en/messages.json b/keepassxc-browser/_locales/en/messages.json index b6f96c2..715e50f 100644 --- a/keepassxc-browser/_locales/en/messages.json +++ b/keepassxc-browser/_locales/en/messages.json @@ -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." } } diff --git a/keepassxc-browser/background/init.js b/keepassxc-browser/background/init.js index 73b2550..ac0ea86 100644 --- a/keepassxc-browser/background/init.js +++ b/keepassxc-browser/background/init.js @@ -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() { diff --git a/keepassxc-browser/common/global_ui.js b/keepassxc-browser/common/global_ui.js index 582a441..6c8adca 100644 --- a/keepassxc-browser/common/global_ui.js +++ b/keepassxc-browser/common/global_ui.js @@ -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, + }); + } +}; diff --git a/keepassxc-browser/manifest.json b/keepassxc-browser/manifest.json index 25990f3..f90819b 100755 --- a/keepassxc-browser/manifest.json +++ b/keepassxc-browser/manifest.json @@ -162,6 +162,7 @@ "nativeMessaging", "notifications", "offscreen", + "privacy", "storage", "tabs", "webNavigation", diff --git a/keepassxc-browser/options/getting_started.css b/keepassxc-browser/options/getting_started.css new file mode 100644 index 0000000..8ddcfd0 --- /dev/null +++ b/keepassxc-browser/options/getting_started.css @@ -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%; +} diff --git a/keepassxc-browser/options/getting_started.html b/keepassxc-browser/options/getting_started.html new file mode 100644 index 0000000..c48ff55 --- /dev/null +++ b/keepassxc-browser/options/getting_started.html @@ -0,0 +1,114 @@ + + + + + + + + + + + + + + + + + + + + + + +
+

+ + +
+
+ + +
+
+

+ +
+ +

+
+

+

+ + + +
+ + + +
+ + + +

+
+
+ + +
+
+ + +
+
+ + +
+ + +
+ + +
+
+ + +
+
+
+ + +
+
+ + +
+
+
+ + +
+
+ + +
+
+
+ + +
+
+ + +
+
+
+ +
+
+
+ + diff --git a/keepassxc-browser/options/getting_started.js b/keepassxc-browser/options/getting_started.js new file mode 100644 index 0000000..9d99320 --- /dev/null +++ b/keepassxc-browser/options/getting_started.js @@ -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); + } +})(); diff --git a/keepassxc-browser/options/options.html b/keepassxc-browser/options/options.html index 28e851d..eb2a3de 100644 --- a/keepassxc-browser/options/options.html +++ b/keepassxc-browser/options/options.html @@ -351,11 +351,20 @@ -
+
+ + +
+
+ + +
+
+
diff --git a/keepassxc-browser/options/options.js b/keepassxc-browser/options/options.js index c06a530..29d47c7 100644 --- a/keepassxc-browser/options/options.js +++ b/keepassxc-browser/options/options.js @@ -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;