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

import Foundation
import SignalServiceKit
import UIKit

class BackupRecoveryKeyReminderCoordinator {
    private let aep: AccountEntropyPool
    private let fromViewController: UIViewController
    private let onSuccess: () -> Void

    private weak var backupKeyReminderNavController: UINavigationController?

    init(
        aep: AccountEntropyPool,
        fromViewController: UIViewController,
        onSuccess: @escaping () -> Void,
    ) {
        self.aep = aep
        self.fromViewController = fromViewController
        self.onSuccess = onSuccess
    }

    func presentVerifyFlow() {
        let navController = UINavigationController()
        backupKeyReminderNavController = navController

        // Retain ourselves as long as the nav controller is presented.
        ObjectRetainer.retainObject(self, forLifetimeOf: navController)

        navController.viewControllers = [
            ReminderEnterRecoveryKeyViewController(
                aep: aep,
                onForgotKeyTapped: { [weak self] in
                    self?.showRecordRecoveryKey()
                },
                onEntryConfirmed: { [weak self] in
                    self?.showKeepKeySafeSheet()
                },
            ),
        ]

        fromViewController.present(navController, animated: true)
    }

    private func showKeepKeySafeSheet() {
        let keepKeySafeSheet = BackupKeepKeySafeSheet(
            onContinue: { [weak self] in
                guard let self else { return }

                backupKeyReminderNavController?.dismiss(animated: true)
                onSuccess()
            },
            secondaryButton: .dismissing(
                title: CommonStrings.cancelButton,
                style: .secondary,
            ),
        )

        backupKeyReminderNavController?.present(keepKeySafeSheet, animated: true)
    }

    private func showRecordRecoveryKey() {
        Task { @MainActor in
            guard
                let authSuccess = await LocalDeviceAuthentication().performBiometricAuth(),
                let backupKeyReminderNavController
            else { return }

            _showRecordRecoveryKey(
                backupKeyReminderNavController: backupKeyReminderNavController,
                localDeviceAuthSuccess: authSuccess,
                aep: aep,
            )
        }
    }

    private func _showRecordRecoveryKey(
        backupKeyReminderNavController: UINavigationController,
        localDeviceAuthSuccess: LocalDeviceAuthentication.AuthSuccess,
        aep: AccountEntropyPool,
    ) {
        backupKeyReminderNavController.pushViewController(
            BackupRecordKeyViewController(
                aepMode: .current(aep, localDeviceAuthSuccess),
                options: [],
            ),
            animated: true,
        )
    }
}

// MARK: -

private final class ReminderEnterRecoveryKeyViewController: EnterAccountEntropyPoolViewController {
    init(
        aep: AccountEntropyPool,
        onForgotKeyTapped: @escaping () -> Void,
        onEntryConfirmed: @escaping () -> Void,
    ) {
        super.init()

        configure(
            aepValidationPolicy: .acceptOnly(aep),
            colorConfig: ColorConfig(
                background: UIColor.Signal.background,
                aepEntryBackground: UIColor.Signal.quaternaryFill,
            ),
            headerStrings: HeaderStrings(
                title: OWSLocalizedString(
                    "BACKUP_RECOVERY_KEY_REMINDER_TITLE",
                    comment: "Title for a screen asking users to enter their recovery key, for reminder purposes.",
                ),
                subtitle: OWSLocalizedString(
                    "BACKUP_RECOVERY_KEY_REMINDER_SUBTITLE",
                    comment: "Subtitle for a screen asking users to enter their recovery key, for reminder purposes.",
                ),
            ),
            footerButtonConfig: FooterButtonConfig(
                title: OWSLocalizedString(
                    "BACKUP_RECOVERY_KEY_REMINDER_FORGOT_KEY_BUTTON",
                    comment: "Title for a button offering help if the user has forgotten their recovery key.",
                ),
                action: {
                    onForgotKeyTapped()
                },
            ),
            onEntryConfirmed: { _ in
                onEntryConfirmed()
            },
        )
    }
}