fill.ts

1.5 KB · raw

1import { isVisible } from "./detect";2import { extractDomain } from "../shared/domain";34function getRegistrableDomain(hostname: string): string {5  return extractDomain(hostname) ?? hostname;6}78function checkFormAction(form: HTMLFormElement | null, expectedDomain: string): boolean {9  if (!form?.action) return true;10  try {11    const actionUrl = new URL(form.action);12    const actionDomain = getRegistrableDomain(actionUrl.hostname);13    if (actionDomain !== expectedDomain) {14      return false;15    }16  } catch {}17  return true;18}1920export function fillFields(21  usernameEl: HTMLInputElement | null,22  passwordEl: HTMLInputElement | null,23  username: string,24  password: string,25  form?: HTMLFormElement | null,26  expectedDomain?: string27): void {28  if (expectedDomain && form && !checkFormAction(form, expectedDomain)) {29    return;30  }31  // Fill username regardless of visibility — on SPA step-by-step login flows32  // the username input may be visually hidden but still tracked by the form.33  if (usernameEl && username) {34    setNativeValue(usernameEl, username);35  }36  if (passwordEl && isVisible(passwordEl)) {37    setNativeValue(passwordEl, password);38  }39}4041function setNativeValue(el: HTMLInputElement, value: string): void {42  const nativeInputValueSetter = Object.getOwnPropertyDescriptor(43    window.HTMLInputElement.prototype,44    "value"45  )?.set;46  nativeInputValueSetter?.call(el, value);47  el.dispatchEvent(new Event("input", { bubbles: true }));48  el.dispatchEvent(new Event("change", { bubbles: true }));49}