import { isVisible } from "./detect"; import { extractDomain } from "../shared/domain"; function getRegistrableDomain(hostname: string): string { return extractDomain(hostname) ?? hostname; } function checkFormAction(form: HTMLFormElement | null, expectedDomain: string): boolean { if (!form?.action) return true; try { const actionUrl = new URL(form.action); const actionDomain = getRegistrableDomain(actionUrl.hostname); if (actionDomain !== expectedDomain) { return false; } } catch {} return true; } export function fillFields( usernameEl: HTMLInputElement | null, passwordEl: HTMLInputElement | null, username: string, password: string, form?: HTMLFormElement | null, expectedDomain?: string ): void { if (expectedDomain && form && !checkFormAction(form, expectedDomain)) { return; } // Fill username regardless of visibility — on SPA step-by-step login flows // the username input may be visually hidden but still tracked by the form. if (usernameEl && username) { setNativeValue(usernameEl, username); } if (passwordEl && isVisible(passwordEl)) { setNativeValue(passwordEl, password); } } function setNativeValue(el: HTMLInputElement, value: string): void { const nativeInputValueSetter = Object.getOwnPropertyDescriptor( window.HTMLInputElement.prototype, "value" )?.set; nativeInputValueSetter?.call(el, value); el.dispatchEvent(new Event("input", { bubbles: true })); el.dispatchEvent(new Event("change", { bubbles: true })); }