308 lines · 11.2 KB · Swift
RawDownload
import Foundation#if os(macOS)import SweetCookieKit#endif #if os(macOS)enum WindsurfDevinSessionImporter {    nonisolated(unsafe) static var importSessionsOverrideForTesting:        ((BrowserDetection, ((String) -> Void)?) -> [SessionInfo])?    nonisolated(unsafe) static var importPreferredSessionsOverrideForTesting:        ((BrowserDetection, ((String) -> Void)?) -> [SessionInfo])?    nonisolated(unsafe) static var importFallbackSessionsOverrideForTesting:        ((BrowserDetection, ((String) -> Void)?) -> [SessionInfo])?    static let defaultPreferredBrowsers: [Browser] = [.chrome]    static let fallbackBrowsers: [Browser] = [        .chromeBeta,        .chromeCanary,        .edge,        .edgeBeta,        .edgeCanary,        .brave,        .braveBeta,        .braveNightly,        .vivaldi,        .arc,        .arcBeta,        .arcCanary,        .dia,        .chatgptAtlas,        .chromium,        .helium,    ]     struct SessionInfo: Equatable {        let session: WindsurfDevinSessionAuth        let sourceLabel: String    }     static func importSessions(        browserDetection: BrowserDetection,        logger: ((String) -> Void)? = nil) -> [SessionInfo]    {        if let override = self.importSessionsOverrideForTesting {            return override(browserDetection, logger)        }         let log: (String) -> Void = { msg in logger?("[windsurf-storage] \(msg)") }        let preferredSessions = self.importSessions(            browserDetection: browserDetection,            browsers: self.defaultPreferredBrowsers,            logger: log)        if !preferredSessions.isEmpty {            return preferredSessions        }         log("No Windsurf devin session found in Chrome; trying fallback Chromium browsers")        let sessions = self.importSessions(            browserDetection: browserDetection,            browsers: self.fallbackBrowsersExcluding(self.defaultPreferredBrowsers),            logger: log)         if sessions.isEmpty {            log("No Windsurf devin session found in browser local storage")        }         return sessions    }     static func importPreferredSessions(        browserDetection: BrowserDetection,        logger: ((String) -> Void)? = nil) -> [SessionInfo]    {        if let override = self.importPreferredSessionsOverrideForTesting {            return override(browserDetection, logger)        }        let log: (String) -> Void = { msg in logger?("[windsurf-storage] \(msg)") }        return self.importSessions(            browserDetection: browserDetection,            browsers: self.defaultPreferredBrowsers,            logger: log)    }     static func importFallbackSessions(        browserDetection: BrowserDetection,        logger: ((String) -> Void)? = nil) -> [SessionInfo]    {        if let override = self.importFallbackSessionsOverrideForTesting {            return override(browserDetection, logger)        }        let log: (String) -> Void = { msg in logger?("[windsurf-storage] \(msg)") }        return self.importSessions(            browserDetection: browserDetection,            browsers: self.fallbackBrowsersExcluding(self.defaultPreferredBrowsers),            logger: log)    }     static func fallbackBrowsersExcluding(_ preferredBrowsers: [Browser]) -> [Browser] {        let preferred = Set(preferredBrowsers)        return self.fallbackBrowsers.filter { !preferred.contains($0) }    }     static func deduplicateSessions(_ sessions: [SessionInfo]) -> [SessionInfo] {        var deduplicated: [SessionInfo] = []        var seenSessionTokens = Set<String>()         for session in sessions {            guard seenSessionTokens.insert(session.session.sessionToken).inserted else { continue }            deduplicated.append(session)        }         return deduplicated    }     static func session(from storage: [String: String], sourceLabel: String) -> SessionInfo? {        guard let sessionToken = storage["devin_session_token"],              let auth1Token = storage["devin_auth1_token"],              let accountID = storage["devin_account_id"],              let primaryOrgID = storage["devin_primary_org_id"]        else {            return nil        }         return SessionInfo(            session: WindsurfDevinSessionAuth(                sessionToken: sessionToken,                auth1Token: auth1Token,                accountID: accountID,                primaryOrgID: primaryOrgID),            sourceLabel: sourceLabel)    }     static func decodedStorageValue(_ value: String) -> String {        let trimmed = value.trimmingCharacters(in: .whitespacesAndNewlines)        guard !trimmed.isEmpty else { return trimmed }         if let data = trimmed.data(using: .utf8),           let decoded = try? JSONDecoder().decode(String.self, from: data)        {            return decoded.trimmingCharacters(in: .whitespacesAndNewlines)        }         return trimmed.trimmingCharacters(in: CharacterSet(charactersIn: "\""))            .trimmingCharacters(in: .whitespacesAndNewlines)    }     struct LocalStorageCandidate {        let label: String        let url: URL    }     struct LocalStorageSnapshot: Equatable {        let storage: [String: String]        let sourceSuffix: String?    }     typealias LocalStorageOriginEntries = (        origin: URL,        entries: [SweetCookieKit.ChromiumLocalStorageEntry])     static let localStorageOrigins = [        URL(string: "https://app.devin.ai")!,        URL(string: "https://windsurf.com")!,    ]     private static func importSessions(        browserDetection: BrowserDetection,        browsers: [Browser],        logger: @escaping (String) -> Void) -> [SessionInfo]    {        var sessions: [SessionInfo] = []        let candidates = self.chromeLocalStorageCandidates(            browserDetection: browserDetection,            browsers: browsers)        if !candidates.isEmpty {            logger("Chrome local storage candidates: \(candidates.count)")        }         for candidate in candidates {            let snapshots = self.readLocalStorageSnapshots(from: candidate.url, logger: logger)            for snapshot in snapshots {                let sourceLabel = self.sourceLabel(candidate.label, suffix: snapshot.sourceSuffix)                guard let session = self.session(from: snapshot.storage, sourceLabel: sourceLabel) else { continue }                logger("Found Windsurf devin session in \(sourceLabel)")                sessions.append(session)            }        }         return self.deduplicateSessions(sessions)    }     static func chromeLocalStorageCandidates(        browserDetection: BrowserDetection,        browsers: [Browser]) -> [LocalStorageCandidate]    {        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, url: levelDBURL)        }    }     private static func readLocalStorageSnapshots(        from levelDBURL: URL,        logger: ((String) -> Void)? = nil) -> [LocalStorageSnapshot]    {        let originEntries = Self.localStorageOrigins.map { origin in            let entries = SweetCookieKit.ChromiumLocalStorageReader.readEntries(                for: origin.absoluteString,                in: levelDBURL,                logger: logger)            return (origin: origin, entries: entries)        }         let textEntries = SweetCookieKit.ChromiumLocalStorageReader.readTextEntries(            in: levelDBURL,            logger: logger)        return self.localStorageSnapshots(from: originEntries, textEntries: textEntries)    }     static func localStorageSnapshots(        from originEntries: [LocalStorageOriginEntries],        textEntries: [SweetCookieKit.ChromiumLevelDBTextEntry]) -> [LocalStorageSnapshot]    {        var snapshots = self.localStorageSnapshots(from: originEntries)        let textStorage = self.storage(from: textEntries)        if textStorage.count == Self.targetKeys.count {            snapshots.append(LocalStorageSnapshot(storage: textStorage, sourceSuffix: nil))        }         return snapshots    }     static func localStorageSnapshots(from originEntries: [LocalStorageOriginEntries]) -> [LocalStorageSnapshot] {        originEntries.compactMap { originEntry in            let storage = self.storage(from: originEntry.entries)            guard storage.count == Self.targetKeys.count else { return nil }            return LocalStorageSnapshot(                storage: storage,                sourceSuffix: originEntry.origin.host ?? originEntry.origin.absoluteString)        }    }     private static func storage(        from entries: [SweetCookieKit.ChromiumLocalStorageEntry]) -> [String: String]    {        var storage: [String: String] = [:]        for entry in entries where storage[entry.key] == nil && Self.targetKeys.contains(entry.key) {            storage[entry.key] = self.decodedStorageValue(entry.value)        }        return storage    }     private static func storage(        from entries: [SweetCookieKit.ChromiumLevelDBTextEntry]) -> [String: String]    {        var storage: [String: String] = [:]        for entry in entries {            guard storage[entry.key] == nil, Self.targetKeys.contains(entry.key) else { continue }            storage[entry.key] = self.decodedStorageValue(entry.value)        }         return storage    }     private static func sourceLabel(_ label: String, suffix: String?) -> String {        guard let suffix else { return label }        return "\(label) (\(suffix))"    }     private static let targetKeys: Set<String> = [        "devin_session_token",        "devin_auth1_token",        "devin_account_id",        "devin_primary_org_id",    ]}#endif