mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-02 12:07:55 +00:00
Show an alert when entering an account provider that requires Element Pro. (#4326)
This commit is contained in:
@@ -659,6 +659,9 @@
|
||||
"screen_change_account_provider_other" = "Other";
|
||||
"screen_change_account_provider_subtitle" = "Use a different account provider, such as your own private server or a work account.";
|
||||
"screen_change_account_provider_title" = "Change account provider";
|
||||
"screen_change_server_error_element_pro_required_action_ios" = "App Store";
|
||||
"screen_change_server_error_element_pro_required_message" = "The Element Pro app is required on %1$@. Please download it from the store.";
|
||||
"screen_change_server_error_element_pro_required_title" = "Element Pro required";
|
||||
"screen_change_server_error_invalid_homeserver" = "We couldn't reach this homeserver. Please check that you have entered the homeserver URL correctly. If the URL is correct, contact your homeserver administrator for further help.";
|
||||
"screen_change_server_error_invalid_well_known" = "Server isn't available due to an issue in the .well-known file:\n%1$@";
|
||||
"screen_change_server_error_no_sliding_sync_message" = "The selected account provider does not support sliding sync. An upgrade to the server is needed to use %1$@.";
|
||||
|
||||
@@ -33,6 +33,11 @@ class AppHooks: AppHooksProtocol {
|
||||
certificateValidatorHook = hook
|
||||
}
|
||||
|
||||
private(set) var elementWellKnownHook: ElementWellKnownHookProtocol = DefaultElementWellKnownHook()
|
||||
func registerElementWellKnownHook(_ hook: ElementWellKnownHookProtocol) {
|
||||
elementWellKnownHook = hook
|
||||
}
|
||||
|
||||
private(set) var roomScreenHook: RoomScreenHookProtocol = DefaultRoomScreenHook()
|
||||
func registerRoomScreenHook(_ hook: RoomScreenHookProtocol) {
|
||||
roomScreenHook = hook
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
//
|
||||
// Copyright 2025 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
|
||||
|
||||
protocol ElementWellKnownHookProtocol {
|
||||
func validate(using client: ClientProtocol) async -> Result<Void, ElementWellKnownError>
|
||||
}
|
||||
|
||||
struct DefaultElementWellKnownHook: ElementWellKnownHookProtocol {
|
||||
/// A best effort implementation to let Element X advertise to users when they should be using
|
||||
/// Element Pro. In an ideal world the backend would be able to validate the client's requests
|
||||
/// instead of relying on it to check a well-known file for this.
|
||||
func validate(using client: ClientProtocol) async -> Result<Void, ElementWellKnownError> {
|
||||
guard case let .success(wellKnownData) = await client.elementWellKnown() else {
|
||||
// Nothing to check, carry on as normal.
|
||||
return .success(())
|
||||
}
|
||||
|
||||
do {
|
||||
let wellKnown = try JSONDecoder().decode(ElementWellKnown.self, from: wellKnownData)
|
||||
if wellKnown.enforceElementPro == true {
|
||||
let serverName = client.server() ?? client.homeserver()
|
||||
let displayableServerName = LoginHomeserver(address: serverName, loginMode: .unknown).address
|
||||
return .failure(.elementProRequired(serverName: displayableServerName))
|
||||
} else {
|
||||
return .success(())
|
||||
}
|
||||
} catch {
|
||||
// If it doesn't decode we have to assume it's a 404 page or similar.
|
||||
return .success(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private struct ElementWellKnown: Decodable {
|
||||
var version: Int
|
||||
var enforceElementPro: Bool?
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case version
|
||||
case enforceElementPro = "enforce_element_pro"
|
||||
}
|
||||
}
|
||||
|
||||
enum ElementWellKnownError: Error {
|
||||
case elementProRequired(serverName: String)
|
||||
}
|
||||
@@ -189,6 +189,9 @@ final class AppSettings {
|
||||
private(set) var elementWebHosts = ["app.element.io", "staging.element.io", "develop.element.io"]
|
||||
/// The domain that account provisioning links will be hosted on - used for handling the links.
|
||||
private(set) var accountProvisioningHost = "mobile.element.io"
|
||||
/// The App Store URL for Element Pro, shown to the user when a homeserver requires that app.
|
||||
/// **Note:** This property isn't overridable as it in unexpected for forks to come across the error (or to even have a "Pro" app).
|
||||
let elementProAppStoreURL: URL = "https://apps.apple.com/app/element-pro-for-work/id6502951615"
|
||||
|
||||
@UserPreference(key: UserDefaultsKeys.appAppearance, defaultValue: .system, storageType: .userDefaults(store))
|
||||
var appAppearance: AppAppearance
|
||||
|
||||
@@ -363,6 +363,7 @@ class AuthenticationFlowCoordinator: FlowCoordinatorProtocol {
|
||||
|
||||
let parameters = ServerSelectionScreenCoordinatorParameters(authenticationService: authenticationService,
|
||||
authenticationFlow: authenticationFlow,
|
||||
appSettings: appSettings,
|
||||
userIndicatorController: userIndicatorController)
|
||||
let coordinator = ServerSelectionScreenCoordinator(parameters: parameters)
|
||||
|
||||
@@ -408,6 +409,7 @@ class AuthenticationFlowCoordinator: FlowCoordinatorProtocol {
|
||||
let parameters = LoginScreenCoordinatorParameters(authenticationService: authenticationService,
|
||||
loginHint: loginHint,
|
||||
userIndicatorController: userIndicatorController,
|
||||
appSettings: appSettings,
|
||||
analytics: analytics)
|
||||
let coordinator = LoginScreenCoordinator(parameters: parameters)
|
||||
|
||||
|
||||
@@ -1258,6 +1258,14 @@ internal enum L10n {
|
||||
internal static var screenChangeAccountProviderSubtitle: String { return L10n.tr("Localizable", "screen_change_account_provider_subtitle") }
|
||||
/// Change account provider
|
||||
internal static var screenChangeAccountProviderTitle: String { return L10n.tr("Localizable", "screen_change_account_provider_title") }
|
||||
/// App Store
|
||||
internal static var screenChangeServerErrorElementProRequiredActionIos: String { return L10n.tr("Localizable", "screen_change_server_error_element_pro_required_action_ios") }
|
||||
/// The Element Pro app is required on %1$@. Please download it from the store.
|
||||
internal static func screenChangeServerErrorElementProRequiredMessage(_ p1: Any) -> String {
|
||||
return L10n.tr("Localizable", "screen_change_server_error_element_pro_required_message", String(describing: p1))
|
||||
}
|
||||
/// Element Pro required
|
||||
internal static var screenChangeServerErrorElementProRequiredTitle: String { return L10n.tr("Localizable", "screen_change_server_error_element_pro_required_title") }
|
||||
/// We couldn't reach this homeserver. Please check that you have entered the homeserver URL correctly. If the URL is correct, contact your homeserver administrator for further help.
|
||||
internal static var screenChangeServerErrorInvalidHomeserver: String { return L10n.tr("Localizable", "screen_change_server_error_invalid_homeserver") }
|
||||
/// Server isn't available due to an issue in the .well-known file:
|
||||
|
||||
@@ -25,11 +25,18 @@ extension AuthenticationClientFactoryMock {
|
||||
supportsOIDCCreatePrompt: false,
|
||||
supportsPasswordLogin: false)),
|
||||
"server.net": ClientSDKMock(configuration: .init(serverAddress: "server.net",
|
||||
homeserverURL: "https://matrix.example.com",
|
||||
homeserverURL: "https://matrix.server.net",
|
||||
slidingSyncVersion: .native,
|
||||
oidcLoginURL: nil,
|
||||
supportsOIDCCreatePrompt: false,
|
||||
supportsPasswordLogin: false))
|
||||
supportsPasswordLogin: false)),
|
||||
"secure.gov": ClientSDKMock(configuration: .init(serverAddress: "secure.gov",
|
||||
homeserverURL: "https://ess.secure.gov",
|
||||
slidingSyncVersion: .native,
|
||||
oidcLoginURL: "https://auth.secure.gov/oidc",
|
||||
supportsOIDCCreatePrompt: false,
|
||||
supportsPasswordLogin: false,
|
||||
elementWellKnown: "{\"version\":1,\"enforce_element_pro\":true}"))
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ extension ClientSDKMock {
|
||||
var oidcLoginURL: String? = "https://account.matrix.org/authorize"
|
||||
var supportsOIDCCreatePrompt = true
|
||||
var supportsPasswordLogin = true
|
||||
var elementWellKnown: String?
|
||||
var validCredentials = (username: "alice", password: "12345678")
|
||||
|
||||
// MARK: Session
|
||||
@@ -51,6 +52,14 @@ extension ClientSDKMock {
|
||||
|
||||
userIdReturnValue = configuration.userID
|
||||
sessionReturnValue = configuration.session
|
||||
getUrlUrlClosure = { url in
|
||||
guard url.contains(".well-known/element/element.json") else { throw MockError.generic }
|
||||
if let elementWellKnown = configuration.elementWellKnown {
|
||||
return elementWellKnown
|
||||
} else {
|
||||
throw MockError.generic
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ struct LoginScreenCoordinatorParameters {
|
||||
/// An optional hint that can be used to pre-fill the form.
|
||||
let loginHint: String?
|
||||
let userIndicatorController: UserIndicatorControllerProtocol
|
||||
let appSettings: AppSettings
|
||||
let analytics: AnalyticsService
|
||||
}
|
||||
|
||||
@@ -46,6 +47,7 @@ final class LoginScreenCoordinator: CoordinatorProtocol {
|
||||
viewModel = LoginScreenViewModel(authenticationService: parameters.authenticationService,
|
||||
loginHint: parameters.loginHint,
|
||||
userIndicatorController: parameters.userIndicatorController,
|
||||
appSettings: parameters.appSettings,
|
||||
analytics: parameters.analytics)
|
||||
}
|
||||
|
||||
|
||||
@@ -70,6 +70,8 @@ enum LoginScreenErrorType: Hashable {
|
||||
case invalidWellKnownAlert(String)
|
||||
/// An alert that allows the user to learn about sliding sync.
|
||||
case slidingSyncAlert
|
||||
/// An alert that informs the user that Element Pro should be used for a particular server.
|
||||
case elementProAlert
|
||||
/// An alert that informs the user that login failed due to a refresh token being returned.
|
||||
case refreshTokenAlert
|
||||
/// The response from the homeserver was unexpected.
|
||||
|
||||
@@ -13,6 +13,7 @@ typealias LoginScreenViewModelType = StateStoreViewModelV2<LoginScreenViewState,
|
||||
class LoginScreenViewModel: LoginScreenViewModelType, LoginScreenViewModelProtocol {
|
||||
private let authenticationService: AuthenticationServiceProtocol
|
||||
private let userIndicatorController: UserIndicatorControllerProtocol
|
||||
private let appSettings: AppSettings
|
||||
private let analytics: AnalyticsService
|
||||
|
||||
private var actionsSubject: PassthroughSubject<LoginScreenViewModelAction, Never> = .init()
|
||||
@@ -23,9 +24,11 @@ class LoginScreenViewModel: LoginScreenViewModelType, LoginScreenViewModelProtoc
|
||||
init(authenticationService: AuthenticationServiceProtocol,
|
||||
loginHint: String?,
|
||||
userIndicatorController: UserIndicatorControllerProtocol,
|
||||
appSettings: AppSettings,
|
||||
analytics: AnalyticsService) {
|
||||
self.authenticationService = authenticationService
|
||||
self.userIndicatorController = userIndicatorController
|
||||
self.appSettings = appSettings
|
||||
self.analytics = analytics
|
||||
|
||||
let username = switch loginHint {
|
||||
@@ -146,6 +149,16 @@ class LoginScreenViewModel: LoginScreenViewModelType, LoginScreenViewModelProtoc
|
||||
|
||||
// Clear out the invalid username to avoid an attempted login to matrix.org
|
||||
state.bindings.username = ""
|
||||
case .elementProRequired(let serverName):
|
||||
state.bindings.alertInfo = AlertInfo(id: .elementProAlert,
|
||||
title: L10n.screenChangeServerErrorElementProRequiredTitle,
|
||||
message: L10n.screenChangeServerErrorElementProRequiredMessage(serverName),
|
||||
primaryButton: .init(title: L10n.screenChangeServerErrorElementProRequiredActionIos) {
|
||||
UIApplication.shared.open(self.appSettings.elementProAppStoreURL)
|
||||
},
|
||||
secondaryButton: .init(title: L10n.actionCancel, role: .cancel, action: nil))
|
||||
// Clear out the invalid username to avoid an attempted login to matrix.org
|
||||
state.bindings.username = ""
|
||||
case .sessionTokenRefreshNotSupported:
|
||||
state.bindings.alertInfo = AlertInfo(id: .refreshTokenAlert,
|
||||
title: L10n.commonServerNotSupported,
|
||||
|
||||
@@ -159,6 +159,7 @@ struct LoginScreen_Previews: PreviewProvider, TestablePreview {
|
||||
let viewModel = LoginScreenViewModel(authenticationService: authenticationService,
|
||||
loginHint: nil,
|
||||
userIndicatorController: UserIndicatorControllerMock(),
|
||||
appSettings: ServiceLocator.shared.settings,
|
||||
analytics: ServiceLocator.shared.analytics)
|
||||
|
||||
if withCredentials {
|
||||
|
||||
+1
@@ -40,6 +40,7 @@ final class ServerConfirmationScreenCoordinator: CoordinatorProtocol {
|
||||
viewModel = ServerConfirmationScreenViewModel(authenticationService: parameters.authenticationService,
|
||||
mode: mode,
|
||||
authenticationFlow: parameters.authenticationFlow,
|
||||
appSettings: parameters.appSettings,
|
||||
userIndicatorController: parameters.userIndicatorController)
|
||||
}
|
||||
|
||||
|
||||
+2
@@ -94,6 +94,8 @@ enum ServerConfirmationScreenAlert: Hashable {
|
||||
case login
|
||||
/// An alert that informs the user that registration isn't supported.
|
||||
case registration
|
||||
/// An alert that informs the user that Element Pro should be used for a particular server.
|
||||
case elementProRequired(serverName: String)
|
||||
/// An unknown error has occurred.
|
||||
case unknownError
|
||||
}
|
||||
|
||||
+13
@@ -13,6 +13,7 @@ typealias ServerConfirmationScreenViewModelType = StateStoreViewModelV2<ServerCo
|
||||
class ServerConfirmationScreenViewModel: ServerConfirmationScreenViewModelType, ServerConfirmationScreenViewModelProtocol {
|
||||
let authenticationService: AuthenticationServiceProtocol
|
||||
let authenticationFlow: AuthenticationFlow
|
||||
let appSettings: AppSettings
|
||||
let userIndicatorController: UserIndicatorControllerProtocol
|
||||
|
||||
private var actionsSubject: PassthroughSubject<ServerConfirmationScreenViewModelAction, Never> = .init()
|
||||
@@ -24,9 +25,11 @@ class ServerConfirmationScreenViewModel: ServerConfirmationScreenViewModelType,
|
||||
init(authenticationService: AuthenticationServiceProtocol,
|
||||
mode: ServerConfirmationScreenMode,
|
||||
authenticationFlow: AuthenticationFlow,
|
||||
appSettings: AppSettings,
|
||||
userIndicatorController: UserIndicatorControllerProtocol) {
|
||||
self.authenticationService = authenticationService
|
||||
self.authenticationFlow = authenticationFlow
|
||||
self.appSettings = appSettings
|
||||
self.userIndicatorController = userIndicatorController
|
||||
|
||||
let pickerSelection: String? = switch mode {
|
||||
@@ -94,6 +97,8 @@ class ServerConfirmationScreenViewModel: ServerConfirmationScreenViewModelType,
|
||||
displayError(.login)
|
||||
case .registrationNotSupported:
|
||||
displayError(.registration)
|
||||
case .elementProRequired(let serverName):
|
||||
displayError(.elementProRequired(serverName: serverName))
|
||||
default:
|
||||
displayError(.unknownError)
|
||||
}
|
||||
@@ -184,6 +189,14 @@ class ServerConfirmationScreenViewModel: ServerConfirmationScreenViewModelType,
|
||||
state.bindings.alertInfo = AlertInfo(id: .registration,
|
||||
title: L10n.commonServerNotSupported,
|
||||
message: L10n.errorAccountCreationNotPossible)
|
||||
case .elementProRequired(let serverName):
|
||||
state.bindings.alertInfo = AlertInfo(id: .elementProRequired(serverName: serverName),
|
||||
title: L10n.screenChangeServerErrorElementProRequiredTitle,
|
||||
message: L10n.screenChangeServerErrorElementProRequiredMessage(serverName),
|
||||
primaryButton: .init(title: L10n.screenChangeServerErrorElementProRequiredActionIos) {
|
||||
UIApplication.shared.open(self.appSettings.elementProAppStoreURL)
|
||||
},
|
||||
secondaryButton: .init(title: L10n.actionCancel, role: .cancel, action: nil))
|
||||
case .unknownError:
|
||||
state.bindings.alertInfo = AlertInfo(id: .unknownError)
|
||||
}
|
||||
|
||||
+1
@@ -162,6 +162,7 @@ struct ServerConfirmationScreen_Previews: PreviewProvider, TestablePreview {
|
||||
ServerConfirmationScreenViewModel(authenticationService: AuthenticationService.mock,
|
||||
mode: mode,
|
||||
authenticationFlow: flow,
|
||||
appSettings: ServiceLocator.shared.settings,
|
||||
userIndicatorController: UserIndicatorControllerMock())
|
||||
}
|
||||
}
|
||||
|
||||
+2
@@ -12,6 +12,7 @@ struct ServerSelectionScreenCoordinatorParameters {
|
||||
/// The service used to authenticate the user.
|
||||
let authenticationService: AuthenticationServiceProtocol
|
||||
let authenticationFlow: AuthenticationFlow
|
||||
let appSettings: AppSettings
|
||||
let userIndicatorController: UserIndicatorControllerProtocol
|
||||
}
|
||||
|
||||
@@ -38,6 +39,7 @@ final class ServerSelectionScreenCoordinator: CoordinatorProtocol {
|
||||
self.parameters = parameters
|
||||
viewModel = ServerSelectionScreenViewModel(authenticationService: parameters.authenticationService,
|
||||
authenticationFlow: parameters.authenticationFlow,
|
||||
appSettings: parameters.appSettings,
|
||||
userIndicatorController: parameters.userIndicatorController)
|
||||
userIndicatorController = parameters.userIndicatorController
|
||||
}
|
||||
|
||||
+2
@@ -66,4 +66,6 @@ enum ServerSelectionScreenErrorType: Hashable {
|
||||
case loginAlert
|
||||
/// An alert that informs the user that registration isn't supported.
|
||||
case registrationAlert
|
||||
/// An alert that informs the user that Element Pro should be used for a particular server.
|
||||
case elementProAlert
|
||||
}
|
||||
|
||||
+11
@@ -13,6 +13,7 @@ typealias ServerSelectionScreenViewModelType = StateStoreViewModelV2<ServerSelec
|
||||
class ServerSelectionScreenViewModel: ServerSelectionScreenViewModelType, ServerSelectionScreenViewModelProtocol {
|
||||
private let authenticationService: AuthenticationServiceProtocol
|
||||
private let authenticationFlow: AuthenticationFlow
|
||||
private let appSettings: AppSettings
|
||||
private let userIndicatorController: UserIndicatorControllerProtocol
|
||||
|
||||
private var actionsSubject: PassthroughSubject<ServerSelectionScreenViewModelAction, Never> = .init()
|
||||
@@ -23,9 +24,11 @@ class ServerSelectionScreenViewModel: ServerSelectionScreenViewModelType, Server
|
||||
|
||||
init(authenticationService: AuthenticationServiceProtocol,
|
||||
authenticationFlow: AuthenticationFlow,
|
||||
appSettings: AppSettings,
|
||||
userIndicatorController: UserIndicatorControllerProtocol) {
|
||||
self.authenticationService = authenticationService
|
||||
self.authenticationFlow = authenticationFlow
|
||||
self.appSettings = appSettings
|
||||
self.userIndicatorController = userIndicatorController
|
||||
|
||||
let bindings = ServerSelectionScreenBindings(homeserverAddress: authenticationService.homeserver.value.address)
|
||||
@@ -96,6 +99,14 @@ class ServerSelectionScreenViewModel: ServerSelectionScreenViewModelType, Server
|
||||
state.bindings.alertInfo = AlertInfo(id: .registrationAlert,
|
||||
title: L10n.commonServerNotSupported,
|
||||
message: L10n.errorAccountCreationNotPossible)
|
||||
case .elementProRequired(let serverName):
|
||||
state.bindings.alertInfo = AlertInfo(id: .elementProAlert,
|
||||
title: L10n.screenChangeServerErrorElementProRequiredTitle,
|
||||
message: L10n.screenChangeServerErrorElementProRequiredMessage(serverName),
|
||||
primaryButton: .init(title: L10n.screenChangeServerErrorElementProRequiredActionIos) {
|
||||
UIApplication.shared.open(self.appSettings.elementProAppStoreURL)
|
||||
},
|
||||
secondaryButton: .init(title: L10n.actionCancel, role: .cancel, action: nil))
|
||||
default:
|
||||
showFooterMessage(L10n.errorUnknown)
|
||||
}
|
||||
|
||||
+1
@@ -115,6 +115,7 @@ struct ServerSelection_Previews: PreviewProvider, TestablePreview {
|
||||
|
||||
let viewModel = ServerSelectionScreenViewModel(authenticationService: authenticationService,
|
||||
authenticationFlow: .login,
|
||||
appSettings: ServiceLocator.shared.settings,
|
||||
userIndicatorController: UserIndicatorControllerMock())
|
||||
viewModel.context.homeserverAddress = homeserverAddress
|
||||
if homeserverAddress == "thisisbad" {
|
||||
|
||||
@@ -52,6 +52,7 @@ class AuthenticationService: AuthenticationServiceProtocol {
|
||||
var homeserver = LoginHomeserver(address: homeserverAddress, loginMode: .unknown)
|
||||
|
||||
let client = try await makeClient(homeserverAddress: homeserverAddress)
|
||||
try await appHooks.elementWellKnownHook.validate(using: client).get()
|
||||
let loginDetails = await client.homeserverLoginDetails()
|
||||
|
||||
MXLog.info("Sliding sync: \(client.slidingSyncVersion())")
|
||||
@@ -81,6 +82,8 @@ class AuthenticationService: AuthenticationServiceProtocol {
|
||||
} catch ClientBuildError.SlidingSyncVersion(let error) {
|
||||
MXLog.info("User entered a homeserver that isn't configured for sliding sync: \(error)")
|
||||
return .failure(.slidingSyncNotAvailable)
|
||||
} catch ElementWellKnownError.elementProRequired(let serverName) {
|
||||
return .failure(.elementProRequired(serverName: serverName))
|
||||
} catch {
|
||||
MXLog.error("Failed configuring a server: \(error)")
|
||||
return .failure(.invalidHomeserverAddress)
|
||||
@@ -176,6 +179,7 @@ class AuthenticationService: AuthenticationServiceProtocol {
|
||||
|
||||
do {
|
||||
let client = try await makeClient(homeserverAddress: scannedServerName)
|
||||
try await appHooks.elementWellKnownHook.validate(using: client).get()
|
||||
try await client.loginWithQrCode(qrCodeData: qrData,
|
||||
oidcConfiguration: appSettings.oidcConfiguration.rustValue,
|
||||
progressListener: listener)
|
||||
@@ -184,6 +188,8 @@ class AuthenticationService: AuthenticationServiceProtocol {
|
||||
} catch let error as HumanQrLoginError {
|
||||
MXLog.error("QRCode login error: \(error)")
|
||||
return .failure(error.serviceError)
|
||||
} catch ElementWellKnownError.elementProRequired(let serverName) {
|
||||
return .failure(.elementProRequired(serverName: serverName))
|
||||
} catch {
|
||||
MXLog.error("QRCode login unknown error: \(error)")
|
||||
return .failure(.qrCodeError(.unknown))
|
||||
|
||||
@@ -30,6 +30,7 @@ enum AuthenticationServiceError: Error, Equatable {
|
||||
case slidingSyncNotAvailable
|
||||
case loginNotSupported
|
||||
case registrationNotSupported
|
||||
case elementProRequired(serverName: String)
|
||||
case accountDeactivated
|
||||
case failedLoggingIn
|
||||
case sessionTokenRefreshNotSupported
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
//
|
||||
// Copyright 2025 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 elementWellKnown() async -> Result<Data, ClientProxyError> {
|
||||
let serverNameURLString = if let userIDServerName = try? userIdServerName() {
|
||||
"https://\(userIDServerName)"
|
||||
} else {
|
||||
server() ?? homeserver()
|
||||
}
|
||||
|
||||
do {
|
||||
guard let url = URL(string: serverNameURLString)?.appending(path: "/.well-known/element/element.json") else {
|
||||
return .failure(.invalidServerName)
|
||||
}
|
||||
|
||||
let response = try await getUrl(url: url.absoluteString)
|
||||
|
||||
guard let data = response.data(using: .utf8) else {
|
||||
return .failure(.invalidResponse)
|
||||
}
|
||||
|
||||
return .success(data)
|
||||
} catch {
|
||||
return .failure(.sdkError(error))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -34,6 +34,7 @@ enum ClientProxyError: Error {
|
||||
|
||||
case invalidMedia
|
||||
case invalidServerName
|
||||
case invalidResponse
|
||||
case failedUploadingMedia(ErrorKind)
|
||||
case roomPreviewIsPrivate
|
||||
case failedRetrievingUserIdentity
|
||||
|
||||
@@ -117,6 +117,7 @@ class MockScreen: Identifiable {
|
||||
let navigationStackCoordinator = NavigationStackCoordinator()
|
||||
let coordinator = ServerSelectionScreenCoordinator(parameters: .init(authenticationService: AuthenticationService.mock,
|
||||
authenticationFlow: .login,
|
||||
appSettings: ServiceLocator.shared.settings,
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController))
|
||||
navigationStackCoordinator.setRootCoordinator(coordinator)
|
||||
return navigationStackCoordinator
|
||||
|
||||
Reference in New Issue
Block a user