105 lines
3.8 KiB
Swift
105 lines
3.8 KiB
Swift
import Foundation
|
|
|
|
public enum TokenAccountInjection: Sendable {
|
|
case cookieHeader
|
|
case environment(key: String)
|
|
}
|
|
|
|
public struct TokenAccountSupport: Sendable {
|
|
public let title: String
|
|
public let subtitle: String
|
|
public let placeholder: String
|
|
public let injection: TokenAccountInjection
|
|
public let requiresManualCookieSource: Bool
|
|
public let cookieName: String?
|
|
public let environmentKeysToScrub: [String]
|
|
|
|
public init(
|
|
title: String,
|
|
subtitle: String,
|
|
placeholder: String,
|
|
injection: TokenAccountInjection,
|
|
requiresManualCookieSource: Bool,
|
|
cookieName: String?,
|
|
environmentKeysToScrub: [String] = [])
|
|
{
|
|
self.title = title
|
|
self.subtitle = subtitle
|
|
self.placeholder = placeholder
|
|
self.injection = injection
|
|
self.requiresManualCookieSource = requiresManualCookieSource
|
|
self.cookieName = cookieName
|
|
self.environmentKeysToScrub = environmentKeysToScrub
|
|
}
|
|
}
|
|
|
|
public enum TokenAccountSupportCatalog {
|
|
public static func support(for provider: UsageProvider) -> TokenAccountSupport? {
|
|
supportByProvider[provider]
|
|
}
|
|
|
|
public static func envOverride(for provider: UsageProvider, token: String) -> [String: String]? {
|
|
guard let support = self.support(for: provider) else { return nil }
|
|
switch support.injection {
|
|
case let .environment(key):
|
|
return [key: token]
|
|
case .cookieHeader:
|
|
if provider == .claude,
|
|
case let route = ClaudeCredentialRouting.resolve(tokenAccountToken: token, manualCookieHeader: nil)
|
|
{
|
|
switch route {
|
|
case let .oauth(accessToken):
|
|
return [ClaudeOAuthCredentialsStore.environmentTokenKey: accessToken]
|
|
case let .adminAPIKey(apiKey):
|
|
return [ClaudeAdminAPISettingsReader.adminAPIKeyEnvironmentKey: apiKey]
|
|
case .none, .webCookie:
|
|
break
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
}
|
|
|
|
public static func scrubEnvironmentForSelectedAccount(
|
|
_ environment: inout [String: String],
|
|
provider: UsageProvider,
|
|
token _: String)
|
|
{
|
|
guard let support = self.support(for: provider) else { return }
|
|
switch support.injection {
|
|
case let .environment(key):
|
|
environment.removeValue(forKey: key)
|
|
for key in support.environmentKeysToScrub {
|
|
environment.removeValue(forKey: key)
|
|
}
|
|
case .cookieHeader:
|
|
guard provider == .claude else { return }
|
|
environment.removeValue(forKey: ClaudeOAuthCredentialsStore.environmentTokenKey)
|
|
for key in ClaudeAdminAPISettingsReader.apiKeyEnvironmentKeys {
|
|
environment.removeValue(forKey: key)
|
|
}
|
|
}
|
|
}
|
|
|
|
public static func normalizedCookieHeader(for provider: UsageProvider, token: String) -> String {
|
|
guard let support = self.support(for: provider) else {
|
|
return token.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
}
|
|
return self.normalizedCookieHeader(token, support: support)
|
|
}
|
|
|
|
public static func isClaudeOAuthToken(_ token: String) -> Bool {
|
|
ClaudeCredentialRouting.resolve(tokenAccountToken: token, manualCookieHeader: nil).isOAuth
|
|
}
|
|
|
|
public static func normalizedCookieHeader(_ token: String, support: TokenAccountSupport) -> String {
|
|
let trimmed = token.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
guard let cookieName = support.cookieName else { return trimmed }
|
|
let lower = trimmed.lowercased()
|
|
if lower.contains("cookie:") || trimmed.contains("=") {
|
|
return trimmed
|
|
}
|
|
return "\(cookieName)=\(trimmed)"
|
|
}
|
|
}
|