console fill: never copy Google session cookies by default (device-bound); own profile in a Chrome started without automation switches

Google binds its session cookies to the device (Device Bound Session Credentials) and signs out
sessions whose cookies look stolen, which can sign the owner out of their real Chrome. The default is
now storebound's own profile per store; storebound starts Chrome itself (--user-data-dir,
--remote-debugging-port=0, no --enable-automation, navigator.webdriver false) and attaches over CDP.
--use-chrome-session google|apple is an explicit opt-in that warns. /signin/rejected is said plainly.
This commit is contained in:
CRTkafa 2026-10-12 07:46:04 +08:00
parent e0bef82b06
commit 0035931734
22 changed files with 456 additions and 156 deletions

View file

@ -8,7 +8,7 @@ import { existsSync, mkdirSync, mkdtempSync, rmSync, symlinkSync, writeFileSync
import { hostname, tmpdir } from 'node:os';
import { join } from 'node:path';
import { openConsoleBrowser } from '../cli/console/session';
import { installedBrowsers, launch, launchCandidates, launchPersistent, profileHolder } from '../cli/shots/browser';
import { installedBrowsers, launch, launchCandidates, launchPersistent, persistentExecutable, profileHolder } from '../cli/shots/browser';
/* eslint-disable @typescript-eslint/no-explicit-any */
@ -123,21 +123,19 @@ describe('profile held by another browser', () => {
});
describe('console fill', () => {
test('the persistent launch gets executablePath = STOREBOUND_CHROME when it is set', async () => {
const exe = join(tmp, 'Chrome for Testing');
writeFileSync(exe, '');
const before = process.env.STOREBOUND_CHROME;
process.env.STOREBOUND_CHROME = exe;
try {
const f = fakeCache('sb-chrome', ['chromium_headless_shell-1187'], { chrome: true });
const b = await openConsoleBrowser(tmp, { store: 'apple', fresh: true, profileDir: join(tmp, 'sb-profile'), say: () => {}, launchDeps: { pw: f.pw } });
expect(b.mode).toBe('profile');
expect(f.calls).toHaveLength(1);
expect(f.calls[0].executablePath).toBe(exe);
expect(f.calls[0].channel).toBeUndefined();
expect(f.calls[0].args).toContain('--restore-last-session');
} finally {
if (before === undefined) delete process.env.STOREBOUND_CHROME; else process.env.STOREBOUND_CHROME = before;
}
test('the window starts STOREBOUND_CHROME first, then Google Chrome, then full Chromium; the copy only Google Chrome', () => {
const i = { storeboundChrome: '/x/Chrome for Testing', chrome: CHROME, chromium: '/c' };
expect(persistentExecutable('visible', i).path).toBe('/x/Chrome for Testing');
expect(persistentExecutable('visible', { ...i, storeboundChrome: null }).path).toBe(CHROME);
expect(persistentExecutable('visible', { storeboundChrome: null, chrome: null, chromium: '/c' }).path).toBe('/c');
expect(persistentExecutable('chrome', i).path).toBe(CHROME);
expect(() => persistentExecutable('chrome', { ...i, chrome: null })).toThrow('Install Google Chrome.');
expect(() => persistentExecutable('visible', { storeboundChrome: null, chrome: null, chromium: null }, { STOREBOUND_CHROME: '/gone' })).toThrow('STOREBOUND_CHROME /gone: no such file');
});
test('openConsoleBrowser with nothing installed: the resolver error, nothing launched', async () => {
const f = fakeCache('none', []);
const e = await openConsoleBrowser(tmp, { store: 'apple', fresh: true, profileDir: join(tmp, 'sb-profile'), say: () => {}, launchDeps: { pw: f.pw, installed: { storeboundChrome: null, chrome: null, chromium: null } } }).catch(x => x as Error);
expect((e as Error).message).toContain('no usable browser');
expect(f.calls).toEqual([]);
});
});