#if os(macOS)import Foundationimport SweetCookieKitimport WebKit @MainActor// swiftlint:disable:next type_body_lengthpublic struct OpenAIDashboardBrowserCookieImporter { public struct FoundAccount: Sendable, Hashable { public let sourceLabel: String public let email: String public init(sourceLabel: String, email: String) { self.sourceLabel = sourceLabel self.email = email } } public enum ImportError: LocalizedError { case noCookiesFound case browserAccessDenied(details: String) case dashboardStillRequiresLogin case noMatchingAccount(found: [FoundAccount]) case manualCookieHeaderInvalid public var errorDescription: String? { switch self { case .noCookiesFound: return "No browser cookies found." case let .browserAccessDenied(details): return "Browser cookie access denied. \(details)" case .dashboardStillRequiresLogin: return "Browser cookies imported, but dashboard still requires login." case let .noMatchingAccount(found): if found.isEmpty { return "No matching OpenAI web session found in browsers." } let display = found .sorted { lhs, rhs in if lhs.sourceLabel == rhs.sourceLabel { return lhs.email < rhs.email } return lhs.sourceLabel < rhs.sourceLabel } .map { "\($0.sourceLabel)=\($0.email)" } .joined(separator: ", ") return "OpenAI web session does not match Codex account. Found: \(display)." case .manualCookieHeaderInvalid: return "Manual cookie header is missing a valid OpenAI session cookie." } } } public struct ImportResult: Sendable { public let sourceLabel: String public let cookieCount: Int public let signedInEmail: String? public let matchesCodexEmail: Bool public init( sourceLabel: String, cookieCount: Int, signedInEmail: String?, matchesCodexEmail: Bool) { self.sourceLabel = sourceLabel self.cookieCount = cookieCount self.signedInEmail = signedInEmail self.matchesCodexEmail = matchesCodexEmail } } public init(browserDetection: BrowserDetection) { self.browserDetection = browserDetection } private let browserDetection: BrowserDetection struct PersistentValidationTimeout: Error {} nonisolated static func shouldTrustVerifiedSession(afterPersistFailure error: Error) -> Bool { error is PersistentValidationTimeout } nonisolated static func persistentValidationFailure(_ error: Error) -> Error { let nsError = error as NSError guard nsError.domain == NSURLErrorDomain, nsError.code == NSURLErrorTimedOut else { return error } return PersistentValidationTimeout() } private struct ImportDiagnostics { var mismatches: [FoundAccount] = [] var foundAnyCookies: Bool = false var foundUnknownEmail: Bool = false var accessDeniedHints: [String] = [] } private struct ImportContext { let targetEmail: String? let allowAnyAccount: Bool let cacheScope: CookieHeaderCache.Scope? let deadline: Date? } private static let cookieDomains = ["chatgpt.com", "openai.com"] private nonisolated static let cookieClient = BrowserCookieClient() private static let cookieImportOrder: BrowserCookieImportOrder = ProviderDefaults.metadata[.codex]?.browserCookieOrder ?? Browser.defaultImportOrder private enum CandidateEvaluation { case match(candidate: Candidate, signedInEmail: String) case mismatch(candidate: Candidate, signedInEmail: String) case loggedIn(candidate: Candidate, signedInEmail: String) case unknown(candidate: Candidate) case loginRequired(candidate: Candidate) } public func importBestCookies( intoAccountEmail targetEmail: String?, allowAnyAccount: Bool = false, preferCachedCookieHeader: Bool = true, cacheScope: CookieHeaderCache.Scope? = nil, deadline: Date? = nil, logger: ((String) -> Void)? = nil) async throws -> ImportResult { let log: (String) -> Void = { message in logger?("[web] \(message)") } let targetEmail = targetEmail?.trimmingCharacters(in: .whitespacesAndNewlines) let normalizedTarget = targetEmail?.isEmpty == false ? targetEmail : nil let context = ImportContext( targetEmail: normalizedTarget, allowAnyAccount: allowAnyAccount, cacheScope: cacheScope, deadline: deadline) if normalizedTarget != nil { log("Codex email known; matching required.") } else { guard context.allowAnyAccount else { throw ImportError.noCookiesFound } log("Codex email unknown; importing any signed-in session.") } var diagnostics = ImportDiagnostics() if preferCachedCookieHeader { let cached = try await Self.runBoundedCookieCacheOperation(deadline: deadline) { CookieHeaderCache.loadSerialized(provider: .codex, scope: cacheScope) } if let cached, !cached.cookieHeader.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty { log("Using cached cookie header from \(cached.sourceLabel)") do { return try await self.importManualCookies( cookieHeader: cached.cookieHeader, intoAccountEmail: context.targetEmail, allowAnyAccount: context.allowAnyAccount, cacheScope: cacheScope, deadline: deadline, logger: log) } catch let error as ImportError { switch error { case .manualCookieHeaderInvalid, .noMatchingAccount, .dashboardStillRequiresLogin: do { _ = try await Self.runBoundedCookieCacheOperation(deadline: deadline) { CookieHeaderCache.clear(provider: .codex, scope: cacheScope) } } catch { log("Stale cookie cache cleanup did not finish before the web deadline.") } default: throw error } } catch { throw error } } } else { log("Skipping cached cookie header; forcing fresh browser import") } // Filter to cookie-eligible browsers to avoid unnecessary keychain prompts let installedBrowsers = Self.cookieImportOrder.cookieImportCandidates(using: self.browserDetection) for browserSource in installedBrowsers { _ = try Self.remainingTimeout(until: deadline) if let match = try await self.trySource( browserSource, context: context, deadline: deadline, log: log, diagnostics: &diagnostics) { return match } } _ = try Self.remainingTimeout(until: deadline) if !diagnostics.mismatches.isEmpty { let found = Array(Set(diagnostics.mismatches)).sorted { lhs, rhs in if lhs.sourceLabel == rhs.sourceLabel { return lhs.email < rhs.email } return lhs.sourceLabel < rhs.sourceLabel } log("No matching browser session found. Candidate count: \(found.count)") throw ImportError.noMatchingAccount(found: found) } if diagnostics.foundUnknownEmail || diagnostics.foundAnyCookies { log("No matching browser session found (email unknown).") throw ImportError.noMatchingAccount(found: []) } if !diagnostics.accessDeniedHints.isEmpty { let details = diagnostics.accessDeniedHints.joined(separator: " ") log("Cookie access denied: \(details)") throw ImportError.browserAccessDenied(details: details) } throw ImportError.noCookiesFound } public func importManualCookies( cookieHeader: String, intoAccountEmail targetEmail: String?, allowAnyAccount: Bool = false, cacheScope: CookieHeaderCache.Scope? = nil, deadline: Date? = nil, logger: ((String) -> Void)? = nil) async throws -> ImportResult { let log: (String) -> Void = { message in logger?("[web] \(message)") } let normalizedTarget = targetEmail?.trimmingCharacters(in: .whitespacesAndNewlines) let allowAnyAccount = allowAnyAccount || normalizedTarget == nil || normalizedTarget?.isEmpty == true guard let normalized = CookieHeaderNormalizer.normalize(cookieHeader) else { throw ImportError.manualCookieHeaderInvalid } let pairs = CookieHeaderNormalizer.pairs(from: normalized) guard !pairs.isEmpty else { throw ImportError.manualCookieHeaderInvalid } let cookies = self.cookies(from: pairs) guard !cookies.isEmpty else { throw ImportError.manualCookieHeaderInvalid } let candidate = Candidate(label: "Manual", cookies: cookies) switch try await self.evaluateCandidate( candidate, targetEmail: normalizedTarget, allowAnyAccount: allowAnyAccount, deadline: deadline, log: log) { case let .match(_, signedInEmail): return try await self.persistVerifiedCandidate( candidate: candidate, targetEmail: signedInEmail, cacheScope: cacheScope, deadline: deadline, logger: log) case let .loggedIn(_, signedInEmail): return try await self.persistVerifiedCandidate( candidate: candidate, targetEmail: signedInEmail, cacheScope: cacheScope, deadline: deadline, logger: log) case let .mismatch(_, signedInEmail): throw ImportError.noMatchingAccount(found: [FoundAccount(sourceLabel: "Manual", email: signedInEmail)]) case .unknown: if allowAnyAccount { return try await self.persistToDefaultStore( candidate: candidate, deadline: deadline, logger: log) } throw ImportError.noMatchingAccount(found: []) case .loginRequired: throw ImportError.manualCookieHeaderInvalid } } private func trySafari( context: ImportContext, deadline: Date?, log: @escaping (String) -> Void, diagnostics: inout ImportDiagnostics) async throws -> ImportResult? { // Safari first: avoids touching Keychain ("Chrome Safe Storage") when Safari already matches. do { let query = BrowserCookieQuery(domains: Self.cookieDomains) let sources = try await Self.runBoundedCookieLoad(deadline: deadline) { try Self.cookieClient.codexBarRecords(matching: query, in: .safari) } _ = try Self.remainingTimeout(until: deadline) guard !sources.isEmpty else { log("Safari contained 0 matching records.") return nil } for source in sources { _ = try Self.remainingTimeout(until: deadline) let cookies = BrowserCookieClient.makeHTTPCookies(source.records, origin: query.origin) guard !cookies.isEmpty else { log("\(source.label) produced 0 HTTPCookies.") continue } diagnostics.foundAnyCookies = true log("Loaded \(cookies.count) cookies from \(source.label) (\(self.cookieSummary(cookies)))") let candidate = Candidate(label: source.label, cookies: cookies) if let match = try await self.applyCandidate( candidate, context: context, deadline: deadline, log: log, diagnostics: &diagnostics) { return match } } return nil } catch let error as URLError where error.code == .timedOut { throw error } catch let error as BrowserCookieError { BrowserCookieAccessGate.recordIfNeeded(error) if let hint = error.accessDeniedHint { diagnostics.accessDeniedHints.append(hint) } log("Safari cookie load failed: \(error.localizedDescription)") return nil } catch { log("Safari cookie load failed: \(error.localizedDescription)") return nil } } /// Generic cookie loader for any non-Safari browser (Chrome, Edge, Firefox, Brave, Arc, etc.). /// SweetCookieKit handles engine-specific decryption internally. private func tryBrowser( _ browser: Browser, context: ImportContext, deadline: Date?, log: @escaping (String) -> Void, diagnostics: inout ImportDiagnostics) async throws -> ImportResult? { do { let query = BrowserCookieQuery(domains: Self.cookieDomains) let sources = try await Self.runBoundedCookieLoad(deadline: deadline) { try Self.cookieClient.codexBarRecords(matching: query, in: browser) } _ = try Self.remainingTimeout(until: deadline) guard !sources.isEmpty else { log("\(browser.displayName) contained 0 matching records.") return nil } for source in sources { _ = try Self.remainingTimeout(until: deadline) let cookies = BrowserCookieClient.makeHTTPCookies(source.records, origin: query.origin) guard !cookies.isEmpty else { log("\(source.label) produced 0 HTTPCookies.") continue } diagnostics.foundAnyCookies = true log("Loaded \(cookies.count) cookies from \(source.label) (\(self.cookieSummary(cookies)))") let candidate = Candidate(label: source.label, cookies: cookies) if let match = try await self.applyCandidate( candidate, context: context, deadline: deadline, log: log, diagnostics: &diagnostics) { return match } } return nil } catch let error as URLError where error.code == .timedOut { throw error } catch let error as BrowserCookieError { BrowserCookieAccessGate.recordIfNeeded(error) if let hint = error.accessDeniedHint { diagnostics.accessDeniedHints.append(hint) } log("\(browser.displayName) cookie load failed: \(error.localizedDescription)") return nil } catch { log("\(browser.displayName) cookie load failed: \(error.localizedDescription)") return nil } } private func trySource( _ source: Browser, context: ImportContext, deadline: Date?, log: @escaping (String) -> Void, diagnostics: inout ImportDiagnostics) async throws -> ImportResult? { switch source { case .safari: try await self.trySafari( context: context, deadline: deadline, log: log, diagnostics: &diagnostics) default: // All non-Safari browsers (Chrome, Edge, Firefox, Brave, Arc, etc.) // share the same cookie loading path via SweetCookieKit. try await self.tryBrowser( source, context: context, deadline: deadline, log: log, diagnostics: &diagnostics) } } private func applyCandidate( _ candidate: Candidate, context: ImportContext, deadline: Date?, log: @escaping (String) -> Void, diagnostics: inout ImportDiagnostics) async throws -> ImportResult? { switch try await self.evaluateCandidate( candidate, targetEmail: context.targetEmail, allowAnyAccount: context.allowAnyAccount, deadline: deadline, log: log) { case let .match(candidate, signedInEmail): log("Selected \(candidate.label) (matches Codex: \(signedInEmail))") guard let targetEmail = context.targetEmail else { return nil } if let result = try? await self.persistVerifiedCandidate( candidate: candidate, targetEmail: targetEmail, cacheScope: context.cacheScope, deadline: deadline, logger: log) { await self.cacheCookies( candidate: candidate, scope: context.cacheScope, deadline: deadline, logger: log) return result } _ = try Self.remainingTimeout(until: deadline) return nil case let .mismatch(candidate, signedInEmail): try await self.handleMismatch( candidate: candidate, signedInEmail: signedInEmail, context: context, log: log, diagnostics: &diagnostics) _ = try Self.remainingTimeout(until: deadline) return nil case let .loggedIn(candidate, signedInEmail): log("Selected \(candidate.label) (signed in: \(signedInEmail))") if let result = try? await self.persistVerifiedCandidate( candidate: candidate, targetEmail: signedInEmail, cacheScope: context.cacheScope, deadline: deadline, logger: log) { await self.cacheCookies( candidate: candidate, scope: context.cacheScope, deadline: deadline, logger: log) return result } _ = try Self.remainingTimeout(until: deadline) return nil case .unknown: if context.allowAnyAccount { log("Selected \(candidate.label) (signed in: unknown)") if let result = try? await self.persistToDefaultStore( candidate: candidate, deadline: deadline, logger: log) { await self.cacheCookies( candidate: candidate, scope: context.cacheScope, deadline: deadline, logger: log) return result } _ = try Self.remainingTimeout(until: deadline) return nil } diagnostics.foundUnknownEmail = true return nil case .loginRequired: return nil } } private func evaluateCandidate(Lines 1–500 of 974. Load more
#if os(macOS) import Foundation import SweetCookieKit import WebKit @MainActor // swiftlint:disable:next type_body_length public struct OpenAIDashboardBrowserCookieImporter { public struct FoundAccount: Sendable, Hashable { public let sourceLabel: String public let email: String public init(sourceLabel: String, email: String) { self.sourceLabel = sourceLabel self.email = email } } public enum ImportError: LocalizedError { case noCookiesFound case browserAccessDenied(details: String) case dashboardStillRequiresLogin case noMatchingAccount(found: [FoundAccount]) case manualCookieHeaderInvalid public var errorDescription: String? { switch self { case .noCookiesFound: return "No browser cookies found." case let .browserAccessDenied(details): return "Browser cookie access denied. \(details)" case .dashboardStillRequiresLogin: return "Browser cookies imported, but dashboard still requires login." case let .noMatchingAccount(found): if found.isEmpty { return "No matching OpenAI web session found in browsers." } let display = found .sorted { lhs, rhs in if lhs.sourceLabel == rhs.sourceLabel { return lhs.email < rhs.email } return lhs.sourceLabel < rhs.sourceLabel } .map { "\($0.sourceLabel)=\($0.email)" } .joined(separator: ", ") return "OpenAI web session does not match Codex account. Found: \(display)." case .manualCookieHeaderInvalid: return "Manual cookie header is missing a valid OpenAI session cookie." } } } public struct ImportResult: Sendable { public let sourceLabel: String public let cookieCount: Int public let signedInEmail: String? public let matchesCodexEmail: Bool public init( sourceLabel: String, cookieCount: Int, signedInEmail: String?, matchesCodexEmail: Bool) { self.sourceLabel = sourceLabel self.cookieCount = cookieCount self.signedInEmail = signedInEmail self.matchesCodexEmail = matchesCodexEmail } } public init(browserDetection: BrowserDetection) { self.browserDetection = browserDetection } private let browserDetection: BrowserDetection struct PersistentValidationTimeout: Error {} nonisolated static func shouldTrustVerifiedSession(afterPersistFailure error: Error) -> Bool { error is PersistentValidationTimeout } nonisolated static func persistentValidationFailure(_ error: Error) -> Error { let nsError = error as NSError guard nsError.domain == NSURLErrorDomain, nsError.code == NSURLErrorTimedOut else { return error } return PersistentValidationTimeout() } private struct ImportDiagnostics { var mismatches: [FoundAccount] = [] var foundAnyCookies: Bool = false var foundUnknownEmail: Bool = false var accessDeniedHints: [String] = [] } private struct ImportContext { let targetEmail: String? let allowAnyAccount: Bool let cacheScope: CookieHeaderCache.Scope? let deadline: Date? } private static let cookieDomains = ["chatgpt.com", "openai.com"] private nonisolated static let cookieClient = BrowserCookieClient() private static let cookieImportOrder: BrowserCookieImportOrder = ProviderDefaults.metadata[.codex]?.browserCookieOrder ?? Browser.defaultImportOrder private enum CandidateEvaluation { case match(candidate: Candidate, signedInEmail: String) case mismatch(candidate: Candidate, signedInEmail: String) case loggedIn(candidate: Candidate, signedInEmail: String) case unknown(candidate: Candidate) case loginRequired(candidate: Candidate) } public func importBestCookies( intoAccountEmail targetEmail: String?, allowAnyAccount: Bool = false, preferCachedCookieHeader: Bool = true, cacheScope: CookieHeaderCache.Scope? = nil, deadline: Date? = nil, logger: ((String) -> Void)? = nil) async throws -> ImportResult { let log: (String) -> Void = { message in logger?("[web] \(message)") } let targetEmail = targetEmail?.trimmingCharacters(in: .whitespacesAndNewlines) let normalizedTarget = targetEmail?.isEmpty == false ? targetEmail : nil let context = ImportContext( targetEmail: normalizedTarget, allowAnyAccount: allowAnyAccount, cacheScope: cacheScope, deadline: deadline) if normalizedTarget != nil { log("Codex email known; matching required.") } else { guard context.allowAnyAccount else { throw ImportError.noCookiesFound } log("Codex email unknown; importing any signed-in session.") } var diagnostics = ImportDiagnostics() if preferCachedCookieHeader { let cached = try await Self.runBoundedCookieCacheOperation(deadline: deadline) { CookieHeaderCache.loadSerialized(provider: .codex, scope: cacheScope) } if let cached, !cached.cookieHeader.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty { log("Using cached cookie header from \(cached.sourceLabel)") do { return try await self.importManualCookies( cookieHeader: cached.cookieHeader, intoAccountEmail: context.targetEmail, allowAnyAccount: context.allowAnyAccount, cacheScope: cacheScope, deadline: deadline, logger: log) } catch let error as ImportError { switch error { case .manualCookieHeaderInvalid, .noMatchingAccount, .dashboardStillRequiresLogin: do { _ = try await Self.runBoundedCookieCacheOperation(deadline: deadline) { CookieHeaderCache.clear(provider: .codex, scope: cacheScope) } } catch { log("Stale cookie cache cleanup did not finish before the web deadline.") } default: throw error } } catch { throw error } } } else { log("Skipping cached cookie header; forcing fresh browser import") } // Filter to cookie-eligible browsers to avoid unnecessary keychain prompts let installedBrowsers = Self.cookieImportOrder.cookieImportCandidates(using: self.browserDetection) for browserSource in installedBrowsers { _ = try Self.remainingTimeout(until: deadline) if let match = try await self.trySource( browserSource, context: context, deadline: deadline, log: log, diagnostics: &diagnostics) { return match } } _ = try Self.remainingTimeout(until: deadline) if !diagnostics.mismatches.isEmpty { let found = Array(Set(diagnostics.mismatches)).sorted { lhs, rhs in if lhs.sourceLabel == rhs.sourceLabel { return lhs.email < rhs.email } return lhs.sourceLabel < rhs.sourceLabel } log("No matching browser session found. Candidate count: \(found.count)") throw ImportError.noMatchingAccount(found: found) } if diagnostics.foundUnknownEmail || diagnostics.foundAnyCookies { log("No matching browser session found (email unknown).") throw ImportError.noMatchingAccount(found: []) } if !diagnostics.accessDeniedHints.isEmpty { let details = diagnostics.accessDeniedHints.joined(separator: " ") log("Cookie access denied: \(details)") throw ImportError.browserAccessDenied(details: details) } throw ImportError.noCookiesFound } public func importManualCookies( cookieHeader: String, intoAccountEmail targetEmail: String?, allowAnyAccount: Bool = false, cacheScope: CookieHeaderCache.Scope? = nil, deadline: Date? = nil, logger: ((String) -> Void)? = nil) async throws -> ImportResult { let log: (String) -> Void = { message in logger?("[web] \(message)") } let normalizedTarget = targetEmail?.trimmingCharacters(in: .whitespacesAndNewlines) let allowAnyAccount = allowAnyAccount || normalizedTarget == nil || normalizedTarget?.isEmpty == true guard let normalized = CookieHeaderNormalizer.normalize(cookieHeader) else { throw ImportError.manualCookieHeaderInvalid } let pairs = CookieHeaderNormalizer.pairs(from: normalized) guard !pairs.isEmpty else { throw ImportError.manualCookieHeaderInvalid } let cookies = self.cookies(from: pairs) guard !cookies.isEmpty else { throw ImportError.manualCookieHeaderInvalid } let candidate = Candidate(label: "Manual", cookies: cookies) switch try await self.evaluateCandidate( candidate, targetEmail: normalizedTarget, allowAnyAccount: allowAnyAccount, deadline: deadline, log: log) { case let .match(_, signedInEmail): return try await self.persistVerifiedCandidate( candidate: candidate, targetEmail: signedInEmail, cacheScope: cacheScope, deadline: deadline, logger: log) case let .loggedIn(_, signedInEmail): return try await self.persistVerifiedCandidate( candidate: candidate, targetEmail: signedInEmail, cacheScope: cacheScope, deadline: deadline, logger: log) case let .mismatch(_, signedInEmail): throw ImportError.noMatchingAccount(found: [FoundAccount(sourceLabel: "Manual", email: signedInEmail)]) case .unknown: if allowAnyAccount { return try await self.persistToDefaultStore( candidate: candidate, deadline: deadline, logger: log) } throw ImportError.noMatchingAccount(found: []) case .loginRequired: throw ImportError.manualCookieHeaderInvalid } } private func trySafari( context: ImportContext, deadline: Date?, log: @escaping (String) -> Void, diagnostics: inout ImportDiagnostics) async throws -> ImportResult? { // Safari first: avoids touching Keychain ("Chrome Safe Storage") when Safari already matches. do { let query = BrowserCookieQuery(domains: Self.cookieDomains) let sources = try await Self.runBoundedCookieLoad(deadline: deadline) { try Self.cookieClient.codexBarRecords(matching: query, in: .safari) } _ = try Self.remainingTimeout(until: deadline) guard !sources.isEmpty else { log("Safari contained 0 matching records.") return nil } for source in sources { _ = try Self.remainingTimeout(until: deadline) let cookies = BrowserCookieClient.makeHTTPCookies(source.records, origin: query.origin) guard !cookies.isEmpty else { log("\(source.label) produced 0 HTTPCookies.") continue } diagnostics.foundAnyCookies = true log("Loaded \(cookies.count) cookies from \(source.label) (\(self.cookieSummary(cookies)))") let candidate = Candidate(label: source.label, cookies: cookies) if let match = try await self.applyCandidate( candidate, context: context, deadline: deadline, log: log, diagnostics: &diagnostics) { return match } } return nil } catch let error as URLError where error.code == .timedOut { throw error } catch let error as BrowserCookieError { BrowserCookieAccessGate.recordIfNeeded(error) if let hint = error.accessDeniedHint { diagnostics.accessDeniedHints.append(hint) } log("Safari cookie load failed: \(error.localizedDescription)") return nil } catch { log("Safari cookie load failed: \(error.localizedDescription)") return nil } } /// Generic cookie loader for any non-Safari browser (Chrome, Edge, Firefox, Brave, Arc, etc.). /// SweetCookieKit handles engine-specific decryption internally. private func tryBrowser( _ browser: Browser, context: ImportContext, deadline: Date?, log: @escaping (String) -> Void, diagnostics: inout ImportDiagnostics) async throws -> ImportResult? { do { let query = BrowserCookieQuery(domains: Self.cookieDomains) let sources = try await Self.runBoundedCookieLoad(deadline: deadline) { try Self.cookieClient.codexBarRecords(matching: query, in: browser) } _ = try Self.remainingTimeout(until: deadline) guard !sources.isEmpty else { log("\(browser.displayName) contained 0 matching records.") return nil } for source in sources { _ = try Self.remainingTimeout(until: deadline) let cookies = BrowserCookieClient.makeHTTPCookies(source.records, origin: query.origin) guard !cookies.isEmpty else { log("\(source.label) produced 0 HTTPCookies.") continue } diagnostics.foundAnyCookies = true log("Loaded \(cookies.count) cookies from \(source.label) (\(self.cookieSummary(cookies)))") let candidate = Candidate(label: source.label, cookies: cookies) if let match = try await self.applyCandidate( candidate, context: context, deadline: deadline, log: log, diagnostics: &diagnostics) { return match } } return nil } catch let error as URLError where error.code == .timedOut { throw error } catch let error as BrowserCookieError { BrowserCookieAccessGate.recordIfNeeded(error) if let hint = error.accessDeniedHint { diagnostics.accessDeniedHints.append(hint) } log("\(browser.displayName) cookie load failed: \(error.localizedDescription)") return nil } catch { log("\(browser.displayName) cookie load failed: \(error.localizedDescription)") return nil } } private func trySource( _ source: Browser, context: ImportContext, deadline: Date?, log: @escaping (String) -> Void, diagnostics: inout ImportDiagnostics) async throws -> ImportResult? { switch source { case .safari: try await self.trySafari( context: context, deadline: deadline, log: log, diagnostics: &diagnostics) default: // All non-Safari browsers (Chrome, Edge, Firefox, Brave, Arc, etc.) // share the same cookie loading path via SweetCookieKit. try await self.tryBrowser( source, context: context, deadline: deadline, log: log, diagnostics: &diagnostics) } } private func applyCandidate( _ candidate: Candidate, context: ImportContext, deadline: Date?, log: @escaping (String) -> Void, diagnostics: inout ImportDiagnostics) async throws -> ImportResult? { switch try await self.evaluateCandidate( candidate, targetEmail: context.targetEmail, allowAnyAccount: context.allowAnyAccount, deadline: deadline, log: log) { case let .match(candidate, signedInEmail): log("Selected \(candidate.label) (matches Codex: \(signedInEmail))") guard let targetEmail = context.targetEmail else { return nil } if let result = try? await self.persistVerifiedCandidate( candidate: candidate, targetEmail: targetEmail, cacheScope: context.cacheScope, deadline: deadline, logger: log) { await self.cacheCookies( candidate: candidate, scope: context.cacheScope, deadline: deadline, logger: log) return result } _ = try Self.remainingTimeout(until: deadline) return nil case let .mismatch(candidate, signedInEmail): try await self.handleMismatch( candidate: candidate, signedInEmail: signedInEmail, context: context, log: log, diagnostics: &diagnostics) _ = try Self.remainingTimeout(until: deadline) return nil case let .loggedIn(candidate, signedInEmail): log("Selected \(candidate.label) (signed in: \(signedInEmail))") if let result = try? await self.persistVerifiedCandidate( candidate: candidate, targetEmail: signedInEmail, cacheScope: context.cacheScope, deadline: deadline, logger: log) { await self.cacheCookies( candidate: candidate, scope: context.cacheScope, deadline: deadline, logger: log) return result } _ = try Self.remainingTimeout(until: deadline) return nil case .unknown: if context.allowAnyAccount { log("Selected \(candidate.label) (signed in: unknown)") if let result = try? await self.persistToDefaultStore( candidate: candidate, deadline: deadline, logger: log) { await self.cacheCookies( candidate: candidate, scope: context.cacheScope, deadline: deadline, logger: log) return result } _ = try Self.remainingTimeout(until: deadline) return nil } diagnostics.foundUnknownEmail = true return nil case .loginRequired: return nil } } private func evaluateCandidate(