diff --git a/ElementX.xcodeproj/project.pbxproj b/ElementX.xcodeproj/project.pbxproj index e22b121631..47d5b6e063 100644 --- a/ElementX.xcodeproj/project.pbxproj +++ b/ElementX.xcodeproj/project.pbxproj @@ -615,6 +615,7 @@ 89B909AC66B96FA054EF3C14 /* InvitedRoomProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E95B3BDB80531C85CD50AE6 /* InvitedRoomProxy.swift */; }; 8A0BD60CA4A6004DB06B5403 /* MediaUploadingPreprocessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 669F35C505ACE1110589F875 /* MediaUploadingPreprocessor.swift */; }; 8A5064CAC8E5F3B18645621D /* CallNotificationRoomTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD6E082B0507FB28F966516A /* CallNotificationRoomTimelineView.swift */; }; + 8A6CB15C8FC68F557750BF54 /* AuthenticationClientBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F569CFB77E0D40BD82203D9 /* AuthenticationClientBuilder.swift */; }; 8A83D715940378B9BA9F739E /* RoomInviterLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7EB58E4E8D6D634C246AD5C2 /* RoomInviterLabel.swift */; }; 8AA84EF202F2EFC8453A97BD /* SecureBackupRecoveryKeyScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 645E027C112740573D27765C /* SecureBackupRecoveryKeyScreenModels.swift */; }; 8AB8ED1051216546CB35FA0E /* UserSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E5E9C044BEB7C70B1378E91 /* UserSession.swift */; }; @@ -1248,6 +1249,7 @@ 0E95B3BDB80531C85CD50AE6 /* InvitedRoomProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InvitedRoomProxy.swift; sourceTree = ""; }; 0EE9EAF0309A2A1D67D8FAF5 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = sv; path = sv.lproj/Localizable.stringsdict; sourceTree = ""; }; 0F5567A7EF6F2AB9473236F6 /* DocumentPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DocumentPicker.swift; sourceTree = ""; }; + 0F569CFB77E0D40BD82203D9 /* AuthenticationClientBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationClientBuilder.swift; sourceTree = ""; }; 0F64447FF544298A6A3BEF85 /* NotificationSettingsScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingsScreenModels.swift; sourceTree = ""; }; 0FA60F848D1C14F873F9621A /* RoomMemberDetailsScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMemberDetailsScreenCoordinator.swift; sourceTree = ""; }; 105429F29096729EDD3152CF /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/SAS.strings; sourceTree = ""; }; @@ -4586,6 +4588,7 @@ AAFDD509929A0CCF8BCE51EB /* Authentication */ = { isa = PBXGroup; children = ( + 0F569CFB77E0D40BD82203D9 /* AuthenticationClientBuilder.swift */, F3A1AB5A84D843B6AC8D5F1E /* AuthenticationService.swift */, 5E75948AA1FE1D1A7809931F /* AuthenticationServiceProtocol.swift */, 65C2B80DD0BF6F10BB5FA922 /* MockAuthenticationServiceProxy.swift */, @@ -6181,6 +6184,7 @@ 88F348E2CB14FF71CBBB665D /* AudioRoomTimelineItemContent.swift in Sources */, 7BD2123144A32F082CECC108 /* AudioRoomTimelineView.swift in Sources */, 9278EC51D24E57445B290521 /* AudioSessionProtocol.swift in Sources */, + 8A6CB15C8FC68F557750BF54 /* AuthenticationClientBuilder.swift in Sources */, 67E9926C4572C54F59FCA91A /* AuthenticationFlowCoordinator.swift in Sources */, 9847B056C1A216C314D21E68 /* AuthenticationService.swift in Sources */, 56DACDD379A86A1F5DEFE7BE /* AuthenticationServiceProtocol.swift in Sources */, diff --git a/ElementX/Sources/Application/AppSettings.swift b/ElementX/Sources/Application/AppSettings.swift index 2ac15cdd76..1de3fd83ca 100644 --- a/ElementX/Sources/Application/AppSettings.swift +++ b/ElementX/Sources/Application/AppSettings.swift @@ -43,7 +43,7 @@ final class AppSettings { case elementCallEncryptionEnabled // Feature flags - case simplifiedSlidingSyncEnabled + case slidingSyncDiscovery case publicSearchEnabled case fuzzyRoomListSearchEnabled case pinningEnabled @@ -106,10 +106,6 @@ final class AppSettings { /// so that it can be passed to Rust as a ServerName for well-known discovery. private(set) var defaultHomeserverAddress = "matrix.org" - /// An override of the homeserver's Sliding Sync proxy URL. This allows development against servers - /// that don't yet have an officially trusted proxy configured in their well-known. - let slidingSyncProxyURL: URL? = nil - /// The task identifier used for background app refresh. Also used in main target's the Info.plist let backgroundAppRefreshTaskIdentifier = "io.element.elementx.background.refresh" @@ -284,6 +280,10 @@ final class AppSettings { @UserPreference(key: UserDefaultsKeys.pinningEnabled, defaultValue: false, storageType: .userDefaults(store)) var pinningEnabled + + enum SlidingSyncDiscovery: Codable { case proxy, native, forceNative } + @UserPreference(key: UserDefaultsKeys.slidingSyncDiscovery, defaultValue: .proxy, storageType: .userDefaults(store)) + var slidingSyncDiscovery: SlidingSyncDiscovery #endif @@ -291,9 +291,4 @@ final class AppSettings { @UserPreference(key: UserDefaultsKeys.logLevel, defaultValue: TracingConfiguration.LogLevel.info, storageType: .userDefaults(store)) var logLevel - - // MARK: Shared Feature Flags - - @UserPreference(key: UserDefaultsKeys.simplifiedSlidingSyncEnabled, defaultValue: false, storageType: .userDefaults(store)) - var simplifiedSlidingSyncEnabled } diff --git a/ElementX/Sources/FlowCoordinators/SettingsFlowCoordinator.swift b/ElementX/Sources/FlowCoordinators/SettingsFlowCoordinator.swift index 07489230e5..78c3b4b01b 100644 --- a/ElementX/Sources/FlowCoordinators/SettingsFlowCoordinator.swift +++ b/ElementX/Sources/FlowCoordinators/SettingsFlowCoordinator.swift @@ -232,7 +232,7 @@ class SettingsFlowCoordinator: FlowCoordinatorProtocol { } private func presentDeveloperOptions() { - let coordinator = DeveloperOptionsScreenCoordinator() + let coordinator = DeveloperOptionsScreenCoordinator(isUsingNativeSlidingSync: parameters.userSession.clientProxy.slidingSyncVersion == .native) coordinator.actions .sink { [weak self] action in @@ -241,8 +241,6 @@ class SettingsFlowCoordinator: FlowCoordinatorProtocol { switch action { case .clearCache: actionsSubject.send(.clearCache) - case .forceLogout: - actionsSubject.send(.forceLogout) } } .store(in: &cancellables) diff --git a/ElementX/Sources/Other/Extensions/ClientBuilder.swift b/ElementX/Sources/Other/Extensions/ClientBuilder.swift index b395f2f33e..665896c910 100644 --- a/ElementX/Sources/Other/Extensions/ClientBuilder.swift +++ b/ElementX/Sources/Other/Extensions/ClientBuilder.swift @@ -22,19 +22,18 @@ extension ClientBuilder { static func baseBuilder(setupEncryption: Bool = true, httpProxy: String? = nil, slidingSync: ClientBuilderSlidingSync, - slidingSyncProxy: URL? = nil, sessionDelegate: ClientSessionDelegate, appHooks: AppHooks) -> ClientBuilder { var builder = ClientBuilder() - .slidingSyncProxy(slidingSyncProxy: slidingSyncProxy?.absoluteString) .enableCrossProcessRefreshLock(processId: InfoPlistReader.main.bundleIdentifier, sessionDelegate: sessionDelegate) .userAgent(userAgent: UserAgentBuilder.makeASCIIUserAgent()) .requestConfig(config: .init(retryLimit: 0, timeout: 30000, maxConcurrentRequests: nil, retryTimeout: nil)) builder = switch slidingSync { case .restored: builder - case .discovered: builder.requiresSlidingSync() - case .simplified: builder.simplifiedSlidingSync(enable: true) + case .discoverProxy: builder.slidingSyncVersionBuilder(versionBuilder: .discoverProxy) + case .discoverNative: builder.slidingSyncVersionBuilder(versionBuilder: .discoverNative) + case .forceNative: builder.slidingSyncVersionBuilder(versionBuilder: .native) } if setupEncryption { @@ -56,7 +55,9 @@ enum ClientBuilderSlidingSync { /// The proxy will be supplied when restoring the Session. case restored /// A proxy must be discovered whilst building the session. - case discovered - /// Use Simplified Sliding Sync (discovery isn't a thing yet). - case simplified + case discoverProxy + /// Native sliding sync must be discovered whilst building the session. + case discoverNative + /// Forces native sliding sync without discovering it. + case forceNative } diff --git a/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/DeveloperOptionsScreenCoordinator.swift b/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/DeveloperOptionsScreenCoordinator.swift index 57df849963..cb97cd7ae0 100644 --- a/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/DeveloperOptionsScreenCoordinator.swift +++ b/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/DeveloperOptionsScreenCoordinator.swift @@ -19,8 +19,6 @@ import SwiftUI enum DeveloperOptionsScreenCoordinatorAction { case clearCache - /// Logout without a confirmation to avoid losing keys when trying SSS. - case forceLogout } final class DeveloperOptionsScreenCoordinator: CoordinatorProtocol { @@ -33,9 +31,10 @@ final class DeveloperOptionsScreenCoordinator: CoordinatorProtocol { actionsSubject.eraseToAnyPublisher() } - init() { + init(isUsingNativeSlidingSync: Bool) { viewModel = DeveloperOptionsScreenViewModel(developerOptions: ServiceLocator.shared.settings, - elementCallBaseURL: ServiceLocator.shared.settings.elementCallBaseURL) + elementCallBaseURL: ServiceLocator.shared.settings.elementCallBaseURL, + isUsingNativeSlidingSync: isUsingNativeSlidingSync) viewModel.actions .sink { [weak self] action in @@ -44,8 +43,6 @@ final class DeveloperOptionsScreenCoordinator: CoordinatorProtocol { switch action { case .clearCache: actionsSubject.send(.clearCache) - case .forceLogout: - actionsSubject.send(.forceLogout) } } .store(in: &cancellables) diff --git a/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/DeveloperOptionsScreenModels.swift b/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/DeveloperOptionsScreenModels.swift index ba618ad297..2a04944c20 100644 --- a/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/DeveloperOptionsScreenModels.swift +++ b/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/DeveloperOptionsScreenModels.swift @@ -18,13 +18,16 @@ import Foundation enum DeveloperOptionsScreenViewModelAction { case clearCache - /// Logout without a confirmation to avoid losing keys when trying SSS. - case forceLogout } struct DeveloperOptionsScreenViewState: BindableState { let elementCallBaseURL: URL + let isUsingNativeSlidingSync: Bool var bindings: DeveloperOptionsScreenViewStateBindings + + var slidingSyncFooter: String { + "The method used to configure sliding sync when signing in. Changing this setting has no effect until you sign out.\n\nYour current session is using \(isUsingNativeSlidingSync ? "native sliding sync." : "a sliding sync proxy.")" + } } // periphery: ignore - subscripts are seen as false positive @@ -48,7 +51,7 @@ enum DeveloperOptionsScreenViewAction { protocol DeveloperOptionsProtocol: AnyObject { var logLevel: TracingConfiguration.LogLevel { get set } - var simplifiedSlidingSyncEnabled: Bool { get set } + var slidingSyncDiscovery: AppSettings.SlidingSyncDiscovery { get set } var hideUnreadMessagesBadge: Bool { get set } var elementCallBaseURLOverride: URL? { get set } var fuzzyRoomListSearchEnabled: Bool { get set } diff --git a/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/DeveloperOptionsScreenViewModel.swift b/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/DeveloperOptionsScreenViewModel.swift index e6450adc3c..fb62f2af1d 100644 --- a/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/DeveloperOptionsScreenViewModel.swift +++ b/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/DeveloperOptionsScreenViewModel.swift @@ -26,21 +26,11 @@ class DeveloperOptionsScreenViewModel: DeveloperOptionsScreenViewModelType, Deve actionsSubject.eraseToAnyPublisher() } - init(developerOptions: DeveloperOptionsProtocol, elementCallBaseURL: URL) { + init(developerOptions: DeveloperOptionsProtocol, elementCallBaseURL: URL, isUsingNativeSlidingSync: Bool) { let bindings = DeveloperOptionsScreenViewStateBindings(developerOptions: developerOptions) - let state = DeveloperOptionsScreenViewState(elementCallBaseURL: elementCallBaseURL, bindings: bindings) + let state = DeveloperOptionsScreenViewState(elementCallBaseURL: elementCallBaseURL, isUsingNativeSlidingSync: isUsingNativeSlidingSync, bindings: bindings) super.init(initialViewState: state) - - context.$viewState - .map(\.bindings.simplifiedSlidingSyncEnabled) - .removeDuplicates() - .dropFirst() // Ignore the initial value received when opening the screen. - .sink { [weak self] isEnabled in - MXLog.error("Toggled simplifiedSlidingSyncEnabled: \(isEnabled). Signing out.") - self?.actionsSubject.send(.forceLogout) - } - .store(in: &cancellables) } override func process(viewAction: DeveloperOptionsScreenViewAction) { diff --git a/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/View/DeveloperOptionsScreen.swift b/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/View/DeveloperOptionsScreen.swift index 3f3ed9eb16..e1c1ee4965 100644 --- a/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/View/DeveloperOptionsScreen.swift +++ b/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/View/DeveloperOptionsScreen.swift @@ -32,11 +32,16 @@ struct DeveloperOptionsScreen: View { LogLevelConfigurationView(logLevel: $context.logLevel) } - Section("Sliding Sync") { - Toggle(isOn: $context.simplifiedSlidingSyncEnabled) { - Text("Simplified Sliding Sync") - Text("When toggled you'll be logged out of the app and will need to log in again.") + Section { + Picker("Discovery", selection: $context.slidingSyncDiscovery) { + Text("Proxy only").tag(AppSettings.SlidingSyncDiscovery.proxy) + Text("Automatic").tag(AppSettings.SlidingSyncDiscovery.native) + Text("Force Native ⚠️").tag(AppSettings.SlidingSyncDiscovery.forceNative) } + } header: { + Text("Sliding Sync") + } footer: { + Text(context.viewState.slidingSyncFooter) } Section("Message Pinning") { @@ -174,7 +179,8 @@ private struct LogLevelConfigurationView: View { struct DeveloperOptionsScreen_Previews: PreviewProvider { static let viewModel = DeveloperOptionsScreenViewModel(developerOptions: ServiceLocator.shared.settings, - elementCallBaseURL: ServiceLocator.shared.settings.elementCallBaseURL) + elementCallBaseURL: ServiceLocator.shared.settings.elementCallBaseURL, + isUsingNativeSlidingSync: true) static var previews: some View { NavigationStack { DeveloperOptionsScreen(context: viewModel.context) diff --git a/ElementX/Sources/Services/Authentication/AuthenticationClientBuilder.swift b/ElementX/Sources/Services/Authentication/AuthenticationClientBuilder.swift new file mode 100644 index 0000000000..42555699f0 --- /dev/null +++ b/ElementX/Sources/Services/Authentication/AuthenticationClientBuilder.swift @@ -0,0 +1,88 @@ +// +// Copyright 2024 New Vector Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Foundation +import MatrixRustSDK + +/// A wrapper around `ClientBuilder` to share reusable code between Normal and QR logins. +struct AuthenticationClientBuilder { + let sessionDirectories: SessionDirectories + let passphrase: String + let clientSessionDelegate: ClientSessionDelegate + + let appSettings: AppSettings + let appHooks: AppHooks + + /// Builds a Client for login using OIDC or password authentication. + func build(homeserverAddress: String) async throws -> Client { + if appSettings.slidingSyncDiscovery == .forceNative { + return try await makeClientBuilder(slidingSync: .forceNative).serverNameOrHomeserverUrl(serverNameOrUrl: homeserverAddress).build() + } + + if appSettings.slidingSyncDiscovery == .native { + do { + return try await makeClientBuilder(slidingSync: .discoverNative).serverNameOrHomeserverUrl(serverNameOrUrl: homeserverAddress).build() + } catch { + MXLog.warning("Native sliding sync not available: \(error)") + MXLog.info("Falling back to a sliding sync proxy.") + } + } + + return try await makeClientBuilder(slidingSync: .discoverProxy).serverNameOrHomeserverUrl(serverNameOrUrl: homeserverAddress).build() + } + + /// Builds a Client, authenticating with the given QR code data. + func buildWithQRCode(qrCodeData: QrCodeData, + oidcConfiguration: OIDCConfigurationProxy, + progressListener: QrLoginProgressListenerProxy) async throws -> Client { + if appSettings.slidingSyncDiscovery == .forceNative { + return try await makeClientBuilder(slidingSync: .forceNative).buildWithQrCode(qrCodeData: qrCodeData, + oidcConfiguration: oidcConfiguration.rustValue, + progressListener: progressListener) + } + + if appSettings.slidingSyncDiscovery == .native { + do { + return try await makeClientBuilder(slidingSync: .discoverNative).buildWithQrCode(qrCodeData: qrCodeData, + oidcConfiguration: oidcConfiguration.rustValue, + progressListener: progressListener) + } catch HumanQrLoginError.SlidingSyncNotAvailable { + MXLog.warning("Native sliding sync not available") + MXLog.info("Falling back to a sliding sync proxy.") + } catch { + throw error + } + } + + return try await makeClientBuilder(slidingSync: .discoverProxy).buildWithQrCode(qrCodeData: qrCodeData, + oidcConfiguration: oidcConfiguration.rustValue, + progressListener: progressListener) + } + + // MARK: - Private + + /// The base builder configuration used for authentication within the app. + private func makeClientBuilder(slidingSync: ClientBuilderSlidingSync) -> ClientBuilder { + ClientBuilder + .baseBuilder(httpProxy: appSettings.websiteURL.globalProxy, + slidingSync: slidingSync, + sessionDelegate: clientSessionDelegate, + appHooks: appHooks) + .sessionPaths(dataPath: sessionDirectories.dataPath, + cachePath: sessionDirectories.cachePath) + .passphrase(passphrase: passphrase) + } +} diff --git a/ElementX/Sources/Services/Authentication/AuthenticationService.swift b/ElementX/Sources/Services/Authentication/AuthenticationService.swift index 956435d038..1b7e0cae34 100644 --- a/ElementX/Sources/Services/Authentication/AuthenticationService.swift +++ b/ElementX/Sources/Services/Authentication/AuthenticationService.swift @@ -47,9 +47,11 @@ class AuthenticationService: AuthenticationServiceProtocol { do { var homeserver = LoginHomeserver(address: homeserverAddress, loginMode: .unknown) - let client = try await makeClientBuilder().serverNameOrHomeserverUrl(serverNameOrUrl: homeserverAddress).build() + let client = try await makeClientBuilder().build(homeserverAddress: homeserverAddress) let loginDetails = await client.homeserverLoginDetails() + MXLog.info("Sliding sync: \(client.slidingSyncVersion())") + if loginDetails.supportsOidcLogin() { homeserver.loginMode = .oidc } else if loginDetails.supportsPasswordLogin() { @@ -64,7 +66,7 @@ class AuthenticationService: AuthenticationServiceProtocol { } catch ClientBuildError.WellKnownDeserializationError(let error) { MXLog.error("The user entered a server with an invalid well-known file: \(error)") return .failure(.invalidWellKnown(error)) - } catch ClientBuildError.SlidingSyncNotAvailable { + } catch ClientBuildError.SlidingSyncVersion(let error) { MXLog.info("User entered a homeserver that isn't configured for sliding sync.") return .failure(.slidingSyncNotAvailable) } catch { @@ -138,20 +140,16 @@ class AuthenticationService: AuthenticationServiceProtocol { // MARK: - Private - private func makeClientBuilder() -> ClientBuilder { + private func makeClientBuilder() -> AuthenticationClientBuilder { // 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, - sessionDelegate: userSessionStore.clientSessionDelegate, - appHooks: appHooks) - .sessionPaths(dataPath: sessionDirectories.dataPath, - cachePath: sessionDirectories.cachePath) - .passphrase(passphrase: passphrase) + return AuthenticationClientBuilder(sessionDirectories: sessionDirectories, + passphrase: passphrase, + clientSessionDelegate: userSessionStore.clientSessionDelegate, + appSettings: appSettings, + appHooks: appHooks) } private func rotateSessionDirectory() { diff --git a/ElementX/Sources/Services/QRCode/QRCodeLoginService.swift b/ElementX/Sources/Services/QRCode/QRCodeLoginService.swift index e9dee279a4..aa54f17bbc 100644 --- a/ElementX/Sources/Services/QRCode/QRCodeLoginService.swift +++ b/ElementX/Sources/Services/QRCode/QRCodeLoginService.swift @@ -57,9 +57,10 @@ final class QRCodeLoginService: QRCodeLoginServiceProtocol { } do { - let client = try await makeClientBuilder().buildWithQrCode(qrCodeData: qrData, - oidcConfiguration: appSettings.oidcConfiguration.rustValue, + let client = try await makeClientBuilder().buildWithQRCode(qrCodeData: qrData, + oidcConfiguration: appSettings.oidcConfiguration, progressListener: listener) + MXLog.info("Sliding sync: \(client.slidingSyncVersion())") return await userSession(for: client) } catch let error as HumanQrLoginError { MXLog.error("QRCode login error: \(error)") @@ -72,20 +73,16 @@ final class QRCodeLoginService: QRCodeLoginServiceProtocol { // MARK: - Private - private func makeClientBuilder() -> ClientBuilder { + private func makeClientBuilder() -> AuthenticationClientBuilder { // 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) - .sessionPaths(dataPath: sessionDirectories.dataPath, - cachePath: sessionDirectories.cachePath) - .passphrase(passphrase: passphrase) + return AuthenticationClientBuilder(sessionDirectories: sessionDirectories, + passphrase: passphrase, + clientSessionDelegate: userSessionStore.clientSessionDelegate, + appSettings: appSettings, + appHooks: appHooks) } private func rotateSessionDirectory() {