mirror of
https://gitlab.opencode.de/bwi/bundesmessenger/clients/bundesmessenger-ios.git
synced 2026-04-18 07:28:28 +02:00
Log errors before throwing. Remove white colour. Remove AuthenticationCoordinatorState added during rebase.
199 lines
8.1 KiB
Swift
199 lines
8.1 KiB
Swift
//
|
|
// Copyright 2022 New Vector Ltd
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
//
|
|
|
|
import Foundation
|
|
|
|
/// The parameters used for registration requests.
|
|
struct RegistrationParameters: Codable {
|
|
/// Authentication parameters
|
|
var auth: AuthenticationParameters?
|
|
|
|
/// The account username
|
|
var username: String?
|
|
|
|
/// The account password
|
|
var password: String?
|
|
|
|
/// Device name
|
|
var initialDeviceDisplayName: String?
|
|
|
|
/// Temporary flag to notify the server that we support MSISDN flow. Used to prevent old app
|
|
/// versions to end up in fallback because the HS returns the MSISDN flow which they don't support
|
|
var xShowMSISDN: Bool?
|
|
|
|
enum CodingKeys: String, CodingKey {
|
|
case auth
|
|
case username
|
|
case password
|
|
case initialDeviceDisplayName = "initial_device_display_name"
|
|
case xShowMSISDN = "x_show_msisdn"
|
|
}
|
|
|
|
/// The parameters as a JSON dictionary for use in MXRestClient.
|
|
func dictionary() throws -> [String: Any] {
|
|
let jsonData = try JSONEncoder().encode(self)
|
|
let object = try JSONSerialization.jsonObject(with: jsonData)
|
|
guard let dictionary = object as? [String: Any] else {
|
|
MXLog.error("[RegistrationParameters] dictionary: Unexpected type decoded \(type(of: object)). Expected a Dictionary.")
|
|
throw AuthenticationError.dictionaryError
|
|
}
|
|
|
|
return dictionary
|
|
}
|
|
}
|
|
|
|
/// The data passed to the `auth` parameter in authentication requests.
|
|
struct AuthenticationParameters: Codable {
|
|
/// The type of authentication taking place. The identifier from `MXLoginFlowType`.
|
|
let type: String
|
|
|
|
/// Note: session can be null for reset password request
|
|
var session: String?
|
|
|
|
/// parameter for "m.login.recaptcha" type
|
|
var captchaResponse: String?
|
|
|
|
/// parameter for "m.login.email.identity" type
|
|
var threePIDCredentials: ThreePIDCredentials?
|
|
|
|
enum CodingKeys: String, CodingKey {
|
|
case type
|
|
case session
|
|
case captchaResponse = "response"
|
|
case threePIDCredentials = "threepid_creds"
|
|
}
|
|
|
|
/// Creates the authentication parameters for a captcha step.
|
|
static func captchaParameters(session: String, captchaResponse: String) -> AuthenticationParameters {
|
|
AuthenticationParameters(type: kMXLoginFlowTypeRecaptcha, session: session, captchaResponse: captchaResponse)
|
|
}
|
|
|
|
/// Creates the authentication parameters for a third party ID step using an email address.
|
|
static func emailIdentityParameters(session: String, threePIDCredentials: ThreePIDCredentials) -> AuthenticationParameters {
|
|
AuthenticationParameters(type: kMXLoginFlowTypeEmailIdentity, session: session, threePIDCredentials: threePIDCredentials)
|
|
}
|
|
|
|
// Note that there is a bug in Synapse (needs investigation), but if we pass .msisdn,
|
|
// the homeserver answer with the login flow with MatrixError fields and not with a simple MatrixError 401.
|
|
/// Creates the authentication parameters for a third party ID step using a phone number.
|
|
static func msisdnIdentityParameters(session: String, threePIDCredentials: ThreePIDCredentials) -> AuthenticationParameters {
|
|
AuthenticationParameters(type: kMXLoginFlowTypeMSISDN, session: session, threePIDCredentials: threePIDCredentials)
|
|
}
|
|
|
|
/// Creates the authentication parameters for a password reset step.
|
|
static func resetPasswordParameters(clientSecret: String, sessionID: String) -> AuthenticationParameters {
|
|
AuthenticationParameters(type: kMXLoginFlowTypeEmailIdentity,
|
|
session: nil,
|
|
threePIDCredentials: ThreePIDCredentials(clientSecret: clientSecret, sessionID: sessionID))
|
|
}
|
|
}
|
|
|
|
/// The result from a response of a registration flow step.
|
|
enum RegistrationResult {
|
|
/// Registration has completed, creating an `MXSession` for the account.
|
|
case success(MXSession)
|
|
/// The request was successful but there are pending steps to complete.
|
|
case flowResponse(FlowResult)
|
|
}
|
|
|
|
/// The state of an authentication flow after a step has been completed.
|
|
struct FlowResult {
|
|
/// The stages in the flow that are yet to be completed.
|
|
let missingStages: [Stage]
|
|
/// The stages in the flow that have been completed.
|
|
let completedStages: [Stage]
|
|
|
|
/// A stage in the authentication flow.
|
|
enum Stage {
|
|
/// The stage with the type `m.login.recaptcha`.
|
|
case reCaptcha(mandatory: Bool, publicKey: String)
|
|
|
|
/// The stage with the type `m.login.email.identity`.
|
|
case email(mandatory: Bool)
|
|
|
|
/// The stage with the type `m.login.msisdn`.
|
|
case msisdn(mandatory: Bool)
|
|
|
|
/// The stage with the type `m.login.dummy`.
|
|
///
|
|
/// This stage can be mandatory if there is no other stages. In this case the account cannot
|
|
/// be created by just sending a username and a password, the dummy stage has to be completed.
|
|
case dummy(mandatory: Bool)
|
|
|
|
/// The stage with the type `m.login.terms`.
|
|
case terms(mandatory: Bool, policies: [String: String])
|
|
|
|
/// A stage of an unknown type.
|
|
case other(mandatory: Bool, type: String, params: [AnyHashable: Any])
|
|
|
|
/// Whether the stage is a dummy stage that is also mandatory.
|
|
var isDummyAndMandatory: Bool {
|
|
guard case let .dummy(isMandatory) = self else { return false }
|
|
return isMandatory
|
|
}
|
|
}
|
|
}
|
|
|
|
extension MXAuthenticationSession {
|
|
/// The flows from the session mapped as a `FlowResult` value.
|
|
var flowResult: FlowResult {
|
|
let allFlowTypes = Set(flows.flatMap { $0.stages ?? [] })
|
|
var missingStages = [FlowResult.Stage]()
|
|
var completedStages = [FlowResult.Stage]()
|
|
|
|
allFlowTypes.forEach { flow in
|
|
let isMandatory = flows.allSatisfy { $0.stages.contains(flow) }
|
|
|
|
let stage: FlowResult.Stage
|
|
switch flow {
|
|
case kMXLoginFlowTypeRecaptcha:
|
|
let parameters = params[flow] as? [AnyHashable: Any]
|
|
let publicKey = parameters?["public_key"] as? String
|
|
stage = .reCaptcha(mandatory: isMandatory, publicKey: publicKey ?? "")
|
|
case kMXLoginFlowTypeDummy:
|
|
stage = .dummy(mandatory: isMandatory)
|
|
case kMXLoginFlowTypeTerms:
|
|
let parameters = params[flow] as? [String: String]
|
|
stage = .terms(mandatory: isMandatory, policies: parameters ?? [:])
|
|
case kMXLoginFlowTypeMSISDN:
|
|
stage = .msisdn(mandatory: isMandatory)
|
|
case kMXLoginFlowTypeEmailIdentity:
|
|
stage = .email(mandatory: isMandatory)
|
|
default:
|
|
let parameters = params[flow] as? [AnyHashable: Any]
|
|
stage = .other(mandatory: isMandatory, type: flow, params: parameters ?? [:])
|
|
}
|
|
|
|
if let completed = completed, completed.contains(flow) {
|
|
completedStages.append(stage)
|
|
} else {
|
|
missingStages.append(stage)
|
|
}
|
|
}
|
|
|
|
return FlowResult(missingStages: missingStages, completedStages: completedStages)
|
|
}
|
|
|
|
/// Determines the next stage to be completed in the flow.
|
|
func nextUncompletedStage(flowIndex: Int = 0) -> String? {
|
|
guard flows.count < flowIndex else { return nil }
|
|
return flows[flowIndex].stages.first {
|
|
guard let completed = completed else { return false }
|
|
return !completed.contains($0)
|
|
}
|
|
}
|
|
}
|