[#1097] Zashi-iOS audit Issue E
- copy with expiry time set draft [#1097] Zashi-iOS audit Issue E - copy to pasteboard has been removed from recovery phrase seed completely - copy seed to pasteboard added to the debug menu, please note, the debug menu will not be in production build, issue #1113
This commit is contained in:
parent
6970b6ff60
commit
746b6859a7
|
@ -335,7 +335,6 @@ let package = Package(
|
|||
"MnemonicClient",
|
||||
"Models",
|
||||
"NumberFormatter",
|
||||
"Pasteboard",
|
||||
"UIComponents",
|
||||
"Utils",
|
||||
"WalletStorage",
|
||||
|
@ -374,6 +373,7 @@ let package = Package(
|
|||
"Models",
|
||||
"NumberFormatter",
|
||||
"OnboardingFlow",
|
||||
"Pasteboard",
|
||||
"ReadTransactionsStorage",
|
||||
"RecoveryPhraseDisplay",
|
||||
"RestoreWalletStorage",
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
import Foundation
|
||||
import ComposableArchitecture
|
||||
import Models
|
||||
import Pasteboard
|
||||
import WalletStorage
|
||||
import ZcashLightClientKit
|
||||
import Utils
|
||||
|
@ -22,20 +21,17 @@ public struct RecoveryPhraseDisplay {
|
|||
@Presents public var alert: AlertState<Action>?
|
||||
public var phrase: RecoveryPhrase?
|
||||
public var showBackButton = false
|
||||
public var showCopyToBufferAlert = false
|
||||
public var birthday: Birthday?
|
||||
public var birthdayValue: String?
|
||||
|
||||
public init(
|
||||
phrase: RecoveryPhrase? = nil,
|
||||
showBackButton: Bool = false,
|
||||
showCopyToBufferAlert: Bool = false,
|
||||
birthday: Birthday? = nil,
|
||||
birthdayValue: String? = nil
|
||||
) {
|
||||
self.phrase = phrase
|
||||
self.showBackButton = showBackButton
|
||||
self.showCopyToBufferAlert = showCopyToBufferAlert
|
||||
self.birthday = birthday
|
||||
self.birthdayValue = birthdayValue
|
||||
}
|
||||
|
@ -43,12 +39,10 @@ public struct RecoveryPhraseDisplay {
|
|||
|
||||
public enum Action: Equatable {
|
||||
case alert(PresentationAction<Action>)
|
||||
case copyToBufferPressed
|
||||
case finishedPressed
|
||||
case onAppear
|
||||
}
|
||||
|
||||
@Dependency(\.pasteboard) var pasteboard
|
||||
@Dependency(\.walletStorage) var walletStorage
|
||||
@Dependency(\.numberFormatter) var numberFormatter
|
||||
|
||||
|
@ -81,12 +75,6 @@ public struct RecoveryPhraseDisplay {
|
|||
case .alert(.dismiss):
|
||||
state.alert = nil
|
||||
return .none
|
||||
|
||||
case .copyToBufferPressed:
|
||||
guard let phrase = state.phrase?.toString() else { return .none }
|
||||
pasteboard.setString(phrase)
|
||||
state.showCopyToBufferAlert = true
|
||||
return .none
|
||||
|
||||
case .finishedPressed:
|
||||
return .none
|
||||
|
|
|
@ -93,16 +93,6 @@ public struct RecoveryPhraseDisplayView: View {
|
|||
.onAppear { store.send(.onAppear) }
|
||||
.alert($store.scope(state: \.alert, action: \.alert))
|
||||
.zashiBack(false, hidden: !store.showBackButton)
|
||||
.toolbarAction {
|
||||
Button {
|
||||
store.send(.copyToBufferPressed)
|
||||
} label: {
|
||||
Text(L10n.General.tapToCopy)
|
||||
.font(.custom(FontFamily.Inter.bold.name, size: 11))
|
||||
.underline()
|
||||
.foregroundColor(Asset.Colors.primary.color)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.navigationBarBackButtonHidden()
|
||||
|
@ -120,7 +110,6 @@ public struct RecoveryPhraseDisplayView: View {
|
|||
initialState: RecoveryPhraseDisplay.State(
|
||||
phrase: .placeholder,
|
||||
showBackButton: true,
|
||||
showCopyToBufferAlert: false,
|
||||
birthdayValue: nil
|
||||
)
|
||||
) {
|
||||
|
@ -135,7 +124,6 @@ public struct RecoveryPhraseDisplayView: View {
|
|||
extension RecoveryPhraseDisplay.State {
|
||||
public static let initial = RecoveryPhraseDisplay.State(
|
||||
phrase: nil,
|
||||
showCopyToBufferAlert: false,
|
||||
birthday: nil
|
||||
)
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ import Foundation
|
|||
import ZcashLightClientKit
|
||||
import Generated
|
||||
import Models
|
||||
import Pasteboard
|
||||
|
||||
/// In this file is a collection of helpers that control all state and action related operations
|
||||
/// for the `RootReducer` with a connection to the UI navigation.
|
||||
|
@ -20,6 +21,7 @@ extension RootReducer {
|
|||
public indirect enum DebugAction: Equatable {
|
||||
case cancelRescan
|
||||
case cantStartSync(ZcashError)
|
||||
case copySeedToPasteboard
|
||||
case flagUpdated
|
||||
case rateTheApp
|
||||
case rescanBlockchain
|
||||
|
@ -83,6 +85,12 @@ extension RootReducer {
|
|||
}
|
||||
.cancellable(id: WalletConfigCancelId.timer, cancelInFlight: true)
|
||||
|
||||
case .debug(.copySeedToPasteboard):
|
||||
let storedWallet = try? walletStorage.exportWallet()
|
||||
guard let phrase = storedWallet?.seedPhrase.value() else { return .none }
|
||||
pasteboard.setString(phrase.redacted)
|
||||
return .none
|
||||
|
||||
case let .debug(.walletConfigLoaded(walletConfig)):
|
||||
return Effect.send(.updateStateAfterConfigUpdate(walletConfig))
|
||||
|
||||
|
|
|
@ -118,6 +118,7 @@ public struct RootReducer: Reducer {
|
|||
@Dependency(\.mainQueue) var mainQueue
|
||||
@Dependency(\.mnemonic) var mnemonic
|
||||
@Dependency(\.numberFormatter) var numberFormatter
|
||||
@Dependency(\.pasteboard) var pasteboard
|
||||
@Dependency(\.sdkSynchronizer) var sdkSynchronizer
|
||||
@Dependency(\.userStoredPreferences) var userStoredPreferences
|
||||
@Dependency(\.walletConfigProvider) var walletConfigProvider
|
||||
|
|
|
@ -180,10 +180,14 @@ private extension RootView {
|
|||
}
|
||||
#endif
|
||||
|
||||
Button(L10n.Root.Debug.Option.copySeed) {
|
||||
viewStore.send(.debug(.copySeedToPasteboard))
|
||||
}
|
||||
|
||||
Button(L10n.Root.Debug.Option.rescanBlockchain) {
|
||||
viewStore.send(.debug(.rescanBlockchain))
|
||||
}
|
||||
|
||||
|
||||
Button(L10n.Root.Debug.Option.nukeWallet) {
|
||||
viewStore.send(.initialization(.nukeWalletRequest))
|
||||
}
|
||||
|
|
|
@ -189,7 +189,6 @@ extension AdvancedSettingsReducer.State {
|
|||
phraseDisplayState: RecoveryPhraseDisplay.State(
|
||||
phrase: nil,
|
||||
showBackButton: false,
|
||||
showCopyToBufferAlert: false,
|
||||
birthday: nil
|
||||
),
|
||||
privateDataConsentState: .initial,
|
||||
|
@ -208,7 +207,6 @@ extension AdvancedSettingsStore {
|
|||
initialState: .init(
|
||||
phraseDisplayState: RecoveryPhraseDisplay.State(
|
||||
phrase: nil,
|
||||
showCopyToBufferAlert: false,
|
||||
birthday: nil
|
||||
),
|
||||
privateDataConsentState: .initial,
|
||||
|
|
|
@ -396,6 +396,8 @@ public enum L10n {
|
|||
public enum Option {
|
||||
/// Rate the App
|
||||
public static let appReview = L10n.tr("Localizable", "root.debug.option.appReview", fallback: "Rate the App")
|
||||
/// Copy seed to pasteboard
|
||||
public static let copySeed = L10n.tr("Localizable", "root.debug.option.copySeed", fallback: "Copy seed to pasteboard")
|
||||
/// Export Logs
|
||||
public static let exportLogs = L10n.tr("Localizable", "root.debug.option.exportLogs", fallback: "Export Logs")
|
||||
/// [Be careful] Nuke Wallet
|
||||
|
|
|
@ -292,6 +292,7 @@ Sharing this private data is irrevocable — once you have shared this private d
|
|||
"root.debug.navigationTitle" = "Startup";
|
||||
"root.debug.option.restartApp" = "Restart the App";
|
||||
"root.debug.option.rescanBlockchain" = "Rescan Blockchain";
|
||||
"root.debug.option.copySeed" = "Copy seed to pasteboard";
|
||||
"root.debug.option.nukeWallet" = "[Be careful] Nuke Wallet";
|
||||
"root.debug.option.exportLogs" = "Export Logs";
|
||||
"root.debug.option.appReview" = "Rate the App";
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
9E34519529C4A4BF00177D16 /* AddressDetailsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E207C382966EF87003E2C9B /* AddressDetailsTests.swift */; };
|
||||
9E34519629C4A4D800177D16 /* secantUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D4E7A2526B364180058B01E /* secantUITests.swift */; };
|
||||
9E34519729C4A51100177D16 /* RecoveryPhraseBackupTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DFE93DE272C6D4B000FCCA5 /* RecoveryPhraseBackupTests.swift */; };
|
||||
9E34519829C4A51100177D16 /* RecoveryPhraseDisplayReducerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D1C1AA227611EFD0004AF6A /* RecoveryPhraseDisplayReducerTests.swift */; };
|
||||
9E34519A29C4A52F00177D16 /* BalanceBreakdownTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E94C61F28AA7DEE008256E9 /* BalanceBreakdownTests.swift */; };
|
||||
9E34519B29C4A90700177D16 /* DeeplinkTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EAB4675285B5C7C002904A0 /* DeeplinkTests.swift */; };
|
||||
9E34519C29C4A91A00177D16 /* HomeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E3911382848AD500073DD9A /* HomeTests.swift */; };
|
||||
|
@ -107,7 +106,6 @@
|
|||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
0D1C1AA227611EFD0004AF6A /* RecoveryPhraseDisplayReducerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecoveryPhraseDisplayReducerTests.swift; sourceTree = "<group>"; };
|
||||
0D26AF94299E8196005260EE /* secant-mainnet.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "secant-mainnet.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
0D3B01EB298DAF89007EBCDA /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
|
||||
0D4E7A0526B364170058B01E /* secant-testnet.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "secant-testnet.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
|
@ -308,7 +306,6 @@
|
|||
0DFE93DD272C6D4B000FCCA5 /* BackupFlowTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0D1C1AA227611EFD0004AF6A /* RecoveryPhraseDisplayReducerTests.swift */,
|
||||
0DFE93DE272C6D4B000FCCA5 /* RecoveryPhraseBackupTests.swift */,
|
||||
);
|
||||
path = BackupFlowTests;
|
||||
|
@ -973,7 +970,6 @@
|
|||
9E3451AA29C84ED500177D16 /* CurrencySelectionTests.swift in Sources */,
|
||||
9E3451C529C857E400177D16 /* TransactionListSnapshotTests.swift in Sources */,
|
||||
9EEB06C62B344F1E00EEE50F /* SyncProgressTests.swift in Sources */,
|
||||
9E34519829C4A51100177D16 /* RecoveryPhraseDisplayReducerTests.swift in Sources */,
|
||||
9E34519C29C4A91A00177D16 /* HomeTests.swift in Sources */,
|
||||
9E1FAFB72AF2C6D40084CA3D /* PrivateDataConsentSnapshotTests.swift in Sources */,
|
||||
9E3451BB29C857C800177D16 /* HomeSnapshotTests.swift in Sources */,
|
||||
|
|
|
@ -1,51 +0,0 @@
|
|||
//
|
||||
// RecoveryPhraseDisplayStoreTests.swift
|
||||
// secantTests
|
||||
//
|
||||
// Created by Francisco Gindre on 12/8/21.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import ComposableArchitecture
|
||||
import Pasteboard
|
||||
import Models
|
||||
import RecoveryPhraseDisplay
|
||||
@testable import secant_testnet
|
||||
|
||||
class RecoveryPhraseDisplayTests: XCTestCase {
|
||||
@MainActor func testCopyToBuffer() async {
|
||||
let testPasteboard = PasteboardClient.testPasteboard
|
||||
|
||||
let store = TestStore(
|
||||
initialState: RecoveryPhraseDisplay.test
|
||||
) {
|
||||
RecoveryPhraseDisplay()
|
||||
}
|
||||
|
||||
store.dependencies.pasteboard = testPasteboard
|
||||
|
||||
await store.send(.copyToBufferPressed) { state in
|
||||
state.phrase = .placeholder
|
||||
state.showCopyToBufferAlert = true
|
||||
}
|
||||
|
||||
XCTAssertEqual(
|
||||
testPasteboard.getString(),
|
||||
RecoveryPhrase.placeholder.toString()
|
||||
)
|
||||
|
||||
await store.finish()
|
||||
}
|
||||
}
|
||||
|
||||
private extension RecoveryPhraseDisplay {
|
||||
static let test = RecoveryPhraseDisplay.State(
|
||||
phrase: .placeholder,
|
||||
showCopyToBufferAlert: false
|
||||
)
|
||||
|
||||
static let empty = RecoveryPhraseDisplay.State(
|
||||
phrase: .initial,
|
||||
showCopyToBufferAlert: false
|
||||
)
|
||||
}
|
Loading…
Reference in New Issue