-
Notifications
You must be signed in to change notification settings - Fork 3k
fix(desktop): parse NO_PROXY ports strictly #5498
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,7 +7,10 @@ | |
| /** Split a comma-separated string into trimmed, non-empty entries. */ | ||
| export function splitCommaSeparated(str: string | undefined): string[] { | ||
| if (!str) return []; | ||
| return str.split(',').map(s => s.trim()).filter(Boolean); | ||
| return str | ||
| .split(',') | ||
| .map((s) => s.trim()) | ||
| .filter(Boolean); | ||
| } | ||
|
|
||
| export interface NoProxyRule { | ||
|
|
@@ -19,6 +22,14 @@ export interface NoProxyRule { | |
| wildcard: boolean; | ||
| } | ||
|
|
||
| function parsePort(raw: string): number | undefined { | ||
| if (!/^\d+$/.test(raw)) return undefined; | ||
| const port = Number(raw); | ||
| return Number.isInteger(port) && port >= 0 && port <= 65535 | ||
| ? port | ||
| : undefined; | ||
| } | ||
|
|
||
| /** | ||
| * Parse a comma-separated NO_PROXY string into structured rules. | ||
| * | ||
|
|
@@ -33,8 +44,8 @@ export function parseNoProxyRules(noProxy: string | undefined): NoProxyRule[] { | |
| if (!noProxy) return []; | ||
|
|
||
| return splitCommaSeparated(noProxy) | ||
| .map(entry => entry.toLowerCase()) | ||
| .map(entry => { | ||
| .map((entry) => entry.toLowerCase()) | ||
| .map((entry) => { | ||
| if (entry === '*') { | ||
| return { host: '*', wildcard: true }; | ||
| } | ||
|
|
@@ -49,21 +60,24 @@ export function parseNoProxyRules(noProxy: string | undefined): NoProxyRule[] { | |
| const ipv6Host = cleaned.slice(1, closeBracket); | ||
| const afterBracket = cleaned.slice(closeBracket + 1); | ||
| if (afterBracket.startsWith(':')) { | ||
| const port = parseInt(afterBracket.slice(1), 10); | ||
| if (!isNaN(port)) { | ||
| const port = parsePort(afterBracket.slice(1)); | ||
| if (port !== undefined) { | ||
| return { host: ipv6Host, port, wildcard: false }; | ||
| } | ||
| } | ||
| return { host: ipv6Host, wildcard: false }; | ||
| if (afterBracket === '') { | ||
| return { host: ipv6Host, wildcard: false }; | ||
| } | ||
| return { host: cleaned, wildcard: false }; | ||
| } | ||
| } | ||
|
|
||
| // Check for port (non-IPv6) | ||
| const lastColon = cleaned.lastIndexOf(':'); | ||
| if (lastColon > 0) { | ||
| const host = cleaned.slice(0, lastColon); | ||
| const port = parseInt(cleaned.slice(lastColon + 1), 10); | ||
| if (!isNaN(port)) { | ||
| const port = parsePort(cleaned.slice(lastColon + 1)); | ||
| if (port !== undefined) { | ||
| return { host, port, wildcard: false }; | ||
| } | ||
| } | ||
|
|
@@ -78,14 +92,19 @@ export function parseNoProxyRules(noProxy: string | undefined): NoProxyRule[] { | |
| /** Default ports by protocol, used when URL omits an explicit port. */ | ||
| const DEFAULT_PORTS: Record<string, number> = { 'http:': 80, 'https:': 443 }; | ||
|
|
||
| export function shouldBypassProxy(url: string | URL, rules: NoProxyRule[]): boolean { | ||
| export function shouldBypassProxy( | ||
| url: string | URL, | ||
| rules: NoProxyRule[], | ||
| ): boolean { | ||
| if (rules.length === 0) return false; | ||
|
|
||
| const parsed = typeof url === 'string' ? new URL(url) : url; | ||
| const hostname = parsed.hostname.toLowerCase(); | ||
| // Strip brackets from IPv6 | ||
| const host = hostname.startsWith('[') ? hostname.slice(1, -1) : hostname; | ||
| const port = parsed.port ? parseInt(parsed.port, 10) : DEFAULT_PORTS[parsed.protocol]; | ||
| const port = parsed.port | ||
| ? parseInt(parsed.port, 10) | ||
| : DEFAULT_PORTS[parsed.protocol]; | ||
|
|
||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Suggestion] The PR converts both — DeepSeek/deepseek-v4-pro via Qwen Code /review |
||
| for (const rule of rules) { | ||
| if (rule.wildcard) return true; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[Suggestion] After
/^\d+$/regex validation,Number(raw)always produces a non-negative integer —Number.isInteger()andport >= 0are guaranteed true. Onlyport <= 65535carries decision value.— DeepSeek/deepseek-v4-pro via Qwen Code /review