export type NetworkProxyMode = 'system' | 'manual' | 'direct' export type NetworkProxySettings = Readonly<{ mode: NetworkProxyMode server?: string bypassRules?: string }> export const DEFAULT_NETWORK_PROXY_SETTINGS: NetworkProxySettings = Object.freeze({ mode: 'system' }) const SUPPORTED_PROXY_PROTOCOLS = new Set(['http:', 'https:', 'socks:', 'socks4:', 'socks5:']) const normalizeBypassRules = (value: unknown): string | undefined => { if (typeof value !== 'string') return undefined const entries = value .split(/[,;\n]/) .map((entry) => entry.trim()) .filter(Boolean) return entries.length > 0 ? [...new Set(entries)].join(',') : undefined } const normalizeProxyServer = (value: unknown): string | undefined => { if (typeof value !== 'string' || !value.trim()) return undefined try { const url = new URL(value.trim()) if ( !SUPPORTED_PROXY_PROTOCOLS.has(url.protocol) || !url.hostname || url.username || url.password || (url.pathname !== '' && url.pathname !== '/') || url.search || url.hash ) { return undefined } return `${url.protocol}//${url.host}` } catch { return undefined } } export const networkProxyValidationMessage = (value: unknown): string | undefined => { if (!value || typeof value !== 'object') return 'Choose a proxy mode.' const candidate = value as Record if (candidate.mode !== 'system' && candidate.mode !== 'manual' && candidate.mode !== 'direct') { return 'Choose System, Manual, or Direct.' } if (candidate.mode !== 'manual') return undefined if (typeof candidate.server !== 'string' || !candidate.server.trim()) { return 'Enter a proxy server URL, for example http://127.0.0.1:1086.' } try { const url = new URL(candidate.server.trim()) if (!SUPPORTED_PROXY_PROTOCOLS.has(url.protocol)) { return 'Use an http, https, socks, socks4, or socks5 proxy URL.' } if (!url.hostname) return 'Enter a proxy URL with a host name or IP address.' if (url.username || url.password) { return 'Proxy URLs with embedded usernames or passwords are not supported.' } if ((url.pathname !== '' && url.pathname !== '/') || url.search || url.hash) { return 'Enter only the proxy scheme, host, and optional port.' } } catch { return 'Enter a complete proxy URL, for example http://127.0.0.1:1086.' } return undefined } export const normalizeNetworkProxySettings = (value: unknown): NetworkProxySettings | undefined => { if (networkProxyValidationMessage(value)) return undefined const candidate = value as Record if (candidate.mode === 'system') return DEFAULT_NETWORK_PROXY_SETTINGS if (candidate.mode === 'direct') return Object.freeze({ mode: 'direct' }) const server = normalizeProxyServer(candidate.server) if (!server) return undefined const bypassRules = normalizeBypassRules(candidate.bypassRules) return Object.freeze({ mode: 'manual', server, ...(bypassRules ? { bypassRules } : {}) }) } export const resolveNetworkProxySettings = (value: unknown): NetworkProxySettings => normalizeNetworkProxySettings(value) ?? DEFAULT_NETWORK_PROXY_SETTINGS