diff --git a/Decred Wallet/Features/App Launch/StartScreenViewController.swift b/Decred Wallet/Features/App Launch/StartScreenViewController.swift index 71292d47e..4d2783ec1 100644 --- a/Decred Wallet/Features/App Launch/StartScreenViewController.swift +++ b/Decred Wallet/Features/App Launch/StartScreenViewController.swift @@ -255,7 +255,7 @@ class StartScreenViewController: UIViewController, CAAnimationDelegate { } catch let error { DispatchQueue.main.async { if error.isInvalidPassphraseError { - dialogDelegate?.displayError(errorMessage: StartupPinOrPassword.invalidSecurityCodeMessage()) + dialogDelegate?.displayPassphraseError(errorMessage: StartupPinOrPassword.invalidSecurityCodeMessage()) } else { dialogDelegate?.displayError(errorMessage: error.localizedDescription) } diff --git a/Decred Wallet/Features/Custom Dialogs/SimpleTextInputDialog.swift b/Decred Wallet/Features/Custom Dialogs/SimpleTextInputDialog.swift index bd63d14f9..5ac8c55b7 100644 --- a/Decred Wallet/Features/Custom Dialogs/SimpleTextInputDialog.swift +++ b/Decred Wallet/Features/Custom Dialogs/SimpleTextInputDialog.swift @@ -13,6 +13,13 @@ typealias SimpleTextInputDialogCallback = (_ userInput: String, _ dialogDelegate protocol InputDialogDelegate { func dismissDialog() func displayError(errorMessage: String) + func displayPassphraseError(errorMessage: String) +} + +extension InputDialogDelegate { + func displayPassphraseError(errorMessage: String) { + + } } class SimpleTextInputDialog: UIViewController { diff --git a/Decred Wallet/Features/More/More Features/Security Tools/Sign Message/SignMessageViewController.swift b/Decred Wallet/Features/More/More Features/Security Tools/Sign Message/SignMessageViewController.swift index f34351d4e..3f26f5b57 100644 --- a/Decred Wallet/Features/More/More Features/Security Tools/Sign Message/SignMessageViewController.swift +++ b/Decred Wallet/Features/More/More Features/Security Tools/Sign Message/SignMessageViewController.swift @@ -180,7 +180,7 @@ class SignMessageViewController: UIViewController, FloatingPlaceholderTextViewDe } else if error!.isInvalidPassphraseError { let errorMessage = SpendingPinOrPassword.invalidSecurityCodeMessage(for: self.wallet.id_) - dialogDelegate?.displayError(errorMessage: errorMessage) + dialogDelegate?.displayPassphraseError(errorMessage: errorMessage) } else { print("sign error:", error!.localizedDescription) dialogDelegate?.dismissDialog() diff --git a/Decred Wallet/Features/More/More Features/Settings/SettingsController.swift b/Decred Wallet/Features/More/More Features/Settings/SettingsController.swift index a0258dc8e..3dd3aa715 100644 --- a/Decred Wallet/Features/More/More Features/Settings/SettingsController.swift +++ b/Decred Wallet/Features/More/More Features/Settings/SettingsController.swift @@ -281,7 +281,7 @@ class SettingsController: UITableViewController { } catch let error { DispatchQueue.main.async { if error.isInvalidPassphraseError { - dialogDelegate?.displayError(errorMessage: StartupPinOrPassword.invalidSecurityCodeMessage()) + dialogDelegate?.displayPassphraseError(errorMessage: StartupPinOrPassword.invalidSecurityCodeMessage()) } else { dialogDelegate?.displayError(errorMessage: error.localizedDescription) } diff --git a/Decred Wallet/Features/Security/RequestPasswordViewController.swift b/Decred Wallet/Features/Security/RequestPasswordViewController.swift index 6470fa5a1..860faedf8 100644 --- a/Decred Wallet/Features/Security/RequestPasswordViewController.swift +++ b/Decred Wallet/Features/Security/RequestPasswordViewController.swift @@ -24,6 +24,8 @@ class RequestPasswordViewController: SecurityCodeRequestBaseViewController, UITe @IBOutlet weak var btnSubmit: Button! var dissmisSenderOnCancel = false + + var passwordTrials = 0 override func viewDidLoad() { super.viewDidLoad() @@ -200,9 +202,37 @@ class RequestPasswordViewController: SecurityCodeRequestBaseViewController, UITe return true } + override func showPassphraseError(text: String) { + passwordTrials = passwordTrials + 1 + + _showError(text: text) + self.passwordInput.isEnabled = false + self.btnSubmit.isEnabled = false + + DispatchQueue.global(qos: .userInitiated).async { + var delay = 2.0 + if (self.passwordTrials % 2 == 0) { + delay = 5.0 + } + + let delayTime = DispatchTime.now() + delay + DispatchQueue.main.asyncAfter(deadline: delayTime) { + self.passwordInput.text = "" + self.hideError() + self.passwordInput.isEnabled = true + self.passwordInput.becomeFirstResponder() + } + + } + } + override func showError(text: String) { super.showError(text: text) + _showError(text: text) + } + + func _showError(text: String) { self.passwordErrorLabel.text = text self.passwordErrorLabel.isHidden = false diff --git a/Decred Wallet/Features/Security/RequestPinViewController.swift b/Decred Wallet/Features/Security/RequestPinViewController.swift index 20434df19..85e7a70f1 100644 --- a/Decred Wallet/Features/Security/RequestPinViewController.swift +++ b/Decred Wallet/Features/Security/RequestPinViewController.swift @@ -34,6 +34,8 @@ class RequestPinViewController: SecurityCodeRequestBaseViewController { textfield.textContentType = .password return textfield }() + + var pinTrials = 0 override func viewDidLoad() { super.viewDidLoad() @@ -218,10 +220,38 @@ class RequestPinViewController: SecurityCodeRequestBaseViewController { self.dismissView() } } + + override func showPassphraseError(text: String) { + pinTrials = pinTrials + 1 + + _showError(text: text) + self.pinHiddenInput.isEnabled = false + self.btnSubmit.isEnabled = false + + DispatchQueue.global(qos: .userInitiated).async { + + var delay = 2.0 + if (self.pinTrials % 2 == 0) { + delay = 5.0 + } + + let delayTime = DispatchTime.now() + delay + DispatchQueue.main.asyncAfter(deadline: delayTime) { + self.pinHiddenInput.text = "" + self.hideError() + self.pinHiddenInput.isEnabled = true + self.pinHiddenInput.becomeFirstResponder() + } + } + } override func showError(text: String) { super.showError(text: text) + _showError(text: text) + } + + private func _showError(text: String){ self.errorLabel.text = text self.errorLabel.isHidden = false diff --git a/Decred Wallet/Features/Security/SecurityCodeRequestBaseViewController.swift b/Decred Wallet/Features/Security/SecurityCodeRequestBaseViewController.swift index f11a3e658..ddb62120a 100644 --- a/Decred Wallet/Features/Security/SecurityCodeRequestBaseViewController.swift +++ b/Decred Wallet/Features/Security/SecurityCodeRequestBaseViewController.swift @@ -50,6 +50,9 @@ class SecurityCodeRequestBaseViewController: UIViewController { func hideError() { self.isInErrorState = false } + + func showPassphraseError(text: String) { + } } extension SecurityCodeRequestBaseViewController: InputDialogDelegate { @@ -60,6 +63,10 @@ extension SecurityCodeRequestBaseViewController: InputDialogDelegate { func displayError(errorMessage: String) { self.showError(text: errorMessage) } + + func displayPassphraseError(errorMessage: String) { + self.showPassphraseError(text: errorMessage) + } } extension SecurityCodeRequestBaseViewController: KeyboardVisibilityDelegate { diff --git a/Decred Wallet/Features/Seed Backup/SeedBackupVerifyViewController.swift b/Decred Wallet/Features/Seed Backup/SeedBackupVerifyViewController.swift index b140f169c..655dcf6cb 100644 --- a/Decred Wallet/Features/Seed Backup/SeedBackupVerifyViewController.swift +++ b/Decred Wallet/Features/Seed Backup/SeedBackupVerifyViewController.swift @@ -87,9 +87,8 @@ class SeedBackupVerifyViewController: UIViewController { } catch { DispatchQueue.main.async { if error.isInvalidPassphraseError { - print(error.localizedDescription) let errorMessage = SpendingPinOrPassword.invalidSecurityCodeMessage(for: self.walletID) - dialogDelegate?.displayError(errorMessage: errorMessage) + dialogDelegate?.displayPassphraseError(errorMessage: errorMessage) self.groupedSeedWordsTableView?.isUserInteractionEnabled = true } else if error.localizedDescription == DcrlibwalletErrInvalid { self.groupedSeedWordsTableView?.isUserInteractionEnabled = true diff --git a/Decred Wallet/Features/Seed Backup/SeedWordsDisplayViewController.swift b/Decred Wallet/Features/Seed Backup/SeedWordsDisplayViewController.swift index 875f9d388..66295ca1c 100644 --- a/Decred Wallet/Features/Seed Backup/SeedWordsDisplayViewController.swift +++ b/Decred Wallet/Features/Seed Backup/SeedWordsDisplayViewController.swift @@ -66,15 +66,20 @@ class SeedWordsDisplayViewController: UIViewController { .with(submitBtnText: LocalizedStrings.confirm) .should(showCancelButton: true) .requestCurrentCode(sender: self, dismissSenderOnCancel: true) { privatePass, _, dialogDelegate in - var errorOrNil: NSError? = nil - if let decryptedSeed = WalletLoader.shared.multiWallet.wallet(withID: self.walletID)?.decryptSeed(privatePass.utf8Bits, error: &errorOrNil) { - if errorOrNil == nil { + var error: NSError? = nil + if let decryptedSeed = WalletLoader.shared.multiWallet.wallet(withID: self.walletID)?.decryptSeed(privatePass.utf8Bits, error: &error) { + if error == nil { self.seed = decryptedSeed dialogDelegate?.dismissDialog() self.displaySeed() } else { - let errorMessage = SpendingPinOrPassword.invalidSecurityCodeMessage(for: self.walletID) - dialogDelegate?.displayError(errorMessage: errorMessage) + if error!.isInvalidPassphraseError { + let errorMessage = SpendingPinOrPassword.invalidSecurityCodeMessage(for: self.walletID) + dialogDelegate?.displayPassphraseError(errorMessage: errorMessage) + }else { + dialogDelegate?.displayError(errorMessage: error!.localizedDescription) + } + } } } diff --git a/Decred Wallet/Features/Send/ConfirmToSendFundViewController.swift b/Decred Wallet/Features/Send/ConfirmToSendFundViewController.swift index e564dfe2f..2e8b217d9 100644 --- a/Decred Wallet/Features/Send/ConfirmToSendFundViewController.swift +++ b/Decred Wallet/Features/Send/ConfirmToSendFundViewController.swift @@ -140,7 +140,7 @@ class ConfirmToSendFundViewController: UIViewController, UITextFieldDelegate { self.onSendCompleted?() } else if error!.isInvalidPassphraseError { let errorMessage = SpendingPinOrPassword.invalidSecurityCodeMessage(for: self.sourceWalletID) - dialogDelegate?.displayError(errorMessage: errorMessage) + dialogDelegate?.displayPassphraseError(errorMessage: errorMessage) } else { print("send error:", error!.localizedDescription) dialogDelegate?.dismissDialog() diff --git a/Decred Wallet/Features/Wallets/WalletSettingsViewController.swift b/Decred Wallet/Features/Wallets/WalletSettingsViewController.swift index 6234fdbd2..3faa18fef 100644 --- a/Decred Wallet/Features/Wallets/WalletSettingsViewController.swift +++ b/Decred Wallet/Features/Wallets/WalletSettingsViewController.swift @@ -108,11 +108,13 @@ class WalletSettingsViewController: UIViewController { } } catch let error { DispatchQueue.main.async { - var errorMessage = error.localizedDescription if error.isInvalidPassphraseError { - errorMessage = SpendingPinOrPassword.invalidSecurityCodeMessage(for: self.wallet.id_) + let errorMessage = SpendingPinOrPassword.invalidSecurityCodeMessage(for: self.wallet.id_) + dialogDelegate?.displayPassphraseError(errorMessage: errorMessage) + } else { + dialogDelegate?.displayError(errorMessage: error.localizedDescription) } - dialogDelegate?.displayError(errorMessage: errorMessage) + } } } @@ -132,11 +134,13 @@ class WalletSettingsViewController: UIViewController { } } catch let error { DispatchQueue.main.async { - var errorMessage = error.localizedDescription if error.isInvalidPassphraseError { - errorMessage = SpendingPinOrPassword.invalidSecurityCodeMessage(for: self.wallet.id_) + let errorMessage = SpendingPinOrPassword.invalidSecurityCodeMessage(for: self.wallet.id_) + dialogDelegate?.displayPassphraseError(errorMessage: errorMessage) + } else { + dialogDelegate?.displayError(errorMessage: error.localizedDescription) } - dialogDelegate?.displayError(errorMessage: errorMessage) + } } } diff --git a/Decred Wallet/Features/Wallets/WalletsViewController.swift b/Decred Wallet/Features/Wallets/WalletsViewController.swift index ac87498a4..56965519b 100644 --- a/Decred Wallet/Features/Wallets/WalletsViewController.swift +++ b/Decred Wallet/Features/Wallets/WalletsViewController.swift @@ -107,7 +107,7 @@ class WalletsViewController: UIViewController { onVerifiedSuccess() } catch let error { if error.isInvalidPassphraseError { - completion?.displayError(errorMessage: StartupPinOrPassword.invalidSecurityCodeMessage()) + completion?.displayPassphraseError(errorMessage: StartupPinOrPassword.invalidSecurityCodeMessage()) } else { completion?.displayError(errorMessage: error.localizedDescription) } @@ -335,7 +335,12 @@ extension WalletsViewController: WalletInfoTableViewCellDelegate { } } catch { DispatchQueue.main.async { - completion?.displayError(errorMessage: error.localizedDescription) + if error.isInvalidPassphraseError { + let errorMessage = SpendingPinOrPassword.invalidSecurityCodeMessage(for: wallet.id) + completion?.displayPassphraseError(errorMessage: errorMessage) + } else { + completion?.displayError(errorMessage: error.localizedDescription) + } } } } diff --git a/Decred Wallet/Wallet Utils/SingleToMultiWalletMigration.swift b/Decred Wallet/Wallet Utils/SingleToMultiWalletMigration.swift index 29101d086..a9ed671af 100644 --- a/Decred Wallet/Wallet Utils/SingleToMultiWalletMigration.swift +++ b/Decred Wallet/Wallet Utils/SingleToMultiWalletMigration.swift @@ -85,7 +85,7 @@ class SingleToMultiWalletMigration { DispatchQueue.main.async { if error.isInvalidPassphraseError { - dialogDelegate?.displayError(errorMessage: StartupPinOrPassword.invalidSecurityCodeMessage()) + dialogDelegate?.displayPassphraseError(errorMessage: StartupPinOrPassword.invalidSecurityCodeMessage()) } else { dialogDelegate?.displayError(errorMessage: error.localizedDescription) } diff --git a/Decred Wallet/Wallet Utils/SpendingPinOrPassword.swift b/Decred Wallet/Wallet Utils/SpendingPinOrPassword.swift index 34821661e..00fad6f75 100644 --- a/Decred Wallet/Wallet Utils/SpendingPinOrPassword.swift +++ b/Decred Wallet/Wallet Utils/SpendingPinOrPassword.swift @@ -51,7 +51,7 @@ struct SpendingPinOrPassword { DispatchQueue.main.async { if error.isInvalidPassphraseError { newCodeRequestDelegate?.dismissDialog() - currentCodeRequestDelegate?.displayError(errorMessage: self.invalidSecurityCodeMessage(for: walletID)) + currentCodeRequestDelegate?.displayPassphraseError(errorMessage: self.invalidSecurityCodeMessage(for: walletID)) } else { newCodeRequestDelegate?.displayError(errorMessage: error.localizedDescription) } diff --git a/Decred Wallet/Wallet Utils/StartupPinOrPassword.swift b/Decred Wallet/Wallet Utils/StartupPinOrPassword.swift index 2cebb4604..a64d7490b 100644 --- a/Decred Wallet/Wallet Utils/StartupPinOrPassword.swift +++ b/Decred Wallet/Wallet Utils/StartupPinOrPassword.swift @@ -98,7 +98,7 @@ struct StartupPinOrPassword { DispatchQueue.main.async { if error.isInvalidPassphraseError { newCodeRequestDelegate?.dismissDialog() - currentCodeRequestDelegate?.displayError(errorMessage: self.invalidSecurityCodeMessage()) + currentCodeRequestDelegate?.displayPassphraseError(errorMessage: self.invalidSecurityCodeMessage()) } else { newCodeRequestDelegate?.displayError(errorMessage: error.localizedDescription) } diff --git a/Decred Wallet/Wallet Utils/SyncManager.swift b/Decred Wallet/Wallet Utils/SyncManager.swift index 5ec9138ff..e5ce12c80 100644 --- a/Decred Wallet/Wallet Utils/SyncManager.swift +++ b/Decred Wallet/Wallet Utils/SyncManager.swift @@ -100,13 +100,14 @@ class SyncManager: NSObject { waitGroup.leave() } } catch let error { - var errorMessage = error.localizedDescription - if error.isInvalidPassphraseError { - errorMessage = SpendingPinOrPassword.invalidSecurityCodeMessage(for: wallet) - } DispatchQueue.main.async { - dialogDelegate?.displayError(errorMessage: errorMessage) + if error.isInvalidPassphraseError { + let errorMessage = SpendingPinOrPassword.invalidSecurityCodeMessage(for: wallet) + dialogDelegate?.displayPassphraseError(errorMessage: errorMessage) + } else { + dialogDelegate?.displayError(errorMessage: error.localizedDescription) + } } } }