From 76aab09616f2efbf186b2c3700cc84f4bb6c50f4 Mon Sep 17 00:00:00 2001 From: kaitranntt Date: Tue, 30 Dec 2025 15:03:11 -0500 Subject: [PATCH] fix(cliproxy): use correct default port (8317) for remote HTTP connections MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Root cause: Inconsistent default port logic across code paths. - Test Connection used 8317 (correct) - Actual API calls used 80 (wrong) Changes: - Add centralized getRemoteDefaultPort() helper in config-generator.ts - Fix proxy-target-resolver.ts to use shared helper - Fix rewriteLocalhostUrls() and getRemoteEnvVars() in config-generator.ts - Update remote-proxy-client.ts to use shared helper (DRY) Fixes all 3 reported issues: 1. Port empty → now correctly uses :8317 instead of :80 2. BASEURL construction → now includes correct port 3. CLIProxy Plus auth → now fetches from remote on correct port --- src/cliproxy/config-generator.ts | 63 ++++++++++++++++++++++----- src/cliproxy/proxy-target-resolver.ts | 20 +++++---- src/cliproxy/remote-proxy-client.ts | 17 ++------ 3 files changed, 69 insertions(+), 31 deletions(-) diff --git a/src/cliproxy/config-generator.ts b/src/cliproxy/config-generator.ts index 5a73a2e4..bb4872a7 100644 --- a/src/cliproxy/config-generator.ts +++ b/src/cliproxy/config-generator.ts @@ -62,6 +62,41 @@ function ensureRequiredEnvVars( /** Default CLIProxy port */ export const CLIPROXY_DEFAULT_PORT = 8317; +/** + * Normalize protocol to lowercase and validate. + * Handles runtime case sensitivity (e.g., 'HTTPS' → 'https'). + * Defaults to 'http' for invalid values. + */ +export function normalizeProtocol(protocol: string | undefined): 'http' | 'https' { + if (!protocol) return 'http'; + const normalized = protocol.toLowerCase(); + if (normalized === 'https') return 'https'; + if (normalized === 'http') return 'http'; + // Invalid protocol (e.g., 'ftp') - default to http + return 'http'; +} + +/** + * Validate and sanitize port number for remote connections. + * Returns undefined for invalid ports (letting caller use default). + * Valid range: 1-65535, must be integer. + */ +export function validateRemotePort(port: number | undefined): number | undefined { + if (port === undefined || port === null) return undefined; + if (typeof port !== 'number' || !Number.isInteger(port)) return undefined; + if (port <= 0 || port > 65535) return undefined; + return port; +} + +/** + * Get default port for remote CLIProxyAPI based on protocol. + * - HTTP: 8317 (CLIProxyAPI default) + * - HTTPS: 443 (standard SSL port) + */ +export function getRemoteDefaultPort(protocol: 'http' | 'https'): number { + return protocol === 'https' ? 443 : CLIPROXY_DEFAULT_PORT; +} + /** Internal API key for CCS-managed requests */ export const CCS_INTERNAL_API_KEY = 'ccs-internal-managed'; @@ -548,11 +583,15 @@ function rewriteLocalhostUrls( const localhostPattern = /^https?:\/\/(127\.0\.0\.1|localhost|0\.0\.0\.0)(:\d+)?/i; if (!localhostPattern.test(baseUrl)) return result; - // Build remote URL with smart port handling - const defaultPort = remoteConfig.protocol === 'https' ? 443 : 80; - const effectivePort = remoteConfig.port ?? defaultPort; - const portSuffix = effectivePort === defaultPort ? '' : `:${effectivePort}`; - const remoteBaseUrl = `${remoteConfig.protocol}://${remoteConfig.host}${portSuffix}/api/provider/${provider}`; + // Build remote URL with smart port handling (8317 for HTTP, 443 for HTTPS) + // Validate port and normalize protocol for defensive handling + const normalizedProtocol = normalizeProtocol(remoteConfig.protocol); + const validatedPort = validateRemotePort(remoteConfig.port); + const effectivePort = validatedPort ?? getRemoteDefaultPort(normalizedProtocol); + // Omit port suffix for standard web ports (80/443) for cleaner URLs + const standardWebPort = normalizedProtocol === 'https' ? 443 : 80; + const portSuffix = effectivePort === standardWebPort ? '' : `:${effectivePort}`; + const remoteBaseUrl = `${normalizedProtocol}://${remoteConfig.host}${portSuffix}/api/provider/${provider}`; result.ANTHROPIC_BASE_URL = remoteBaseUrl; @@ -686,11 +725,15 @@ export function getRemoteEnvVars( remoteConfig: { host: string; port?: number; protocol: 'http' | 'https'; authToken?: string }, customSettingsPath?: string ): Record { - // Build URL with smart port handling - omit if using protocol default - const defaultPort = remoteConfig.protocol === 'https' ? 443 : 80; - const effectivePort = remoteConfig.port ?? defaultPort; - const portSuffix = effectivePort === defaultPort ? '' : `:${effectivePort}`; - const baseUrl = `${remoteConfig.protocol}://${remoteConfig.host}${portSuffix}/api/provider/${provider}`; + // Build URL with smart port handling (8317 for HTTP, 443 for HTTPS) + // Validate port and normalize protocol for defensive handling + const normalizedProtocol = normalizeProtocol(remoteConfig.protocol); + const validatedPort = validateRemotePort(remoteConfig.port); + const effectivePort = validatedPort ?? getRemoteDefaultPort(normalizedProtocol); + // Omit port suffix for standard web ports (80/443) for cleaner URLs + const standardWebPort = normalizedProtocol === 'https' ? 443 : 80; + const portSuffix = effectivePort === standardWebPort ? '' : `:${effectivePort}`; + const baseUrl = `${normalizedProtocol}://${remoteConfig.host}${portSuffix}/api/provider/${provider}`; // Get global env vars (DISABLE_TELEMETRY, etc.) const globalEnv = getGlobalEnvVars(); diff --git a/src/cliproxy/proxy-target-resolver.ts b/src/cliproxy/proxy-target-resolver.ts index 64778f44..7124c7a1 100644 --- a/src/cliproxy/proxy-target-resolver.ts +++ b/src/cliproxy/proxy-target-resolver.ts @@ -7,9 +7,12 @@ import { loadOrCreateUnifiedConfig } from '../config/unified-config-loader'; import type { CliproxyServerConfig } from '../config/unified-config-types'; - -/** Default CLIProxyAPI port */ -const DEFAULT_CLIPROXY_PORT = 8317; +import { + CLIPROXY_DEFAULT_PORT, + getRemoteDefaultPort, + normalizeProtocol, + validateRemotePort, +} from './config-generator'; /** Resolved proxy target for making requests */ export interface ProxyTarget { @@ -42,10 +45,11 @@ export function getProxyTarget(): ProxyTarget { const config = loadCliproxyServerConfig(); if (config?.remote?.enabled && config.remote?.host) { - const protocol = config.remote.protocol ?? 'http'; - // Default port based on protocol if not specified - const defaultPort = protocol === 'https' ? 443 : 80; - const port = config.remote.port ?? defaultPort; + // Normalize protocol (handles case sensitivity and invalid values) + const protocol = normalizeProtocol(config.remote.protocol); + // Validate port (returns undefined for invalid, triggering default) + const validatedPort = validateRemotePort(config.remote.port); + const port = validatedPort ?? getRemoteDefaultPort(protocol); return { host: config.remote.host, @@ -58,7 +62,7 @@ export function getProxyTarget(): ProxyTarget { return { host: '127.0.0.1', - port: config?.local?.port ?? DEFAULT_CLIPROXY_PORT, + port: config?.local?.port ?? CLIPROXY_DEFAULT_PORT, protocol: 'http', isRemote: false, }; diff --git a/src/cliproxy/remote-proxy-client.ts b/src/cliproxy/remote-proxy-client.ts index f6b51385..a2197fe0 100644 --- a/src/cliproxy/remote-proxy-client.ts +++ b/src/cliproxy/remote-proxy-client.ts @@ -6,6 +6,7 @@ */ import * as https from 'https'; +import { getRemoteDefaultPort, validateRemotePort } from './config-generator'; /** Error codes for remote proxy status */ export type RemoteProxyErrorCode = @@ -52,17 +53,6 @@ export interface RemoteProxyClientConfig { /** Default timeout for remote proxy requests (aggressive for CLI UX) */ const DEFAULT_TIMEOUT_MS = 2000; -/** - * Get default port for CLIProxyAPI based on protocol. - * - HTTP: 8317 (CLIProxyAPI default for local/dev scenarios) - * - HTTPS: 443 (standard SSL port for production remote servers) - * - * This matches the UI labels shown to users. - */ -function getDefaultPort(protocol: 'http' | 'https'): number { - return protocol === 'https' ? 443 : 8317; -} - /** * Get standard web port for protocol (for URL display omission) * These are the ports that browsers/HTTP clients use by default. @@ -74,10 +64,11 @@ function getStandardWebPort(protocol: 'http' | 'https'): number { /** * Get effective port for CLIProxyAPI connection. - * If port is provided, use it. Otherwise use protocol-based default. + * Validates port and uses protocol-based default for invalid/undefined values. */ function getEffectivePort(port: number | undefined, protocol: 'http' | 'https'): number { - return port ?? getDefaultPort(protocol); + const validatedPort = validateRemotePort(port); + return validatedPort ?? getRemoteDefaultPort(protocol); } /**