fancy new browser
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 75 lines 3.0 kB view raw
1import Foundation 2import MereKit 3 4/// Bridges the cookie stores between the two engines when switching a tab. 5/// 6/// The core problem: WKWebView and CEF maintain completely separate HTTP cookie 7/// stores. A user logged into GitHub in a WebKit tab will not be logged in when 8/// the same URL is opened in a Chromium tab. 9/// 10/// This controller extracts cookies for a given URL from the source engine's 11/// store and injects them into the destination engine's store before navigation. 12/// 13/// Limitations: 14/// - HttpOnly cookies set by servers are readable from WKHTTPCookieStore but 15/// may not be extractable from CEF's cookie manager depending on CEF version. 16/// - Secure cookies are transferred in-process (no network exposure), which is safe. 17/// - Session cookies are transferred but may expire immediately if the destination 18/// engine's session handling differs. 19@MainActor 20public final class CookieSyncController { 21 22 private let webkit: any BrowserContext 23 private let chromium: (any BrowserContext)? 24 25 public init(webkit: any BrowserContext, chromium: (any BrowserContext)?) { 26 self.webkit = webkit 27 self.chromium = chromium 28 } 29 30 /// Copy cookies for `url` from `sourceEngine` into the other engine's store. 31 public func sync(from sourceEngine: EngineType, url: URL) async { 32 switch sourceEngine { 33 case .webkit: 34 guard let chromium else { return } 35 let cookies = await webkit.cookies(for: url) 36 await chromium.setCookies(cookies, for: url) 37 38 case .chromium: 39 guard let chromium else { return } 40 let cookies = await chromium.cookies(for: url) 41 await webkit.setCookies(cookies, for: url) 42 } 43 } 44 45 /// Full bidirectional sync for all cookies on a domain. 46 /// Call this periodically if keeping both engines logged in simultaneously. 47 public func fullSync(url: URL) async { 48 guard let chromium else { return } 49 let webkitCookies = await webkit.cookies(for: url) 50 let chromiumCookies = await chromium.cookies(for: url) 51 52 // Merge: newest cookie wins on conflict 53 let merged = merge(webkitCookies, chromiumCookies) 54 await webkit.setCookies(merged, for: url) 55 await chromium.setCookies(merged, for: url) 56 } 57 58 private func merge(_ a: [HTTPCookie], _ b: [HTTPCookie]) -> [HTTPCookie] { 59 var result: [String: HTTPCookie] = [:] 60 for cookie in a + b { 61 let key = "\(cookie.domain)|\(cookie.path)|\(cookie.name)" 62 if let existing = result[key] { 63 // Keep the one with a later expiry, or b if equal 64 if let expA = existing.expiresDate, let expB = cookie.expiresDate, expB > expA { 65 result[key] = cookie 66 } else if existing.expiresDate == nil { 67 result[key] = cookie 68 } 69 } else { 70 result[key] = cookie 71 } 72 } 73 return Array(result.values) 74 } 75}