Files
openidea/src/platform/proxySettings.ts
T
l0ng-aiandClaude 9d4e778c7b feat(settings): HTTP Proxy settings for the IDE's outgoing connections (#194)
* feat(settings): HTTP Proxy settings for the IDE's outgoing connections

Add Appearance & Behavior › System Settings › HTTP Proxy with three modes:
No proxy, Auto-detect proxy settings (the default; environment proxy as
before) and Manual proxy configuration (HTTP or SOCKS, host and port, a
comma-separated "No proxy for" list with `*` wildcards, optional proxy
authentication). "Check connection…" GETs a URL with the settings as edited
and reports the status or the error.

- ide-core: `ProxySettings` plus routing (no-proxy globs, loopback always
  direct, credentials percent-encoded), the current proxy for the process,
  curl arguments and child-process variables.
- ide-http: `client::build` / `client::shared` is the one HTTP client
  constructor; the HTTP Client requests and the update check go through it.
- ide-tools: curl downloads (tools, JDKs, debug adapters, agent registry,
  remote server) follow the setting.
- A manual proxy reaches child processes (language servers, debug adapters,
  terminals, git) as HTTP_PROXY / HTTPS_PROXY / ALL_PROXY / NO_PROXY.
- The proxy password is kept in the owner-only saved passwords file
  (`proxy-password.json` in the app data directory), not in settings.toml.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(host): Allow the Unix-only post-start test helpers on Windows

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-29 10:43:30 +08:00

83 lines
2.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* System Settings › HTTP Proxy as the UI consumes it (mirrors
* `ide-core::proxy_settings` defaults). Normalisation never throws.
*/
export type ProxyModeValid = "none" | "auto" | "manual";
export type ProxyKindValid = "http" | "socks";
export interface ProxySettingsValid {
mode: ProxyModeValid;
kind: ProxyKindValid;
host: string;
port: number;
/** Comma-separated host globs reached directly (`*.example.com, 192.168.*`). */
noProxy: string;
authenticate: boolean;
login: string;
/** Kept in the saved passwords by the backend, not in settings.toml. */
password: string;
}
export const PROXY_DEFAULT_PORT: Record<ProxyKindValid, number> = {
http: 80,
socks: 1080,
};
export const PROXY_PORT_LIMITS = { min: 1, max: 65535 } as const;
export const DEFAULT_PROXY: ProxySettingsValid = {
mode: "auto",
kind: "http",
host: "",
port: PROXY_DEFAULT_PORT.http,
noProxy: "",
authenticate: false,
login: "",
password: "",
};
type Obj = Record<string, unknown>;
const obj = (v: unknown): Obj => (v && typeof v === "object" && !Array.isArray(v) ? (v as Obj) : {});
const str = (v: unknown) => (typeof v === "string" ? v : "");
export function validateProxy(raw: unknown): ProxySettingsValid {
const p = obj(raw);
const mode: ProxyModeValid = p.mode === "none" || p.mode === "manual" ? p.mode : "auto";
const kind: ProxyKindValid = p.kind === "socks" ? "socks" : "http";
const port =
typeof p.port === "number" &&
Number.isInteger(p.port) &&
p.port >= PROXY_PORT_LIMITS.min &&
p.port <= PROXY_PORT_LIMITS.max
? p.port
: PROXY_DEFAULT_PORT[kind];
return {
mode,
kind,
host: str(p.host),
port,
noProxy: str(p.noProxy),
authenticate: p.authenticate === true,
login: str(p.login),
password: str(p.password),
};
}
/** Switching HTTP ⇄ SOCKS moves a default port along. */
export function withProxyKind(p: ProxySettingsValid, kind: ProxyKindValid): ProxySettingsValid {
const port = p.port === PROXY_DEFAULT_PORT[p.kind] ? PROXY_DEFAULT_PORT[kind] : p.port;
return { ...p, kind, port };
}
/** What keeps a manual configuration from working (as the backend checks it), or `null`. */
export function proxyProblem(p: ProxySettingsValid): string | null {
if (p.mode !== "manual") return null;
const host = p.host.trim();
if (!host) return "Proxy host is empty";
if (/[/@\s]/.test(host)) return "Invalid proxy host";
if (p.port < PROXY_PORT_LIMITS.min || p.port > PROXY_PORT_LIMITS.max) {
return "Proxy port must be between 1 and 65535";
}
if (p.authenticate && !p.login.trim()) return "Proxy login is empty";
return null;
}