Files
keepassgo/browser/extension/content.js
T

88 lines
2.9 KiB
JavaScript

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;
});