mirror of
https://github.com/element-hq/element-x-ios.git
synced 2025-03-10 21:39:12 +00:00
Ensure multiple mandatory verification flows can be ran consecutively (e.g. following encryption resets) (#3722)
* Ensure multiple mandatory verification flows can be ran consecutively (e.g. following encryption resets) * Disabled the back button on the verification screen only when verified and waiting for the security state publisher
This commit is contained in:
parent
4856ffd3b2
commit
97069850f5
@ -38,7 +38,7 @@ class OnboardingFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
|
|
||||||
enum Event: EventType {
|
enum Event: EventType {
|
||||||
case next
|
case next
|
||||||
case nextSkippingIdentityConfimed
|
case nextSkippingIdentityConfirmed
|
||||||
}
|
}
|
||||||
|
|
||||||
private let stateMachine: StateMachine<State, Event>
|
private let stateMachine: StateMachine<State, Event>
|
||||||
@ -79,6 +79,8 @@ class OnboardingFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
|
|
||||||
stateMachine = .init(state: .initial)
|
stateMachine = .init(state: .initial)
|
||||||
|
|
||||||
|
configureStateMachine()
|
||||||
|
|
||||||
// Verification can change as part of the onboarding flow by verifying with
|
// Verification can change as part of the onboarding flow by verifying with
|
||||||
// another device, using a recovery key or by resetting one's crypto identity.
|
// another device, using a recovery key or by resetting one's crypto identity.
|
||||||
// It can also happen that onboarding started before it had a chance to update,
|
// It can also happen that onboarding started before it had a chance to update,
|
||||||
@ -86,15 +88,14 @@ class OnboardingFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
// Handle all those cases here instead of spreading them throughout the code.
|
// Handle all those cases here instead of spreading them throughout the code.
|
||||||
verificationStateCancellable = userSession.sessionSecurityStatePublisher
|
verificationStateCancellable = userSession.sessionSecurityStatePublisher
|
||||||
.map(\.verificationState)
|
.map(\.verificationState)
|
||||||
.removeDuplicates()
|
.receive(on: DispatchQueue.main)
|
||||||
.sink { [weak self] value in
|
.sink { [weak self] value in
|
||||||
guard let self,
|
guard let self,
|
||||||
value == .verified,
|
value == .verified,
|
||||||
stateMachine.state == .identityConfirmation else { return }
|
stateMachine.state == .identityConfirmation else { return }
|
||||||
|
|
||||||
appSettings.hasRunIdentityConfirmationOnboarding = true
|
appSettings.hasRunIdentityConfirmationOnboarding = true
|
||||||
stateMachine.tryEvent(.nextSkippingIdentityConfimed)
|
stateMachine.tryEvent(.nextSkippingIdentityConfirmed)
|
||||||
self.verificationStateCancellable = nil
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,8 +112,6 @@ class OnboardingFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
fatalError("This flow coordinator shouldn't have been started")
|
fatalError("This flow coordinator shouldn't have been started")
|
||||||
}
|
}
|
||||||
|
|
||||||
configureStateMachine()
|
|
||||||
|
|
||||||
rootNavigationStackCoordinator.setFullScreenCoverCoordinator(navigationStackCoordinator, animated: !isNewLogin)
|
rootNavigationStackCoordinator.setFullScreenCoverCoordinator(navigationStackCoordinator, animated: !isNewLogin)
|
||||||
|
|
||||||
stateMachine.tryEvent(.next)
|
stateMachine.tryEvent(.next)
|
||||||
@ -146,6 +145,7 @@ class OnboardingFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func configureStateMachine() {
|
private func configureStateMachine() {
|
||||||
|
stateMachine.addRoute(.init(fromState: .finished, toState: .initial))
|
||||||
stateMachine.addRouteMapping { [weak self] event, fromState, _ in
|
stateMachine.addRouteMapping { [weak self] event, fromState, _ in
|
||||||
guard let self else {
|
guard let self else {
|
||||||
return nil
|
return nil
|
||||||
@ -164,7 +164,7 @@ class OnboardingFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
return .finished
|
return .finished
|
||||||
|
|
||||||
case (.identityConfirmation, _, _, _, _):
|
case (.identityConfirmation, _, _, _, _):
|
||||||
if event == .nextSkippingIdentityConfimed {
|
if event == .nextSkippingIdentityConfirmed {
|
||||||
// Used when the verification state has updated to verified
|
// Used when the verification state has updated to verified
|
||||||
// after starting the onboarding flow
|
// after starting the onboarding flow
|
||||||
switch (requiresAppLockSetup, requiresAnalyticsSetup, requiresNotificationsSetup) {
|
switch (requiresAppLockSetup, requiresAnalyticsSetup, requiresNotificationsSetup) {
|
||||||
@ -225,9 +225,18 @@ class OnboardingFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
presentNotificationPermissionsScreen()
|
presentNotificationPermissionsScreen()
|
||||||
case (_, _, .finished):
|
case (_, _, .finished):
|
||||||
rootNavigationStackCoordinator.setFullScreenCoverCoordinator(nil)
|
rootNavigationStackCoordinator.setFullScreenCoverCoordinator(nil)
|
||||||
|
stateMachine.tryState(.initial)
|
||||||
|
case (.finished, _, .initial):
|
||||||
|
break
|
||||||
default:
|
default:
|
||||||
fatalError("Unknown transition: \(context)")
|
fatalError("Unknown transition: \(context)")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let event = context.event {
|
||||||
|
MXLog.info("Transitioning from `\(context.fromState)` to `\(context.toState)` with event `\(event)`")
|
||||||
|
} else {
|
||||||
|
MXLog.info("Transitioning from \(context.fromState)` to `\(context.toState)`")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stateMachine.addErrorHandler { context in
|
stateMachine.addErrorHandler { context in
|
||||||
@ -251,7 +260,7 @@ class OnboardingFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
presentRecoveryKeyScreen()
|
presentRecoveryKeyScreen()
|
||||||
case .skip:
|
case .skip:
|
||||||
appSettings.hasRunIdentityConfirmationOnboarding = true
|
appSettings.hasRunIdentityConfirmationOnboarding = true
|
||||||
stateMachine.tryEvent(.nextSkippingIdentityConfimed)
|
stateMachine.tryEvent(.nextSkippingIdentityConfirmed)
|
||||||
case .reset:
|
case .reset:
|
||||||
startEncryptionResetFlow()
|
startEncryptionResetFlow()
|
||||||
case .logout:
|
case .logout:
|
||||||
|
@ -220,6 +220,8 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func attemptStartingOnboarding() {
|
func attemptStartingOnboarding() {
|
||||||
|
MXLog.info("Attempting to start onboarding")
|
||||||
|
|
||||||
if onboardingFlowCoordinator.shouldStart {
|
if onboardingFlowCoordinator.shouldStart {
|
||||||
clearRoute(animated: false)
|
clearRoute(animated: false)
|
||||||
onboardingFlowCoordinator.start()
|
onboardingFlowCoordinator.start()
|
||||||
@ -340,7 +342,6 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
userSession.sessionSecurityStatePublisher
|
userSession.sessionSecurityStatePublisher
|
||||||
.map(\.verificationState)
|
.map(\.verificationState)
|
||||||
.filter { $0 != .unknown }
|
.filter { $0 != .unknown }
|
||||||
.removeDuplicates()
|
|
||||||
.receive(on: DispatchQueue.main)
|
.receive(on: DispatchQueue.main)
|
||||||
.sink { [weak self] _ in
|
.sink { [weak self] _ in
|
||||||
guard let self else { return }
|
guard let self else { return }
|
||||||
|
@ -24,6 +24,7 @@ struct SessionVerificationScreen: View {
|
|||||||
.background()
|
.background()
|
||||||
.backgroundStyle(.compound.bgCanvasDefault)
|
.backgroundStyle(.compound.bgCanvasDefault)
|
||||||
.interactiveDismissDisabled()
|
.interactiveDismissDisabled()
|
||||||
|
.navigationBarBackButtonHidden(context.viewState.verificationState == .verified)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Private
|
// MARK: - Private
|
||||||
|
@ -47,7 +47,6 @@ class UserSession: UserSessionProtocol {
|
|||||||
MXLog.info("Session security state changed, verificationState: \($0), recoveryState: \($1)")
|
MXLog.info("Session security state changed, verificationState: \($0), recoveryState: \($1)")
|
||||||
return SessionSecurityState(verificationState: $0, recoveryState: $1)
|
return SessionSecurityState(verificationState: $0, recoveryState: $1)
|
||||||
}
|
}
|
||||||
.removeDuplicates()
|
|
||||||
.receive(on: DispatchQueue.main)
|
.receive(on: DispatchQueue.main)
|
||||||
.sink { [weak self] value in
|
.sink { [weak self] value in
|
||||||
self?.sessionSecurityStateSubject.send(value)
|
self?.sessionSecurityStateSubject.send(value)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user