← Commit history
nb 0.4.6: an owner may force_close its own OS window (open_os_window cleanup path was refusing its opener)
5 files changed
+23−9
bridge/BRIDGE_VERSION+1−1@@ -1 +1 @@-0.4.5+0.4.6
bridge/bridge.json+1−1@@ -2,7 +2,7 @@ "manifest_version": 1, "name": "native-browser", "displayName": "Adom Native Browser",- "version": "0.4.5",+ "version": "0.4.6", "expectedExtensionVersion": "0.2.5", "description": "Drives the user's REAL signed-in Chrome/Edge, in two layers. Layer 1 (nb) needs NOTHING installed and works on any machine: nbrowser_open_os_window (open a URL in the user's real profile, background+flashing, the OAuth/consent path), nbrowser_os_windows, nbrowser_profiles, nbrowser_wake_profile, nbrowser_force_close. Layer 2 (nbe, the Adom Native Browser Extension) unlocks the rest: CDP driving (navigate/click/read/screenshot) inside their logged-in profile. The bridge binds an ephemeral loopback port and the native-messaging host pumps stdio <-> bridge.", "homepage": "https://wiki.adom.inc/adom/nb-bridge",
bridge/package.json+1−1@@ -1,6 +1,6 @@ { "name": "adom-native-browser-bridge",- "version": "0.4.5",+ "version": "0.4.6", "private": true, "description": "Native-browser bridge for Bridge (ab): layer 1 (nb) plus layer 2 via nbe, the Adom Native Browser Extension (Chrome + Edge).", "main": "server.js",
bridge/server.js+15−1@@ -1754,7 +1754,21 @@ function dispatch(verb, args) { } catch {} const w = ws.find((x) => x.hwnd === hwnd); if (!w) return resolve({ success: false, errorCode: 'bad_window', error: `hwnd ${hwnd} is not a live BROWSER window`, _hint: 'OS-level force_close only targets real Chrome/Edge windows (Chrome_WidgetWin class). Find candidates with desktop_list_windows; for windows the extension CAN see, use force_close {windowId} instead.' });- for (const [sid, h] of sessionHwnd) if (h === hwnd) return resolve({ success: false, errorCode: 'owned_by_other', error: `⛔ force_close REFUSED: hwnd ${hwnd} belongs to live nbe session '${sid}'. Cross-thread ownership is ABSOLUTE.`, _hint: 'Only that thread may close its window (nbrowser_close_window). If it is truly abandoned its badge idle-expires and its thread cleans up.' });+ // Cross-thread ownership is absolute - but YOUR OWN window is yours to close. Without this+ // owner check the documented cleanup path for open_os_window (force_close {hwnd}, the ONLY way+ // to close an extension-free OS window) refused its own opener as 'owned_by_other', so every+ // conscientious thread that tried to clean up its auth litter was told no (found 2026-08-22+ // during the health audit; the two-step ticket below still gates the actual close).+ for (const [sid, h] of sessionHwnd) {+ if (h !== hwnd) continue;+ const ownerC = sessionCaller.get(sid), ownerT = sessionThread.get(sid);+ const me = (() => { try { const c = callerLabel(); return c && (c.thread || c); } catch { return null; } })();+ const mine = (args.sessionId && args.sessionId === sid)+ || (me && ownerC && String(ownerC.thread || ownerC) === String(me))+ || (me && ownerT && String(ownerT) === String(me));+ if (!mine) return resolve({ success: false, errorCode: 'owned_by_other', error: `⛔ force_close REFUSED: hwnd ${hwnd} belongs to live nbe session '${sid}'. Cross-thread ownership is ABSOLUTE.`, _hint: 'Only that thread may close its window (nbrowser_close_window). If it is truly abandoned its badge idle-expires and its thread cleans up.' });+ break; // it is yours - fall through to the two-step attestation gate+ } if (!args.overrideTicket) { const ticket = 'os-' + Math.random().toString(36).slice(2, 10); _osCloseTickets.set(ticket, { hwnd, expires: Date.now() + 60000 });
native-browser-bridge-manifest.json+5−5@@ -1,8 +1,8 @@ { "manifest_version": 1,- "version": "0.4.5",- "url": "https://wiki.adom.inc/download/adom/nb-bridge/0.4.5/native-browser-bridge-v0.4.5.zip",- "sha256": "44f36006ab9631bf5728d1328af70a93f0fa6adbd3c3ec765dadd430d0393083",- "size": 105314,- "released_at": "2026-08-22T14:23:40Z"+ "version": "0.4.6",+ "url": "https://wiki.adom.inc/download/adom/nb-bridge/0.4.6/native-browser-bridge-v0.4.6.zip",+ "sha256": "1c1200b898c6806e9daf933e82e6baa0ad5c681eaf1e4fba2206b04d19899fdf",+ "size": 105694,+ "released_at": "2026-08-22T14:26:07Z" }