mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-03 16:10:20 +00:00
Simplify authentication logic
matrix.org now supports MAS so we don't need the web registration helper anymore.
This commit is contained in:
@@ -16,10 +16,10 @@ class AuthenticationServiceTests: XCTestCase {
|
||||
|
||||
var service: AuthenticationService!
|
||||
|
||||
func testLogin() async {
|
||||
setupMocks()
|
||||
func testPasswordLogin() async {
|
||||
setupMocks(serverAddress: "example.com")
|
||||
|
||||
switch await service.configure(for: "matrix.org", flow: .login) {
|
||||
switch await service.configure(for: "example.com", flow: .login) {
|
||||
case .success:
|
||||
break
|
||||
case .failure(let error):
|
||||
@@ -27,7 +27,7 @@ class AuthenticationServiceTests: XCTestCase {
|
||||
}
|
||||
|
||||
XCTAssertEqual(service.flow, .login)
|
||||
XCTAssertEqual(service.homeserver.value, .mockMatrixDotOrg)
|
||||
XCTAssertEqual(service.homeserver.value, .mockBasicServer)
|
||||
|
||||
switch await service.login(username: "alice", password: "12345678", initialDeviceName: nil, deviceID: nil) {
|
||||
case .success:
|
||||
@@ -40,7 +40,21 @@ class AuthenticationServiceTests: XCTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
func testConfigureRegister() async {
|
||||
func testConfigureLoginWithOIDC() async {
|
||||
setupMocks()
|
||||
|
||||
switch await service.configure(for: "matrix.org", flow: .login) {
|
||||
case .success:
|
||||
break
|
||||
case .failure(let error):
|
||||
XCTFail("Unexpected failure: \(error)")
|
||||
}
|
||||
|
||||
XCTAssertEqual(service.flow, .login)
|
||||
XCTAssertEqual(service.homeserver.value, .mockMatrixDotOrg)
|
||||
}
|
||||
|
||||
func testConfigureRegisterWithOIDC() async {
|
||||
setupMocks()
|
||||
|
||||
switch await service.configure(for: "matrix.org", flow: .register) {
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
//
|
||||
// Copyright 2024 New Vector Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
// Please see LICENSE files in the repository root for full details.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
|
||||
@testable import ElementX
|
||||
@testable import MatrixRustSDK
|
||||
|
||||
class ClientProtocolTests: XCTestCase {
|
||||
let server = "https://matrix.org"
|
||||
let userIDServerName = "matrix.org"
|
||||
let wellKnownURL = "https://matrix.org/.well-known/element/element.json"
|
||||
|
||||
var client: ClientProtocol!
|
||||
|
||||
func testWellKnownLoggedOut() async {
|
||||
// Given a client that is logged out but has discovered a server.
|
||||
let client = ClientSDKMock()
|
||||
client.userIdServerNameThrowableError = MockError.notAvailable
|
||||
client.serverReturnValue = server
|
||||
|
||||
// When discovering a server that contains the registration helper URL.
|
||||
client.getUrlUrlClosure = { [wellKnownURL] url in
|
||||
guard url == wellKnownURL else {
|
||||
XCTFail("An unexpected URL was used.")
|
||||
throw MockError.notAvailable
|
||||
}
|
||||
return "{\"registration_helper_url\":\"https://develop.element.io/#/mobile_register\"}"
|
||||
}
|
||||
|
||||
guard case let .success(wellKnown) = await client.getElementWellKnown() else {
|
||||
XCTFail("The request should succeed.")
|
||||
return
|
||||
}
|
||||
|
||||
// Then the well-known should include that URL.
|
||||
XCTAssertEqual(wellKnown, .init(call: nil, registrationHelperUrl: "https://develop.element.io/#/mobile_register"))
|
||||
}
|
||||
|
||||
func testWellKnownLoggedIn() async {
|
||||
// Given a client that is logged in.
|
||||
let client = ClientSDKMock()
|
||||
client.userIdServerNameReturnValue = userIDServerName
|
||||
|
||||
// When discovering a server that contains a custom call widget URL.
|
||||
client.getUrlUrlClosure = { [wellKnownURL] url in
|
||||
guard url == wellKnownURL else {
|
||||
XCTFail("An unexpected URL was used.")
|
||||
throw MockError.notAvailable
|
||||
}
|
||||
return "{\"call\":{\"widget_url\":\"https://call.element.dev\"}}"
|
||||
}
|
||||
|
||||
guard case let .success(wellKnown) = await client.getElementWellKnown() else {
|
||||
XCTFail("The request should succeed.")
|
||||
return
|
||||
}
|
||||
|
||||
// Then the well-known should include that URL.
|
||||
XCTAssertEqual(wellKnown, .init(call: .init(widgetUrl: "https://call.element.dev"), registrationHelperUrl: nil))
|
||||
}
|
||||
|
||||
enum MockError: Error {
|
||||
case notAvailable
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@ class LoginScreenViewModelTests: XCTestCase {
|
||||
var clientBuilderFactory: AuthenticationClientBuilderFactoryMock!
|
||||
var service: AuthenticationServiceProtocol!
|
||||
|
||||
private func setupViewModel(homeserverAddress: String = "matrix.org") async {
|
||||
private func setupViewModel(homeserverAddress: String = "example.com") async {
|
||||
clientBuilderFactory = AuthenticationClientBuilderFactoryMock(configuration: .init())
|
||||
service = AuthenticationService(userSessionStore: UserSessionStoreMock(configuration: .init()),
|
||||
encryptionKeyProvider: EncryptionKeyProvider(),
|
||||
@@ -36,18 +36,9 @@ class LoginScreenViewModelTests: XCTestCase {
|
||||
analytics: ServiceLocator.shared.analytics)
|
||||
}
|
||||
|
||||
func testMatrixDotOrg() async {
|
||||
// Given the initial view model configured for matrix.org.
|
||||
await setupViewModel()
|
||||
|
||||
// Then the view state should contain a homeserver that matches matrix.org and show the login form.
|
||||
XCTAssertEqual(context.viewState.homeserver, .mockMatrixDotOrg, "The homeserver data should match the default homeserver.")
|
||||
XCTAssertEqual(context.viewState.loginMode, .password, "The login form should be shown.")
|
||||
}
|
||||
|
||||
func testBasicServer() async {
|
||||
// Given the view model configured for a basic server example.com that only supports password authentication.
|
||||
await setupViewModel(homeserverAddress: "example.com")
|
||||
await setupViewModel()
|
||||
|
||||
// Then the view state should be updated with the homeserver and show the login form.
|
||||
XCTAssertEqual(context.viewState.homeserver, .mockBasicServer, "The homeserver data should should match the new homeserver.")
|
||||
|
||||
@@ -89,9 +89,9 @@ class ServerConfirmationScreenViewModelTests: XCTestCase {
|
||||
|
||||
func testRegistrationNotSupportedAlert() async throws {
|
||||
// Given a view model for registration using a service that hasn't been configured and the default server doesn't support registration.
|
||||
setupViewModel(authenticationFlow: .register, supportsRegistrationHelper: false)
|
||||
// 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)
|
||||
XCTAssertFalse(service.homeserver.value.supportsRegistration)
|
||||
XCTAssertEqual(clientBuilderFactory.makeBuilderSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 0)
|
||||
XCTAssertNil(context.alertInfo)
|
||||
|
||||
@@ -100,16 +100,15 @@ class ServerConfirmationScreenViewModelTests: XCTestCase {
|
||||
context.send(viewAction: .confirm)
|
||||
try await deferred.fulfill()
|
||||
|
||||
// Then the configured homeserver should be used and no additional call should be made to the service.
|
||||
// Then the configuration should fail with an alert about not supporting registration.
|
||||
XCTAssertEqual(clientBuilderFactory.makeBuilderSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 1)
|
||||
XCTAssertEqual(context.alertInfo?.id, .registration)
|
||||
}
|
||||
|
||||
func testLoginNotSupportedAlert() async throws {
|
||||
// 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, supportsRegistrationHelper: false, supportsPasswordLogin: false)
|
||||
setupViewModel(authenticationFlow: .login, supportsOIDC: false, supportsOIDCCreatePrompt: false, supportsPasswordLogin: false)
|
||||
XCTAssertEqual(service.homeserver.value.loginMode, .unknown)
|
||||
XCTAssertFalse(service.homeserver.value.supportsRegistration)
|
||||
XCTAssertEqual(clientBuilderFactory.makeBuilderSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 0)
|
||||
XCTAssertNil(context.alertInfo)
|
||||
|
||||
@@ -125,14 +124,11 @@ class ServerConfirmationScreenViewModelTests: XCTestCase {
|
||||
|
||||
// MARK: - Helpers
|
||||
|
||||
private func setupViewModel(authenticationFlow: AuthenticationFlow, supportsRegistrationHelper: Bool = true, supportsPasswordLogin: Bool = true) {
|
||||
private func setupViewModel(authenticationFlow: AuthenticationFlow, supportsOIDC: Bool = true, supportsOIDCCreatePrompt: Bool = true, supportsPasswordLogin: Bool = true) {
|
||||
// Manually create a configuration as the default homeserver address setting is immutable.
|
||||
let clientConfiguration: ClientSDKMock.Configuration = if supportsRegistrationHelper {
|
||||
.init(supportsPasswordLogin: supportsPasswordLogin)
|
||||
} else {
|
||||
.init(supportsPasswordLogin: supportsPasswordLogin, elementWellKnown: "")
|
||||
}
|
||||
let client = ClientSDKMock(configuration: clientConfiguration)
|
||||
let client = ClientSDKMock(configuration: .init(oidcLoginURL: supportsOIDC ? "https://account.matrix.org/authorize" : nil,
|
||||
supportsOIDCCreatePrompt: supportsOIDCCreatePrompt,
|
||||
supportsPasswordLogin: supportsPasswordLogin))
|
||||
let configuration = AuthenticationClientBuilderMock.Configuration(homeserverClients: ["matrix.org": client],
|
||||
qrCodeClient: client)
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@ class ServerSelectionScreenViewModelTests: XCTestCase {
|
||||
// Given a view model for login.
|
||||
setupViewModel(authenticationFlow: .login)
|
||||
XCTAssertEqual(service.homeserver.value.loginMode, .unknown)
|
||||
XCTAssertFalse(service.homeserver.value.supportsRegistration)
|
||||
XCTAssertEqual(clientBuilderFactory.makeBuilderSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 0)
|
||||
|
||||
// When selecting matrix.org.
|
||||
@@ -39,7 +38,6 @@ class ServerSelectionScreenViewModelTests: XCTestCase {
|
||||
// Given a view model for login.
|
||||
setupViewModel(authenticationFlow: .login)
|
||||
XCTAssertEqual(service.homeserver.value.loginMode, .unknown)
|
||||
XCTAssertFalse(service.homeserver.value.supportsRegistration)
|
||||
XCTAssertEqual(clientBuilderFactory.makeBuilderSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 0)
|
||||
XCTAssertNil(context.alertInfo)
|
||||
|
||||
@@ -58,7 +56,6 @@ class ServerSelectionScreenViewModelTests: XCTestCase {
|
||||
// Given a view model for registration.
|
||||
setupViewModel(authenticationFlow: .register)
|
||||
XCTAssertEqual(service.homeserver.value.loginMode, .unknown)
|
||||
XCTAssertFalse(service.homeserver.value.supportsRegistration)
|
||||
XCTAssertEqual(clientBuilderFactory.makeBuilderSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 0)
|
||||
|
||||
// When selecting matrix.org.
|
||||
@@ -76,7 +73,6 @@ class ServerSelectionScreenViewModelTests: XCTestCase {
|
||||
// Given a view model for registration.
|
||||
setupViewModel(authenticationFlow: .register)
|
||||
XCTAssertEqual(service.homeserver.value.loginMode, .unknown)
|
||||
XCTAssertFalse(service.homeserver.value.supportsRegistration)
|
||||
XCTAssertEqual(clientBuilderFactory.makeBuilderSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 0)
|
||||
XCTAssertNil(context.alertInfo)
|
||||
|
||||
|
||||
@@ -9,39 +9,14 @@ import XCTest
|
||||
|
||||
@testable import ElementX
|
||||
|
||||
@MainActor
|
||||
class SoftLogoutViewModelTests: XCTestCase {
|
||||
let credentials = SoftLogoutScreenCredentials(userID: "mock_user_id",
|
||||
homeserverName: "https://matrix.org",
|
||||
homeserverName: "https://example.com",
|
||||
userDisplayName: "mock_username",
|
||||
deviceID: "ABCDEFGH")
|
||||
|
||||
@MainActor func testInitialStateForMatrixOrg() {
|
||||
let viewModel = SoftLogoutScreenViewModel(credentials: credentials,
|
||||
homeserver: .mockMatrixDotOrg,
|
||||
keyBackupNeeded: true)
|
||||
let context = viewModel.context
|
||||
|
||||
// Given a view model where the user hasn't yet sent the verification email.
|
||||
XCTAssert(context.password.isEmpty, "The view model should start with an empty password.")
|
||||
XCTAssertFalse(context.viewState.canSubmit, "The view model should start with an invalid password.")
|
||||
XCTAssertEqual(context.viewState.loginMode, .password, "The view model should show login form for the given homeserver.")
|
||||
XCTAssert(context.viewState.showRecoverEncryptionKeysMessage, "The view model should show recover encryption keys message.")
|
||||
}
|
||||
|
||||
@MainActor func testInitialStateForMatrixOrgPasswordEntered() {
|
||||
let viewModel = SoftLogoutScreenViewModel(credentials: credentials,
|
||||
homeserver: .mockMatrixDotOrg,
|
||||
keyBackupNeeded: true,
|
||||
password: "12345678")
|
||||
let context = viewModel.context
|
||||
|
||||
// Given a view model where the user hasn't yet sent the verification email.
|
||||
XCTAssertTrue(context.viewState.canSubmit, "The view model should start with a valid password.")
|
||||
XCTAssertEqual(context.viewState.loginMode, .password, "The view model should show login form for the given homeserver.")
|
||||
XCTAssert(context.viewState.showRecoverEncryptionKeysMessage, "The view model should show recover encryption keys message.")
|
||||
}
|
||||
|
||||
@MainActor func testInitialStateForBasicServer() {
|
||||
func testInitialStateForBasicServer() {
|
||||
let viewModel = SoftLogoutScreenViewModel(credentials: credentials,
|
||||
homeserver: .mockBasicServer,
|
||||
keyBackupNeeded: false)
|
||||
@@ -53,10 +28,23 @@ class SoftLogoutViewModelTests: XCTestCase {
|
||||
XCTAssertEqual(context.viewState.loginMode, .password, "The view model should show login form for the given homeserver.")
|
||||
XCTAssertFalse(context.viewState.showRecoverEncryptionKeysMessage, "The view model should not show recover encryption keys message.")
|
||||
}
|
||||
|
||||
@MainActor func testInitialStateForOIDC() {
|
||||
|
||||
func testInitialStateForBasicServerPasswordEntered() {
|
||||
let viewModel = SoftLogoutScreenViewModel(credentials: credentials,
|
||||
homeserver: .mockOIDC,
|
||||
homeserver: .mockBasicServer,
|
||||
keyBackupNeeded: true,
|
||||
password: "12345678")
|
||||
let context = viewModel.context
|
||||
|
||||
// Given a view model where the user hasn't yet sent the verification email.
|
||||
XCTAssertTrue(context.viewState.canSubmit, "The view model should start with a valid password.")
|
||||
XCTAssertEqual(context.viewState.loginMode, .password, "The view model should show login form for the given homeserver.")
|
||||
XCTAssert(context.viewState.showRecoverEncryptionKeysMessage, "The view model should show recover encryption keys message.")
|
||||
}
|
||||
|
||||
func testInitialStateForOIDC() {
|
||||
let viewModel = SoftLogoutScreenViewModel(credentials: credentials,
|
||||
homeserver: .mockMatrixDotOrg,
|
||||
keyBackupNeeded: false)
|
||||
let context = viewModel.context
|
||||
|
||||
@@ -67,7 +55,7 @@ class SoftLogoutViewModelTests: XCTestCase {
|
||||
XCTAssertFalse(context.viewState.showRecoverEncryptionKeysMessage, "The view model should not show recover encryption keys message.")
|
||||
}
|
||||
|
||||
@MainActor func testInitialStateForUnsupported() {
|
||||
func testInitialStateForUnsupported() {
|
||||
let viewModel = SoftLogoutScreenViewModel(credentials: credentials,
|
||||
homeserver: .mockUnsupported,
|
||||
keyBackupNeeded: false)
|
||||
|
||||
Reference in New Issue
Block a user