zashi-ios-wallet-private/secant/Features/Root/RootInitialization.swift

210 lines
9.9 KiB
Swift
Raw Normal View History

//
// RootInitialization.swift
// secant-testnet
//
// Created by Lukáš Korba on 01.12.2022.
//
import ComposableArchitecture
/// In this file is a collection of helpers that control all state and action related operations
2023-01-02 07:18:58 -08:00
/// for the `RootReducer` with a connection to the app/wallet initialization and erasure of the wallet.
extension RootReducer {
enum InitializationAction: Equatable {
case appDelegate(AppDelegateAction)
case checkBackupPhraseValidation
case checkWalletInitialization
Add crash reporter to secant (#531) * [#525] Adds functions to configure, testCrash and check if it can start. This adds a build phase where a dummy file is added to the project to make the build and Plist copy happy. When building in the CI there will be a script to replace this Plist file with the real one that then will be copied to the bundle Crashlytics will be "off" by default and then be turned on when starting up to be an Opt-Out thing. This is the only way it can be turned off later. reference: https://firebase.google.com/docs/crashlytics/customize-crash-reports?platform=ios#enable_opt-in_reporting The app will start with crash reporting turned off and will set it up on by default on the application's code. Then if the user wants to opt-out of crash reporting, it can. Otherwise, it won't be possible. Adds opting out of crash reporting as a stored user preference. This adds a value inside UserPreferencesStorage and its live and mock counterparts. also creates a builer for `CrashReporterClient` that has a Dependency to `@Dependency(\.userStoredPreferences)` and sets the references for the client to set the appropriate values into the user storage `UserPreferencesStorage` as been adapted to be a TCA Dependency. `SettingsStore` now as a `Toogle()` to turn off and on crash reporting. But it doesn't work yet because I haven't found out how to make a TCA Binding that can rely on an initial value that is not hardcoded but injected from somewhere else. See https://www.pointfree.co/episodes/ep158-safer-conciser-forms-part-1 https://www.pointfree.co/episodes/ep158-safer-conciser-forms-part-2 Adds Test Crash button and enable crash reporting Adds upload-symbols run script phase Closes #525 Add a custom build environment variable "UPLOAD_CRASHLYTICS_SYMBOLS" that will let Xcode skip the upload_symbols script for debug builds Fix Initialization tests * bump build
2023-02-15 13:18:18 -08:00
case configureCrashReporter
case createNewWallet
case initializeSDK
case nukeWallet
case respondToWalletInitializationState(InitializationState)
}
// swiftlint:disable:next cyclomatic_complexity
func initializationReduce() -> Reduce<RootReducer.State, RootReducer.Action> {
Reduce { state, action in
switch action {
case .initialization(.appDelegate(.didFinishLaunching)):
// TODO: [#524] finish all the wallet events according to definition, https://github.com/zcash/secant-ios-wallet/issues/524
LoggerProxy.event(".appDelegate(.didFinishLaunching)")
Add crash reporter to secant (#531) * [#525] Adds functions to configure, testCrash and check if it can start. This adds a build phase where a dummy file is added to the project to make the build and Plist copy happy. When building in the CI there will be a script to replace this Plist file with the real one that then will be copied to the bundle Crashlytics will be "off" by default and then be turned on when starting up to be an Opt-Out thing. This is the only way it can be turned off later. reference: https://firebase.google.com/docs/crashlytics/customize-crash-reports?platform=ios#enable_opt-in_reporting The app will start with crash reporting turned off and will set it up on by default on the application's code. Then if the user wants to opt-out of crash reporting, it can. Otherwise, it won't be possible. Adds opting out of crash reporting as a stored user preference. This adds a value inside UserPreferencesStorage and its live and mock counterparts. also creates a builer for `CrashReporterClient` that has a Dependency to `@Dependency(\.userStoredPreferences)` and sets the references for the client to set the appropriate values into the user storage `UserPreferencesStorage` as been adapted to be a TCA Dependency. `SettingsStore` now as a `Toogle()` to turn off and on crash reporting. But it doesn't work yet because I haven't found out how to make a TCA Binding that can rely on an initial value that is not hardcoded but injected from somewhere else. See https://www.pointfree.co/episodes/ep158-safer-conciser-forms-part-1 https://www.pointfree.co/episodes/ep158-safer-conciser-forms-part-2 Adds Test Crash button and enable crash reporting Adds upload-symbols run script phase Closes #525 Add a custom build environment variable "UPLOAD_CRASHLYTICS_SYMBOLS" that will let Xcode skip the upload_symbols script for debug builds Fix Initialization tests * bump build
2023-02-15 13:18:18 -08:00
/// We need to fetch data from keychain, in order to be 100% sure the keychain can be read we delay the check a bit
return .concatenate(
EffectTask(value: .initialization(.configureCrashReporter)),
EffectTask(value: .initialization(.checkWalletInitialization))
.delay(for: 0.02, scheduler: mainQueue)
.eraseToEffect()
)
/// Evaluate the wallet's state based on keychain keys and database files presence
case .initialization(.checkWalletInitialization):
let walletState = RootReducer.walletInitializationState(
databaseFiles: databaseFiles,
walletStorage: walletStorage,
zcashSDKEnvironment: zcashSDKEnvironment
)
return EffectTask(value: .initialization(.respondToWalletInitializationState(walletState)))
/// Respond to all possible states of the wallet and initiate appropriate side effects including errors handling
case .initialization(.respondToWalletInitializationState(let walletState)):
switch walletState {
case .failed:
// TODO: [#221] error we need to handle (https://github.com/zcash/secant-ios-wallet/issues/221)
state.appInitializationState = .failed
case .keysMissing:
// TODO: [#221] error we need to handle (https://github.com/zcash/secant-ios-wallet/issues/221)
state.appInitializationState = .keysMissing
case .initialized, .filesMissing:
if walletState == .filesMissing {
state.appInitializationState = .filesMissing
}
return .concatenate(
EffectTask(value: .initialization(.initializeSDK)),
EffectTask(value: .initialization(.checkBackupPhraseValidation))
)
case .uninitialized:
state.appInitializationState = .uninitialized
return EffectTask(value: .destination(.updateDestination(.onboarding)))
.delay(for: 3, scheduler: mainQueue)
.eraseToEffect()
.cancellable(id: CancelId.self, cancelInFlight: true)
}
return .none
/// Stored wallet is present, database files may or may not be present, trying to initialize app state variables and environments.
/// When initialization succeeds user is taken to the home screen.
case .initialization(.initializeSDK):
do {
state.storedWallet = try walletStorage.exportWallet()
guard let storedWallet = state.storedWallet else {
state.appInitializationState = .failed
// TODO: [#221] fatal error we need to handle (https://github.com/zcash/secant-ios-wallet/issues/221)
return .none
}
try mnemonic.isValid(storedWallet.seedPhrase.value())
let seedBytes = try mnemonic.toSeed(storedWallet.seedPhrase.value())
let birthday = state.storedWallet?.birthday?.value() ?? zcashSDKEnvironment.defaultBirthday
let initializer = try RootReducer.prepareInitializer(
for: storedWallet.seedPhrase.value(),
birthday: birthday,
databaseFiles: databaseFiles,
derivationTool: derivationTool,
mnemonic: mnemonic,
zcashSDKEnvironment: zcashSDKEnvironment
)
try sdkSynchronizer.prepareWith(initializer: initializer, seedBytes: seedBytes)
try sdkSynchronizer.start()
return .none
} catch {
// TODO: [#221] error we need to handle (https://github.com/zcash/secant-ios-wallet/issues/221)
state.appInitializationState = .failed
return .none
}
case .initialization(.checkBackupPhraseValidation):
guard let storedWallet = state.storedWallet else {
state.appInitializationState = .failed
// TODO: [#221] fatal error we need to handle (https://github.com/zcash/secant-ios-wallet/issues/221)
return .none
}
var landingDestination = RootReducer.DestinationState.Destination.home
if !storedWallet.hasUserPassedPhraseBackupTest {
do {
let phraseWords = try mnemonic.asWords(storedWallet.seedPhrase.value())
let recoveryPhrase = RecoveryPhrase(words: phraseWords.map { $0.redacted })
state.phraseDisplayState.phrase = recoveryPhrase
state.phraseValidationState = randomRecoveryPhrase.random(recoveryPhrase)
landingDestination = .phraseDisplay
} catch {
// TODO: [#201] - merge with issue 201 (https://github.com/zcash/secant-ios-wallet/issues/201) and its Error States
return .none
}
}
state.appInitializationState = .initialized
return EffectTask(value: .destination(.updateDestination(landingDestination)))
.delay(for: 3, scheduler: mainQueue)
.eraseToEffect()
.cancellable(id: CancelId.self, cancelInFlight: true)
case .initialization(.createNewWallet):
do {
// get the random english mnemonic
let newRandomPhrase = try mnemonic.randomMnemonic()
let birthday = try zcashSDKEnvironment.lightWalletService.latestBlockHeight()
// store the wallet to the keychain
try walletStorage.importWallet(newRandomPhrase, birthday, .english, false)
// start the backup phrase validation test
let randomRecoveryPhraseWords = try mnemonic.asWords(newRandomPhrase)
let recoveryPhrase = RecoveryPhrase(words: randomRecoveryPhraseWords.map { $0.redacted })
state.phraseDisplayState.phrase = recoveryPhrase
state.phraseValidationState = randomRecoveryPhrase.random(recoveryPhrase)
return .concatenate(
EffectTask(value: .initialization(.initializeSDK)),
EffectTask(value: .phraseValidation(.displayBackedUpPhrase))
)
} catch {
// TODO: [#201] - merge with issue 221 (https://github.com/zcash/secant-ios-wallet/issues/221) and its Error States
}
return .none
case .phraseValidation(.succeed):
do {
try walletStorage.markUserPassedPhraseBackupTest()
} catch {
// TODO: [#221] error we need to handle, issue #221 (https://github.com/zcash/secant-ios-wallet/issues/221)
}
return .none
case .initialization(.nukeWallet):
walletStorage.nukeWallet()
do {
try databaseFiles.nukeDbFilesFor(zcashSDKEnvironment.network)
} catch {
// TODO: [#221] error we need to handle, issue #221 (https://github.com/zcash/secant-ios-wallet/issues/221)
}
return .none
case .welcome(.debugMenuStartup), .home(.debugMenuStartup):
return .concatenate(
EffectTask.cancel(id: CancelId.self),
EffectTask(value: .destination(.updateDestination(.startup)))
)
case .onboarding(.importWallet(.successfullyRecovered)):
return EffectTask(value: .destination(.updateDestination(.home)))
case .onboarding(.importWallet(.initializeSDK)):
return EffectTask(value: .initialization(.initializeSDK))
case .onboarding(.createNewWallet):
return EffectTask(value: .initialization(.createNewWallet))
case .home, .destination, .onboarding, .phraseDisplay, .phraseValidation, .sandbox, .welcome:
return .none
Add crash reporter to secant (#531) * [#525] Adds functions to configure, testCrash and check if it can start. This adds a build phase where a dummy file is added to the project to make the build and Plist copy happy. When building in the CI there will be a script to replace this Plist file with the real one that then will be copied to the bundle Crashlytics will be "off" by default and then be turned on when starting up to be an Opt-Out thing. This is the only way it can be turned off later. reference: https://firebase.google.com/docs/crashlytics/customize-crash-reports?platform=ios#enable_opt-in_reporting The app will start with crash reporting turned off and will set it up on by default on the application's code. Then if the user wants to opt-out of crash reporting, it can. Otherwise, it won't be possible. Adds opting out of crash reporting as a stored user preference. This adds a value inside UserPreferencesStorage and its live and mock counterparts. also creates a builer for `CrashReporterClient` that has a Dependency to `@Dependency(\.userStoredPreferences)` and sets the references for the client to set the appropriate values into the user storage `UserPreferencesStorage` as been adapted to be a TCA Dependency. `SettingsStore` now as a `Toogle()` to turn off and on crash reporting. But it doesn't work yet because I haven't found out how to make a TCA Binding that can rely on an initial value that is not hardcoded but injected from somewhere else. See https://www.pointfree.co/episodes/ep158-safer-conciser-forms-part-1 https://www.pointfree.co/episodes/ep158-safer-conciser-forms-part-2 Adds Test Crash button and enable crash reporting Adds upload-symbols run script phase Closes #525 Add a custom build environment variable "UPLOAD_CRASHLYTICS_SYMBOLS" that will let Xcode skip the upload_symbols script for debug builds Fix Initialization tests * bump build
2023-02-15 13:18:18 -08:00
case .initialization(.configureCrashReporter):
crashReporter.configure(
!userStoredPreferences.isUserOptedOutOfCrashReporting()
)
return .none
}
}
}
}