Add a ClientBuilder hook. (#3056)
This commit is contained in:
@@ -82,6 +82,7 @@
|
||||
1146E9EDCF8344F7D6E0D553 /* MockCoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0376C429FAB1687C3D905F3E /* MockCoder.swift */; };
|
||||
119AE9A3FC6E0606C1146528 /* NotificationSettingsEditScreenRoomCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C97F8963B14EB0AF3940DDBF /* NotificationSettingsEditScreenRoomCell.swift */; };
|
||||
11A6B8E3CBDBF0A4107FF4CE /* OnboardingFlowCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3285BD95B564CA2A948E511 /* OnboardingFlowCoordinator.swift */; };
|
||||
121DDBFAD88B785630852C9A /* AppHooks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2B048CB133239700CD890F5D /* AppHooks.swift */; };
|
||||
126EE01D8BEAEF26105D83C5 /* RoomDetailsScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1A5FEF17ED7E6176D922D4F /* RoomDetailsScreen.swift */; };
|
||||
12C867E85E6D12EEDFD0B127 /* CustomStringConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96C4762F8D6112E43117DB2F /* CustomStringConvertible.swift */; };
|
||||
12CCA59536EDD99A3272CF77 /* AppSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = AC3F82523D6F48B926D6AF68 /* AppSettings.swift */; };
|
||||
@@ -5712,6 +5713,7 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
121DDBFAD88B785630852C9A /* AppHooks.swift in Sources */,
|
||||
43F06DF42EC00B3CE2B020A4 /* AppSettings.swift in Sources */,
|
||||
F253AAB4C8F06208173C9C4A /* Assets.swift in Sources */,
|
||||
484202C5D50983442D24D061 /* AttributedString.swift in Sources */,
|
||||
|
||||
@@ -102,7 +102,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
|
||||
|
||||
let keychainController = KeychainController(service: .sessions,
|
||||
accessGroup: InfoPlistReader.main.keychainAccessGroupIdentifier)
|
||||
userSessionStore = UserSessionStore(keychainController: keychainController)
|
||||
userSessionStore = UserSessionStore(keychainController: keychainController, appHooks: appHooks)
|
||||
|
||||
let appLockService = AppLockService(keychainController: keychainController, appSettings: appSettings)
|
||||
let appLockNavigationCoordinator = NavigationRootCoordinator()
|
||||
@@ -458,10 +458,12 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
|
||||
let encryptionKeyProvider = EncryptionKeyProvider()
|
||||
let authenticationService = AuthenticationService(userSessionStore: userSessionStore,
|
||||
encryptionKeyProvider: encryptionKeyProvider,
|
||||
appSettings: appSettings)
|
||||
appSettings: appSettings,
|
||||
appHooks: appHooks)
|
||||
let qrCodeLoginService = QRCodeLoginService(encryptionKeyProvider: encryptionKeyProvider,
|
||||
userSessionStore: userSessionStore,
|
||||
appSettings: appSettings)
|
||||
appSettings: appSettings,
|
||||
appHooks: appHooks)
|
||||
|
||||
authenticationFlowCoordinator = AuthenticationFlowCoordinator(authenticationService: authenticationService,
|
||||
qrCodeLoginService: qrCodeLoginService,
|
||||
@@ -489,7 +491,8 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
|
||||
|
||||
let authenticationService = AuthenticationService(userSessionStore: userSessionStore,
|
||||
encryptionKeyProvider: EncryptionKeyProvider(),
|
||||
appSettings: appSettings)
|
||||
appSettings: appSettings,
|
||||
appHooks: appHooks)
|
||||
_ = await authenticationService.configure(for: userSession.clientProxy.homeserver)
|
||||
|
||||
let parameters = SoftLogoutScreenCoordinatorParameters(authenticationService: authenticationService,
|
||||
|
||||
@@ -15,10 +15,12 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import MatrixRustSDK
|
||||
|
||||
// MARK: Registration
|
||||
|
||||
class AppHooks: AppHooksProtocol {
|
||||
#if IS_MAIN_APP
|
||||
private var appSettingsHook: AppSettingsHookProtocol?
|
||||
func registerAppSettingsHook(_ hook: AppSettingsHookProtocol) {
|
||||
appSettingsHook = hook
|
||||
@@ -38,6 +40,17 @@ class AppHooks: AppHooksProtocol {
|
||||
guard let bugReportHook else { return bugReport }
|
||||
return bugReportHook.run(bugReport: bugReport)
|
||||
}
|
||||
#endif
|
||||
|
||||
private var clientBuilderHook: ClientBuilderHookProtocol?
|
||||
func registerClientBuilderHook(_ hook: ClientBuilderHookProtocol) {
|
||||
clientBuilderHook = hook
|
||||
}
|
||||
|
||||
func runClientBuilderHook(_ clientBuilder: ClientBuilder) -> ClientBuilder {
|
||||
guard let clientBuilderHook else { return clientBuilder }
|
||||
return clientBuilderHook.run(builder: clientBuilder)
|
||||
}
|
||||
}
|
||||
|
||||
protocol AppHooksProtocol {
|
||||
@@ -50,6 +63,7 @@ extension AppHooksProtocol {
|
||||
|
||||
// MARK: Protocols
|
||||
|
||||
#if IS_MAIN_APP
|
||||
protocol AppSettingsHookProtocol {
|
||||
func run(appSettings: AppSettings) -> AppSettings
|
||||
}
|
||||
@@ -57,3 +71,8 @@ protocol AppSettingsHookProtocol {
|
||||
protocol BugReportHookProtocol {
|
||||
func run(bugReport: BugReport) -> BugReport
|
||||
}
|
||||
#endif
|
||||
|
||||
protocol ClientBuilderHookProtocol {
|
||||
func run(builder: ClientBuilder) -> ClientBuilder
|
||||
}
|
||||
|
||||
@@ -19,7 +19,11 @@ import MatrixRustSDK
|
||||
|
||||
extension ClientBuilder {
|
||||
/// A helper method that applies the common builder modifiers needed for the app.
|
||||
static func baseBuilder(setupEncryption: Bool = true, httpProxy: String? = nil, slidingSyncProxy: URL? = nil, sessionDelegate: ClientSessionDelegate) -> ClientBuilder {
|
||||
static func baseBuilder(setupEncryption: Bool = true,
|
||||
httpProxy: String? = nil,
|
||||
slidingSyncProxy: URL? = nil,
|
||||
sessionDelegate: ClientSessionDelegate,
|
||||
appHooks: AppHooks) -> ClientBuilder {
|
||||
var builder = ClientBuilder()
|
||||
.slidingSyncProxy(slidingSyncProxy: slidingSyncProxy?.absoluteString)
|
||||
.enableCrossProcessRefreshLock(processId: InfoPlistReader.main.bundleIdentifier, sessionDelegate: sessionDelegate)
|
||||
@@ -36,6 +40,6 @@ extension ClientBuilder {
|
||||
builder = builder.proxy(url: httpProxy)
|
||||
}
|
||||
|
||||
return builder
|
||||
return appHooks.runClientBuilderHook(builder)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,15 +25,17 @@ class AuthenticationService: AuthenticationServiceProtocol {
|
||||
|
||||
private let userSessionStore: UserSessionStoreProtocol
|
||||
private let appSettings: AppSettings
|
||||
private let appHooks: AppHooks
|
||||
|
||||
private let homeserverSubject: CurrentValueSubject<LoginHomeserver, Never>
|
||||
var homeserver: CurrentValuePublisher<LoginHomeserver, Never> { homeserverSubject.asCurrentValuePublisher() }
|
||||
|
||||
init(userSessionStore: UserSessionStoreProtocol, encryptionKeyProvider: EncryptionKeyProviderProtocol, appSettings: AppSettings) {
|
||||
init(userSessionStore: UserSessionStoreProtocol, encryptionKeyProvider: EncryptionKeyProviderProtocol, appSettings: AppSettings, appHooks: AppHooks) {
|
||||
sessionDirectory = .sessionsBaseDirectory.appending(component: UUID().uuidString)
|
||||
passphrase = encryptionKeyProvider.generateKey().base64EncodedString()
|
||||
self.userSessionStore = userSessionStore
|
||||
self.appSettings = appSettings
|
||||
self.appHooks = appHooks
|
||||
|
||||
homeserverSubject = .init(LoginHomeserver(address: appSettings.defaultHomeserverAddress,
|
||||
loginMode: .unknown))
|
||||
@@ -140,7 +142,8 @@ class AuthenticationService: AuthenticationServiceProtocol {
|
||||
ClientBuilder
|
||||
.baseBuilder(httpProxy: appSettings.websiteURL.globalProxy,
|
||||
slidingSyncProxy: appSettings.slidingSyncProxyURL,
|
||||
sessionDelegate: userSessionStore.clientSessionDelegate)
|
||||
sessionDelegate: userSessionStore.clientSessionDelegate,
|
||||
appHooks: appHooks)
|
||||
.sessionPath(path: sessionDirectory.path(percentEncoded: false))
|
||||
.passphrase(passphrase: passphrase)
|
||||
.requiresSlidingSync()
|
||||
|
||||
@@ -22,8 +22,10 @@ import MatrixRustSDK
|
||||
final class QRCodeLoginService: QRCodeLoginServiceProtocol {
|
||||
private let sessionDirectory: URL
|
||||
private let passphrase: String
|
||||
|
||||
private let userSessionStore: UserSessionStoreProtocol
|
||||
private let appSettings: AppSettings
|
||||
private let appHooks: AppHooks
|
||||
|
||||
private let qrLoginProgressSubject = PassthroughSubject<QrLoginProgress, Never>()
|
||||
var qrLoginProgressPublisher: AnyPublisher<QrLoginProgress, Never> {
|
||||
@@ -32,11 +34,13 @@ final class QRCodeLoginService: QRCodeLoginServiceProtocol {
|
||||
|
||||
init(encryptionKeyProvider: EncryptionKeyProviderProtocol,
|
||||
userSessionStore: UserSessionStoreProtocol,
|
||||
appSettings: AppSettings) {
|
||||
self.userSessionStore = userSessionStore
|
||||
self.appSettings = appSettings
|
||||
appSettings: AppSettings,
|
||||
appHooks: AppHooks) {
|
||||
sessionDirectory = .sessionsBaseDirectory.appending(component: UUID().uuidString)
|
||||
passphrase = encryptionKeyProvider.generateKey().base64EncodedString()
|
||||
self.userSessionStore = userSessionStore
|
||||
self.appSettings = appSettings
|
||||
self.appHooks = appHooks
|
||||
}
|
||||
|
||||
func loginWithQRCode(data: Data) async -> Result<UserSessionProtocol, QRCodeLoginServiceError> {
|
||||
@@ -56,7 +60,8 @@ final class QRCodeLoginService: QRCodeLoginServiceProtocol {
|
||||
let client = try await ClientBuilder
|
||||
.baseBuilder(httpProxy: appSettings.websiteURL.globalProxy,
|
||||
slidingSyncProxy: appSettings.slidingSyncProxyURL,
|
||||
sessionDelegate: userSessionStore.clientSessionDelegate)
|
||||
sessionDelegate: userSessionStore.clientSessionDelegate,
|
||||
appHooks: appHooks)
|
||||
.sessionPath(path: sessionDirectory.path(percentEncoded: false))
|
||||
.passphrase(passphrase: passphrase)
|
||||
.requiresSlidingSync()
|
||||
|
||||
@@ -20,6 +20,7 @@ import MatrixRustSDK
|
||||
|
||||
class UserSessionStore: UserSessionStoreProtocol {
|
||||
private let keychainController: KeychainControllerProtocol
|
||||
private let appHooks: AppHooks
|
||||
private let matrixSDKStateKey = "matrix-sdk-state"
|
||||
|
||||
/// Whether or not there are sessions in the store.
|
||||
@@ -29,8 +30,9 @@ class UserSessionStore: UserSessionStoreProtocol {
|
||||
|
||||
var clientSessionDelegate: ClientSessionDelegate { keychainController }
|
||||
|
||||
init(keychainController: KeychainControllerProtocol) {
|
||||
init(keychainController: KeychainControllerProtocol, appHooks: AppHooks) {
|
||||
self.keychainController = keychainController
|
||||
self.appHooks = appHooks
|
||||
}
|
||||
|
||||
/// Deletes all data stored in the shared container and keychain
|
||||
@@ -120,7 +122,8 @@ class UserSessionStore: UserSessionStoreProtocol {
|
||||
|
||||
let builder = ClientBuilder
|
||||
.baseBuilder(httpProxy: URL(string: homeserverURL)?.globalProxy,
|
||||
sessionDelegate: keychainController)
|
||||
sessionDelegate: keychainController,
|
||||
appHooks: appHooks)
|
||||
.sessionPath(path: credentials.restorationToken.sessionDirectory.path(percentEncoded: false))
|
||||
.username(username: credentials.userID)
|
||||
.homeserverUrl(url: homeserverURL)
|
||||
|
||||
@@ -50,6 +50,8 @@ class NotificationServiceExtension: UNNotificationServiceExtension {
|
||||
private var handler: ((UNNotificationContent) -> Void)?
|
||||
private var modifiedContent: UNMutableNotificationContent?
|
||||
|
||||
private let appHooks = AppHooks()
|
||||
|
||||
// Used to create one single UserSession across process/instances/runs
|
||||
private static let serialQueue = DispatchQueue(label: "io.element.elementx.nse")
|
||||
private static var userSession: NSEUserSession?
|
||||
@@ -82,9 +84,9 @@ class NotificationServiceExtension: UNNotificationServiceExtension {
|
||||
if Self.userSession == nil {
|
||||
// This function might be run concurrently and from different processes
|
||||
// It's imperative that we create **at most** one UserSession/Client per process
|
||||
Task.synchronous {
|
||||
Task.synchronous { [appHooks] in
|
||||
do {
|
||||
Self.userSession = try await NSEUserSession(credentials: credentials, clientSessionDelegate: keychainController)
|
||||
Self.userSession = try await NSEUserSession(credentials: credentials, clientSessionDelegate: keychainController, appHooks: appHooks)
|
||||
} catch {
|
||||
MXLog.error("Failed creating user session with error: \(error)")
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ final class NSEUserSession {
|
||||
imageCache: .onlyOnDisk)
|
||||
private let delegateHandle: TaskHandle?
|
||||
|
||||
init(credentials: KeychainCredentials, clientSessionDelegate: ClientSessionDelegate) async throws {
|
||||
init(credentials: KeychainCredentials, clientSessionDelegate: ClientSessionDelegate, appHooks: AppHooks) async throws {
|
||||
userID = credentials.userID
|
||||
if credentials.restorationToken.passphrase != nil {
|
||||
MXLog.info("Restoring client with encrypted store.")
|
||||
@@ -35,7 +35,8 @@ final class NSEUserSession {
|
||||
let clientBuilder = ClientBuilder
|
||||
.baseBuilder(setupEncryption: false,
|
||||
httpProxy: URL(string: homeserverURL)?.globalProxy,
|
||||
sessionDelegate: clientSessionDelegate)
|
||||
sessionDelegate: clientSessionDelegate,
|
||||
appHooks: appHooks)
|
||||
.sessionPath(path: credentials.restorationToken.sessionDirectory.path(percentEncoded: false))
|
||||
.username(username: credentials.userID)
|
||||
.homeserverUrl(url: homeserverURL)
|
||||
|
||||
@@ -107,3 +107,4 @@ targets:
|
||||
- path: ../../ElementX/Sources/Services/UserSession/RestorationToken.swift
|
||||
- path: ../../ElementX/Sources/Services/ElementCall/ElementCallServiceConstants.swift
|
||||
- path: ../../ElementX/Sources/Application/AppSettings.swift
|
||||
- path: ../../ElementX/Sources/Hooks/AppHooks.swift
|
||||
|
||||
Reference in New Issue
Block a user