function isVisibleInput(input) { if (!(input instanceof HTMLInputElement)) { return false; } if (input.disabled || input.readOnly) { return false; } const style = window.getComputedStyle(input); if (style.display === "none" || style.visibility === "hidden") { return false; } return input.offsetParent !== null || style.position === "fixed"; } function dispatchFillEvents(input) { if (typeof InputEvent === "function") { input.dispatchEvent(new InputEvent("input", { bubbles: true, data: input.value, inputType: "insertText" })); } else { input.dispatchEvent(new Event("input", { bubbles: true })); } input.dispatchEvent(new Event("change", { bubbles: true })); } function setInputValue(input, value) { const prototype = Object.getPrototypeOf(input); const descriptor = prototype ? Object.getOwnPropertyDescriptor(prototype, "value") : null; if (descriptor?.set) { descriptor.set.call(input, value); return; } input.value = value; } function findPasswordInput() { return Array.from(document.querySelectorAll('input[type="password"]')).find(isVisibleInput) || null; } function findUsernameInput(passwordInput) { const form = passwordInput?.form || null; const scope = form || document; const candidates = Array.from(scope.querySelectorAll('input[type="text"], input[type="email"], input:not([type]), input[autocomplete="username"], input[autocomplete="email"]')) .filter(isVisibleInput); if (passwordInput) { const sameForm = candidates.filter((input) => input.form === passwordInput.form); if (sameForm.length !== 0) { const priorSibling = sameForm.find((input) => typeof input.compareDocumentPosition === "function" && Boolean(input.compareDocumentPosition(passwordInput) & Node.DOCUMENT_POSITION_FOLLOWING) ); return priorSibling || sameForm[0]; } } return candidates[0] || null; } function fillCredential(credential) { const passwordInput = findPasswordInput(); const usernameInput = findUsernameInput(passwordInput); if (usernameInput && credential.username) { usernameInput.focus(); setInputValue(usernameInput, credential.username); dispatchFillEvents(usernameInput); } if (passwordInput && credential.password) { passwordInput.focus(); setInputValue(passwordInput, credential.password); dispatchFillEvents(passwordInput); } if (!usernameInput && !passwordInput) { return { ok: false, error: "No fillable username or password fields were found." }; } return { ok: true }; } (globalThis.browser ?? globalThis.chrome).runtime.onMessage.addListener((message, _sender, sendResponse) => { if (message?.type !== "keepassgo-fill-credential") { return false; } try { sendResponse(fillCredential(message.credential || {})); } catch (error) { sendResponse({ ok: false, error: error instanceof Error ? error.message : String(error) }); } return false; });