This commit is contained in:
samque1983 2026-07-14 19:17:08 -07:00 committed by GitHub
commit 07693af1bf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 43 additions and 0 deletions

View File

@ -15,6 +15,7 @@
* restores state. Falls back to clean slate on any failure.
*/
import { execSync } from 'child_process';
import { chromium, type Browser, type BrowserContext, type BrowserContextOptions, type Page, type Locator, type Cookie } from 'playwright';
import { writeSecureFile, mkdirSecure } from './file-permissions';
import { addConsoleEntry, addNetworkEntry, addDialogEntry, networkBuffer, type DialogEntry } from './buffers';
@ -354,6 +355,48 @@ export class BrowserManager {
launchArgs.push('--no-sandbox');
}
// System proxy handling on macOS. Local VPN/proxy apps (Shadowrocket,
// ClashX, Surge) intercept traffic in TWO modes that need OPPOSITE
// Chromium configs:
//
// HTTP-proxy-only mode: app registers at 127.0.0.1:<port> as an HTTPS
// proxy. Chromium inherits via system proxy → proxy MITMs TLS →
// Chromium rejects the MITM cert → net_error -100. Fix:
// --proxy-server=direct:// bypasses the proxy entirely.
//
// TUN mode: app creates a utun interface (typically 198.18.0.0/15,
// the IANA benchmark range) and captures ALL traffic at the
// routing layer. direct:// does NOT escape — packets still flow
// through TUN and get MITM'd. But when Chromium connects to the
// HTTPS proxy explicitly (inherited from system), the proxy
// serves a cert signed by a CA installed in the macOS keychain
// that Chromium trusts on that path → works. So: no flag works,
// direct:// breaks.
//
// Default: opt-in via BROWSE_NO_PROXY=1 (preserves original behavior).
// Auto-override: if user set =1 but current VPN is in TUN mode
// (detected via utun interface in 198.18.x.x), skip the flag and log.
// This protects users with `export BROWSE_NO_PROXY=1` in their shell
// rc when their VPN app silently switches modes.
if (process.env.BROWSE_NO_PROXY === '1') {
let tunMode = false;
if (process.platform === 'darwin') {
try {
const ifOut = execSync('ifconfig', { encoding: 'utf8', timeout: 2000 });
tunMode = /^utun\d+:[\s\S]*?inet 198\.18\./m.test(ifOut);
} catch {
// ifconfig failed — assume non-TUN (preserves original behavior).
}
}
if (tunMode) {
console.log('[browse] BROWSE_NO_PROXY=1 but VPN appears to be in TUN mode (utun with 198.18.x.x). Skipping --proxy-server=direct:// because it would break TLS in this mode. Set BROWSE_NO_PROXY=force to override.');
} else {
launchArgs.push('--proxy-server=direct://');
}
} else if (process.env.BROWSE_NO_PROXY === 'force') {
launchArgs.push('--proxy-server=direct://');
}
if (extensionsDir) {
// Skip --load-extension when running against a custom Chromium build that
// already bakes the extension in (e.g., GBrowser / GStack Browser.app).