From 02d9d799a66ee8ec20e439f7dfd9b9d72f252e8e Mon Sep 17 00:00:00 2001 From: Ayushya Amitabh Date: Tue, 6 Oct 2026 20:18:20 -0400 Subject: [PATCH] iOS: authenticate each request by its own header only (no cookies/credential cache) Two accounts can share one server; the Share Extension's folder listing and the upload sessions now ignore cookies and stored credentials so one account's session can never answer for another. Logs each PROPFIND (user, path, status). Co-Authored-By: Claude Sonnet 5.5 --- ios/Runner/Native/TransferManager.swift | 5 +++++ ios/Shared/DavFolders.swift | 17 ++++++++++++++++- ios/Shared/ShareUpload.swift | 4 ++++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/ios/Runner/Native/TransferManager.swift b/ios/Runner/Native/TransferManager.swift index dae9465..a303c07 100644 --- a/ios/Runner/Native/TransferManager.swift +++ b/ios/Runner/Native/TransferManager.swift @@ -34,6 +34,11 @@ final class TransferManager: NSObject { config.sessionSendsLaunchEvents = true config.isDiscretionary = false config.waitsForConnectivity = true + // Two accounts can share a server: authenticate by the request's own + // header only, never a cookie another account's request left behind. + config.httpShouldSetCookies = false + config.httpCookieAcceptPolicy = .never + config.urlCredentialStorage = nil return URLSession(configuration: config, delegate: self, delegateQueue: nil) }() diff --git a/ios/Shared/DavFolders.swift b/ios/Shared/DavFolders.swift index bb502c6..98f538a 100644 --- a/ios/Shared/DavFolders.swift +++ b/ios/Shared/DavFolders.swift @@ -149,6 +149,20 @@ enum DavClient { /// Every child folder, hidden and external ones included - the sheet's /// toggles filter that list in memory, so changing one doesn't refetch. + /// Two accounts can live on the same server, so a request must be + /// authenticated by its own `Authorization` header alone - never by a + /// session cookie or credential a previous account's request left behind + /// in the shared stores, or the second account could be answered as the + /// first. + private static let session: URLSession = { + let config = URLSessionConfiguration.ephemeral + config.httpShouldSetCookies = false + config.httpCookieAcceptPolicy = .never + config.urlCredentialStorage = nil + config.requestCachePolicy = .reloadIgnoringLocalCacheData + return URLSession(configuration: config) + }() + static func listFolders(account: SharedAccount, path: String) async throws -> [DavFolder] { guard let url = WebDAV.fileURL(serverUrl: account.serverUrl, username: account.username, remotePath: path) else { throw TransferError(message: "Invalid server address.") } @@ -160,8 +174,9 @@ enum DavClient { request.httpBody = body.data(using: .utf8) request.timeoutInterval = 20 - let (data, response) = try await URLSession.shared.data(for: request) + let (data, response) = try await session.data(for: request) let status = (response as? HTTPURLResponse)?.statusCode ?? 0 + NSLog("[DavClient] PROPFIND %@ as %@ -> %d", url.path, account.username, status) guard status == 207 else { throw TransferError(message: status == 401 ? "Signed out - open Noo to sign in again." : "Server returned \(status).") } diff --git a/ios/Shared/ShareUpload.swift b/ios/Shared/ShareUpload.swift index cb1a9a2..eb68ff1 100644 --- a/ios/Shared/ShareUpload.swift +++ b/ios/Shared/ShareUpload.swift @@ -16,6 +16,10 @@ enum ShareUpload { config.sessionSendsLaunchEvents = true config.isDiscretionary = false config.waitsForConnectivity = true + // Authenticate by the request's own header only (see DavClient.session). + config.httpShouldSetCookies = false + config.httpCookieAcceptPolicy = .never + config.urlCredentialStorage = nil return config }