Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  OnboardingCompletionService.swift   Sprache: JAVA

 

import CocoaLumberjackSwift
import Foundation
import Keychain
import RemoteSecretProtocol
import ThreemaFramework

/// Service responsible for handling the completion steps after identity setup.
/// This includes database migration, nickname persistence, email/phone linking,
/// contact sync, and Threema Safe setup.
@MainActor
final class OnboardingCompletionService {
    
    // MARK: - Properties
    
    private let bootstrapIdentityStore: any BootstrapIdentityStoreProtocol
    private let licenseStore: any LicenseStoreAdapterProtocol
    private let bootstrapUserSettings: any BootstrapUserSettingsProtocol
    private let bootstrapContactStore: any BootstrapContactStoreProtocol
    private let bootstrapServerAPI: any BootstrapServerAPIProtocol
    private let bootstrapPhoneNumberNormalizer: any PhoneNumberNormalizerProtocol
    private let bootstrapMDM: any BootstrapMDMSetupProtocol
    private let safeComponentsFactory: SafeComponentsFactory
    
    // MARK: - Initialization
    
    init(
        bootstrapIdentityStore: any BootstrapIdentityStoreProtocol,
        licenseStore: any LicenseStoreAdapterProtocol,
        bootstrapUserSettings: any BootstrapUserSettingsProtocol,
        bootstrapContactStore: any BootstrapContactStoreProtocol,
        bootstrapServerAPI: any BootstrapServerAPIProtocol,
        bootstrapPhoneNumberNormalizer: any PhoneNumberNormalizerProtocol,
        bootstrapMDM: any BootstrapMDMSetupProtocol,
        safeComponentsFactory: SafeComponentsFactory
    ) {
        self.bootstrapIdentityStore = bootstrapIdentityStore
        self.licenseStore = licenseStore
        self.bootstrapUserSettings = bootstrapUserSettings
        self.bootstrapContactStore = bootstrapContactStore
        self.bootstrapServerAPI = bootstrapServerAPI
        self.bootstrapPhoneNumberNormalizer = bootstrapPhoneNumberNormalizer
        self.bootstrapMDM = bootstrapMDM
        self.safeComponentsFactory = safeComponentsFactory
    }
    
    // MARK: - Public Methods
    
    /// Runs database and app migrations, updates feature mask, and sets app setup state.
    /// - Parameters:
    ///   - remoteSecretManager: The remote secret manager for database initialization
    ///   - keychainManager: The keychain manager for database initialization
    /// - Throws: Error if migration fails
    func runMigrationsAndSetup(
        remoteSecretManager: any RemoteSecretManagerProtocol,
        businessInjector: BusinessInjectorProtocol
    ) async throws {
        try await SetupApp.runDatabaseMigrationIfNeeded(remoteSecretManager: remoteSecretManager)
        try await SetupApp.runAppMigrationIfNeeded(businessInjector: businessInjector)
        try await FeatureMask.updateLocal()
        
        AppSetup.state = .identitySetupComplete
    }
    
    /// Persists the nickname from setup configuration to the identity store.
    /// - Parameter nickname: The nickname to persist, or nil to skip
    func persistNickname(_ nickname: String?) {
        guard let nickname, !nickname.isEmpty else {
            return
        }
        
        bootstrapIdentityStore.pushFromName = nickname
        licenseStore.performUpdateWorkInfo()
    }
    
    /// Synchronizes contacts from address book if enabled.
    /// - Parameter syncContacts: Whether to sync contacts
    /// - Returns: True if sync was performed and succeeded, false if skipped
    /// - Throws: Error if synchronization fails
    @discardableResult
    func syncContacts(
        _ syncContacts: Bool,
        userSettings: any UserSettingsProtocol
    ) async throws -> Bool {
        userSettings.syncContacts = syncContacts
        
        guard syncContacts else {
            return false
        }
        
        return try await bootstrapContactStore.synchronizeAddressBook(forceFullSync: true)
    }
    
    /// Links an email address to the identity.
    /// - Parameter email: The email address to link, or nil to skip
    /// - Returns: True if linking was performed, false if skipped
    /// - Throws: Error if linking fails
    @discardableResult
    func linkEmail(_ email: String?) async throws -> Bool {
        guard let email, !email.isEmpty else {
            return false
        }
        
        guard bootstrapIdentityStore.linkedEmail?.isEmpty ?? true else {
            return false
        }
        
        return try await bootstrapServerAPI.linkEmail(email)
    }
    
