Merge pull request #6201 from vector-im/doug/5654_login_flow

Add login screen to new flow.
This commit is contained in:
Doug
2022-05-31 17:04:50 +01:00
committed by GitHub
35 changed files with 1343 additions and 255 deletions
@@ -84,14 +84,7 @@ class AuthenticationService: NSObject {
}
func startFlow(_ flow: AuthenticationFlow, for homeserverAddress: String) async throws {
reset()
let loginFlows = try await loginFlow(for: homeserverAddress)
state.homeserver = .init(address: loginFlows.homeserverAddress,
addressFromUser: homeserverAddress,
preferredLoginMode: loginFlows.loginMode,
loginModeSupportedTypes: loginFlows.supportedLoginTypes)
var (client, homeserver) = try await loginFlow(for: homeserverAddress)
let loginWizard = LoginWizard(client: client)
self.loginWizard = loginWizard
@@ -99,17 +92,20 @@ class AuthenticationService: NSObject {
if flow == .register {
do {
let registrationWizard = RegistrationWizard(client: client)
state.homeserver.registrationFlow = try await registrationWizard.registrationFlow()
homeserver.registrationFlow = try await registrationWizard.registrationFlow()
self.registrationWizard = registrationWizard
} catch {
guard state.homeserver.preferredLoginMode.hasSSO, error as? RegistrationError == .registrationDisabled else {
guard homeserver.preferredLoginMode.hasSSO, error as? RegistrationError == .registrationDisabled else {
throw error
}
// Continue without throwing when registration is disabled but SSO is available.
}
}
state.flow = flow
// The state and client are set after trying the registration flow to
// ensure the existing state isn't wiped out when an error occurs.
self.state = AuthenticationState(flow: flow, homeserver: homeserver)
self.client = client
}
/// Get a SSO url
@@ -170,10 +166,11 @@ class AuthenticationService: NSObject {
// MARK: - Private
/// Request the supported login flows for this homeserver.
/// Query the supported login flows for the supplied homeserver.
/// This is the first method to call to be able to get a wizard to login or to create an account
/// - Parameter homeserverAddress: The homeserver string entered by the user.
private func loginFlow(for homeserverAddress: String) async throws -> LoginFlowResult {
/// - Returns: A tuple containing the REST client for the server along with the homeserver state containing the login flows.
private func loginFlow(for homeserverAddress: String) async throws -> (AuthenticationRestClient, AuthenticationState.Homeserver) {
let homeserverAddress = HomeserverAddress.sanitized(homeserverAddress)
guard var homeserverURL = URL(string: homeserverAddress) else {
@@ -181,8 +178,6 @@ class AuthenticationService: NSObject {
throw AuthenticationError.invalidHomeserver
}
let state = AuthenticationState(flow: .login, homeserverAddress: homeserverAddress)
if let wellKnown = try? await wellKnown(for: homeserverURL),
let baseURL = URL(string: wellKnown.homeServer.baseUrl) {
homeserverURL = baseURL
@@ -193,28 +188,26 @@ class AuthenticationService: NSObject {
let loginFlow = try await getLoginFlowResult(client: client)
self.client = client
self.state = state
return loginFlow
let homeserver = AuthenticationState.Homeserver(address: loginFlow.homeserverAddress,
addressFromUser: homeserverAddress,
preferredLoginMode: loginFlow.loginMode)
return (client, homeserver)
}
/// Request the supported login flows for the corresponding session.
/// This method is used to get the flows for a server after a soft-logout.
/// - Parameter session: The MXSession where a soft-logout has occurred.
private func loginFlow(for session: MXSession) async throws -> LoginFlowResult {
private func loginFlow(for session: MXSession) async throws -> (AuthenticationRestClient, AuthenticationState.Homeserver) {
guard let client = session.matrixRestClient else {
MXLog.error("[AuthenticationService] loginFlow called on a session that doesn't have a matrixRestClient.")
throw AuthenticationError.missingMXRestClient
}
let state = AuthenticationState(flow: .login, homeserverAddress: client.homeserver)
let loginFlow = try await getLoginFlowResult(client: session.matrixRestClient)
self.client = client
self.state = state
return loginFlow
let homeserver = AuthenticationState.Homeserver(address: loginFlow.homeserverAddress,
preferredLoginMode: loginFlow.loginMode)
return (client, homeserver)
}
private func getLoginFlowResult(client: MXRestClient) async throws -> LoginFlowResult {
@@ -30,16 +30,24 @@ struct AuthenticationState {
self.homeserver = Homeserver(address: homeserverAddress)
}
init(flow: AuthenticationFlow, homeserver: Homeserver) {
self.flow = flow
self.homeserver = homeserver
}
struct Homeserver {
/// The homeserver address as returned by the server.
var address: String
/// The homeserver address as input by the user (it can differ to the well-known request).
var addressFromUser: String?
/// The homeserver's address formatted to be displayed to the user in labels, text fields etc.
var displayableAddress: String {
let address = addressFromUser ?? address
return address.replacingOccurrences(of: "https://", with: "") // Only remove https. Leave http to indicate the server doesn't use SSL.
}
/// The preferred login mode for the server
var preferredLoginMode: LoginMode = .unknown
/// Supported types for the login.
var loginModeSupportedTypes = [MXLoginFlow]()
/// The response returned when querying the homeserver for registration flows.
var registrationFlow: RegistrationResult?
@@ -49,5 +57,14 @@ struct AuthenticationState {
guard let url = URL(string: address) else { return false }
return url.host == "matrix.org" || url.host == "matrix-client.matrix.org"
}
/// The homeserver mapped into view data that is ready for display.
var viewData: AuthenticationHomeserverViewData {
AuthenticationHomeserverViewData(address: displayableAddress,
isMatrixDotOrg: isMatrixDotOrg,
showLoginForm: preferredLoginMode.supportsPasswordFlow,
showRegistrationForm: registrationFlow != nil,
ssoIdentityProviders: preferredLoginMode.ssoIdentityProviders ?? [])
}
}
}