Merge the AuthenticationService with the QRCodeLoginService. (#4323)

* Merge the AuthenticationServer with the QRCodeLoginService.

* Merge AuthenticationClientBuilderFactory and AuthenticationClientBuilder into AuthenticationClientFactory

The separation is no longer needed now that password/OIDC login and QR code login have a similar API shape.
This commit is contained in:
Doug
2025-07-15 17:59:15 +01:00
committed by GitHub
parent 07093c2b1a
commit a489ec8a8c
20 changed files with 275 additions and 502 deletions

View File

@@ -11,7 +11,7 @@ import XCTest
@MainActor
class ServerConfirmationScreenViewModelTests: XCTestCase {
var clientBuilderFactory: AuthenticationClientBuilderFactoryMock!
var clientFactory: AuthenticationClientFactoryMock!
var client: ClientSDKMock!
var service: AuthenticationServiceProtocol!
var appSettings: AppSettings!
@@ -37,7 +37,7 @@ class ServerConfirmationScreenViewModelTests: XCTestCase {
setupViewModel(authenticationFlow: .login)
XCTAssertEqual(service.homeserver.value.loginMode, .unknown)
XCTAssertEqual(context.viewState.mode, .confirmation(service.homeserver.value.address))
XCTAssertEqual(clientBuilderFactory.makeBuilderSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 0)
XCTAssertEqual(clientFactory.makeClientHomeserverAddressSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 0)
XCTAssertEqual(client.urlForOidcOidcConfigurationPromptLoginHintDeviceIdCallsCount, 0)
// When continuing from the confirmation screen.
@@ -46,7 +46,7 @@ class ServerConfirmationScreenViewModelTests: XCTestCase {
try await deferred.fulfill()
// Then a call to configure service should be made.
XCTAssertEqual(clientBuilderFactory.makeBuilderSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 1)
XCTAssertEqual(clientFactory.makeClientHomeserverAddressSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 1)
XCTAssertEqual(client.urlForOidcOidcConfigurationPromptLoginHintDeviceIdCallsCount, 1)
XCTAssertEqual(client.urlForOidcOidcConfigurationPromptLoginHintDeviceIdReceivedArguments?.prompt, .consent)
XCTAssertEqual(service.homeserver.value.loginMode, .oidc(supportsCreatePrompt: true))
@@ -61,7 +61,7 @@ class ServerConfirmationScreenViewModelTests: XCTestCase {
}
XCTAssertEqual(service.homeserver.value.loginMode, .oidc(supportsCreatePrompt: true))
XCTAssertEqual(context.viewState.mode, .confirmation(service.homeserver.value.address))
XCTAssertEqual(clientBuilderFactory.makeBuilderSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 1)
XCTAssertEqual(clientFactory.makeClientHomeserverAddressSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 1)
XCTAssertEqual(client.urlForOidcOidcConfigurationPromptLoginHintDeviceIdCallsCount, 0)
// When continuing from the confirmation screen.
@@ -70,7 +70,7 @@ class ServerConfirmationScreenViewModelTests: XCTestCase {
try await deferred.fulfill()
// Then the configured homeserver should be used and no additional client should be built.
XCTAssertEqual(clientBuilderFactory.makeBuilderSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 1)
XCTAssertEqual(clientFactory.makeClientHomeserverAddressSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 1)
XCTAssertEqual(client.urlForOidcOidcConfigurationPromptLoginHintDeviceIdCallsCount, 1)
XCTAssertEqual(client.urlForOidcOidcConfigurationPromptLoginHintDeviceIdReceivedArguments?.prompt, .consent)
}
@@ -80,7 +80,7 @@ class ServerConfirmationScreenViewModelTests: XCTestCase {
setupViewModel(authenticationFlow: .register)
XCTAssertEqual(service.homeserver.value.loginMode, .unknown)
XCTAssertEqual(context.viewState.mode, .confirmation(service.homeserver.value.address))
XCTAssertEqual(clientBuilderFactory.makeBuilderSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 0)
XCTAssertEqual(clientFactory.makeClientHomeserverAddressSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 0)
XCTAssertEqual(client.urlForOidcOidcConfigurationPromptLoginHintDeviceIdCallsCount, 0)
// When continuing from the confirmation screen.
@@ -89,7 +89,7 @@ class ServerConfirmationScreenViewModelTests: XCTestCase {
try await deferred.fulfill()
// Then a call to configure service should be made.
XCTAssertEqual(clientBuilderFactory.makeBuilderSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 1)
XCTAssertEqual(clientFactory.makeClientHomeserverAddressSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 1)
XCTAssertEqual(client.urlForOidcOidcConfigurationPromptLoginHintDeviceIdCallsCount, 1)
// The create prompt is broken: https://github.com/element-hq/matrix-authentication-service/issues/3429
// XCTAssertEqual(client.urlForOidcOidcConfigurationPromptReceivedArguments?.prompt, .create)
@@ -105,7 +105,7 @@ class ServerConfirmationScreenViewModelTests: XCTestCase {
}
XCTAssertEqual(service.homeserver.value.loginMode, .oidc(supportsCreatePrompt: true))
XCTAssertEqual(context.viewState.mode, .confirmation(service.homeserver.value.address))
XCTAssertEqual(clientBuilderFactory.makeBuilderSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 1)
XCTAssertEqual(clientFactory.makeClientHomeserverAddressSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 1)
XCTAssertEqual(client.urlForOidcOidcConfigurationPromptLoginHintDeviceIdCallsCount, 0)
// When continuing from the confirmation screen.
@@ -114,7 +114,7 @@ class ServerConfirmationScreenViewModelTests: XCTestCase {
try await deferred.fulfill()
// Then the configured homeserver should be used and no additional client should be built.
XCTAssertEqual(clientBuilderFactory.makeBuilderSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 1)
XCTAssertEqual(clientFactory.makeClientHomeserverAddressSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 1)
// The create prompt is broken: https://github.com/element-hq/matrix-authentication-service/issues/3429
// XCTAssertEqual(client.urlForOidcOidcConfigurationPromptReceivedArguments?.prompt, .create)
XCTAssertEqual(client.urlForOidcOidcConfigurationPromptLoginHintDeviceIdCallsCount, 1)
@@ -125,7 +125,7 @@ class ServerConfirmationScreenViewModelTests: XCTestCase {
setupViewModel(authenticationFlow: .login, supportsOIDC: false)
XCTAssertEqual(service.homeserver.value.loginMode, .unknown)
XCTAssertEqual(context.viewState.mode, .confirmation(service.homeserver.value.address))
XCTAssertEqual(clientBuilderFactory.makeBuilderSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 0)
XCTAssertEqual(clientFactory.makeClientHomeserverAddressSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 0)
XCTAssertEqual(client.urlForOidcOidcConfigurationPromptLoginHintDeviceIdCallsCount, 0)
// When continuing from the confirmation screen.
@@ -134,7 +134,7 @@ class ServerConfirmationScreenViewModelTests: XCTestCase {
try await deferred.fulfill()
// Then a call to configure service should be made, but not for the OIDC URL.
XCTAssertEqual(clientBuilderFactory.makeBuilderSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 1)
XCTAssertEqual(clientFactory.makeClientHomeserverAddressSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 1)
XCTAssertEqual(client.urlForOidcOidcConfigurationPromptLoginHintDeviceIdCallsCount, 0)
XCTAssertEqual(service.homeserver.value.loginMode, .password)
}
@@ -148,7 +148,7 @@ class ServerConfirmationScreenViewModelTests: XCTestCase {
}
XCTAssertEqual(service.homeserver.value.loginMode, .password)
XCTAssertEqual(context.viewState.mode, .confirmation(service.homeserver.value.address))
XCTAssertEqual(clientBuilderFactory.makeBuilderSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 1)
XCTAssertEqual(clientFactory.makeClientHomeserverAddressSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 1)
XCTAssertEqual(client.urlForOidcOidcConfigurationPromptLoginHintDeviceIdCallsCount, 0)
// When continuing from the confirmation screen.
@@ -157,7 +157,7 @@ class ServerConfirmationScreenViewModelTests: XCTestCase {
try await deferred.fulfill()
// Then the configured homeserver should be used and no additional client should be built, nor a call to get the OIDC URL.
XCTAssertEqual(clientBuilderFactory.makeBuilderSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 1)
XCTAssertEqual(clientFactory.makeClientHomeserverAddressSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 1)
XCTAssertEqual(client.urlForOidcOidcConfigurationPromptLoginHintDeviceIdCallsCount, 0)
}
@@ -166,7 +166,7 @@ class ServerConfirmationScreenViewModelTests: XCTestCase {
// Note: We don't currently take the create prompt into account when determining registration support.
setupViewModel(authenticationFlow: .register, supportsOIDC: false, supportsOIDCCreatePrompt: false)
XCTAssertEqual(service.homeserver.value.loginMode, .unknown)
XCTAssertEqual(clientBuilderFactory.makeBuilderSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 0)
XCTAssertEqual(clientFactory.makeClientHomeserverAddressSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 0)
XCTAssertNil(context.alertInfo)
// When continuing from the confirmation screen.
@@ -175,7 +175,7 @@ class ServerConfirmationScreenViewModelTests: XCTestCase {
try await deferred.fulfill()
// Then the configuration should fail with an alert about not supporting registration.
XCTAssertEqual(clientBuilderFactory.makeBuilderSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 1)
XCTAssertEqual(clientFactory.makeClientHomeserverAddressSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 1)
XCTAssertEqual(context.alertInfo?.id, .registration)
}
@@ -183,7 +183,7 @@ class ServerConfirmationScreenViewModelTests: XCTestCase {
// Given a view model for login using a service that hasn't been configured and the default server doesn't support login.
setupViewModel(authenticationFlow: .login, supportsOIDC: false, supportsOIDCCreatePrompt: false, supportsPasswordLogin: false)
XCTAssertEqual(service.homeserver.value.loginMode, .unknown)
XCTAssertEqual(clientBuilderFactory.makeBuilderSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 0)
XCTAssertEqual(clientFactory.makeClientHomeserverAddressSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 0)
XCTAssertNil(context.alertInfo)
// When continuing from the confirmation screen.
@@ -192,7 +192,7 @@ class ServerConfirmationScreenViewModelTests: XCTestCase {
try await deferred.fulfill()
// Then the configuration should fail with an alert about not supporting login.
XCTAssertEqual(clientBuilderFactory.makeBuilderSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 1)
XCTAssertEqual(clientFactory.makeClientHomeserverAddressSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 1)
XCTAssertEqual(context.alertInfo?.id, .login)
}
@@ -203,7 +203,7 @@ class ServerConfirmationScreenViewModelTests: XCTestCase {
setupViewModel(authenticationFlow: .login, restrictedFlow: true)
XCTAssertEqual(service.homeserver.value.loginMode, .unknown)
XCTAssertEqual(context.viewState.mode, .picker(appSettings.accountProviders))
XCTAssertEqual(clientBuilderFactory.makeBuilderSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 0)
XCTAssertEqual(clientFactory.makeClientHomeserverAddressSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 0)
XCTAssertEqual(client.urlForOidcOidcConfigurationPromptLoginHintDeviceIdCallsCount, 0)
// When continuing from the confirmation screen.
@@ -212,7 +212,7 @@ class ServerConfirmationScreenViewModelTests: XCTestCase {
try await deferred.fulfill()
// Then a call to configure service should be made.
XCTAssertEqual(clientBuilderFactory.makeBuilderSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 1)
XCTAssertEqual(clientFactory.makeClientHomeserverAddressSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 1)
XCTAssertEqual(client.urlForOidcOidcConfigurationPromptLoginHintDeviceIdCallsCount, 1)
XCTAssertEqual(client.urlForOidcOidcConfigurationPromptLoginHintDeviceIdReceivedArguments?.prompt, .consent)
XCTAssertEqual(service.homeserver.value.loginMode, .oidc(supportsCreatePrompt: true))
@@ -227,7 +227,7 @@ class ServerConfirmationScreenViewModelTests: XCTestCase {
}
XCTAssertEqual(service.homeserver.value.loginMode, .oidc(supportsCreatePrompt: true))
XCTAssertEqual(context.viewState.mode, .picker(appSettings.accountProviders))
XCTAssertEqual(clientBuilderFactory.makeBuilderSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 1)
XCTAssertEqual(clientFactory.makeClientHomeserverAddressSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 1)
XCTAssertEqual(client.urlForOidcOidcConfigurationPromptLoginHintDeviceIdCallsCount, 0)
// When continuing from the confirmation screen.
@@ -236,7 +236,7 @@ class ServerConfirmationScreenViewModelTests: XCTestCase {
try await deferred.fulfill()
// Then the configured homeserver should be used and no additional client should be built.
XCTAssertEqual(clientBuilderFactory.makeBuilderSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 1)
XCTAssertEqual(clientFactory.makeClientHomeserverAddressSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 1)
XCTAssertEqual(client.urlForOidcOidcConfigurationPromptLoginHintDeviceIdCallsCount, 1)
XCTAssertEqual(client.urlForOidcOidcConfigurationPromptLoginHintDeviceIdReceivedArguments?.prompt, .consent)
}
@@ -246,7 +246,7 @@ class ServerConfirmationScreenViewModelTests: XCTestCase {
setupViewModel(authenticationFlow: .login, supportsOIDC: false, restrictedFlow: true)
XCTAssertEqual(service.homeserver.value.loginMode, .unknown)
XCTAssertEqual(context.viewState.mode, .picker(appSettings.accountProviders))
XCTAssertEqual(clientBuilderFactory.makeBuilderSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 0)
XCTAssertEqual(clientFactory.makeClientHomeserverAddressSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 0)
XCTAssertEqual(client.urlForOidcOidcConfigurationPromptLoginHintDeviceIdCallsCount, 0)
// When continuing from the confirmation screen.
@@ -255,7 +255,7 @@ class ServerConfirmationScreenViewModelTests: XCTestCase {
try await deferred.fulfill()
// Then a call to configure service should be made, but not for the OIDC URL.
XCTAssertEqual(clientBuilderFactory.makeBuilderSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 1)
XCTAssertEqual(clientFactory.makeClientHomeserverAddressSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 1)
XCTAssertEqual(client.urlForOidcOidcConfigurationPromptLoginHintDeviceIdCallsCount, 0)
XCTAssertEqual(service.homeserver.value.loginMode, .password)
}
@@ -269,7 +269,7 @@ class ServerConfirmationScreenViewModelTests: XCTestCase {
}
XCTAssertEqual(service.homeserver.value.loginMode, .password)
XCTAssertEqual(context.viewState.mode, .picker(appSettings.accountProviders))
XCTAssertEqual(clientBuilderFactory.makeBuilderSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 1)
XCTAssertEqual(clientFactory.makeClientHomeserverAddressSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 1)
XCTAssertEqual(client.urlForOidcOidcConfigurationPromptLoginHintDeviceIdCallsCount, 0)
// When continuing from the confirmation screen.
@@ -278,7 +278,7 @@ class ServerConfirmationScreenViewModelTests: XCTestCase {
try await deferred.fulfill()
// Then the configured homeserver should be used and no additional client should be built, nor a call to get the OIDC URL.
XCTAssertEqual(clientBuilderFactory.makeBuilderSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 1)
XCTAssertEqual(clientFactory.makeClientHomeserverAddressSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 1)
XCTAssertEqual(client.urlForOidcOidcConfigurationPromptLoginHintDeviceIdCallsCount, 0)
}
@@ -316,12 +316,12 @@ class ServerConfirmationScreenViewModelTests: XCTestCase {
client = ClientSDKMock(configuration: .init(oidcLoginURL: supportsOIDC ? "https://account.matrix.org/authorize" : nil,
supportsOIDCCreatePrompt: supportsOIDCCreatePrompt,
supportsPasswordLogin: supportsPasswordLogin))
let configuration = AuthenticationClientBuilderMock.Configuration(homeserverClients: ["matrix.org": client])
let configuration = AuthenticationClientFactoryMock.Configuration(homeserverClients: ["matrix.org": client])
clientBuilderFactory = AuthenticationClientBuilderFactoryMock(configuration: .init(builderConfiguration: configuration))
clientFactory = AuthenticationClientFactoryMock(configuration: configuration)
service = AuthenticationService(userSessionStore: UserSessionStoreMock(configuration: .init()),
encryptionKeyProvider: EncryptionKeyProvider(),
clientBuilderFactory: clientBuilderFactory,
clientFactory: clientFactory,
appSettings: appSettings,
appHooks: AppHooks())