import Foundation #if os(macOS)import SweetCookieKit private let minimaxCookieImportOrder: BrowserCookieImportOrder = ProviderDefaults.metadata[.minimax]?.browserCookieOrder ?? Browser.defaultImportOrder public enum MiniMaxCookieImporter { private static let log = CodexBarLog.logger(LogCategories.minimaxCookie) private static let cookieClient = BrowserCookieClient() private static let cookieDomains = [ "platform.minimax.io", "openplatform.minimax.io", "minimax.io", "platform.minimaxi.com", "openplatform.minimaxi.com", "minimaxi.com", ] public struct SessionInfo: Sendable { public let cookies: [HTTPCookie] public let sourceLabel: String public init(cookies: [HTTPCookie], sourceLabel: String) { self.cookies = cookies self.sourceLabel = sourceLabel } public var cookieHeader: String { self.cookies.map { "\($0.name)=\($0.value)" }.joined(separator: "; ") } } public static func importSessions( browserDetection: BrowserDetection, logger: ((String) -> Void)? = nil) throws -> [SessionInfo] { var sessions: [SessionInfo] = [] // Filter to cookie-eligible browsers to avoid unnecessary keychain prompts let installedBrowsers = minimaxCookieImportOrder.cookieImportCandidates(using: browserDetection) for browserSource in installedBrowsers { do { let perSource = try self.importSessions(from: browserSource, logger: logger) sessions.append(contentsOf: perSource) } catch { BrowserCookieAccessGate.recordIfNeeded(error) self.emit( "\(browserSource.displayName) cookie import failed: \(error.localizedDescription)", logger: logger) } } guard !sessions.isEmpty else { throw MiniMaxCookieImportError.noCookies } return sessions } public static func importSessions( from browserSource: Browser, logger: ((String) -> Void)? = nil) throws -> [SessionInfo] { let query = BrowserCookieQuery(domains: self.cookieDomains) let log: (String) -> Void = { msg in self.emit(msg, logger: logger) } let sources = try Self.cookieClient.codexBarRecords( matching: query, in: browserSource, logger: log) var sessions: [SessionInfo] = [] let grouped = Dictionary(grouping: sources, by: { $0.store.profile.id }) let sortedGroups = grouped.values.sorted { lhs, rhs in self.mergedLabel(for: lhs) < self.mergedLabel(for: rhs) } for group in sortedGroups where !group.isEmpty { let label = self.mergedLabel(for: group) let mergedRecords = self.mergeRecords(group) guard !mergedRecords.isEmpty else { continue } let httpCookies = BrowserCookieClient.makeHTTPCookies(mergedRecords, origin: query.origin) guard !httpCookies.isEmpty else { continue } log("Found \(httpCookies.count) MiniMax cookies in \(label)") log("\(label) cookie names: \(self.cookieNames(from: httpCookies))") if let token = httpCookies.first(where: { $0.name == "HERTZ-SESSION" })?.value { let hint = token.contains(".") ? "jwt" : "opaque" log("\(label) HERTZ-SESSION: \(token.count) chars (\(hint))") } sessions.append(SessionInfo(cookies: httpCookies, sourceLabel: label)) } return sessions } public static func importSession( browserDetection: BrowserDetection, logger: ((String) -> Void)? = nil) throws -> SessionInfo { let sessions = try self.importSessions(browserDetection: browserDetection, logger: logger) guard let first = sessions.first else { throw MiniMaxCookieImportError.noCookies } return first } public static func hasSession(browserDetection: BrowserDetection, logger: ((String) -> Void)? = nil) -> Bool { do { return try !self.importSessions(browserDetection: browserDetection, logger: logger).isEmpty } catch { return false } } private static func cookieNames(from cookies: [HTTPCookie]) -> String { let names = Set(cookies.map { "\($0.name)@\($0.domain)" }).sorted() return names.joined(separator: ", ") } private static func emit(_ message: String, logger: ((String) -> Void)?) { logger?("[minimax-cookie] \(message)") self.log.debug(message) } private static func mergedLabel(for sources: [BrowserCookieStoreRecords]) -> String { guard let base = sources.map(\.label).min() else { return "Unknown" } if base.hasSuffix(" (Network)") { return String(base.dropLast(" (Network)".count)) } return base } private static func mergeRecords(_ sources: [BrowserCookieStoreRecords]) -> [BrowserCookieRecord] { let sortedSources = sources.sorted { lhs, rhs in self.storePriority(lhs.store.kind) < self.storePriority(rhs.store.kind) } var mergedByKey: [String: BrowserCookieRecord] = [:] for source in sortedSources { for record in source.records { let key = self.recordKey(record) if let existing = mergedByKey[key] { if self.shouldReplace(existing: existing, candidate: record) { mergedByKey[key] = record } } else { mergedByKey[key] = record } } } return Array(mergedByKey.values) } private static func storePriority(_ kind: BrowserCookieStoreKind) -> Int { switch kind { case .network: 0 case .primary: 1 case .safari: 2 } } private static func recordKey(_ record: BrowserCookieRecord) -> String { "\(record.name)|\(record.domain)|\(record.path)" } private static func shouldReplace(existing: BrowserCookieRecord, candidate: BrowserCookieRecord) -> Bool { switch (existing.expires, candidate.expires) { case let (lhs?, rhs?): rhs > lhs case (nil, .some): true case (.some, nil): false case (nil, nil): false } }} enum MiniMaxCookieImportError: LocalizedError { case noCookies var errorDescription: String? { switch self { case .noCookies: "No MiniMax session cookies found in browsers." } }}#endif
import Foundation
#if os(macOS)
import SweetCookieKit
private let minimaxCookieImportOrder: BrowserCookieImportOrder =
ProviderDefaults.metadata[.minimax]?.browserCookieOrder ?? Browser.defaultImportOrder
public enum MiniMaxCookieImporter {
private static let log = CodexBarLog.logger(LogCategories.minimaxCookie)
private static let cookieClient = BrowserCookieClient()
private static let cookieDomains = [
"platform.minimax.io",
"openplatform.minimax.io",
"minimax.io",
"platform.minimaxi.com",
"openplatform.minimaxi.com",
"minimaxi.com",
]
public struct SessionInfo: Sendable {
public let cookies: [HTTPCookie]
public let sourceLabel: String
public init(cookies: [HTTPCookie], sourceLabel: String) {
self.cookies = cookies
self.sourceLabel = sourceLabel
}
public var cookieHeader: String {
self.cookies.map { "\($0.name)=\($0.value)" }.joined(separator: "; ")
}
}
public static func importSessions(
browserDetection: BrowserDetection,
logger: ((String) -> Void)? = nil) throws -> [SessionInfo]
{
var sessions: [SessionInfo] = []
// Filter to cookie-eligible browsers to avoid unnecessary keychain prompts
let installedBrowsers = minimaxCookieImportOrder.cookieImportCandidates(using: browserDetection)
for browserSource in installedBrowsers {
do {
let perSource = try self.importSessions(from: browserSource, logger: logger)
sessions.append(contentsOf: perSource)
} catch {
BrowserCookieAccessGate.recordIfNeeded(error)
self.emit(
"\(browserSource.displayName) cookie import failed: \(error.localizedDescription)",
logger: logger)
}
}
guard !sessions.isEmpty else {
throw MiniMaxCookieImportError.noCookies
}
return sessions
}
public static func importSessions(
from browserSource: Browser,
logger: ((String) -> Void)? = nil) throws -> [SessionInfo]
{
let query = BrowserCookieQuery(domains: self.cookieDomains)
let log: (String) -> Void = { msg in self.emit(msg, logger: logger) }
let sources = try Self.cookieClient.codexBarRecords(
matching: query,
in: browserSource,
logger: log)
var sessions: [SessionInfo] = []
let grouped = Dictionary(grouping: sources, by: { $0.store.profile.id })
let sortedGroups = grouped.values.sorted { lhs, rhs in
self.mergedLabel(for: lhs) < self.mergedLabel(for: rhs)
}
for group in sortedGroups where !group.isEmpty {
let label = self.mergedLabel(for: group)
let mergedRecords = self.mergeRecords(group)
guard !mergedRecords.isEmpty else { continue }
let httpCookies = BrowserCookieClient.makeHTTPCookies(mergedRecords, origin: query.origin)
guard !httpCookies.isEmpty else { continue }
log("Found \(httpCookies.count) MiniMax cookies in \(label)")
log("\(label) cookie names: \(self.cookieNames(from: httpCookies))")
if let token = httpCookies.first(where: { $0.name == "HERTZ-SESSION" })?.value {
let hint = token.contains(".") ? "jwt" : "opaque"
log("\(label) HERTZ-SESSION: \(token.count) chars (\(hint))")
}
sessions.append(SessionInfo(cookies: httpCookies, sourceLabel: label))
}
return sessions
}
public static func importSession(
browserDetection: BrowserDetection,
logger: ((String) -> Void)? = nil) throws -> SessionInfo
{
let sessions = try self.importSessions(browserDetection: browserDetection, logger: logger)
guard let first = sessions.first else {
throw MiniMaxCookieImportError.noCookies
}
return first
}
public static func hasSession(browserDetection: BrowserDetection, logger: ((String) -> Void)? = nil) -> Bool {
do {
return try !self.importSessions(browserDetection: browserDetection, logger: logger).isEmpty
} catch {
return false
}
}
private static func cookieNames(from cookies: [HTTPCookie]) -> String {
let names = Set(cookies.map { "\($0.name)@\($0.domain)" }).sorted()
return names.joined(separator: ", ")
}
private static func emit(_ message: String, logger: ((String) -> Void)?) {
logger?("[minimax-cookie] \(message)")
self.log.debug(message)
}
private static func mergedLabel(for sources: [BrowserCookieStoreRecords]) -> String {
guard let base = sources.map(\.label).min() else {
return "Unknown"
}
if base.hasSuffix(" (Network)") {
return String(base.dropLast(" (Network)".count))
}
return base
}
private static func mergeRecords(_ sources: [BrowserCookieStoreRecords]) -> [BrowserCookieRecord] {
let sortedSources = sources.sorted { lhs, rhs in
self.storePriority(lhs.store.kind) < self.storePriority(rhs.store.kind)
}
var mergedByKey: [String: BrowserCookieRecord] = [:]
for source in sortedSources {
for record in source.records {
let key = self.recordKey(record)
if let existing = mergedByKey[key] {
if self.shouldReplace(existing: existing, candidate: record) {
mergedByKey[key] = record
}
} else {
mergedByKey[key] = record
}
}
}
return Array(mergedByKey.values)
}
private static func storePriority(_ kind: BrowserCookieStoreKind) -> Int {
switch kind {
case .network: 0
case .primary: 1
case .safari: 2
}
}
private static func recordKey(_ record: BrowserCookieRecord) -> String {
"\(record.name)|\(record.domain)|\(record.path)"
}
private static func shouldReplace(existing: BrowserCookieRecord, candidate: BrowserCookieRecord) -> Bool {
switch (existing.expires, candidate.expires) {
case let (lhs?, rhs?):
rhs > lhs
case (nil, .some):
true
case (.some, nil):
false
case (nil, nil):
false
}
}
}
enum MiniMaxCookieImportError: LocalizedError {
case noCookies
var errorDescription: String? {
switch self {
case .noCookies:
"No MiniMax session cookies found in browsers."
}
}
}
#endif