[#535] Use 0.18.0's wipe() instead of obsolete nuke approach (#549)

- added alert view asking if nuke is triggered or canceled
- wipe of the keychain
- wipe publisher properly used
- functional wipe accessible through debug menu
This commit is contained in:
Lukas Korba 2023-02-27 22:43:38 +01:00 committed by GitHub
parent 148ca941f1
commit 75150da3a4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 114 additions and 36 deletions

View File

@ -3517,8 +3517,8 @@
isa = XCRemoteSwiftPackageReference; isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/zcash/ZcashLightClientKit/"; repositoryURL = "https://github.com/zcash/ZcashLightClientKit/";
requirement = { requirement = {
branch = main; kind = revision;
kind = branch; revision = 3b2d972b2dd0c51e36d76e49fcf58273bf585c1b;
}; };
}; };
6654C7382715A38000901167 /* XCRemoteSwiftPackageReference "swift-composable-architecture" */ = { 6654C7382715A38000901167 /* XCRemoteSwiftPackageReference "swift-composable-architecture" */ = {

View File

@ -338,8 +338,7 @@
"kind" : "remoteSourceControl", "kind" : "remoteSourceControl",
"location" : "https://github.com/zcash/ZcashLightClientKit/", "location" : "https://github.com/zcash/ZcashLightClientKit/",
"state" : { "state" : {
"branch" : "main", "revision" : "3b2d972b2dd0c51e36d76e49fcf58273bf585c1b"
"revision" : "27b99013f7dda11caee0a261361c155490966e7f"
} }
} }
], ],

View File

@ -18,24 +18,11 @@ extension DependencyValues {
} }
enum SDKSynchronizerState: Equatable { enum SDKSynchronizerState: Equatable {
case unknown
case transactionsUpdated
case started
case progressUpdated case progressUpdated
case statusWillUpdate case started
case synced
case stopped case stopped
case disconnected case synced
case syncing case unknown
case downloading
case validating
case scanning
case enhancing
case fetching
case minedTransaction
case foundTransactions
case failed
case connectionStateChanged
} }
enum SDKSynchronizerClientError: Error { enum SDKSynchronizerClientError: Error {
@ -54,6 +41,8 @@ protocol SDKSynchronizerClient {
func stop() func stop()
func synchronizerSynced(_ synchronizerState: SDKSynchronizer.SynchronizerState?) func synchronizerSynced(_ synchronizerState: SDKSynchronizer.SynchronizerState?)
func statusSnapshot() -> SyncStatusSnapshot func statusSnapshot() -> SyncStatusSnapshot
func isSyncing() -> Bool
func isInitialized() -> Bool
func rewind(_ policy: RewindPolicy) async throws func rewind(_ policy: RewindPolicy) async throws
@ -75,6 +64,8 @@ protocol SDKSynchronizerClient {
to recipientAddress: Recipient, to recipientAddress: Recipient,
memo: Memo? memo: Memo?
) -> EffectTask<Result<TransactionState, NSError>> ) -> EffectTask<Result<TransactionState, NSError>>
func wipe() -> AnyPublisher<Void, Error>?
} }
extension SDKSynchronizerClient { extension SDKSynchronizerClient {

View File

@ -75,6 +75,14 @@ class LiveSDKSynchronizerClient: SDKSynchronizerClient {
func stop() { func stop() {
synchronizer?.stop() synchronizer?.stop()
} }
func isSyncing() -> Bool {
latestScannedSynchronizerState?.syncStatus.isSyncing ?? false
}
func isInitialized() -> Bool {
synchronizer != nil
}
func synchronizerStarted() { func synchronizerStarted() {
stateChanged.send(.started) stateChanged.send(.started)
@ -229,4 +237,8 @@ class LiveSDKSynchronizerClient: SDKSynchronizerClient {
} }
} }
} }
func wipe() -> AnyPublisher<Void, Error>? {
synchronizer?.wipe()
}
} }

View File

