diff --git a/.eslintrc b/.eslintrc index 68baaa4..f51de47 100644 --- a/.eslintrc +++ b/.eslintrc @@ -161,6 +161,7 @@ "MIN_TOTP_INPUT_LENGTH": "readonly", "module": "readonly", "nacl": "readonly", + "OBSERVER_OPTIONS": "readonly", "ORANGE_BUTTON": "readonly", "page": "readonly", "Pixels": "readonly", diff --git a/keepassxc-browser/background/event.js b/keepassxc-browser/background/event.js index a6d3055..83c5923 100755 --- a/keepassxc-browser/background/event.js +++ b/keepassxc-browser/background/event.js @@ -13,14 +13,14 @@ kpxcEvent.onMessage = async function(request, sender) { } }; -kpxcEvent.showStatus = async function(tab, configured, internalPoll) { +kpxcEvent.showStatus = async function(tab, configured, internalPoll, forceShowDefault = false) { let keyId = null; if (configured && keepass.databaseHash !== '' && Object.hasOwn(keepass.keyRing, keepass.databaseHash)) { keyId = keepass.keyRing[keepass.databaseHash].id; } - if (!internalPoll) { + if (!internalPoll || forceShowDefault) { browserAction.showDefault(tab); } @@ -76,7 +76,7 @@ kpxcEvent.onSaveSettings = async function(tab, settings) { kpxcEvent.onGetStatus = async function(tab, args = []) { // When internalPoll is true the event is triggered from content script in intervals -> don't poll KeePassXC try { - const [ internalPoll = false, triggerUnlock = false ] = args; + const [ internalPoll = false, triggerUnlock = false, forceShowDefault ] = args; if (!internalPoll) { const response = await keepass.testAssociation(tab, [ true, triggerUnlock ]); if (!response) { @@ -85,7 +85,7 @@ kpxcEvent.onGetStatus = async function(tab, args = []) { } const configured = await keepass.isConfigured(); - return kpxcEvent.showStatus(tab, configured, internalPoll); + return kpxcEvent.showStatus(tab, configured, internalPoll, forceShowDefault); } catch (err) { logError('No status shown: ' + err); return Promise.reject(); diff --git a/keepassxc-browser/content/form.js b/keepassxc-browser/content/form.js index 0207bc7..86a156e 100644 --- a/keepassxc-browser/content/form.js +++ b/keepassxc-browser/content/form.js @@ -166,6 +166,8 @@ kpxcForm.initForm = function(form, credentialFields) { if (submitButton) { submitButton.addEventListener('click', kpxcForm.onSubmit); } + + kpxcUI.pageObserver.observe(form, OBSERVER_OPTIONS); } }; diff --git a/keepassxc-browser/content/keepassxc-browser.js b/keepassxc-browser/content/keepassxc-browser.js index c1a68cc..edfe1ac 100755 --- a/keepassxc-browser/content/keepassxc-browser.js +++ b/keepassxc-browser/content/keepassxc-browser.js @@ -81,8 +81,9 @@ kpxc.clearAllFromPage = function() { kpxcUserAutocomplete.closeList(); } - // Switch back to default popup - sendMessage('get_status', [ true ]); // This is an internal function call + // Clear logins from background and switch back to default popup + sendMessage('page_clear_logins'); + sendMessage('get_status', [ true, false, true ]); // This is an internal function call, forceShowDefault }; // Creates a new combination manually from active element @@ -879,7 +880,7 @@ kpxc.usePredefinedSites = function(currentLocation) { * Content script initialization. */ const initContentScript = async function() { - try { + try { if (document?.documentElement?.ownerDocument?.contentType !== 'text/html' && document?.documentElement?.ownerDocument?.contentType !== 'application/xhtml+xml' ) { diff --git a/keepassxc-browser/content/ui.js b/keepassxc-browser/content/ui.js index fa9f812..137e3bc 100644 --- a/keepassxc-browser/content/ui.js +++ b/keepassxc-browser/content/ui.js @@ -13,6 +13,8 @@ const ORANGE_BUTTON = 'kpxc-button kpxc-orange-button'; const RED_BUTTON = 'kpxc-button kpxc-red-button'; const GRAY_BUTTON_CLASS = 'kpxc-gray-button'; +const OBSERVER_OPTIONS = { attributes: true, attributeFilter: [ 'style' ] }; + const DatabaseState = { DISCONNECTED: 0, LOCKED: 1, @@ -408,7 +410,22 @@ kpxcUI.createWrapperObserver = function() { }; kpxcUI.observeWrapper = function(elem) { - kpxcUI.wrapperObserver.observe(elem, { attributes: true, attributeFilter: [ 'style' ] }); + kpxcUI.wrapperObserver?.observe(elem, OBSERVER_OPTIONS); +}; + +// Observer and style changes +kpxcUI.createPageObserver = function() { + kpxcUI.pageObserver = new MutationObserver(function(mutations, obs) { + for (const mut of mutations) { + const currentStyle = getComputedStyle(mut?.target); + if (currentStyle.opacity && currentStyle.opacity < MIN_OPACITY) { + kpxc.clearAllFromPage(); + } + } + }); + + kpxcUI.pageObserver.observe(document.documentElement, OBSERVER_OPTIONS); + kpxcUI.pageObserver.observe(document.body, OBSERVER_OPTIONS); }; const DOMRectToArray = function(domRect) { @@ -440,6 +457,11 @@ const logDebug = function(message, extra) { } }; +const initObservers = function() { + kpxcUI.createWrapperObserver(); + kpxcUI.createPageObserver(); +}; + document.addEventListener('mousedown', function(e) { if (!e.isTrusted) { return; @@ -456,7 +478,11 @@ document.addEventListener('mouseup', function(e) { kpxcUI.mouseDown = false; }); -document.addEventListener('DOMContentLoaded', kpxcUI.createWrapperObserver()); +if (document.readyState === 'complete' || (document.readyState !== 'loading' && !document.documentElement.doScroll)) { + initObservers(); +} else { + document.addEventListener('DOMContentLoaded', initObservers); +} HTMLDivElement.prototype.appendMultiple = function(...args) { for (const a of args) {