    /// Links a phone number to the identity.
    /// - Parameter phoneNumber: The phone number to link (will be normalized), or nil to skip
    /// - Returns: True if linking was performed, false if skipped
    /// - Throws: Error if linking fails, except on (Custom-) OnPrem where server errors are logged and ignored
    @discardableResult
    func linkPhoneNumber(_ phoneNumber: String?) async throws -> Bool {
        guard let phoneNumber, !phoneNumber.isEmpty else {
            return false
        }
        
        guard bootstrapIdentityStore.linkedMobileNo?.isEmpty ?? true else {
            return false
        }

        let region = bootstrapPhoneNumberNormalizer.userRegion()

        guard let normalizedNumber = bootstrapPhoneNumberNormalizer.e164Format(from: phoneNumber, defaultRegion: region)
        else {
            DDLogWarn("Failed to normalize phone number, skipping link")
            return false
        }
        
        do {
            return try await bootstrapServerAPI.linkMobileNo(normalizedNumber)
        }
        catch {
            // OnPrem servers may not support phone linking, this must not block finishing the onboarding
            guard TargetManager.isOnPrem else {
                throw error
            }
            DDLogError("Linking phone number failed on (Custom-) OnPrem, continuing onboarding: \(error)")
            return false
        }
    }
    
    /// Enables Threema Safe with the provided configuration.
    /// - Parameters:
    ///   - businessInjector: The business injector with all dependencies needed for Safe
    ///   - keychainManager: The keychain manager for Safe storage
    ///   - safePassword: The Safe password from setup configuration
    ///   - safeCustomServer: Custom server URL, or nil
    ///   - safeServerUsername: Server username, or nil
    ///   - safeServerPassword: Server password, or nil
    ///   - safeMaxBackupBytes: Maximum backup size, or nil
    ///   - safeRetentionDays: Retention days, or nil
    /// - Returns: True if Safe was enabled, false if skipped
    /// - Throws: Error if Safe activation fails
    @discardableResult
    func enableSafe(
        businessInjector: any BusinessInjectorProtocol,
        keychainManager: any KeychainManagerProtocol,
        safePassword: String?,
        safeCustomServer: String?,
        safeServerUsername: String?,
        safeServerPassword: String?,
        safeMaxBackupBytes: NSNumber?,
        safeRetentionDays: NSNumber?
    ) async throws -> Bool {
        businessInjector.userSettings.safeIntroShown = true
        
        let safeConfigManager = safeComponentsFactory.createSafeConfigManager(keychainManager: keychainManager)
        let safeAPIService = safeComponentsFactory.createSafeAPIService()
        
        var effectivePassword = safePassword
        if bootstrapMDM.isSafeBackupPasswordPreset {
            effectivePassword = bootstrapMDM.safePassword
        }
        
        let safeStore = safeComponentsFactory.createSafeStore(
            safeConfigManager: safeConfigManager,
            serverAPIConnector: bootstrapServerAPI.serverAPIConnector,
            groupManager: businessInjector.groupManager,
            myIdentityStore: businessInjector.myIdentityStore,
            phoneNumberNormalizer: PhoneNumberNormalizer()
        )
        let safeManager = SafeManager(
            safeConfigManager: safeConfigManager,
            safeStore: safeStore,
            safeAPIService: safeAPIService
        )
        
        guard let password = effectivePassword, password.count >= 8 else {
            DDLogError("Could not enable Threema Safe: invalid password")
            safeManager.deactivate()
            return false
        }
        
        var customServer = safeCustomServer
        var customServerUsername = safeServerUsername
        var customServerPassword = safeServerPassword
        
        if bootstrapMDM.isSafeBackupServerPreset {
            customServer = bootstrapMDM.safeServerURL
            customServerUsername = bootstrapMDM.safeServerUsername
            customServerPassword = bootstrapMDM.safeServerPassword
            
            safeConfigManager.setCustomServer(customServer)
            safeConfigManager.setServer(customServer)
        }
        
        guard let identity = bootstrapIdentityStore.identity else {
            DDLogError("Cannot enable Safe: no identity available")
            return false
        }
        
        try await safeManager.activate(
            identity: identity,
            safePassword: password,
            customServer: customServer,
            serverUser: customServerUsername,
            serverPassword: customServerPassword,
            server: customServer,
            maxBackupBytes: safeMaxBackupBytes,
            retentionDays: safeRetentionDays
        )
        
        return true
    }
}

Messung
CHZG
909510095

¤ Dauer der Verarbeitung: 0.3 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=1104845
#Domains=499266