master
John Lauer v2.0.634 (insiders): background windows proven: default ext lane gets --no-startup-window + --keep-alive-for-test (was… 3fcc8b8 1mo ago
// pup login capture on the EXTENSION lane (2.0.602).
//
// John, 2026-09-17, after typing his Google password into a pup window and finding pup had not kept it:
// "are you fucking kidding me? i did type in my fucking password ... the whole point of pup is that it
// makes my life easier and i stop having to type in damn passwords".
//
// The capture rail existed ONLY on the CDP lane (Page.addScriptToEvaluateOnNewDocument plus the
// __pupCredCapture binding, installed in lib.rs tab-setup and recovery). The extension lane has no CDP
// page instrumentation, and it is the DEFAULT lane, so every login typed in a normal pup window was
// thrown away. This is the same detection logic as rust/verbs/assets/capture-login.js, delivering through
// the service worker instead of a DevTools binding.
//
// Runs in the ISOLATED world (chrome.runtime is needed to reach the worker); it still reads the page's
// DOM, so input.value is available. The MAIN-world HTMLFormElement.prototype.submit hook from the CDP
// copy cannot be installed from here, so a purely programmatic form.submit() is covered by the blur,
// change, keydown and pagehide nets instead.
(() => {
  if (window !== window.top) return;
  if (window.__pupExtCapV === '1') return;
  window.__pupExtCapV = '1';
  const vis = (el) => !!el && !el.disabled && el.offsetParent !== null && el.getClientRects().length > 0;
  const isPwd = (el) => el && el.tagName === 'INPUT' && (el.type === 'password' || el.autocomplete === 'current-password' || el.autocomplete === 'new-password' || /(^|[^a-z])password([^a-z]|$)/i.test(el.name || '') || /(^|[^a-z])password([^a-z]|$)/i.test(el.id || ''));
  let last = '';
  function grab(form) {
    try {
      const scope = form || document;
      const pwd = [...scope.querySelectorAll('input')].filter(vis).filter(isPwd)[0];
      if (!pwd || !pwd.value) return;
      const all = [...scope.querySelectorAll('input')];
      const pi = all.indexOf(pwd);
      let user = [...scope.querySelectorAll('input[autocomplete=username], input[type=email]')].filter(vis).filter((e) => !isPwd(e))[0];
      if (!user) {
        const cands = [...scope.querySelectorAll('input[type=text], input[type=tel], input:not([type])')].filter(vis).filter((e) => !isPwd(e));
        user = cands.slice().reverse().filter((c) => all.indexOf(c) < pi)[0] || cands[0] || null;
      }
      // Google asks for the email on one page and the password on the next, so the password page has no
      // username field at all. Take the address Google prints on it (measured on the real sign-in page).
      let u = user ? user.value : '';
      if (!u && /(^|\.)google\.com$/.test(location.hostname)) {
        const m = (document.body.innerText || '').match(/[\w.+-]+@[\w.-]+\.\w+/);
        if (m) u = m[0];
      }
      const rec = { host: location.hostname, u, p: pwd.value, ts: Date.now() };
      const key = rec.host + '|' + rec.u + '|' + rec.p;
      if (key === last) return;   // blur then submit then pagehide all fire for one login
      last = key;
      chrome.runtime.sendMessage({ t: 'pup-cred', rec }, () => void chrome.runtime.lastError);
    } catch (e) {}
  }
  const formHasPwd = (f) => { try { return !!f && [...f.querySelectorAll('input')].some(isPwd); } catch (e) { return false; } };
  addEventListener('submit', (e) => grab(e.target && e.target.tagName === 'FORM' ? e.target : null), true);
  addEventListener('click', (e) => {
    try {
      const t = e.target && e.target.closest && e.target.closest('button, input[type=submit], [role=button], a');
      if (!t) return;
      const f = t.form || (t.closest && t.closest('form'));
      if (formHasPwd(f)) grab(f); else if (!f) grab(null);
    } catch (e2) {}
  }, true);
  addEventListener('change', (e) => { try { if (isPwd(e.target) && e.target.value) grab(e.target.form || null); } catch (e2) {} }, true);
  addEventListener('blur', (e) => { try { if (isPwd(e.target) && e.target.value) grab(e.target.form || null); } catch (e2) {} }, true);
  addEventListener('keydown', (e) => { try { if (e.key === 'Enter' && isPwd(document.activeElement) && document.activeElement.value) grab(document.activeElement.form || null); } catch (e2) {} }, true);
  addEventListener('pagehide', () => { try { grab(null); } catch (e2) {} }, true);
})();