Simplify authentication logic

matrix.org now supports MAS so we don't need the web registration helper anymore.
This commit is contained in:
Doug
2025-04-10 15:09:40 +01:00
committed by Doug
parent b2c647b1af
commit 1557054753
32 changed files with 86 additions and 709 deletions
@@ -210,8 +210,10 @@ final class AppSettings {
contacts: [supportEmailAddress],
staticRegistrations: oidcStaticRegistrations.mapKeys { $0.absoluteString })
/// A temporary hack to allow registration on matrix.org until MAS is deployed.
let webRegistrationEnabled = true
/// Whether or not the Create Account button is shown on the start screen.
///
/// **Note:** Setting this to false doesn't prevent someone from creating an account when the selected homeserver's MAS allows registration.
let showCreateAccountButton = true
// MARK: - Notifications
@@ -68,7 +68,7 @@ class AuthenticationFlowCoordinator: FlowCoordinatorProtocol {
// MARK: - Private
private func showStartScreen() {
let parameters = AuthenticationStartScreenParameters(webRegistrationEnabled: appSettings.webRegistrationEnabled,
let parameters = AuthenticationStartScreenParameters(showCreateAccountButton: appSettings.showCreateAccountButton,
isBugReportServiceEnabled: bugReportService.isEnabled)
let coordinator = AuthenticationStartScreenCoordinator(parameters: parameters)
@@ -145,10 +145,8 @@ class AuthenticationFlowCoordinator: FlowCoordinatorProtocol {
switch action {
case .continue(let window):
if authenticationService.homeserver.value.loginMode == .oidc, let window {
if authenticationService.homeserver.value.loginMode.supportsOIDCFlow, let window {
showOIDCAuthentication(presentationAnchor: window)
} else if authenticationFlow == .register {
showWebRegistration()
} else {
showLoginScreen()
}
@@ -187,26 +185,6 @@ class AuthenticationFlowCoordinator: FlowCoordinatorProtocol {
navigationStackCoordinator.setSheetCoordinator(navigationCoordinator)
}
private func showWebRegistration() {
let parameters = WebRegistrationScreenCoordinatorParameters(authenticationService: authenticationService,
userIndicatorController: userIndicatorController)
let coordinator = WebRegistrationScreenCoordinator(parameters: parameters)
coordinator.actionsPublisher.sink { [weak self] action in
guard let self else { return }
switch action {
case .cancel:
navigationStackCoordinator.setSheetCoordinator(nil)
case .signedIn(let userSession):
userHasSignedIn(userSession: userSession)
}
}
.store(in: &cancellables)
navigationStackCoordinator.setSheetCoordinator(coordinator)
}
private func showOIDCAuthentication(presentationAnchor: UIWindow) {
startLoading()
@@ -15,19 +15,21 @@ extension AuthenticationClientBuilderMock {
"example.com": ClientSDKMock(configuration: .init(serverAddress: "example.com",
homeserverURL: "https://matrix.example.com",
slidingSyncVersion: .native,
supportsPasswordLogin: true,
elementWellKnown: "")),
oidcLoginURL: nil,
supportsOIDCCreatePrompt: false,
supportsPasswordLogin: true)),
"company.com": ClientSDKMock(configuration: .init(serverAddress: "company.com",
homeserverURL: "https://matrix.company.com",
slidingSyncVersion: .native,
oidcLoginURL: "https://auth.company.com/oidc",
supportsPasswordLogin: false,
elementWellKnown: "")),
supportsOIDCCreatePrompt: false,
supportsPasswordLogin: false)),
"server.net": ClientSDKMock(configuration: .init(serverAddress: "server.net",
homeserverURL: "https://matrix.example.com",
slidingSyncVersion: .native,
supportsPasswordLogin: false,
elementWellKnown: ""))
oidcLoginURL: nil,
supportsOIDCCreatePrompt: false,
supportsPasswordLogin: false))
]
var qrCodeClient = ClientSDKMock(configuration: .init())
}
@@ -76,8 +76,6 @@ extension ClientProxyMock {
recentlyVisitedRoomsReturnValue = .success([])
recentConversationCounterpartsReturnValue = []
getElementWellKnownReturnValue = .success(nil)
loadMediaContentForSourceThrowableError = ClientProxyError.sdkError(ClientProxyMockError.generic)
loadMediaThumbnailForSourceWidthHeightThrowableError = ClientProxyError.sdkError(ClientProxyMockError.generic)
loadMediaFileForSourceFilenameThrowableError = ClientProxyError.sdkError(ClientProxyMockError.generic)
@@ -4281,70 +4281,6 @@ class ClientProxyMock: ClientProxyProtocol, @unchecked Sendable {
return isAliasAvailableReturnValue
}
}
//MARK: - getElementWellKnown
var getElementWellKnownUnderlyingCallsCount = 0
var getElementWellKnownCallsCount: Int {
get {
if Thread.isMainThread {
return getElementWellKnownUnderlyingCallsCount
} else {
var returnValue: Int? = nil
DispatchQueue.main.sync {
returnValue = getElementWellKnownUnderlyingCallsCount
}
return returnValue!
}
}
set {
if Thread.isMainThread {
getElementWellKnownUnderlyingCallsCount = newValue
} else {
DispatchQueue.main.sync {
getElementWellKnownUnderlyingCallsCount = newValue
}
}
}
}
var getElementWellKnownCalled: Bool {
return getElementWellKnownCallsCount > 0
}
var getElementWellKnownUnderlyingReturnValue: Result<ElementWellKnown?, ClientProxyError>!
var getElementWellKnownReturnValue: Result<ElementWellKnown?, ClientProxyError>! {
get {
if Thread.isMainThread {
return getElementWellKnownUnderlyingReturnValue
} else {
var returnValue: Result<ElementWellKnown?, ClientProxyError>? = nil
DispatchQueue.main.sync {
returnValue = getElementWellKnownUnderlyingReturnValue
}
return returnValue!
}
}
set {
if Thread.isMainThread {
getElementWellKnownUnderlyingReturnValue = newValue
} else {
DispatchQueue.main.sync {
getElementWellKnownUnderlyingReturnValue = newValue
}
}
}
}
var getElementWellKnownClosure: (() async -> Result<ElementWellKnown?, ClientProxyError>)?
func getElementWellKnown() async -> Result<ElementWellKnown?, ClientProxyError> {
getElementWellKnownCallsCount += 1
if let getElementWellKnownClosure = getElementWellKnownClosure {
return await getElementWellKnownClosure()
} else {
return getElementWellKnownReturnValue
}
}
//MARK: - clearCaches
var clearCachesUnderlyingCallsCount = 0
@@ -15,9 +15,9 @@ extension ClientSDKMock {
var serverAddress = "matrix.org"
var homeserverURL = "https://matrix-client.matrix.org"
var slidingSyncVersion = SlidingSyncVersion.native
var oidcLoginURL: String?
var oidcLoginURL: String? = "https://account.matrix.org/authorize"
var supportsOIDCCreatePrompt = true
var supportsPasswordLogin = true
var elementWellKnown = "{\"registration_helper_url\":\"https://develop.element.io/#/mobile_register\"}"
var validCredentials = (username: "alice", password: "12345678")
// MARK: Session
@@ -41,7 +41,6 @@ extension ClientSDKMock {
slidingSyncVersionReturnValue = configuration.slidingSyncVersion
userIdServerNameThrowableError = MockError.generic
serverReturnValue = "https://\(configuration.serverAddress)"
getUrlUrlReturnValue = configuration.elementWellKnown
urlForOidcOidcConfigurationPromptReturnValue = OAuthAuthorizationDataSDKMock(configuration: configuration)
loginUsernamePasswordInitialDeviceNameDeviceIdClosure = { username, password, _, _ in
guard username == configuration.validCredentials.username,
@@ -62,6 +61,11 @@ extension HomeserverLoginDetailsSDKMock {
slidingSyncVersionReturnValue = configuration.slidingSyncVersion
supportsPasswordLoginReturnValue = configuration.supportsPasswordLogin
supportsOidcLoginReturnValue = configuration.oidcLoginURL != nil
supportedOidcPromptsReturnValue = switch (configuration.oidcLoginURL, configuration.supportsOIDCCreatePrompt) {
case (.none, _): []
case (.some, true): [.consent, .create]
case (.some, false): [.consent]
}
urlReturnValue = configuration.homeserverURL
}
}
@@ -13,21 +13,13 @@ struct LoginHomeserver: Equatable {
let address: String
/// The types login supported by the homeserver.
var loginMode: LoginMode
/// A temporary helper URL that can be used for registration.
var registrationHelperURL: URL?
/// Creates a new homeserver value.
init(address: String, loginMode: LoginMode, registrationHelperURL: URL? = nil) {
init(address: String, loginMode: LoginMode) {
let address = Self.sanitized(address).components(separatedBy: "://").last ?? address
self.address = address
self.loginMode = loginMode
self.registrationHelperURL = registrationHelperURL
}
/// Whether or not the app is able to register on this homeserver.
var supportsRegistration: Bool {
loginMode == .oidc || (address == "matrix.org" && registrationHelperURL != nil)
}
/// Sanitizes a user entered homeserver address with the following rules
@@ -53,7 +45,7 @@ struct LoginHomeserver: Equatable {
extension LoginHomeserver {
/// A mock homeserver that is configured just like matrix.org.
static var mockMatrixDotOrg: LoginHomeserver {
LoginHomeserver(address: "matrix.org", loginMode: .password, registrationHelperURL: "https://develop.element.io/#/mobile_register")
LoginHomeserver(address: "matrix.org", loginMode: .oidc(supportsCreatePrompt: true))
}
/// A mock homeserver that supports login and registration via a password but has no SSO providers.
@@ -63,7 +55,7 @@ extension LoginHomeserver {
/// A mock homeserver that supports only supports authentication via a single SSO provider.
static var mockOIDC: LoginHomeserver {
LoginHomeserver(address: "company.com", loginMode: .oidc)
LoginHomeserver(address: "company.com", loginMode: .oidc(supportsCreatePrompt: false))
}
/// A mock homeserver that only with no supported login flows.
@@ -12,7 +12,7 @@ enum LoginMode: Equatable {
/// The login mode hasn't been determined yet.
case unknown
/// The homeserver supports login via OpenID Connect.
case oidc
case oidc(supportsCreatePrompt: Bool)
/// The homeserver supports login with a password.
case password
/// The homeserver only allows login with unsupported mechanisms. Use fallback instead.
@@ -69,7 +69,7 @@ class LoginScreenViewModel: LoginScreenViewModelType, LoginScreenViewModelProtoc
Task {
switch await authenticationService.configure(for: homeserverDomain, flow: .login) {
case .success:
if authenticationService.homeserver.value.loginMode == .oidc {
if authenticationService.homeserver.value.loginMode.supportsOIDCFlow {
actionsSubject.send(.configuredForOIDC)
}
stopLoading()
@@ -1,139 +0,0 @@
//
// Copyright 2022-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 Compound
import SwiftUI
import WebKit
struct WebRegistrationScreen: View {
@ObservedObject var context: WebRegistrationScreenViewModel.Context
var body: some View {
NavigationStack {
WebRegistrationWebView(url: context.viewState.url, viewModelContext: context)
.navigationTitle(L10n.screenCreateAccountTitle)
.navigationBarTitleDisplayMode(.inline)
.toolbarBackground(.visible, for: .navigationBar)
.toolbar {
ToolbarItem(placement: .cancellationAction) {
Button(L10n.actionCancel) {
context.send(viewAction: .cancel)
}
}
}
}
}
}
struct WebRegistrationWebView: UIViewRepresentable {
let url: URL
let viewModelContext: WebRegistrationScreenViewModel.Context
func makeUIView(context: Context) -> WKWebView {
context.coordinator.webView
}
func updateUIView(_ webView: WKWebView, context: Context) { }
func makeCoordinator() -> Coordinator {
Coordinator(url: url, viewModelContext: viewModelContext)
}
class Coordinator: NSObject, WKUIDelegate {
private let url: URL
private let viewModelContext: WebRegistrationScreenViewModel.Context
private(set) var webView: WKWebView!
init(url: URL, viewModelContext: WebRegistrationScreenViewModel.Context) {
self.url = url
self.viewModelContext = viewModelContext
super.init()
let eventHandlerName = "elementx"
let userContentController = WKUserContentController()
userContentController.add(WKScriptMessageHandlerWrapper(self), name: eventHandlerName)
let eventHandlerScript = """
window.addEventListener(
"mobileregistrationresponse",
(event) => {
window.webkit.messageHandlers.\(eventHandlerName).postMessage(JSON.stringify(event.detail));
},
false,
);
"""
let userScript = WKUserScript(source: eventHandlerScript, injectionTime: .atDocumentEnd, forMainFrameOnly: false)
userContentController.addUserScript(userScript)
let configuration = WKWebViewConfiguration()
configuration.userContentController = userContentController
configuration.preferences.javaScriptCanOpenWindowsAutomatically = true
webView = WKWebView(frame: .zero, configuration: configuration)
webView.uiDelegate = self
webView.load(URLRequest(url: url))
}
func userContentController(_ userContentController: WKUserContentController,
didReceive message: WKScriptMessage) {
guard let jsonString = message.body as? String, let jsonData = jsonString.data(using: .utf8) else {
MXLog.error("Unexpected response.")
return
}
guard let credentials = try? JSONDecoder().decode(WebRegistrationCredentials.self, from: jsonData) else {
MXLog.error("Invalid response.")
return
}
MXLog.info("Received login credentials.")
viewModelContext.send(viewAction: .signedIn(credentials))
}
// MARK: WKUIDelegate
func webView(_ webView: WKWebView,
createWebViewWith configuration: WKWebViewConfiguration,
for navigationAction: WKNavigationAction,
windowFeatures: WKWindowFeatures) -> WKWebView? {
if let url = navigationAction.request.url, UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url)
}
return nil
}
}
/// Avoids retain loops between the configuration and webView coordinator
private class WKScriptMessageHandlerWrapper: NSObject, WKScriptMessageHandler {
private weak var coordinator: Coordinator?
init(_ coordinator: Coordinator) {
self.coordinator = coordinator
}
// MARK: WKScriptMessageHandler
func userContentController(_ userContentController: WKUserContentController,
didReceive message: WKScriptMessage) {
coordinator?.userContentController(userContentController, didReceive: message)
}
}
}
// MARK: - Previews
struct WebRegistrationScreen_Previews: PreviewProvider {
static let viewModel = WebRegistrationScreenViewModel(registrationHelperURL: "https://develop.element.io/#/mobile_register")
static var previews: some View {
NavigationStack {
WebRegistrationScreen(context: viewModel.context)
}
}
}
@@ -1,83 +0,0 @@
//
// Copyright 2022-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 Combine
import MatrixRustSDK
import SwiftUI
struct WebRegistrationScreenCoordinatorParameters {
/// The service used to authenticate the user.
let authenticationService: AuthenticationServiceProtocol
let userIndicatorController: UserIndicatorControllerProtocol
}
enum WebRegistrationScreenCoordinatorAction: CustomStringConvertible {
case cancel
case signedIn(UserSessionProtocol)
var description: String {
switch self {
case .cancel: "cancel"
case .signedIn: "signedIn"
}
}
}
// Note: This code was based on the LoginScreen, we should move the authentication service logic into the view model.
final class WebRegistrationScreenCoordinator: CoordinatorProtocol {
private let parameters: WebRegistrationScreenCoordinatorParameters
private let viewModel: WebRegistrationScreenViewModelProtocol
private var cancellables = Set<AnyCancellable>()
private let actionsSubject: PassthroughSubject<WebRegistrationScreenCoordinatorAction, Never> = .init()
var actionsPublisher: AnyPublisher<WebRegistrationScreenCoordinatorAction, Never> {
actionsSubject.eraseToAnyPublisher()
}
init(parameters: WebRegistrationScreenCoordinatorParameters) {
self.parameters = parameters
guard let registrationHelperURL = parameters.authenticationService.homeserver.value.registrationHelperURL else {
MXLog.error("Attempted registration without a helper URL.")
fatalError("A helper URL is required.")
}
viewModel = WebRegistrationScreenViewModel(registrationHelperURL: registrationHelperURL)
}
func start() {
viewModel.actionsPublisher.sink { [weak self] action in
MXLog.info("Coordinator: received view model action: \(action)")
guard let self else { return }
switch action {
case .cancel:
actionsSubject.send(.cancel)
case .signedIn(let credentials):
Task { await self.completeRegistration(using: credentials) }
}
}
.store(in: &cancellables)
}
func toPresentable() -> AnyView {
AnyView(WebRegistrationScreen(context: viewModel.context))
}
// MARK: - Private
private func completeRegistration(using credentials: WebRegistrationCredentials) async {
switch await parameters.authenticationService.completeWebRegistration(using: credentials) {
case .success(let userSession):
actionsSubject.send(.signedIn(userSession))
case .failure(let error):
MXLog.error("Failed registration: \(error)")
parameters.userIndicatorController.alertInfo = .init(id: UUID(), title: L10n.errorUnknown, message: String(describing: error))
}
}
}
@@ -1,51 +0,0 @@
//
// Copyright 2022-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 Foundation
enum WebRegistrationScreenViewModelAction: CustomStringConvertible {
case cancel
case signedIn(WebRegistrationCredentials)
var description: String {
switch self {
case .cancel: "cancel"
case .signedIn: "signedIn"
}
}
}
struct WebRegistrationScreenViewState: BindableState {
var url: URL
var bindings = WebRegistrationScreenViewStateBindings()
}
struct WebRegistrationScreenViewStateBindings { }
enum WebRegistrationScreenViewAction: CustomStringConvertible {
case cancel
case signedIn(WebRegistrationCredentials)
var description: String {
switch self {
case .cancel: "cancel"
case .signedIn: "signedIn"
}
}
}
struct WebRegistrationCredentials: Decodable {
let userID: String
let accessToken: String
let deviceID: String
enum CodingKeys: String, CodingKey {
case userID = "user_id"
case accessToken = "access_token"
case deviceID = "device_id"
}
}
@@ -1,34 +0,0 @@
//
// Copyright 2022-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 Combine
import MatrixRustSDK
import SwiftUI
typealias WebRegistrationScreenViewModelType = StateStoreViewModel<WebRegistrationScreenViewState, WebRegistrationScreenViewAction>
class WebRegistrationScreenViewModel: WebRegistrationScreenViewModelType, WebRegistrationScreenViewModelProtocol {
private let actionsSubject: PassthroughSubject<WebRegistrationScreenViewModelAction, Never> = .init()
var actionsPublisher: AnyPublisher<WebRegistrationScreenViewModelAction, Never> {
actionsSubject.eraseToAnyPublisher()
}
init(registrationHelperURL: URL) {
super.init(initialViewState: WebRegistrationScreenViewState(url: registrationHelperURL))
}
override func process(viewAction: WebRegistrationScreenViewAction) {
MXLog.info("View model: received view action: \(viewAction)")
switch viewAction {
case .cancel:
actionsSubject.send(.cancel)
case .signedIn(let credentials):
actionsSubject.send(.signedIn(credentials))
}
}
}
@@ -1,14 +0,0 @@
//
// Copyright 2022-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 Combine
@MainActor
protocol WebRegistrationScreenViewModelProtocol {
var actionsPublisher: AnyPublisher<WebRegistrationScreenViewModelAction, Never> { get }
var context: WebRegistrationScreenViewModelType.Context { get }
}
@@ -9,7 +9,7 @@ import Combine
import SwiftUI
struct AuthenticationStartScreenParameters {
let webRegistrationEnabled: Bool
let showCreateAccountButton: Bool
let isBugReportServiceEnabled: Bool
}
@@ -23,7 +23,7 @@ final class AuthenticationStartScreenCoordinator: CoordinatorProtocol {
}
init(parameters: AuthenticationStartScreenParameters) {
viewModel = AuthenticationStartScreenViewModel(webRegistrationEnabled: parameters.webRegistrationEnabled,
viewModel = AuthenticationStartScreenViewModel(showCreateAccountButton: parameters.showCreateAccountButton,
isBugReportServiceEnabled: parameters.isBugReportServiceEnabled)
}
@@ -24,7 +24,7 @@ enum AuthenticationStartScreenViewModelAction {
}
struct AuthenticationStartScreenViewState: BindableState {
let isWebRegistrationEnabled: Bool
let showCreateAccountButton: Bool
let isQRCodeLoginEnabled: Bool
let isBugReportServiceEnabled: Bool
}
@@ -17,8 +17,8 @@ class AuthenticationStartScreenViewModel: AuthenticationStartScreenViewModelType
actionsSubject.eraseToAnyPublisher()
}
init(webRegistrationEnabled: Bool, isBugReportServiceEnabled: Bool) {
super.init(initialViewState: AuthenticationStartScreenViewState(isWebRegistrationEnabled: webRegistrationEnabled,
init(showCreateAccountButton: Bool, isBugReportServiceEnabled: Bool) {
super.init(initialViewState: AuthenticationStartScreenViewState(showCreateAccountButton: showCreateAccountButton,
isQRCodeLoginEnabled: !ProcessInfo.processInfo.isiOSAppOnMac,
isBugReportServiceEnabled: isBugReportServiceEnabled))
}
@@ -102,7 +102,7 @@ struct AuthenticationStartScreen: View {
.buttonStyle(.compound(.primary))
.accessibilityIdentifier(A11yIdentifiers.authenticationStartScreen.signIn)
if context.viewState.isWebRegistrationEnabled {
if context.viewState.showCreateAccountButton {
Button { context.send(viewAction: .register) } label: {
Text(L10n.screenCreateAccountTitle)
.padding(14)
@@ -129,7 +129,7 @@ struct AuthenticationStartScreen_Previews: PreviewProvider, TestablePreview {
}
static func makeViewModel(isBugReportServiceEnabled: Bool = true) -> AuthenticationStartScreenViewModel {
AuthenticationStartScreenViewModel(webRegistrationEnabled: true,
AuthenticationStartScreenViewModel(showCreateAccountButton: true,
isBugReportServiceEnabled: isBugReportServiceEnabled)
}
}
@@ -292,7 +292,6 @@ private struct CallView: UIViewRepresentable {
struct CallScreen_Previews: PreviewProvider {
static let viewModel = {
let clientProxy = ClientProxyMock()
clientProxy.getElementWellKnownReturnValue = .success(nil)
clientProxy.deviceID = "call-device-id"
let roomProxy = JoinedRoomProxyMock()
@@ -48,27 +48,21 @@ class AuthenticationService: AuthenticationServiceProtocol {
let client = try await makeClientBuilder().build(homeserverAddress: homeserverAddress)
let loginDetails = await client.homeserverLoginDetails()
let elementWellKnown = await client.getElementWellKnown()
MXLog.info("Sliding sync: \(client.slidingSyncVersion())")
homeserver.loginMode = if loginDetails.supportsOidcLogin() {
.oidc
.oidc(supportsCreatePrompt: loginDetails.supportedOidcPrompts().contains(.create))
} else if loginDetails.supportsPasswordLogin() {
.password
} else {
.unsupported
}
homeserver.registrationHelperURL = switch elementWellKnown {
case .success(let wellKnown): wellKnown.registrationHelperUrl.flatMap(URL.init)
case .failure: nil
}
if flow == .login, homeserver.loginMode == .unsupported {
return .failure(.loginNotSupported)
}
if flow == .register, !homeserver.supportsRegistration {
if flow == .register, !homeserver.loginMode.supportsOIDCFlow {
return .failure(.registrationNotSupported)
}
@@ -91,6 +85,8 @@ class AuthenticationService: AuthenticationServiceProtocol {
func urlForOIDCLogin() async -> Result<OIDCAuthorizationDataProxy, AuthenticationServiceError> {
guard let client else { return .failure(.oidcError(.urlFailure)) }
do {
// The create prompt is broken: https://github.com/element-hq/matrix-authentication-service/issues/3429
// let prompt: OidcPrompt = flow == .register ? .create : .consent
let oidcData = try await client.urlForOidc(oidcConfiguration: appSettings.oidcConfiguration.rustValue,
prompt: .consent)
return .success(OIDCAuthorizationDataProxy(underlyingData: oidcData))
@@ -148,25 +144,6 @@ class AuthenticationService: AuthenticationServiceProtocol {
}
}
func completeWebRegistration(using credentials: WebRegistrationCredentials) async -> Result<any UserSessionProtocol, AuthenticationServiceError> {
guard let client else { return .failure(.failedLoggingIn) }
let session = Session(accessToken: credentials.accessToken,
refreshToken: nil,
userId: credentials.userID,
deviceId: credentials.deviceID,
homeserverUrl: client.homeserver(),
oidcData: nil,
slidingSyncVersion: client.slidingSyncVersion())
do {
try await client.restoreSession(session: session)
return await userSession(for: client)
} catch {
MXLog.error("Failed restoring the client using the provided credentials.")
return .failure(.failedUsingWebCredentials)
}
}
func reset() {
homeserverSubject.send(LoginHomeserver(address: appSettings.defaultHomeserverAddress, loginMode: .unknown))
flow = .login
@@ -48,8 +48,6 @@ protocol AuthenticationServiceProtocol {
func loginWithOIDCCallback(_ callbackURL: URL) async -> Result<UserSessionProtocol, AuthenticationServiceError>
/// Performs a password login using the current homeserver.
func login(username: String, password: String, initialDeviceName: String?, deviceID: String?) async -> Result<UserSessionProtocol, AuthenticationServiceError>
/// Completes registration using the credentials obtained via the helper URL.
func completeWebRegistration(using credentials: WebRegistrationCredentials) async -> Result<UserSessionProtocol, AuthenticationServiceError>
/// Resets the current configuration requiring `configure(for:flow:)` to be called again.
func reset()
@@ -1,32 +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 Foundation
import MatrixRustSDK
extension ClientProtocol {
func getElementWellKnown() async -> Result<MatrixRustSDK.ElementWellKnown, ClientProxyError> {
do {
let serverName = if let userIDServerName = try? userIdServerName() {
"https://\(userIDServerName)"
} else {
server()
}
guard let serverName,
let url = URL(string: serverName)?.appending(path: "/.well-known/element/element.json") else {
return .failure(.invalidServerName)
}
let response = try await getUrl(url: url.absoluteString)
let wellKnown = try makeElementWellKnown(string: response)
return .success(wellKnown)
} catch {
return .failure(.sdkError(error))
}
}
}
@@ -703,10 +703,6 @@ class ClientProxy: ClientProxyProtocol {
}
}
func getElementWellKnown() async -> Result<ElementWellKnown?, ClientProxyError> {
await client.getElementWellKnown().map(ElementWellKnown.init)
}
func clearCaches() async -> Result<Void, ClientProxyError> {
do {
return try await .success(client.clearCaches())
@@ -182,8 +182,6 @@ protocol ClientProxyProtocol: AnyObject, MediaLoaderProtocol {
func isAliasAvailable(_ alias: String) async -> Result<Bool, ClientProxyError>
func getElementWellKnown() async -> Result<ElementWellKnown?, ClientProxyError>
@discardableResult func clearCaches() async -> Result<Void, ClientProxyError>
// MARK: - Ignored users
@@ -1,17 +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 Foundation
import MatrixRustSDK
struct ElementWellKnown {
let registrationHelperURL: URL?
init?(_ wellKnown: MatrixRustSDK.ElementWellKnown) {
registrationHelperURL = wellKnown.registrationHelperUrl.flatMap(URL.init)
}
}