mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-04 10:33:45 +00:00
Rename OIDC to OAuth. (#5525)
* Rename OIDC to OAuth. * Update the enterprise submodule.
This commit is contained in:
@@ -46,17 +46,17 @@ struct LoginHomeserver: Equatable {
|
||||
extension LoginHomeserver {
|
||||
/// A mock homeserver that is configured just like matrix.org.
|
||||
static var mockMatrixDotOrg: LoginHomeserver {
|
||||
LoginHomeserver(address: "matrix.org", loginMode: .oidc(supportsCreatePrompt: true))
|
||||
LoginHomeserver(address: "matrix.org", loginMode: .oAuth(supportsCreatePrompt: true))
|
||||
}
|
||||
|
||||
/// A mock homeserver that supports login and registration via a password but has no SSO providers.
|
||||
/// A mock homeserver that supports login and registration via a password but has no OAuth support.
|
||||
static var mockBasicServer: LoginHomeserver {
|
||||
LoginHomeserver(address: "example.com", loginMode: .password)
|
||||
}
|
||||
|
||||
/// A mock homeserver that supports only supports authentication via a single SSO provider.
|
||||
static var mockOIDC: LoginHomeserver {
|
||||
LoginHomeserver(address: "company.com", loginMode: .oidc(supportsCreatePrompt: false))
|
||||
/// A mock homeserver that supports only supports authentication via OAuth.
|
||||
static var mockOAuth: LoginHomeserver {
|
||||
LoginHomeserver(address: "company.com", loginMode: .oAuth(supportsCreatePrompt: false))
|
||||
}
|
||||
|
||||
/// A mock homeserver that only with no supported login flows.
|
||||
|
||||
@@ -13,15 +13,15 @@ enum LoginMode: Equatable {
|
||||
/// The login mode hasn't been determined yet.
|
||||
case unknown
|
||||
/// The homeserver supports login via OpenID Connect.
|
||||
case oidc(supportsCreatePrompt: Bool)
|
||||
case oAuth(supportsCreatePrompt: Bool)
|
||||
/// The homeserver supports login with a password.
|
||||
case password
|
||||
/// The homeserver only allows login with unsupported mechanisms. Use fallback instead.
|
||||
case unsupported
|
||||
|
||||
var supportsOIDCFlow: Bool {
|
||||
var supportsOAuthFlow: Bool {
|
||||
switch self {
|
||||
case .oidc: true
|
||||
case .oAuth: true
|
||||
default: false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,8 +20,8 @@ struct LoginScreenCoordinatorParameters {
|
||||
}
|
||||
|
||||
enum LoginScreenCoordinatorAction {
|
||||
/// The homeserver was updated to one that supports OIDC.
|
||||
case configuredForOIDC
|
||||
/// The homeserver was updated to one that supports OAuth.
|
||||
case configuredForOAuth
|
||||
/// Login was successful.
|
||||
case signedIn(UserSessionProtocol)
|
||||
}
|
||||
@@ -62,8 +62,8 @@ final class LoginScreenCoordinator: CoordinatorProtocol {
|
||||
guard let self else { return }
|
||||
|
||||
switch action {
|
||||
case .configuredForOIDC:
|
||||
actionsSubject.send(.configuredForOIDC)
|
||||
case .configuredForOAuth:
|
||||
actionsSubject.send(.configuredForOAuth)
|
||||
case .signedIn(let userSession):
|
||||
actionsSubject.send(.signedIn(userSession))
|
||||
}
|
||||
|
||||
@@ -9,14 +9,14 @@
|
||||
import Foundation
|
||||
|
||||
enum LoginScreenViewModelAction {
|
||||
/// The homeserver was updated to one that supports OIDC.
|
||||
case configuredForOIDC
|
||||
/// The homeserver was updated to one that supports OAuth.
|
||||
case configuredForOAuth
|
||||
/// Login was successful.
|
||||
case signedIn(UserSessionProtocol)
|
||||
|
||||
var isConfiguredForOIDC: Bool {
|
||||
var isConfiguredForOAuth: Bool {
|
||||
switch self {
|
||||
case .configuredForOIDC: true
|
||||
case .configuredForOAuth: true
|
||||
default: false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,8 +78,8 @@ class LoginScreenViewModel: LoginScreenViewModelType, LoginScreenViewModelProtoc
|
||||
Task {
|
||||
switch await authenticationService.configure(for: homeserverDomain, flow: .login) {
|
||||
case .success:
|
||||
if authenticationService.homeserver.value.loginMode.supportsOIDCFlow {
|
||||
actionsSubject.send(.configuredForOIDC)
|
||||
if authenticationService.homeserver.value.loginMode.supportsOAuthFlow {
|
||||
actionsSubject.send(.configuredForOAuth)
|
||||
}
|
||||
stopLoading()
|
||||
case .failure(let error):
|
||||
|
||||
@@ -27,7 +27,7 @@ struct LoginScreen: View {
|
||||
switch context.viewState.loginMode {
|
||||
case .password:
|
||||
loginForm
|
||||
case .oidc:
|
||||
case .oAuth:
|
||||
// This should never be shown.
|
||||
ProgressView()
|
||||
default:
|
||||
@@ -102,7 +102,7 @@ struct LoginScreen: View {
|
||||
}
|
||||
}
|
||||
|
||||
/// Text shown if neither password or OIDC login is supported.
|
||||
/// Text shown if neither password or OAuth login is supported.
|
||||
var loginUnavailableText: some View {
|
||||
Text(L10n.screenLoginErrorUnsupportedAuthentication)
|
||||
.font(.body)
|
||||
|
||||
+21
-21
@@ -8,15 +8,15 @@
|
||||
|
||||
import AuthenticationServices
|
||||
|
||||
/// Presents a web authentication session for an OIDC request.
|
||||
/// Presents a web authentication session for an OAuth request.
|
||||
///
|
||||
/// In certain instances the URL may require opening an external app instead of using a WAS. Because of this
|
||||
/// it is recommended to not encode the OIDC authentication within any state machines, as there is no guarantee
|
||||
/// it is recommended to not encode the OAuth authentication within any state machines, as there is no guarantee
|
||||
/// that any cancellations/failures will be communicated upwards.
|
||||
@MainActor
|
||||
class OIDCAuthenticationPresenter: NSObject {
|
||||
class OAuthAuthenticationPresenter: NSObject {
|
||||
private let authenticationService: AuthenticationServiceProtocol
|
||||
private let oidcRedirectURL: URL
|
||||
private let redirectURL: URL
|
||||
private let presentationAnchor: UIWindow
|
||||
private let appMediator: AppMediatorProtocol
|
||||
private let userIndicatorController: UserIndicatorControllerProtocol
|
||||
@@ -36,12 +36,12 @@ class OIDCAuthenticationPresenter: NSObject {
|
||||
private var activeRequest: Request?
|
||||
|
||||
init(authenticationService: AuthenticationServiceProtocol,
|
||||
oidcRedirectURL: URL,
|
||||
redirectURL: URL,
|
||||
presentationAnchor: UIWindow,
|
||||
appMediator: AppMediatorProtocol,
|
||||
userIndicatorController: UserIndicatorControllerProtocol) {
|
||||
self.authenticationService = authenticationService
|
||||
self.oidcRedirectURL = oidcRedirectURL
|
||||
self.redirectURL = redirectURL
|
||||
self.presentationAnchor = presentationAnchor
|
||||
self.appMediator = appMediator
|
||||
self.userIndicatorController = userIndicatorController
|
||||
@@ -53,11 +53,11 @@ class OIDCAuthenticationPresenter: NSObject {
|
||||
/// **Note:** The failure case cannot be relied upon as a signal that the authentication has ended.
|
||||
/// In particular if the authentication URL requires opening an external app, then the user may return
|
||||
/// to the app without completing (or cancelling) the authentication.
|
||||
func authenticate(using oidcData: OIDCAuthorizationDataProxy) async -> Result<UserSessionProtocol, AuthenticationServiceError> {
|
||||
func authenticate(using oAuthData: OAuthAuthorizationDataProxy) async -> Result<UserSessionProtocol, AuthenticationServiceError> {
|
||||
let response = await withCheckedContinuation { continuation in
|
||||
let authenticationURL = oidcData.url
|
||||
let authenticationURL = oAuthData.url
|
||||
|
||||
let session = ASWebAuthenticationSession(url: authenticationURL, callback: .oidcRedirectURL(oidcRedirectURL)) { url, error in
|
||||
let session = ASWebAuthenticationSession(url: authenticationURL, callback: .oAuthRedirectURL(redirectURL)) { url, error in
|
||||
MXLog.info("Handling callback from the session.")
|
||||
continuation.resume(returning: Response(url: url, isExternal: false, error: error))
|
||||
}
|
||||
@@ -86,30 +86,30 @@ class OIDCAuthenticationPresenter: NSObject {
|
||||
|
||||
guard let url = response.url else {
|
||||
// Check for user cancellation (on the WAS sheet) to avoid showing an alert in that instance.
|
||||
if response.error?.isOIDCUserCancellation == true {
|
||||
if response.error?.isOAuthUserCancellation == true {
|
||||
// No need to show an error here, just abort and return a failure.
|
||||
await authenticationService.abortOIDCLogin(data: oidcData)
|
||||
return .failure(.oidcError(.userCancellation))
|
||||
await authenticationService.abortOAuthLogin(data: oAuthData)
|
||||
return .failure(.oAuthError(.userCancellation))
|
||||
}
|
||||
|
||||
let errorDescription = response.error.map(String.init(describing:)) ?? "Unknown error"
|
||||
MXLog.error("Missing callback URL from the web authentication session: \(errorDescription)")
|
||||
|
||||
showFailureIndicator()
|
||||
await authenticationService.abortOIDCLogin(data: oidcData)
|
||||
return .failure(.oidcError(.unknown))
|
||||
await authenticationService.abortOAuthLogin(data: oAuthData)
|
||||
return .failure(.oAuthError(.unknown))
|
||||
}
|
||||
|
||||
// Exchanging the callback with the homeserver can be slow, so show the loading indicator while we wait (the modal has already been dismissed).
|
||||
startLoading(delay: .milliseconds(50)) // Small delay to handle a cancellation callback without the indicator showing.
|
||||
defer { stopLoading() }
|
||||
|
||||
switch await authenticationService.loginWithOIDCCallback(url) {
|
||||
switch await authenticationService.loginWithOAuthCallback(url) {
|
||||
case .success(let userSession):
|
||||
return .success(userSession)
|
||||
case .failure(.oidcError(.userCancellation)): // Check for user cancellation (on the MAS web page)
|
||||
case .failure(.oAuthError(.userCancellation)): // Check for user cancellation (on the MAS web page)
|
||||
// No need to show an error here, just return the failure.
|
||||
return .failure(.oidcError(.userCancellation))
|
||||
return .failure(.oAuthError(.userCancellation))
|
||||
case .failure(let error):
|
||||
MXLog.error("Error occurred: \(error)")
|
||||
showFailureIndicator()
|
||||
@@ -163,20 +163,20 @@ class OIDCAuthenticationPresenter: NSObject {
|
||||
|
||||
// MARK: ASWebAuthenticationPresentationContextProviding
|
||||
|
||||
extension OIDCAuthenticationPresenter: ASWebAuthenticationPresentationContextProviding {
|
||||
extension OAuthAuthenticationPresenter: ASWebAuthenticationPresentationContextProviding {
|
||||
func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor {
|
||||
presentationAnchor
|
||||
}
|
||||
}
|
||||
|
||||
extension ASWebAuthenticationSession.Callback {
|
||||
static func oidcRedirectURL(_ url: URL) -> Self {
|
||||
static func oAuthRedirectURL(_ url: URL) -> Self {
|
||||
if url.scheme == "https", let host = url.host() {
|
||||
.https(host: host, path: url.path())
|
||||
} else if let scheme = url.scheme {
|
||||
.customScheme(scheme)
|
||||
} else {
|
||||
fatalError("Invalid OIDC redirect URL: \(url)")
|
||||
fatalError("Invalid OAuth redirect URL: \(url)")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -184,7 +184,7 @@ extension ASWebAuthenticationSession.Callback {
|
||||
// MARK: - Helpers
|
||||
|
||||
extension Error {
|
||||
var isOIDCUserCancellation: Bool {
|
||||
var isOAuthUserCancellation: Bool {
|
||||
let nsError = self as NSError
|
||||
|
||||
if nsError.domain == ASWebAuthenticationSessionErrorDomain,
|
||||
+3
-3
@@ -17,7 +17,7 @@ struct ServerConfirmationScreenCoordinatorParameters {
|
||||
}
|
||||
|
||||
enum ServerConfirmationScreenCoordinatorAction {
|
||||
case continueWithOIDC(data: OIDCAuthorizationDataProxy, window: UIWindow)
|
||||
case continueWithOAuth(data: OAuthAuthorizationDataProxy, window: UIWindow)
|
||||
case continueWithPassword
|
||||
case changeServer
|
||||
}
|
||||
@@ -50,8 +50,8 @@ final class ServerConfirmationScreenCoordinator: CoordinatorProtocol {
|
||||
guard let self else { return }
|
||||
|
||||
switch action {
|
||||
case .continueWithOIDC(let oidcData, let window):
|
||||
actionsSubject.send(.continueWithOIDC(data: oidcData, window: window))
|
||||
case .continueWithOAuth(let oAuthData, let window):
|
||||
actionsSubject.send(.continueWithOAuth(data: oAuthData, window: window))
|
||||
case .continueWithPassword:
|
||||
actionsSubject.send(.continueWithPassword)
|
||||
case .changeServer:
|
||||
|
||||
+4
-4
@@ -9,8 +9,8 @@
|
||||
import SwiftUI
|
||||
|
||||
enum ServerConfirmationScreenViewModelAction {
|
||||
/// Continue the flow using the provided OIDC parameters.
|
||||
case continueWithOIDC(data: OIDCAuthorizationDataProxy, window: UIWindow)
|
||||
/// Continue the flow using the provided OAuth parameters.
|
||||
case continueWithOAuth(data: OAuthAuthorizationDataProxy, window: UIWindow)
|
||||
/// Continue the flow using password authentication.
|
||||
case continueWithPassword
|
||||
/// The user would like to change to a different homeserver.
|
||||
@@ -29,7 +29,7 @@ struct ServerConfirmationScreenViewState: BindableState {
|
||||
var mode: ServerConfirmationScreenMode
|
||||
/// The flow being attempted on the selected homeserver.
|
||||
let authenticationFlow: AuthenticationFlow
|
||||
/// The presentation anchor used for OIDC authentication.
|
||||
/// The presentation anchor used for OAuth authentication.
|
||||
var window: UIWindow?
|
||||
|
||||
var bindings = ServerConfirmationScreenBindings()
|
||||
@@ -76,7 +76,7 @@ struct ServerConfirmationScreenBindings {
|
||||
}
|
||||
|
||||
enum ServerConfirmationScreenViewAction {
|
||||
/// Updates the window used as the OIDC presentation anchor.
|
||||
/// Updates the window used as the OAuth presentation anchor.
|
||||
case updateWindow(UIWindow)
|
||||
/// The user would like to continue with the current homeserver.
|
||||
case confirm
|
||||
|
||||
+4
-4
@@ -133,7 +133,7 @@ class ServerConfirmationScreenViewModel: ServerConfirmationScreenViewModelType,
|
||||
}
|
||||
|
||||
private func fetchLoginURLIfNeededAndContinue() async {
|
||||
guard authenticationService.homeserver.value.loginMode.supportsOIDCFlow else {
|
||||
guard authenticationService.homeserver.value.loginMode.supportsOAuthFlow else {
|
||||
actionsSubject.send(.continueWithPassword)
|
||||
return
|
||||
}
|
||||
@@ -146,9 +146,9 @@ class ServerConfirmationScreenViewModel: ServerConfirmationScreenViewModelType,
|
||||
startLoading() // Uses the same ID, so no need to worry if the indicator already exists
|
||||
defer { stopLoading() }
|
||||
|
||||
switch await authenticationService.urlForOIDCLogin(loginHint: nil) {
|
||||
case .success(let oidcData):
|
||||
actionsSubject.send(.continueWithOIDC(data: oidcData, window: window))
|
||||
switch await authenticationService.urlForOAuthLogin(loginHint: nil) {
|
||||
case .success(let oAuthData):
|
||||
actionsSubject.send(.continueWithOAuth(data: oAuthData, window: window))
|
||||
case .failure:
|
||||
displayError(.unknownError)
|
||||
}
|
||||
|
||||
+3
-3
@@ -17,7 +17,7 @@ enum MockSoftLogoutScreenState: String, CaseIterable {
|
||||
// mock that screen.
|
||||
case emptyPassword
|
||||
case enteredPassword
|
||||
case oidc
|
||||
case oAuth
|
||||
case unsupported
|
||||
case keyBackupNeeded
|
||||
|
||||
@@ -37,9 +37,9 @@ enum MockSoftLogoutScreenState: String, CaseIterable {
|
||||
homeserver: .mockBasicServer,
|
||||
keyBackupNeeded: false,
|
||||
password: "12345678")
|
||||
case .oidc:
|
||||
case .oAuth:
|
||||
return SoftLogoutScreenViewModel(credentials: credentials,
|
||||
homeserver: .mockOIDC,
|
||||
homeserver: .mockOAuth,
|
||||
keyBackupNeeded: false)
|
||||
case .unsupported:
|
||||
return SoftLogoutScreenViewModel(credentials: credentials,
|
||||
|
||||
+21
-21
@@ -46,7 +46,7 @@ final class SoftLogoutScreenCoordinator: CoordinatorProtocol {
|
||||
parameters.authenticationService
|
||||
}
|
||||
|
||||
private var oidcPresenter: OIDCAuthenticationPresenter?
|
||||
private var oAuthPresenter: OAuthAuthenticationPresenter?
|
||||
|
||||
var actions: AnyPublisher<SoftLogoutScreenCoordinatorResult, Never> {
|
||||
actionsSubject.eraseToAnyPublisher()
|
||||
@@ -76,8 +76,8 @@ final class SoftLogoutScreenCoordinator: CoordinatorProtocol {
|
||||
showForgotPasswordScreen()
|
||||
case .clearAllData:
|
||||
actionsSubject.send(.clearAllData)
|
||||
case .continueWithOIDC:
|
||||
continueWithOIDC(presentationAnchor: viewModel.context.viewState.window)
|
||||
case .continueWithOAuth:
|
||||
continueWithOAuth(presentationAnchor: viewModel.context.viewState.window)
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
@@ -91,13 +91,13 @@ final class SoftLogoutScreenCoordinator: CoordinatorProtocol {
|
||||
AnyView(SoftLogoutScreen(context: viewModel.context))
|
||||
}
|
||||
|
||||
func handleOIDCRedirectURL(_ url: URL) {
|
||||
guard let oidcPresenter else {
|
||||
MXLog.error("Failed to find an OIDC request in progress.")
|
||||
func handleOAuthCallbackURL(_ url: URL) {
|
||||
guard let oAuthPresenter else {
|
||||
MXLog.error("Failed to find an OAuth request in progress.")
|
||||
return
|
||||
}
|
||||
|
||||
oidcPresenter.handleUniversalLinkCallback(url)
|
||||
oAuthPresenter.handleUniversalLinkCallback(url)
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
@@ -143,32 +143,32 @@ final class SoftLogoutScreenCoordinator: CoordinatorProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
private func continueWithOIDC(presentationAnchor: UIWindow?) {
|
||||
private func continueWithOAuth(presentationAnchor: UIWindow?) {
|
||||
guard let presentationAnchor else { return }
|
||||
|
||||
startLoading()
|
||||
|
||||
Task {
|
||||
switch await authenticationService.urlForOIDCLogin(loginHint: nil) {
|
||||
switch await authenticationService.urlForOAuthLogin(loginHint: nil) {
|
||||
case .failure(let error):
|
||||
stopLoading()
|
||||
handleError(error)
|
||||
case .success(let oidcData):
|
||||
case .success(let oAuthData):
|
||||
stopLoading()
|
||||
|
||||
let presenter = OIDCAuthenticationPresenter(authenticationService: parameters.authenticationService,
|
||||
oidcRedirectURL: parameters.appSettings.oidcRedirectURL,
|
||||
presentationAnchor: presentationAnchor,
|
||||
appMediator: parameters.appMediator,
|
||||
userIndicatorController: parameters.userIndicatorController)
|
||||
self.oidcPresenter = presenter
|
||||
switch await presenter.authenticate(using: oidcData) {
|
||||
let presenter = OAuthAuthenticationPresenter(authenticationService: parameters.authenticationService,
|
||||
redirectURL: parameters.appSettings.oAuthRedirectURL,
|
||||
presentationAnchor: presentationAnchor,
|
||||
appMediator: parameters.appMediator,
|
||||
userIndicatorController: parameters.userIndicatorController)
|
||||
self.oAuthPresenter = presenter
|
||||
switch await presenter.authenticate(using: oAuthData) {
|
||||
case .success(let userSession):
|
||||
actionsSubject.send(.signedIn(userSession))
|
||||
case .failure(let error):
|
||||
handleError(error)
|
||||
}
|
||||
self.oidcPresenter = nil
|
||||
self.oAuthPresenter = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -180,10 +180,10 @@ final class SoftLogoutScreenCoordinator: CoordinatorProtocol {
|
||||
viewModel.displayError(.alert(L10n.screenLoginErrorInvalidCredentials))
|
||||
case .accountDeactivated:
|
||||
viewModel.displayError(.alert(L10n.screenLoginErrorDeactivatedAccount))
|
||||
case .oidcError(.notSupported):
|
||||
// Temporary alert hijacking the use of .notSupported, can be removed when OIDC support is in the SDK.
|
||||
case .oAuthError(.notSupported):
|
||||
// Temporary alert hijacking the use of .notSupported, can be removed when OAuth support is in the SDK.
|
||||
viewModel.displayError(.alert(L10n.commonServerNotSupported))
|
||||
case .oidcError(.userCancellation):
|
||||
case .oAuthError(.userCancellation):
|
||||
// No need to show an error, the user cancelled authentication.
|
||||
break
|
||||
case .sessionTokenRefreshNotSupported:
|
||||
|
||||
+8
-8
@@ -22,8 +22,8 @@ enum SoftLogoutScreenViewModelAction: CustomStringConvertible {
|
||||
case forgotPassword
|
||||
/// Clear all user data
|
||||
case clearAllData
|
||||
/// Continue using OIDC.
|
||||
case continueWithOIDC
|
||||
/// Continue using OAuth.
|
||||
case continueWithOAuth
|
||||
|
||||
/// A string representation of the result, ignoring any associated values that could leak PII.
|
||||
var description: String {
|
||||
@@ -34,8 +34,8 @@ enum SoftLogoutScreenViewModelAction: CustomStringConvertible {
|
||||
return "forgotPassword"
|
||||
case .clearAllData:
|
||||
return "clearAllData"
|
||||
case .continueWithOIDC:
|
||||
return "continueWithOIDC"
|
||||
case .continueWithOAuth:
|
||||
return "continueWithOAuth"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -58,7 +58,7 @@ struct SoftLogoutScreenViewState: BindableState {
|
||||
homeserver.loginMode
|
||||
}
|
||||
|
||||
/// The presentation anchor used for OIDC authentication.
|
||||
/// The presentation anchor used for OAuth authentication.
|
||||
var window: UIWindow?
|
||||
|
||||
/// Whether to show recover encryption keys message
|
||||
@@ -80,7 +80,7 @@ struct SoftLogoutScreenBindings {
|
||||
}
|
||||
|
||||
enum SoftLogoutScreenViewAction {
|
||||
/// Updates the window used as the OIDC presentation anchor.
|
||||
/// Updates the window used as the OAuth presentation anchor.
|
||||
case updateWindow(UIWindow?)
|
||||
/// Login.
|
||||
case login
|
||||
@@ -88,8 +88,8 @@ enum SoftLogoutScreenViewAction {
|
||||
case forgotPassword
|
||||
/// Clear all user data.
|
||||
case clearAllData
|
||||
/// Continue using OIDC.
|
||||
case continueWithOIDC
|
||||
/// Continue using OAuth.
|
||||
case continueWithOAuth
|
||||
}
|
||||
|
||||
enum SoftLogoutScreenErrorType: Hashable {
|
||||
|
||||
+2
-2
@@ -38,8 +38,8 @@ class SoftLogoutScreenViewModel: SoftLogoutScreenViewModelType, SoftLogoutScreen
|
||||
actionsSubject.send(.forgotPassword)
|
||||
case .clearAllData:
|
||||
actionsSubject.send(.clearAllData)
|
||||
case .continueWithOIDC:
|
||||
actionsSubject.send(.continueWithOIDC)
|
||||
case .continueWithOAuth:
|
||||
actionsSubject.send(.continueWithOAuth)
|
||||
case .updateWindow(let window):
|
||||
guard state.window != window else { return }
|
||||
Task { state.window = window }
|
||||
|
||||
+6
-6
@@ -26,8 +26,8 @@ struct SoftLogoutScreen: View {
|
||||
switch context.viewState.loginMode {
|
||||
case .password:
|
||||
loginForm
|
||||
case .oidc:
|
||||
oidcButton
|
||||
case .oAuth:
|
||||
oAuthButton
|
||||
default:
|
||||
loginUnavailableText
|
||||
}
|
||||
@@ -98,15 +98,15 @@ struct SoftLogoutScreen: View {
|
||||
}
|
||||
}
|
||||
|
||||
/// The OIDC button that can be used for login.
|
||||
var oidcButton: some View {
|
||||
Button { context.send(viewAction: .continueWithOIDC) } label: {
|
||||
/// The OAuth button that can be used for login.
|
||||
var oAuthButton: some View {
|
||||
Button { context.send(viewAction: .continueWithOAuth) } label: {
|
||||
Text(L10n.actionContinue)
|
||||
}
|
||||
.buttonStyle(.compound(.primary))
|
||||
}
|
||||
|
||||
/// Text shown if neither password or OIDC login is supported.
|
||||
/// Text shown if neither password or OAuth login is supported.
|
||||
var loginUnavailableText: some View {
|
||||
Text(L10n.screenLoginErrorUnsupportedAuthentication)
|
||||
.font(.body)
|
||||
|
||||
+3
-3
@@ -24,7 +24,7 @@ enum AuthenticationStartScreenCoordinatorAction {
|
||||
case login
|
||||
case register
|
||||
|
||||
case loginDirectlyWithOIDC(data: OIDCAuthorizationDataProxy, window: UIWindow)
|
||||
case loginDirectlyWithOAuth(data: OAuthAuthorizationDataProxy, window: UIWindow)
|
||||
case loginDirectlyWithPassword(loginHint: String?)
|
||||
|
||||
case reportProblem
|
||||
@@ -65,8 +65,8 @@ final class AuthenticationStartScreenCoordinator: CoordinatorProtocol {
|
||||
case .register:
|
||||
actionsSubject.send(.register)
|
||||
|
||||
case .loginDirectlyWithOIDC(let data, let window):
|
||||
actionsSubject.send(.loginDirectlyWithOIDC(data: data, window: window))
|
||||
case .loginDirectlyWithOAuth(let data, let window):
|
||||
actionsSubject.send(.loginDirectlyWithOAuth(data: data, window: window))
|
||||
case .loginDirectlyWithPassword(let loginHint):
|
||||
actionsSubject.send(.loginDirectlyWithPassword(loginHint: loginHint))
|
||||
|
||||
|
||||
+3
-3
@@ -13,7 +13,7 @@ enum AuthenticationStartScreenViewModelAction: Equatable {
|
||||
case login
|
||||
case register
|
||||
|
||||
case loginDirectlyWithOIDC(data: OIDCAuthorizationDataProxy, window: UIWindow)
|
||||
case loginDirectlyWithOAuth(data: OAuthAuthorizationDataProxy, window: UIWindow)
|
||||
case loginDirectlyWithPassword(loginHint: String?)
|
||||
|
||||
case reportProblem
|
||||
@@ -21,7 +21,7 @@ enum AuthenticationStartScreenViewModelAction: Equatable {
|
||||
}
|
||||
|
||||
struct AuthenticationStartScreenViewState: BindableState {
|
||||
/// The presentation anchor used for OIDC authentication.
|
||||
/// The presentation anchor used for OAuth authentication.
|
||||
var window: UIWindow?
|
||||
|
||||
let serverName: String?
|
||||
@@ -56,7 +56,7 @@ enum AuthenticationStartScreenAlertType {
|
||||
}
|
||||
|
||||
enum AuthenticationStartScreenViewAction {
|
||||
/// Updates the window used as the OIDC presentation anchor.
|
||||
/// Updates the window used as the OAuth presentation anchor.
|
||||
case updateWindow(UIWindow)
|
||||
case developerOptions
|
||||
case reportProblem
|
||||
|
||||
+4
-4
@@ -144,7 +144,7 @@ class AuthenticationStartScreenViewModel: AuthenticationStartScreenViewModelType
|
||||
}
|
||||
}
|
||||
|
||||
guard authenticationService.homeserver.value.loginMode.supportsOIDCFlow else {
|
||||
guard authenticationService.homeserver.value.loginMode.supportsOAuthFlow else {
|
||||
actionsSubject.send(.loginDirectlyWithPassword(loginHint: loginHint))
|
||||
return
|
||||
}
|
||||
@@ -154,9 +154,9 @@ class AuthenticationStartScreenViewModel: AuthenticationStartScreenViewModelType
|
||||
return
|
||||
}
|
||||
|
||||
switch await authenticationService.urlForOIDCLogin(loginHint: loginHint) {
|
||||
case .success(let oidcData):
|
||||
actionsSubject.send(.loginDirectlyWithOIDC(data: oidcData, window: window))
|
||||
switch await authenticationService.urlForOAuthLogin(loginHint: loginHint) {
|
||||
case .success(let oAuthData):
|
||||
actionsSubject.send(.loginDirectlyWithOAuth(data: oAuthData, window: window))
|
||||
case .failure:
|
||||
displayError()
|
||||
}
|
||||
|
||||
+3
-3
@@ -10,7 +10,7 @@ import Combine
|
||||
import SwiftUI
|
||||
|
||||
enum EncryptionResetScreenCoordinatorAction {
|
||||
case requestOIDCAuthorisation(URL)
|
||||
case requestOAuthAuthorisation(URL)
|
||||
case requestPassword(passwordPublisher: PassthroughSubject<String, Never>)
|
||||
case resetFinished
|
||||
case cancel
|
||||
@@ -44,8 +44,8 @@ final class EncryptionResetScreenCoordinator: CoordinatorProtocol {
|
||||
|
||||
guard let self else { return }
|
||||
switch action {
|
||||
case .requestOIDCAuthorisation(let url):
|
||||
self.actionsSubject.send(.requestOIDCAuthorisation(url))
|
||||
case .requestOAuthAuthorisation(let url):
|
||||
self.actionsSubject.send(.requestOAuthAuthorisation(url))
|
||||
case .requestPassword(let passwordPublisher):
|
||||
self.actionsSubject.send(.requestPassword(passwordPublisher: passwordPublisher))
|
||||
case .resetFinished:
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ import Foundation
|
||||
|
||||
enum EncryptionResetScreenViewModelAction {
|
||||
case requestPassword(passwordPublisher: PassthroughSubject<String, Never>)
|
||||
case requestOIDCAuthorisation(url: URL)
|
||||
case requestOAuthAuthorisation(url: URL)
|
||||
case resetFinished
|
||||
case cancel
|
||||
}
|
||||
|
||||
+3
-3
@@ -91,9 +91,9 @@ class EncryptionResetScreenViewModel: EncryptionResetScreenViewModelType, Encryp
|
||||
|
||||
hideLoadingIndicator()
|
||||
|
||||
actionsSubject.send(.requestOIDCAuthorisation(url: url))
|
||||
actionsSubject.send(.requestOAuthAuthorisation(url: url))
|
||||
|
||||
await resetWithOIDCAuthorisation()
|
||||
await resetWithOAuthAuthorisation()
|
||||
}
|
||||
case .failure(let error):
|
||||
MXLog.error("Failed resetting encryption with error \(error)")
|
||||
@@ -121,7 +121,7 @@ class EncryptionResetScreenViewModel: EncryptionResetScreenViewModelType, Encryp
|
||||
}
|
||||
}
|
||||
|
||||
private func resetWithOIDCAuthorisation() async {
|
||||
private func resetWithOAuthAuthorisation() async {
|
||||
guard let identityResetHandle else {
|
||||
fatalError("Requested reset flow continuation without a stored handle")
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ enum QRCodeLoginScreenCoordinatorAction: CustomStringConvertible {
|
||||
case startOver
|
||||
case signInManually
|
||||
case signedIn(userSession: UserSessionProtocol)
|
||||
case requestOIDCAuthorisation(URL, OIDCAccountSettingsPresenter.Continuation)
|
||||
case requestOAuthAuthorisation(URL, OAuthAccountSettingsPresenter.Continuation)
|
||||
case linkedDevice
|
||||
/// Cancel the flow (dismiss the modal).
|
||||
case cancel
|
||||
@@ -34,7 +34,7 @@ enum QRCodeLoginScreenCoordinatorAction: CustomStringConvertible {
|
||||
case .startOver: "startOver"
|
||||
case .signInManually: "signInManually"
|
||||
case .signedIn: "signedIn"
|
||||
case .requestOIDCAuthorisation: "requestOIDCAuthorisation"
|
||||
case .requestOAuthAuthorisation: "requestOAuthAuthorisation"
|
||||
case .linkedDevice: "linkedDevice"
|
||||
case .cancel: "cancel"
|
||||
}
|
||||
@@ -71,8 +71,8 @@ final class QRCodeLoginScreenCoordinator: CoordinatorProtocol {
|
||||
actionsSubject.send(.startOver)
|
||||
case .signedIn(let userSession):
|
||||
actionsSubject.send(.signedIn(userSession: userSession))
|
||||
case .requestOIDCAuthorisation(let url, let continuation):
|
||||
actionsSubject.send(.requestOIDCAuthorisation(url, continuation))
|
||||
case .requestOAuthAuthorisation(let url, let continuation):
|
||||
actionsSubject.send(.requestOAuthAuthorisation(url, continuation))
|
||||
case .linkedDevice:
|
||||
actionsSubject.send(.linkedDevice)
|
||||
case .cancel:
|
||||
|
||||
@@ -16,7 +16,7 @@ enum QRCodeLoginScreenViewModelAction: CustomStringConvertible {
|
||||
case startOver
|
||||
case signInManually
|
||||
case signedIn(userSession: UserSessionProtocol)
|
||||
case requestOIDCAuthorisation(URL, OIDCAccountSettingsPresenter.Continuation)
|
||||
case requestOAuthAuthorisation(URL, OAuthAccountSettingsPresenter.Continuation)
|
||||
case linkedDevice
|
||||
/// Cancel the flow (dismiss the modal).
|
||||
case cancel
|
||||
@@ -26,7 +26,7 @@ enum QRCodeLoginScreenViewModelAction: CustomStringConvertible {
|
||||
case .startOver: "startOver"
|
||||
case .signInManually: "signInManually"
|
||||
case .signedIn: "signedIn"
|
||||
case .requestOIDCAuthorisation: "requestOIDCAuthorisation"
|
||||
case .requestOAuthAuthorisation: "requestOAuthAuthorisation"
|
||||
case .linkedDevice: "linkedDevice"
|
||||
case .cancel: "cancel"
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ class QRCodeLoginScreenViewModel: QRCodeLoginScreenViewModelType, QRCodeLoginScr
|
||||
}
|
||||
|
||||
private var currentTask: AnyCancellable?
|
||||
private var oidcResultTask: AnyCancellable?
|
||||
private var oAuthResultTask: AnyCancellable?
|
||||
|
||||
init(mode: QRCodeLoginScreenMode,
|
||||
canSignInManually: Bool,
|
||||
@@ -182,7 +182,7 @@ class QRCodeLoginScreenViewModel: QRCodeLoginScreenViewModelType, QRCodeLoginScr
|
||||
case .establishingSecureChannel(let checkCodeString):
|
||||
state.state = .displayCode(.deviceCode(checkCodeString))
|
||||
case .waitingForAuthorisation(let url):
|
||||
requestOIDCAuthorization(url: url)
|
||||
requestOAuthAuthorization(url: url)
|
||||
case .syncingSecrets:
|
||||
break // Nothing to do.
|
||||
case .done:
|
||||
@@ -222,7 +222,7 @@ class QRCodeLoginScreenViewModel: QRCodeLoginScreenViewModelType, QRCodeLoginScr
|
||||
case .qrScanned(let checkCodeSender):
|
||||
state.state = .confirmCode(.inputCode(checkCodeSender))
|
||||
case .waitingForAuthorisation(let url):
|
||||
requestOIDCAuthorization(url: url)
|
||||
requestOAuthAuthorization(url: url)
|
||||
case .syncingSecrets:
|
||||
break // Nothing to do.
|
||||
case .done:
|
||||
@@ -257,11 +257,11 @@ class QRCodeLoginScreenViewModel: QRCodeLoginScreenViewModelType, QRCodeLoginScr
|
||||
}
|
||||
}
|
||||
|
||||
private func requestOIDCAuthorization(url: URL) {
|
||||
let (stream, continuation) = AsyncStream<Result<Void, OIDCError>>.makeStream()
|
||||
actionsSubject.send(.requestOIDCAuthorisation(url, continuation))
|
||||
private func requestOAuthAuthorization(url: URL) {
|
||||
let (stream, continuation) = AsyncStream<Result<Void, OAuthError>>.makeStream()
|
||||
actionsSubject.send(.requestOAuthAuthorisation(url, continuation))
|
||||
|
||||
oidcResultTask = Task { [weak self] in
|
||||
oAuthResultTask = Task { [weak self] in
|
||||
for await result in stream {
|
||||
guard let self else { return }
|
||||
switch result {
|
||||
|
||||
+7
-7
@@ -15,13 +15,13 @@ import AuthenticationServices
|
||||
/// have access to this session, and for some reason `prefersEphemeralWebBrowserSession`
|
||||
/// isn't sharing the session back to Safari.
|
||||
@MainActor
|
||||
class OIDCAccountSettingsPresenter: NSObject {
|
||||
class OAuthAccountSettingsPresenter: NSObject {
|
||||
private let accountURL: URL
|
||||
private let oidcRedirectURL: URL
|
||||
private let redirectURL: URL
|
||||
private let presentationAnchor: UIWindow
|
||||
private let appMediator: AppMediatorProtocol
|
||||
|
||||
typealias Continuation = AsyncStream<Result<Void, OIDCError>>.Continuation
|
||||
typealias Continuation = AsyncStream<Result<Void, OAuthError>>.Continuation
|
||||
private let continuation: Continuation?
|
||||
|
||||
init(accountURL: URL,
|
||||
@@ -30,7 +30,7 @@ class OIDCAccountSettingsPresenter: NSObject {
|
||||
appSettings: AppSettings,
|
||||
continuation: Continuation? = nil) {
|
||||
self.accountURL = accountURL
|
||||
oidcRedirectURL = appSettings.oidcRedirectURL
|
||||
redirectURL = appSettings.oAuthRedirectURL
|
||||
self.presentationAnchor = presentationAnchor
|
||||
self.appMediator = appMediator
|
||||
self.continuation = continuation
|
||||
@@ -40,10 +40,10 @@ class OIDCAccountSettingsPresenter: NSObject {
|
||||
|
||||
/// Presents a web authentication session for the supplied data.
|
||||
func start() {
|
||||
let session = ASWebAuthenticationSession(url: accountURL, callback: .oidcRedirectURL(oidcRedirectURL)) { [continuation] _, error in
|
||||
let session = ASWebAuthenticationSession(url: accountURL, callback: .oAuthRedirectURL(redirectURL)) { [continuation] _, error in
|
||||
guard let continuation else { return }
|
||||
|
||||
if error?.isOIDCUserCancellation == true {
|
||||
if error?.isOAuthUserCancellation == true {
|
||||
continuation.yield(.failure(.userCancellation))
|
||||
} else {
|
||||
let errorDescription = error.map(String.init(describing:)) ?? "Unknown error"
|
||||
@@ -70,7 +70,7 @@ class OIDCAccountSettingsPresenter: NSObject {
|
||||
|
||||
// MARK: ASWebAuthenticationPresentationContextProviding
|
||||
|
||||
extension OIDCAccountSettingsPresenter: ASWebAuthenticationPresentationContextProviding {
|
||||
extension OAuthAccountSettingsPresenter: ASWebAuthenticationPresentationContextProviding {
|
||||
func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor {
|
||||
presentationAnchor
|
||||
}
|
||||
Reference in New Issue
Block a user