855 lines · 31.8 KB · Swift
RawDownload
import Foundation#if os(macOS)import SweetCookieKit#endif #if os(macOS)enum MiniMaxLocalStorageImporter {    struct TokenInfo: Sendable {        let accessToken: String        let groupID: String?        let sourceLabel: String    }     static func importAccessTokens(        browserDetection: BrowserDetection,        logger: ((String) -> Void)? = nil) -> [TokenInfo]    {        let log: (String) -> Void = { msg in logger?("[minimax-storage] \(msg)") }        var tokens: [TokenInfo] = []         let chromeCandidates = self.chromeLocalStorageCandidates(browserDetection: browserDetection)        if !chromeCandidates.isEmpty {            log("Chrome local storage candidates: \(chromeCandidates.count)")        }         for candidate in chromeCandidates {            guard case let .chromeLevelDB(levelDBURL) = candidate.kind else { continue }            let snapshot = self.readLocalStorage(from: levelDBURL, logger: log)            if !snapshot.tokens.isEmpty {                let groupID = snapshot.groupID ?? self.groupID(fromJWT: snapshot.tokens.first ?? "")                if groupID != nil {                    log("Found MiniMax group id in \(candidate.label)")                }                for token in snapshot.tokens {                    let hint = token.contains(".") ? "jwt" : "opaque"                    log("Found MiniMax access token in \(candidate.label): \(token.count) chars (\(hint))")                    tokens.append(TokenInfo(accessToken: token, groupID: groupID, sourceLabel: candidate.label))                }            }        }         if tokens.isEmpty {            let sessionCandidates = self.chromeSessionStorageCandidates(browserDetection: browserDetection)            if !sessionCandidates.isEmpty {                log("Chrome session storage candidates: \(sessionCandidates.count)")            }            for candidate in sessionCandidates {                let sessionTokens = self.readSessionStorageTokens(from: candidate.url, logger: log)                guard !sessionTokens.isEmpty else { continue }                for token in sessionTokens {                    let hint = token.contains(".") ? "jwt" : "opaque"                    log("Found MiniMax access token in \(candidate.label): \(token.count) chars (\(hint))")                    let groupID = self.groupID(fromJWT: token)                    tokens.append(TokenInfo(accessToken: token, groupID: groupID, sourceLabel: candidate.label))                }            }        }         if tokens.isEmpty {            let indexedCandidates = self.chromeIndexedDBCandidates(browserDetection: browserDetection)            if !indexedCandidates.isEmpty {                log("Chrome IndexedDB candidates: \(indexedCandidates.count)")            }            for candidate in indexedCandidates {                let indexedTokens = self.readIndexedDBTokens(from: candidate.url, logger: log)                guard !indexedTokens.isEmpty else { continue }                for token in indexedTokens {                    let hint = token.contains(".") ? "jwt" : "opaque"                    log("Found MiniMax access token in \(candidate.label): \(token.count) chars (\(hint))")                    let groupID = self.groupID(fromJWT: token)                    tokens.append(TokenInfo(accessToken: token, groupID: groupID, sourceLabel: candidate.label))                }            }        }         if tokens.isEmpty {            log("No MiniMax access token found in browser storage")        }         return tokens    }     static func importGroupIDs(        browserDetection: BrowserDetection,        logger: ((String) -> Void)? = nil) -> [String: String]    {        let log: (String) -> Void = { msg in logger?("[minimax-storage] \(msg)") }        var results: [String: String] = [:]         let chromeCandidates = self.chromeLocalStorageCandidates(browserDetection: browserDetection)        if !chromeCandidates.isEmpty {            log("Chrome local storage candidates: \(chromeCandidates.count)")        }         for candidate in chromeCandidates {            guard case let .chromeLevelDB(levelDBURL) = candidate.kind else { continue }            let snapshot = self.readLocalStorage(from: levelDBURL, logger: log)            if let groupID = snapshot.groupID, results[candidate.label] == nil {                log("Found MiniMax group id in \(candidate.label)")                results[candidate.label] = groupID            }        }         return results    }     // MARK: - Chrome local storage discovery     private enum LocalStorageSourceKind: Sendable {        case chromeLevelDB(URL)    }     private struct LocalStorageCandidate: Sendable {        let label: String        let kind: LocalStorageSourceKind    }     private struct SessionStorageCandidate: Sendable {        let label: String        let url: URL    }     private struct IndexedDBCandidate: Sendable {        let label: String        let url: URL    }     private static func chromeLocalStorageCandidates(browserDetection: BrowserDetection) -> [LocalStorageCandidate] {        let browsers: [Browser] = [            .chrome,            .chromeBeta,            .chromeCanary,            .edge,            .edgeBeta,            .edgeCanary,            .brave,            .braveBeta,            .braveNightly,            .vivaldi,            .arc,            .arcBeta,            .arcCanary,            .chatgptAtlas,            .chromium,            .helium,        ]         // Filter to browsers with profile data to avoid unnecessary filesystem access        let installedBrowsers = browsers.browsersWithProfileData(using: browserDetection)         let roots = ChromiumProfileLocator            .roots(for: installedBrowsers, homeDirectories: BrowserCookieClient.defaultHomeDirectories())            .map { (url: $0.url, labelPrefix: $0.labelPrefix) }         var candidates: [LocalStorageCandidate] = []        for root in roots {            candidates.append(contentsOf: self.chromeProfileLocalStorageDirs(                root: root.url,                labelPrefix: root.labelPrefix))        }        return candidates    }     private static func chromeProfileLocalStorageDirs(root: URL, labelPrefix: String) -> [LocalStorageCandidate] {        guard let entries = try? FileManager.default.contentsOfDirectory(            at: root,            includingPropertiesForKeys: [.isDirectoryKey],            options: [.skipsHiddenFiles])        else { return [] }         let profileDirs = entries.filter { url in            guard let isDir = (try? url.resourceValues(forKeys: [.isDirectoryKey]).isDirectory), isDir else {                return false            }            let name = url.lastPathComponent            return name == "Default" || name.hasPrefix("Profile ") || name.hasPrefix("user-")        }        .sorted { $0.lastPathComponent < $1.lastPathComponent }         return profileDirs.compactMap { dir in            let levelDBURL = dir.appendingPathComponent("Local Storage").appendingPathComponent("leveldb")            guard FileManager.default.fileExists(atPath: levelDBURL.path) else { return nil }            let label = "\(labelPrefix) \(dir.lastPathComponent)"            return LocalStorageCandidate(label: label, kind: .chromeLevelDB(levelDBURL))        }    }     private static func chromeSessionStorageCandidates(browserDetection: BrowserDetection)    -> [SessionStorageCandidate] {        let browsers: [Browser] = [            .chrome,            .chromeBeta,            .chromeCanary,            .edge,            .edgeBeta,            .edgeCanary,            .brave,            .braveBeta,            .braveNightly,            .vivaldi,            .arc,            .arcBeta,            .arcCanary,            .chatgptAtlas,            .chromium,            .helium,        ]         // Filter to browsers with profile data to avoid unnecessary filesystem access        let installedBrowsers = browsers.browsersWithProfileData(using: browserDetection)         let roots = ChromiumProfileLocator            .roots(for: installedBrowsers, homeDirectories: BrowserCookieClient.defaultHomeDirectories())            .map { (url: $0.url, labelPrefix: $0.labelPrefix) }         var candidates: [SessionStorageCandidate] = []        for root in roots {            candidates.append(contentsOf: self.chromeProfileSessionStorageDirs(                root: root.url,                labelPrefix: root.labelPrefix))        }        return candidates    }     private static func chromeProfileSessionStorageDirs(root: URL, labelPrefix: String) -> [SessionStorageCandidate] {        guard let entries = try? FileManager.default.contentsOfDirectory(            at: root,            includingPropertiesForKeys: [.isDirectoryKey],            options: [.skipsHiddenFiles])        else { return [] }         let profileDirs = entries.filter { url in            guard let isDir = (try? url.resourceValues(forKeys: [.isDirectoryKey]).isDirectory), isDir else {                return false            }            let name = url.lastPathComponent            return name == "Default" || name.hasPrefix("Profile ") || name.hasPrefix("user-")        }        .sorted { $0.lastPathComponent < $1.lastPathComponent }         return profileDirs.compactMap { dir in            let sessionURL = dir.appendingPathComponent("Session Storage")            guard FileManager.default.fileExists(atPath: sessionURL.path) else { return nil }            let label = "\(labelPrefix) \(dir.lastPathComponent) (Session Storage)"            return SessionStorageCandidate(label: label, url: sessionURL)        }    }     private static func chromeIndexedDBCandidates(browserDetection: BrowserDetection) -> [IndexedDBCandidate] {        let browsers: [Browser] = [            .chrome,            .chromeBeta,            .chromeCanary,            .edge,            .edgeBeta,            .edgeCanary,            .brave,            .braveBeta,            .braveNightly,            .vivaldi,            .arc,            .arcBeta,            .arcCanary,            .chatgptAtlas,            .chromium,            .helium,        ]         // Filter to browsers with profile data to avoid unnecessary filesystem access        let installedBrowsers = browsers.browsersWithProfileData(using: browserDetection)         let roots = ChromiumProfileLocator            .roots(for: installedBrowsers, homeDirectories: BrowserCookieClient.defaultHomeDirectories())            .map { (url: $0.url, labelPrefix: $0.labelPrefix) }         var candidates: [IndexedDBCandidate] = []        for root in roots {            candidates.append(contentsOf: self.chromeProfileIndexedDBDirs(                root: root.url,                labelPrefix: root.labelPrefix))        }        return candidates    }     private static func chromeProfileIndexedDBDirs(root: URL, labelPrefix: String) -> [IndexedDBCandidate] {        guard let entries = try? FileManager.default.contentsOfDirectory(            at: root,            includingPropertiesForKeys: [.isDirectoryKey],            options: [.skipsHiddenFiles])        else { return [] }         let profileDirs = entries.filter { url in            guard let isDir = (try? url.resourceValues(forKeys: [.isDirectoryKey]).isDirectory), isDir else {                return false            }            let name = url.lastPathComponent            return name == "Default" || name.hasPrefix("Profile ") || name.hasPrefix("user-")        }        .sorted { $0.lastPathComponent < $1.lastPathComponent }         let targetPrefixes = [            "https_platform.minimax.io_",            "https_www.minimax.io_",            "https_minimax.io_",            "https_platform.minimaxi.com_",            "https_minimaxi.com_",            "https_www.minimaxi.com_",        ]         var candidates: [IndexedDBCandidate] = []        for dir in profileDirs {            let indexedDBRoot = dir.appendingPathComponent("IndexedDB")            guard let dbEntries = try? FileManager.default.contentsOfDirectory(                at: indexedDBRoot,                includingPropertiesForKeys: [.isDirectoryKey],                options: [.skipsHiddenFiles])            else { continue }            for entry in dbEntries {                guard let isDir = (try? entry.resourceValues(forKeys: [.isDirectoryKey]).isDirectory), isDir else {                    continue                }                let name = entry.lastPathComponent                guard targetPrefixes.contains(where: { name.hasPrefix($0) }),                      name.hasSuffix(".indexeddb.leveldb")                else { continue }                let label = "\(labelPrefix) \(dir.lastPathComponent) (IndexedDB)"                candidates.append(IndexedDBCandidate(label: label, url: entry))            }        }        return candidates    }     // MARK: - Token extraction     private struct LocalStorageSnapshot: Sendable {        let tokens: [String]        let groupID: String?    }     private static func readLocalStorage(        from levelDBURL: URL,        logger: ((String) -> Void)? = nil) -> LocalStorageSnapshot    {        let origins = [            "https://platform.minimax.io",            "https://www.minimax.io",            "https://minimax.io",            "https://platform.minimaxi.com",            "https://www.minimaxi.com",            "https://minimaxi.com",        ]        var entries: [SweetCookieKit.ChromiumLocalStorageEntry] = []        for origin in origins {            entries.append(contentsOf: SweetCookieKit.ChromiumLocalStorageReader.readEntries(                for: origin,                in: levelDBURL,                logger: logger))        }         var tokens: [String] = []        var seen = Set<String>()        var groupID: String?        var hasMinimaxSignal = !entries.isEmpty         for entry in entries {            let extracted = self.extractAccessTokens(from: entry.value)            for token in extracted where !seen.contains(token) {                seen.insert(token)                tokens.append(token)            }            if groupID == nil, let match = self.extractGroupID(from: entry.value) {                groupID = match            }        }         if tokens.isEmpty {            let textEntries = SweetCookieKit.ChromiumLocalStorageReader.readTextEntries(                in: levelDBURL,                logger: logger)            let candidateEntries = textEntries.filter { entry in                let key = entry.key.lowercased()                let value = entry.value.lowercased()                return key.contains("minimax.io") || value.contains("minimax.io") ||                    key.contains("minimaxi.com") || value.contains("minimaxi.com")            }            if !candidateEntries.isEmpty {                logger?("[minimax-storage] Local storage text entries: \(candidateEntries.count)")                hasMinimaxSignal = true            }            for entry in candidateEntries {                let extracted = self.extractAccessTokens(from: entry.value)                for token in extracted where !seen.contains(token) {                    if token.contains("."), !self.isMiniMaxJWT(token) {                        continue                    }                    seen.insert(token)                    tokens.append(token)                }                if groupID == nil, let match = self.extractGroupID(from: entry.value) {                    groupID = match                }            }        }         if tokens.isEmpty, hasMinimaxSignal {            let rawCandidates = SweetCookieKit.ChromiumLocalStorageReader.readTokenCandidates(                in: levelDBURL,                minimumLength: 60,                logger: logger)            if !rawCandidates.isEmpty {                logger?("[minimax-storage] Local storage raw token candidates: \(rawCandidates.count)")            }            for candidate in rawCandidates                where self.looksLikeToken(candidate) && self.isMiniMaxJWT(candidate) && !seen.contains(candidate)            {                seen.insert(candidate)                tokens.append(candidate)                if groupID == nil {                    groupID = self.groupID(fromJWT: candidate)                }            }        }         if tokens.isEmpty, !entries.isEmpty {            let sample = entries.prefix(6).map { "\($0.key) (\($0.value.count) chars)" }            logger?("[minimax-storage] Local storage key sample: \(sample.joined(separator: ", "))")            for entry in entries                where entry.key == "user_detail" || entry.key == "persist:root" || entry.key == "access_token"            {                let preview = entry.value.prefix(200)                if entry.key == "access_token" {                    logger?("[minimax-storage] \(entry.key) preview: \(preview) (raw \(entry.rawValueLength) bytes)")                } else {                    logger?("[minimax-storage] \(entry.key) preview: \(preview)")                }                if entry.key == "persist:root" {                    self.logPersistRootKeys(entry.value, logger: logger)                }            }        }         return LocalStorageSnapshot(tokens: tokens, groupID: groupID)    }     private static func readSessionStorageTokens(        from levelDBURL: URL,        logger: ((String) -> Void)? = nil) -> [String]    {        let entries = SweetCookieKit.ChromiumLocalStorageReader.readTextEntries(            in: levelDBURL,            logger: logger)        guard !entries.isEmpty else { return [] }         let origins = [            "https://platform.minimax.io",            "https://www.minimax.io",            "https://minimax.io",            "https://platform.minimaxi.com",            "https://www.minimaxi.com",            "https://minimaxi.com",        ]        let mapIDs = self.sessionStorageMapIDs(in: entries, origins: origins, logger: logger)        if mapIDs.isEmpty {            logger?("[minimax-storage] No MiniMax session storage namespaces found")            return []        }         let mapEntries = entries.filter { entry in            guard let mapID = self.sessionStorageMapID(fromKey: entry.key) else { return false }            return mapIDs.contains(mapID)        }        if mapEntries.isEmpty {            logger?("[minimax-storage] No MiniMax session storage map entries found")            return []        }         let tokenKeySample = mapEntries            .filter { entry in                entry.key.localizedCaseInsensitiveContains("token") ||                    entry.key.localizedCaseInsensitiveContains("auth")            }            .prefix(8)            .map(\.key)        if !tokenKeySample.isEmpty {            logger?("[minimax-storage] MiniMax session storage token keys: \(tokenKeySample.joined(separator: ", "))")        }         var tokens: [String] = []        var seen = Set<String>()        for entry in mapEntries {            let extracted = self.extractAccessTokens(from: entry.value)            for token in extracted where !seen.contains(token) {                seen.insert(token)                tokens.append(token)            }        }         if tokens.isEmpty {            let sample = mapEntries.prefix(8).map { entry in                "\(entry.key) (\(entry.value.count) chars)"

Lines 1–500 of 855.