Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
signalapp
GitHub Repository: signalapp/Signal-iOS
Path: blob/main/Signal/Registration/RegistrationStep.swift
1 views
//
// Copyright 2023 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//

import Foundation

public enum RegistrationStep: Equatable {

    // MARK: - Opening Steps

    case registrationSplash
    case changeNumberSplash
    case permissions

    // MARK: - Quick Restore

    /// Display a QR code similar to provisioning that, when scanned,
    /// sets up a connection for the old device to sent registration information
    /// to the new device.
    case scanQuickRegistrationQrCode

    // MARK: - Actually registering

    /// The user should enter or confirm their phone number.
    /// The number may be pre-filled or empty; either way we will require
    /// the user to confirm the number at least once before proceeding.
    /// The number may be used to send an SMS or as a way to identify the
    /// account being registered for via KBS backup info.
    case phoneNumberEntry(RegistrationPhoneNumberViewState)

    /// If registering via session, the step to enter the verification code.
    case verificationCodeEntry(RegistrationVerificationState)

    /// For the first time we enter the pin. This can be
    /// for first account setup, creating a pin, or if
    /// re-registering and needing to confirm the pin.
    /// When doing first time setup, the pin must be confirmed; that is
    /// considered part of this same "step" and is just a UI detail.
    case pinEntry(RegistrationPinState)

    /// All PIN attempts have been exhausted. The user may still be able to register,
    /// but they cannot recover their kbs backups.
    case pinAttemptsExhaustedWithoutReglock(RegistrationPinAttemptsExhaustedViewState)

    /// At _any_ point during session-based registration, a captcha challenge may be
    /// requested.
    case captchaChallenge

    /// If we encounter reglock, fail to recover the kbs backups (probably because
    /// PIN guesses got used up), we have no choice but to wait out the reglock.
    case reglockTimeout(RegistrationReglockTimeoutState)

    // MARK: From Backup

    /// If the user elects to restore from backup and doesn't have their old phone,
    /// they are prompted to manually enter their recovery key.
    case enterRecoveryKey(RegistrationEnterAccountEntropyPoolState)

    // MARK: - Post-Registration

    /// The path taken to get to the restore options screen
    public enum RestorePath: Equatable {
        public enum BackupTier {
            case free
            case paid
        }

        public enum Platform {
            case android
            case ios
        }

        /// Restore backup, transfer from old device, small skip button
        case quickRestore(BackupTier?, Platform)
        /// Restore backup, prominent skip button
        case manualRestore
        /// Transfer from device, restore backup, prominent skip button
        case unspecified
    }

    /// Prompt the user to choose from the available restore methods
    case chooseRestoreMethod(RestorePath)

    /// Prompt the user to confirm restoring from backup
    case confirmRestoreFromBackup(RegistrationRestoreFromBackupConfirmationState)

    case deviceTransfer(DeviceTransferCoordinator)

    /// If the account has not set whether its phone number should be
    /// discoverable, this step happens after registration is complete.
    /// (Typically skipped during re-registration as a result.)
    case phoneNumberDiscoverability(RegistrationPhoneNumberDiscoverabilityState)

    /// If the account has not set profile info, this step happens after registration is complete.
    /// (Typically skipped during re-registration as a result.)
    case setupProfile(RegistrationProfileState)

    // MARK: - Non-ViewController steps

    public enum ErrorSheet: Equatable {
        /// We received a session that indicates we won't be able to use it to
        /// request a code.
        case sessionCanNeverRequestVerificationCode

        /// We should tell the user their attempt has expired
        /// and they need to start over.
        case sessionInvalidated

        /// The user can no longer submit a verification code.
        /// This could be because the previously sent code expired,
        /// or because they used up their verification code attempts.
        /// In either case, they need to send a new code to proceed.
        case verificationCodeSubmissionUnavailable

        /// The user tried to submit a verification code, but we've never
        /// actually sent a code, so no submission could possibly be correct.
        case submittingVerificationCodeBeforeAnyCodeSent

        /// The user had completed registration, but before finishing
        /// post-registration steps they were deregistered, likely by
        /// another device registering on the same number.
        /// The only path forward is to reset _everything_ and re-register.
        case becameDeregistered(reregParams: RegistrationMode.ReregistrationParams)

        /// A network error occurred. The user can probably fix this by
        /// checking their internet connection.
        case networkError

        /// A generic error occurred. Prefer to use other error types.
        case genericError
    }

    /// Special cases; should display an error on the current screen, whatever it is.
    /// (If this is returned as the first step, show the splash and then this error).
    /// This sheet should be undismissable; the user must ack it to proceed, and doing
    /// so should call `RegistrationCoordinator.nextStep()`
    case showErrorSheet(ErrorSheet)

    /// Special case, should display a banner on the current screen, whatever it is.
    /// Happens if we get a response from the server we can't parse; we assume this means
    /// an app version update is needed to parse it.
    /// (If this is returned as the first step, show the splash and then this error).
    case appUpdateBanner

    /// Special case; done with the registration flow!
    case done

    // MARK: - Logging

    public var logSafeString: String {
        switch self {
        case .registrationSplash: return "registrationSplash"
        case .changeNumberSplash: return "changeNumberSplash"
        case .permissions: return "permissions"
        case .scanQuickRegistrationQrCode: return "scanQuickRegistrationQrCode"
        case .phoneNumberEntry: return "phoneNumberEntry"
        case .verificationCodeEntry: return "verificationCodeEntry"
        case .deviceTransfer: return "deviceTransfer"
        case .pinEntry: return "pinEntry"
        case .pinAttemptsExhaustedWithoutReglock: return "pinAttemptsExhaustedWithoutReglock"
        case .captchaChallenge: return "captchaChallenge"
        case .reglockTimeout: return "reglockTimeout"
        case .enterRecoveryKey: return "enterRecoveryKey"
        case .chooseRestoreMethod: return "chooseRestoreMethod"
        case .confirmRestoreFromBackup: return "confirmRestoreFromBackup"
        case .phoneNumberDiscoverability: return "phoneNumberDiscoverability"
        case .setupProfile: return "setupProfile"
        case .showErrorSheet: return "showErrorSheet"
        case .appUpdateBanner: return "appUpdateBanner"
        case .done: return "done"
        }
    }
}