mirror of
https://github.com/garrytan/gstack.git
synced 2026-06-17 15:20:11 +02:00
7e7530ea3f
Adds browse/src/socks-bridge.ts: a 127.0.0.1-only SOCKS5 listener that
accepts unauthenticated connections from Chromium and relays them through
an authenticated upstream proxy. Chromium does not prompt for SOCKS5 auth
at launch, so this bridge is the workaround for using auth-required
residential SOCKS5 upstreams.
- startSocksBridge({ upstream, port: 0 }) → ephemeral 127.0.0.1 listener
- testUpstream({ upstream, retries: 3, backoffMs: 500, budgetMs: 5000 })
pre-flight that connects to a known endpoint (default 1.1.1.1:443)
- Stream-error policy: kill affected client + upstream sockets on any
error mid-stream; no transport retries (a transport-layer retry can
corrupt browser traffic)
Adds browse/src/proxy-redact.ts: single source of truth for redacting
credentials in any logged proxy URL or upstream config. Every code path
that prints proxy config goes through this helper.
Adds the socks npm dep (~30KB) and 16 tests covering: 127.0.0.1-only
bind, byte-for-byte round trip through the bridge, auth rejection,
mid-stream upstream drop kills client conn, listener teardown,
testUpstream success + retry-exhaust paths, redaction of every
credential shape.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
47 lines
1.4 KiB
TypeScript
47 lines
1.4 KiB
TypeScript
/**
|
|
* Single source of truth for redacting proxy credentials in log lines.
|
|
*
|
|
* Anywhere browse logs a proxy URL (startup banner, error messages, debug
|
|
* output), it MUST go through redactProxyUrl first. Tests assert this for
|
|
* every log path that prints proxy config.
|
|
*/
|
|
|
|
const REDACTED = '***';
|
|
|
|
/**
|
|
* Redact creds in a proxy URL string. Returns the URL with username and
|
|
* password replaced by '***'. If the input isn't parseable as a URL, returns
|
|
* a generic placeholder rather than echoing it back (input may be malformed
|
|
* AND contain creds).
|
|
*/
|
|
export function redactProxyUrl(input: string | null | undefined): string {
|
|
if (!input) return '<no proxy>';
|
|
let url: URL;
|
|
try {
|
|
url = new URL(input);
|
|
} catch {
|
|
return '<malformed proxy url>';
|
|
}
|
|
if (url.username) url.username = REDACTED;
|
|
if (url.password) url.password = REDACTED;
|
|
return url.toString();
|
|
}
|
|
|
|
/**
|
|
* Redact creds in an upstream config object (host/port/userId/password).
|
|
* Returns a plain object suitable for logging.
|
|
*/
|
|
export function redactUpstream(upstream: {
|
|
host: string;
|
|
port: number;
|
|
userId?: string;
|
|
password?: string;
|
|
}): { host: string; port: number; userId?: string; password?: string } {
|
|
return {
|
|
host: upstream.host,
|
|
port: upstream.port,
|
|
...(upstream.userId ? { userId: REDACTED } : {}),
|
|
...(upstream.password ? { password: REDACTED } : {}),
|
|
};
|
|
}
|