diff --git a/CHANGELOG.md b/CHANGELOG.md index b3015a115..ed16210a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ ### Fixed - Localization: improve Simplified Chinese settings and menu translations (#1059). Thanks @narallee! +- Alibaba Token Plan: reject non-HTTPS endpoint overrides and keep the provider building on Linux (#1104). Thanks @YanxinXue! - Build scripts: derive the local development signing team ID from the certificate OU before falling back to the CN suffix (#1095). - Menu bar: keep retrying display-change recovery when macOS leaves status items detached from the current screen (#1077, #1088). - Codex: preserve last successful per-account quota snapshots when later network or DNS refreshes fail (#1097, #1101). Thanks @Yuxin-Qiao! diff --git a/Sources/CodexBarCore/Providers/Alibaba/AlibabaTokenPlanCookieHeader.swift b/Sources/CodexBarCore/Providers/Alibaba/AlibabaTokenPlanCookieHeader.swift index 03791cc95..60c2ab24b 100644 --- a/Sources/CodexBarCore/Providers/Alibaba/AlibabaTokenPlanCookieHeader.swift +++ b/Sources/CodexBarCore/Providers/Alibaba/AlibabaTokenPlanCookieHeader.swift @@ -1,4 +1,7 @@ import Foundation +#if canImport(FoundationNetworking) +import FoundationNetworking +#endif struct AlibabaTokenPlanCookieHeaders: Sendable { private static let cachedAPIHeaderName = "__codexbar_alibaba_token_plan_api" diff --git a/Sources/CodexBarCore/Providers/Alibaba/AlibabaTokenPlanSettingsReader.swift b/Sources/CodexBarCore/Providers/Alibaba/AlibabaTokenPlanSettingsReader.swift index ba7c5c3a3..61948299b 100644 --- a/Sources/CodexBarCore/Providers/Alibaba/AlibabaTokenPlanSettingsReader.swift +++ b/Sources/CodexBarCore/Providers/Alibaba/AlibabaTokenPlanSettingsReader.swift @@ -14,15 +14,19 @@ public struct AlibabaTokenPlanSettingsReader: Sendable { public static func hostOverride( environment: [String: String] = ProcessInfo.processInfo.environment) -> String? { - self.cleaned(environment[self.hostKey]) + guard let raw = self.cleaned(environment[self.hostKey]) else { return nil } + if let scheme = URL(string: raw)?.scheme { + return scheme.lowercased() == "https" ? raw : nil + } + return raw } public static func quotaURL( environment: [String: String] = ProcessInfo.processInfo.environment) -> URL? { guard let raw = self.cleaned(environment[self.quotaURLKey]) else { return nil } - if let url = URL(string: raw), url.scheme != nil { - return url + if let url = URL(string: raw), let scheme = url.scheme { + return scheme.lowercased() == "https" ? url : nil } return URL(string: "https://\(raw)") } diff --git a/Tests/CodexBarTests/AlibabaTokenPlanProviderTests.swift b/Tests/CodexBarTests/AlibabaTokenPlanProviderTests.swift index 853f2412c..65922a235 100644 --- a/Tests/CodexBarTests/AlibabaTokenPlanProviderTests.swift +++ b/Tests/CodexBarTests/AlibabaTokenPlanProviderTests.swift @@ -11,6 +11,46 @@ struct AlibabaTokenPlanSettingsReaderTests { #expect(cookie == "login_aliyunid_ticket=ticket") } + @Test + func `quota URL infers HTTPS scheme`() { + let url = AlibabaTokenPlanSettingsReader.quotaURL(environment: [ + AlibabaTokenPlanSettingsReader.quotaURLKey: "quota.token-plan.test/data/api.json", + ]) + + #expect(url?.scheme == "https") + #expect(url?.host == "quota.token-plan.test") + } + + @Test + func `quota URL rejects non HTTPS schemes`() { + let httpURL = AlibabaTokenPlanSettingsReader.quotaURL(environment: [ + AlibabaTokenPlanSettingsReader.quotaURLKey: "http://quota.token-plan.test/data/api.json", + ]) + let ftpURL = AlibabaTokenPlanSettingsReader.quotaURL(environment: [ + AlibabaTokenPlanSettingsReader.quotaURLKey: "ftp://quota.token-plan.test/data/api.json", + ]) + + #expect(httpURL == nil) + #expect(ftpURL == nil) + } + + @Test + func `host override rejects non HTTPS schemes`() { + let httpHost = AlibabaTokenPlanSettingsReader.hostOverride(environment: [ + AlibabaTokenPlanSettingsReader.hostKey: "http://dashboard.token-plan.test", + ]) + let httpsHost = AlibabaTokenPlanSettingsReader.hostOverride(environment: [ + AlibabaTokenPlanSettingsReader.hostKey: "https://dashboard.token-plan.test", + ]) + let bareHost = AlibabaTokenPlanSettingsReader.hostOverride(environment: [ + AlibabaTokenPlanSettingsReader.hostKey: "dashboard.token-plan.test", + ]) + + #expect(httpHost == nil) + #expect(httpsHost == "https://dashboard.token-plan.test") + #expect(bareHost == "dashboard.token-plan.test") + } + @Test func `default quota URL targets token plan API`() { let url = AlibabaTokenPlanUsageFetcher.defaultQuotaURL