From 5e368118227d62d6b64fee7f9cff8eb61e02f492 Mon Sep 17 00:00:00 2001 From: Doug Date: Mon, 12 Aug 2024 11:00:34 +0100 Subject: [PATCH] Rotate the session directory each time a new client is built for authentication. --- .../Other/Extensions/FileManager.swift | 2 +- .../AuthenticationService.swift | 16 ++++++- .../Services/QRCode/QRCodeLoginService.swift | 43 +++++++++++++------ 3 files changed, 46 insertions(+), 15 deletions(-) diff --git a/ElementX/Sources/Other/Extensions/FileManager.swift b/ElementX/Sources/Other/Extensions/FileManager.swift index f99e57b51d..7d9336c091 100644 --- a/ElementX/Sources/Other/Extensions/FileManager.swift +++ b/ElementX/Sources/Other/Extensions/FileManager.swift @@ -23,7 +23,7 @@ enum FileManagerError: Error { extension FileManager { func directoryExists(at url: URL) -> Bool { var isDirectory: ObjCBool = false - guard fileExists(atPath: url.path(), isDirectory: &isDirectory) else { + guard fileExists(atPath: url.path(percentEncoded: false), isDirectory: &isDirectory) else { return false } return isDirectory.boolValue diff --git a/ElementX/Sources/Services/Authentication/AuthenticationService.swift b/ElementX/Sources/Services/Authentication/AuthenticationService.swift index 21efe55ac8..fada236e69 100644 --- a/ElementX/Sources/Services/Authentication/AuthenticationService.swift +++ b/ElementX/Sources/Services/Authentication/AuthenticationService.swift @@ -20,7 +20,7 @@ import MatrixRustSDK class AuthenticationService: AuthenticationServiceProtocol { private var client: Client? - private let sessionDirectory: URL + private var sessionDirectory: URL private let passphrase: String private let userSessionStore: UserSessionStoreProtocol @@ -139,7 +139,11 @@ class AuthenticationService: AuthenticationServiceProtocol { // MARK: - Private private func makeClientBuilder() -> ClientBuilder { - ClientBuilder + // Use a fresh session directory each time the user enters a different server + // so that caches (e.g. server versions) are always fresh for the new server. + rotateSessionDirectory() + + return ClientBuilder .baseBuilder(httpProxy: appSettings.websiteURL.globalProxy, slidingSync: appSettings.simplifiedSlidingSyncEnabled ? .simplified : .discovered, slidingSyncProxy: appSettings.slidingSyncProxyURL, @@ -149,6 +153,14 @@ class AuthenticationService: AuthenticationServiceProtocol { .passphrase(passphrase: passphrase) } + private func rotateSessionDirectory() { + if FileManager.default.directoryExists(at: sessionDirectory) { + try? FileManager.default.removeItem(at: sessionDirectory) + } + + sessionDirectory = .sessionsBaseDirectory.appending(component: UUID().uuidString) + } + private func userSession(for client: Client) async -> Result { switch await userSessionStore.userSession(for: client, sessionDirectory: sessionDirectory, passphrase: passphrase) { case .success(let clientProxy): diff --git a/ElementX/Sources/Services/QRCode/QRCodeLoginService.swift b/ElementX/Sources/Services/QRCode/QRCodeLoginService.swift index 20dd900286..85bf3efe10 100644 --- a/ElementX/Sources/Services/QRCode/QRCodeLoginService.swift +++ b/ElementX/Sources/Services/QRCode/QRCodeLoginService.swift @@ -20,7 +20,7 @@ import Foundation import MatrixRustSDK final class QRCodeLoginService: QRCodeLoginServiceProtocol { - private let sessionDirectory: URL + private var sessionDirectory: URL private let passphrase: String private let userSessionStore: UserSessionStoreProtocol @@ -57,16 +57,10 @@ final class QRCodeLoginService: QRCodeLoginServiceProtocol { } do { - let client = try await ClientBuilder - .baseBuilder(httpProxy: appSettings.websiteURL.globalProxy, - slidingSync: appSettings.simplifiedSlidingSyncEnabled ? .simplified : .discovered, - slidingSyncProxy: appSettings.slidingSyncProxyURL, - sessionDelegate: userSessionStore.clientSessionDelegate, - appHooks: appHooks) - .sessionPath(path: sessionDirectory.path(percentEncoded: false)) - .passphrase(passphrase: passphrase) - .buildWithQrCode(qrCodeData: qrData, oidcConfiguration: appSettings.oidcConfiguration.rustValue, progressListener: listener) - return await login(client: client) + let client = try await makeClientBuilder().buildWithQrCode(qrCodeData: qrData, + oidcConfiguration: appSettings.oidcConfiguration.rustValue, + progressListener: listener) + return await userSession(for: client) } catch let error as HumanQrLoginError { MXLog.error("QRCode login error: \(error)") return .failure(error.serviceError) @@ -76,7 +70,32 @@ final class QRCodeLoginService: QRCodeLoginServiceProtocol { } } - private func login(client: Client) async -> Result { + // MARK: - Private + + private func makeClientBuilder() -> ClientBuilder { + // Use a fresh session directory each time the user scans a QR code to ensure caches + // (e.g. server versions) are always fresh in case a different server is used. + rotateSessionDirectory() + + return ClientBuilder + .baseBuilder(httpProxy: appSettings.websiteURL.globalProxy, + slidingSync: appSettings.simplifiedSlidingSyncEnabled ? .simplified : .discovered, + slidingSyncProxy: appSettings.slidingSyncProxyURL, + sessionDelegate: userSessionStore.clientSessionDelegate, + appHooks: appHooks) + .sessionPath(path: sessionDirectory.path(percentEncoded: false)) + .passphrase(passphrase: passphrase) + } + + private func rotateSessionDirectory() { + if FileManager.default.directoryExists(at: sessionDirectory) { + try? FileManager.default.removeItem(at: sessionDirectory) + } + + sessionDirectory = .sessionsBaseDirectory.appending(component: UUID().uuidString) + } + + private func userSession(for client: Client) async -> Result { switch await userSessionStore.userSession(for: client, sessionDirectory: sessionDirectory, passphrase: passphrase) { case .success(let session): return .success(session)