Cache overlay discovery prior to checking top-level elements (#2670)

Cache overlay discovery prior to checking top-level elements
This commit is contained in:
Jonathan White 2025-09-09 11:41:17 -04:00 committed by GitHub
parent 77a1f62979
commit 362448eebc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 45 additions and 13 deletions

View file

@ -126,6 +126,7 @@
"isEdge": "readonly",
"isElementInside": "readonly",
"isFirefox": "readonly",
"isIframeAllowed": "readonly",
"keepass": "readonly",
"keepassClient": "readonly",
"kpActions": "readonly",

View file

@ -411,6 +411,38 @@ kpxcFields.isSearchField = function(target) {
return false;
};
// :popover-open selector is supported only with Firefox >= 125 and Chrome >= 114
kpxcFields.discoverOverlays = function() {
try {
kpxcFields.overlays = document.querySelectorAll(':popover-open, [popover]');
} catch (e) {
// Ignore SyntaxError (e.g., unsupported selector)
if (!(e instanceof SyntaxError)) {
logError(e);
}
}
};
// Checks if element has an overlay
kpxcFields.hasOverlay = function(elem) {
try {
return elem?.hasAttribute('popover') || elem?.matches(':popover-open');
} catch (e) {
// Ignore SyntaxError (e.g., unsupported selector)
if (!(e instanceof SyntaxError)) {
logError(e);
}
}
};
// Check the visibility of existing fields
kpxcFields.checkExistingFields = function() {
if (kpxc.inputs?.some(input => !kpxcFields.isVisible(input))) {
kpxc.clearAllFromPage();
kpxc.combinations = [];
}
};
kpxcFields.isTopElement = function(elem, rect) {
if (!elem || !rect) {
return false;
@ -439,19 +471,10 @@ kpxcFields.isTopElement = function(elem, rect) {
}
// Check for popup overlays
try {
// :popover-open selector is supported only with Firefox >= 125 and Chrome >= 114
const overlays = document.querySelectorAll(':popover-open, [popover]');
for (const overlay of overlays) {
const overlayRect = overlay?.getBoundingClientRect();
if (overlayRect && elementsOverlap(rect, overlayRect)) {
return false;
}
}
} catch (e) {
// Ignore SyntaxError (e.g., unsupported selector)
if (!(e instanceof SyntaxError)) {
logError(e);
for (const overlay of kpxcFields.overlays ?? []) {
const overlayRect = overlay?.getBoundingClientRect();
if (overlayRect && elementsOverlap(rect, overlayRect)) {
return false;
}
}

View file

@ -208,6 +208,8 @@ kpxc.getSite = function(sites) {
kpxc.identifyFormInputs = async function() {
const forms = [];
const documentForms = document.forms; // Cache the value just in case
// Used for overlay security detection
kpxcFields.discoverOverlays();
for (const form of documentForms) {
if (!kpxcFields.isVisible(form)) {

View file

@ -72,6 +72,12 @@ kpxcObserverHelper.initObserver = async function() {
continue;
}
if (kpxcFields.hasOverlay(mut.target)) {
kpxcFields.discoverOverlays();
kpxcFields.checkExistingFields();
continue;
}
// Cache style mutations. We only need the last style mutation of the target.
kpxcObserverHelper.cacheStyle(mut, styleMutations, mutations.length);