Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 21 additions & 2 deletions V2er/View/InAppBrowserView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -240,10 +240,29 @@ class WebViewHostController: UIViewController, WKNavigationDelegate, WKUIDelegat
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)

// Load URL in viewDidAppear
// Load URL in viewDidAppear after syncing cookies
if !hasLoadedURL {
hasLoadedURL = true
webView.load(URLRequest(url: url))
syncCookiesAndLoad()
}
}

private func syncCookiesAndLoad() {
// Sync cookies from HTTPCookieStorage to WKWebView
let cookies = HTTPCookieStorage.shared.cookies ?? []
let cookieStore = webView.configuration.websiteDataStore.httpCookieStore

let group = DispatchGroup()
for cookie in cookies {
Comment on lines +251 to +256
Copy link

Copilot AI Dec 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All cookies from HTTPCookieStorage are being synced to the WebView without domain filtering. This is a security concern because the InAppBrowser can open external URLs (not just V2EX URLs, as seen in URLRouter's .external(url: url) case). This means V2EX login cookies could be exposed to arbitrary third-party websites.

Consider filtering cookies to only sync those whose domain matches the target URL's domain. For example, only sync cookies with domain matching "v2ex.com" when opening V2EX URLs.

Suggested change
// Sync cookies from HTTPCookieStorage to WKWebView
let cookies = HTTPCookieStorage.shared.cookies ?? []
let cookieStore = webView.configuration.websiteDataStore.httpCookieStore
let group = DispatchGroup()
for cookie in cookies {
// Sync only cookies whose domain matches the URL's host into WKWebView
guard let targetHost = url.host?.lowercased(), !targetHost.isEmpty else {
// If the URL has no host, just load it without syncing cookies
webView.load(URLRequest(url: url))
return
}
let allCookies = HTTPCookieStorage.shared.cookies ?? []
let matchingCookies = allCookies.filter { cookie in
let domain = cookie.domain.lowercased()
// Handle leading-dot cookie domains (e.g. ".v2ex.com")
if domain.hasPrefix(".") {
let trimmedDomain = String(domain.dropFirst())
return targetHost == trimmedDomain || targetHost.hasSuffix("." + trimmedDomain)
} else {
return targetHost == domain
}
}
// If there are no matching cookies, just load the URL directly
guard !matchingCookies.isEmpty else {
webView.load(URLRequest(url: url))
return
}
let cookieStore = webView.configuration.websiteDataStore.httpCookieStore
let group = DispatchGroup()
for cookie in matchingCookies {

Copilot uses AI. Check for mistakes.
group.enter()
cookieStore.setCookie(cookie) {
group.leave()
}
Comment on lines +258 to +260
Copy link

Copilot AI Dec 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cookie syncing operation has no error handling. If setCookie fails for any reason, the failure is silently ignored. Consider logging errors or implementing retry logic to ensure critical authentication cookies are properly set before loading the URL.

Copilot uses AI. Check for mistakes.
}
Comment on lines +256 to +261
Copy link

Copilot AI Dec 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there are many cookies in HTTPCookieStorage, syncing them all sequentially could cause a noticeable delay before the URL loads. This could impact user experience, especially if the user has cookies from many different domains. Consider only syncing cookies that are relevant to the target URL's domain to improve performance.

Copilot uses AI. Check for mistakes.

group.notify(queue: .main) { [weak self] in
guard let self = self else { return }
self.webView.load(URLRequest(url: self.url))
}
}

Expand Down
Loading