@ -33,6 +33,10 @@ class MockSDKSynchronizerClient: SDKSynchronizerClient {
func stop() { } func stop() { }
func isSyncing() -> Bool { false }
func isInitialized() -> Bool { false }
func synchronizerSynced(_ synchronizerState: SDKSynchronizer.SynchronizerState?) { } func synchronizerSynced(_ synchronizerState: SDKSynchronizer.SynchronizerState?) { }
func statusSnapshot() -> SyncStatusSnapshot { .default } func statusSnapshot() -> SyncStatusSnapshot { .default }
@ -200,4 +204,6 @@ class MockSDKSynchronizerClient: SDKSynchronizerClient {
return EffectTask(value: Result.success(transactionState)) return EffectTask(value: Result.success(transactionState))
} }
func wipe() -> AnyPublisher<Void, Error>? { nil }
} }

View File

@ -32,6 +32,10 @@ class NoopSDKSynchronizer: SDKSynchronizerClient {
func stop() { } func stop() { }
func isSyncing() -> Bool { false }
func isInitialized() -> Bool { false }
func synchronizerSynced(_ synchronizerState: SDKSynchronizer.SynchronizerState?) { } func synchronizerSynced(_ synchronizerState: SDKSynchronizer.SynchronizerState?) { }
func statusSnapshot() -> SyncStatusSnapshot { .default } func statusSnapshot() -> SyncStatusSnapshot { .default }
@ -70,6 +74,8 @@ class NoopSDKSynchronizer: SDKSynchronizerClient {
func updateStateChanged(_ newState: SDKSynchronizerState) { func updateStateChanged(_ newState: SDKSynchronizerState) {
stateChanged = CurrentValueSubject<SDKSynchronizerState, Never>(newState) stateChanged = CurrentValueSubject<SDKSynchronizerState, Never>(newState)
} }
func wipe() -> AnyPublisher<Void, Error>? { nil }
} }
class TestSDKSynchronizerClient: SDKSynchronizerClient { class TestSDKSynchronizerClient: SDKSynchronizerClient {
@ -90,6 +96,10 @@ class TestSDKSynchronizerClient: SDKSynchronizerClient {
func stop() { } func stop() { }
func isSyncing() -> Bool { false }
func isInitialized() -> Bool { false }
func synchronizerSynced(_ synchronizerState: SDKSynchronizer.SynchronizerState?) { } func synchronizerSynced(_ synchronizerState: SDKSynchronizer.SynchronizerState?) { }
func statusSnapshot() -> SyncStatusSnapshot { .default } func statusSnapshot() -> SyncStatusSnapshot { .default }
@ -235,4 +245,6 @@ class TestSDKSynchronizerClient: SDKSynchronizerClient {
func updateStateChanged(_ newState: SDKSynchronizerState) { func updateStateChanged(_ newState: SDKSynchronizerState) {
stateChanged = CurrentValueSubject<SDKSynchronizerState, Never>(newState) stateChanged = CurrentValueSubject<SDKSynchronizerState, Never>(newState)
} }
func wipe() -> AnyPublisher<Void, Error>? { nil }
} }

View File

@ -23,9 +23,10 @@ extension RootReducer {
case welcome case welcome
} }
@BindingState var alert: AlertState<RootReducer.Action>?
var internalDestination: Destination = .welcome var internalDestination: Destination = .welcome
var previousDestination: Destination? var previousDestination: Destination?
var destination: Destination { var destination: Destination {
get { internalDestination } get { internalDestination }
set { set {
@ -39,6 +40,7 @@ extension RootReducer {
case deeplink(URL) case deeplink(URL)
case deeplinkHome case deeplinkHome
case deeplinkSend(Zatoshi, String, String) case deeplinkSend(Zatoshi, String, String)
case dismissAlert
case updateDestination(RootReducer.DestinationState.Destination) case updateDestination(RootReducer.DestinationState.Destination)
} }
@ -112,7 +114,12 @@ extension RootReducer {
} }
return EffectTask(value: .destination(.deeplink(url))) return EffectTask(value: .destination(.deeplink(url)))
case .home, .initialization, .onboarding, .phraseDisplay, .phraseValidation, .sandbox, .welcome, .debug: case .destination(.dismissAlert):
state.destinationState.alert = nil
return .none
case .home, .initialization, .onboarding, .phraseDisplay, .phraseValidation,
.sandbox, .welcome, .binding, .nukeWalletFailed, .nukeWalletSucceeded, .debug:
return .none return .none
} }

View File

@ -21,6 +21,7 @@ extension RootReducer {
case initializeSDK case initializeSDK
case initialSetups case initialSetups
case nukeWallet case nukeWallet
case nukeWalletRequest
case respondToWalletInitializationState(InitializationState) case respondToWalletInitializationState(InitializationState)
case walletConfigChanged(WalletConfig) case walletConfigChanged(WalletConfig)
} }
@ -125,10 +126,9 @@ extension RootReducer {
mnemonic: mnemonic, mnemonic: mnemonic,
zcashSDKEnvironment: zcashSDKEnvironment zcashSDKEnvironment: zcashSDKEnvironment
) )
try sdkSynchronizer.prepareWith(initializer: initializer, seedBytes: seedBytes) try sdkSynchronizer.prepareWith(initializer: initializer, seedBytes: seedBytes)
try sdkSynchronizer.start() try sdkSynchronizer.start()
return .none return .none
} catch { } catch {
// TODO: [#221] error we need to handle (https://github.com/zcash/secant-ios-wallet/issues/221) // TODO: [#221] error we need to handle (https://github.com/zcash/secant-ios-wallet/issues/221)
@ -199,14 +199,57 @@ extension RootReducer {
} }
return .none return .none
case .initialization(.nukeWallet): case .initialization(.nukeWalletRequest):
walletStorage.nukeWallet() state.destinationState.alert = AlertState(
do { title: TextState("Wipe of the wallet"),
try databaseFiles.nukeDbFilesFor(zcashSDKEnvironment.network) message: TextState("Are you sure?"),
} catch { buttons: [
// TODO: [#221] error we need to handle, issue #221 (https://github.com/zcash/secant-ios-wallet/issues/221) .destructive(
} TextState("Yes"),
action: .send(.initialization(.nukeWallet))
),
.cancel(
TextState("No"),
action: .send(.destination(.dismissAlert))
)
]
)
return .none return .none
case .initialization(.nukeWallet):
guard let wipePublisher = sdkSynchronizer.wipe() else {
return EffectTask(value: .nukeWalletFailed)
}
return wipePublisher
.catchToEffect()
.receive(on: mainQueue)
.replaceEmpty(with: .success(Void()))
.map { _ in return RootReducer.Action.nukeWalletSucceeded }
.replaceError(with: RootReducer.Action.nukeWalletFailed)
.eraseToEffect()
.cancellable(id: SynchronizerCancelId.self, cancelInFlight: true)
case .nukeWalletSucceeded:
walletStorage.nukeWallet()
state.onboardingState.destination = nil
state.onboardingState.index = 0
return .concatenate(
.cancel(id: SynchronizerCancelId.self),
EffectTask(value: .initialization(.checkWalletInitialization))
)
case .nukeWalletFailed:
// TODO: [#221] error we need to handle, issue #221 (https://github.com/zcash/secant-ios-wallet/issues/221)
let backDestination: EffectTask<RootReducer.Action>
if let previousDestination = state.destinationState.previousDestination {
backDestination = EffectTask(value: .destination(.updateDestination(previousDestination)))
} else {
backDestination = EffectTask(value: .destination(.updateDestination(state.destinationState.destination)))
}
return .concatenate(
.cancel(id: SynchronizerCancelId.self),
backDestination
)
case .welcome(.debugMenuStartup), .home(.debugMenuStartup): case .welcome(.debugMenuStartup), .home(.debugMenuStartup):
return .concatenate( return .concatenate(
@ -222,8 +265,8 @@ extension RootReducer {
case .onboarding(.createNewWallet): case .onboarding(.createNewWallet):
return EffectTask(value: .initialization(.createNewWallet)) return EffectTask(value: .initialization(.createNewWallet))
case .home, .destination, .onboarding, .phraseDisplay, .phraseValidation, .sandbox, .welcome: case .home, .destination, .onboarding, .phraseDisplay, .phraseValidation, .sandbox, .welcome, .binding:
return .none return .none
case .initialization(.configureCrashReporter): case .initialization(.configureCrashReporter):

View File

@ -6,6 +6,7 @@ typealias RootViewStore = ViewStore<RootReducer.State, RootReducer.Action>
struct RootReducer: ReducerProtocol { struct RootReducer: ReducerProtocol {
enum CancelId {} enum CancelId {}
enum SynchronizerCancelId {}
struct State: Equatable { struct State: Equatable {
var appInitializationState: InitializationState = .uninitialized var appInitializationState: InitializationState = .uninitialized
@ -20,10 +21,13 @@ struct RootReducer: ReducerProtocol {
var welcomeState: WelcomeReducer.State var welcomeState: WelcomeReducer.State
} }
enum Action: Equatable { enum Action: Equatable, BindableAction {
case binding(BindingAction<RootReducer.State>)
case destination(DestinationAction) case destination(DestinationAction)
case home(HomeReducer.Action) case home(HomeReducer.Action)
case initialization(InitializationAction) case initialization(InitializationAction)
case nukeWalletFailed
case nukeWalletSucceeded
case onboarding(OnboardingFlowReducer.Action) case onboarding(OnboardingFlowReducer.Action)
case phraseDisplay(RecoveryPhraseDisplayReducer.Action) case phraseDisplay(RecoveryPhraseDisplayReducer.Action)
case phraseValidation(RecoveryPhraseValidationFlowReducer.Action) case phraseValidation(RecoveryPhraseValidationFlowReducer.Action)
@ -46,6 +50,8 @@ struct RootReducer: ReducerProtocol {
@Dependency(\.zcashSDKEnvironment) var zcashSDKEnvironment @Dependency(\.zcashSDKEnvironment) var zcashSDKEnvironment
var body: some ReducerProtocol<State, Action> { var body: some ReducerProtocol<State, Action> {
BindingReducer()
Scope(state: \.homeState, action: /Action.home) { Scope(state: \.homeState, action: /Action.home) {
HomeReducer() HomeReducer()
} }
@ -144,6 +150,7 @@ extension RootReducer {
network: zcashSDKEnvironment.network, network: zcashSDKEnvironment.network,
spendParamsURL: try databaseFiles.spendParamsURLFor(network), spendParamsURL: try databaseFiles.spendParamsURLFor(network),
outputParamsURL: try databaseFiles.outputParamsURLFor(network), outputParamsURL: try databaseFiles.outputParamsURLFor(network),
saplingParamsSourceURL: SaplingParamsSourceURL.default,
viewingKeys: [viewingKey], viewingKeys: [viewingKey],
walletBirthday: birthday, walletBirthday: birthday,
loggerProxy: OSLogger_(logLevel: .debug, category: LoggerConstants.sdkLogs) loggerProxy: OSLogger_(logLevel: .debug, category: LoggerConstants.sdkLogs)

View File

@ -126,7 +126,7 @@ private extension RootView {
} }
Button("[Be careful] Nuke Wallet") { Button("[Be careful] Nuke Wallet") {
viewStore.send(.initialization(.nukeWallet)) viewStore.send(.initialization(.nukeWalletRequest))
} }
} }
@ -154,6 +154,7 @@ private extension RootView {
} }
} }
} }
.alert(self.store.scope(state: \.destinationState.alert), dismiss: .destination(.dismissAlert))
} }
.navigationBarTitle("Startup") .navigationBarTitle("Startup")
} }

View File

@ -17,7 +17,7 @@ class HomeTests: XCTestCase {
reducer: HomeReducer() reducer: HomeReducer()
) )
store.send(.synchronizerStateChanged(.downloading)) store.send(.synchronizerStateChanged(.progressUpdated))
store.receive(.updateSynchronizerStatus) store.receive(.updateSynchronizerStatus)
} }