← Commit history

Vault now matches credentials across the registrable domain (eTLD+1), like a browser password manager: a login saved on ms.componentsearchengine.com is offered on componentsearchengine.com and its siblings. This is what made imported browser logins usable — they land under whatever host the user saved them on, but the download pages often live on the apex. Exact-host and glob matches still win first; sibling match is scored below them. Includes the pup_download (browser-native) and pup_import_browser_logins verbs and the decrypt verb-rename fix from this line of work.

John Lauer ·ee1d7c0a9a ·2mo ago ·parent e47b758
4 files changed +35−10
adom-bridge-puppeteer-manifest.json+4−4
@@ -1,10 +1,10 @@ {   "manifest_version": 1,   "name": "puppeteer",-  "version": "2.0.143.1",-  "url": "https://wiki.adom.inc/download/adom/pup-bridge/2.0.143.1/adom-bridge-puppeteer-v2.0.143.1.zip",-  "sha256": "a86155383e4e1401ec9224b8d6eb06ec37967f9ab4ce1d3237e04a9798ef07f0",-  "size": 897187,+  "version": "2.0.144",+  "url": "https://wiki.adom.inc/download/adom/pup-bridge/2.0.144/adom-bridge-puppeteer-v2.0.144.zip",+  "sha256": "5317f1f4b49baa6d4ded0dc53e7ea6905fd104fe14104a1bd78f124845fc4415",+  "size": 897850,   "verbPrefixes": [     "browser_",     "desktop_recorder_",
src/BRIDGE_VERSION+1−1
@@ -1 +1 @@-2.0.143.1+2.0.144
src/bridge.json+1−1
@@ -2,7 +2,7 @@   "manifest_version": 1,   "name": "puppeteer",   "displayName": "Puppeteer (Chrome for Testing + Native)",-  "version": "2.0.143.1",+  "version": "2.0.144",   "description": "Drives a browser ALREADY on the machine \u2014 installed Chrome, else Microsoft Edge (every Windows PC ships with Edge) \u2014 launched with a FRESH isolated profile, so the common case has NO ~150 MB Chrome-for-Testing download and it never touches the user's real tabs/logins. Binds its local server to LOOPBACK (127.0.0.1) only, so no Windows Firewall 'allow Node through the firewall' prompt ever pops. Chrome for Testing is fetched only as a LAST RESORT if the machine has no Chromium browser at all. SPAWN-VERIFIED fallback: pup tries each detected browser (Chrome \u2192 Edge \u2192 CfT) and actually launches it, falling through to the next if one won't start (and handling browsers like Edge that relaunch onto another PID), so a corrupt/partial install never hard-fails an open. The browser that launches is cached as the default (persisted across restarts) so it isn't re-probed each time. On spawn the bridge SELF-WARMS: detects browsers + disk, and only if the box has no Chrome/Edge and no cached CfT does it background-fetch CfT so the first open is instant. pup_use pins a specific browser (chrome | edge | cft | auto); {browser:'chrome',install:true} downloads & installs REAL Google Chrome (user-scoped, no admin) on an Edge-only box. pup_readiness (READ-ONLY) reports which browser will be used + the full candidate list + the default + free disk. Every failure returns a specific errorCode + _hint (chrome_install_no_disk, chrome_download_network, chrome_install_permission, chrome_stable_not_detected, \u2026). Launches with FULL browser permissions by default for full debug (strictPermissions:true opts out). Headful automation: open/close windows+tabs, navigate, screenshot, eval JS, record. pup is a GENERIC, non-profile browser only \u2014 every session is a fresh isolated Chrome/Edge process, never the user's real signed-in browser; profile defaults to sessionId. To drive the user's REAL Chrome/Edge (their profile, cookies, SSO), use the Adom browser EXTENSION's nbrowser_* verbs \u2014 a separate bridge, not pup's job. macOS (v1.9.74+): full parity with mac-native mechanics \u2014 background-by-default is the app-level hide (windows stay drivable/screenshottable while hidden), raise/lower map to unhide+activate/hide, pup_alert_window posts a native toast whose click focuses the window, pup_use {browser:'chrome',install:true} installs Chrome from the official dmg, and taskbar identity/badging remains Windows-only.",   "homepage": "https://wiki.adom.inc/adom/adom-bridge",   "author": "Adom Inc.",
src/credential_vault.js+29−4
@@ -76,6 +76,23 @@ function writeIndex(entries) {  // ── Glob matching ────────────────────────────────────────────────────── +// v2.0.144 (John's parts-login campaign): the registrable domain (eTLD+1) of a host, so a+// credential saved on ONE host of a site works on its SIBLINGS — exactly what a browser password+// manager does (a login saved on accounts.example.com is offered on www.example.com). The imported+// browser logins land under whatever host the user saved them on (e.g. ms.componentsearchengine.com),+// but the download/part pages live on the apex (componentsearchengine.com); without this, pup would+// hold the login and still be unable to use it. Heuristic PSL: last two labels, widened to three for+// the common two-part public suffixes (co.uk, com.au, …) so we never over-broaden "bbc.co.uk" to "co.uk".+const _TWO_PART_TLDS = new Set(['co.uk', 'org.uk', 'gov.uk', 'ac.uk', 'com.au', 'net.au', 'org.au', 'co.nz', 'co.jp', 'co.kr', 'com.br', 'com.cn', 'co.in', 'co.za']);+function registrableDomain(host) {+  if (!host) return '';+  const parts = String(host).toLowerCase().replace(/\.$/, '').split('.');+  if (parts.length <= 2) return parts.join('.');+  const lastTwo = parts.slice(-2).join('.');+  if (_TWO_PART_TLDS.has(lastTwo)) return parts.slice(-3).join('.');+  return lastTwo;+}+ function hostMatchesPattern(host, pattern) {   if (!host || !pattern) return false;   const h = host.toLowerCase();@@ -86,16 +103,24 @@ function hostMatchesPattern(host, pattern) {     if (h === suffix.slice(1)) return true;     // bare apex is a valid match     if (h.endsWith(suffix)) return true;   }+  // v2.0.144: same-registrable-domain (sibling host) match, like a browser password manager.+  // Only for non-glob stored hosts; scored below exact/glob so a precise entry always wins first.+  if (!p.startsWith('*.') && registrableDomain(h) && registrableDomain(h) === registrableDomain(p)) return true;   return false; }  // "Best match" = longest non-glob suffix wins. Exact match beats glob match-// of the same length. So "nxp.componentsearchengine.com" entry would win-// over "*.componentsearchengine.com" entry for that exact host.+// of the same length, and both beat a same-registrable-domain sibling match.+// So "nxp.componentsearchengine.com" entry would win over "*.componentsearchengine.com"+// which wins over a sibling like "ms.componentsearchengine.com" for host componentsearchengine.com. function scorePattern(pattern, host) {   if (!hostMatchesPattern(host, pattern)) return -1;-  const exact = !pattern.startsWith('*.');-  return (exact ? 1000 : 0) + pattern.length;+  const h = host.toLowerCase();+  const p = pattern.toLowerCase();+  const exact = p === h;+  const glob = p.startsWith('*.');+  const sibling = !exact && !glob;   // matched only via registrable-domain+  return (exact ? 2000 : glob ? 1000 : sibling ? 500 : 0) + pattern.length; }  // ── Public API ─────────────────────────────────────────────────────────