diff --git a/app/src/main/java/cash/z/ecc/android/ext/Dialogs.kt b/app/src/main/java/cash/z/ecc/android/ext/Dialogs.kt index 27f6f84..3d8f0ef 100644 --- a/app/src/main/java/cash/z/ecc/android/ext/Dialogs.kt +++ b/app/src/main/java/cash/z/ecc/android/ext/Dialogs.kt @@ -46,6 +46,18 @@ fun Context.showUninitializedError(error: Throwable? = null, onDismiss: () -> Un .show() } +fun Context.showInvalidSeedPhraseError(error: Throwable? = null, onDismiss: () -> Unit = {}): Dialog { + return MaterialAlertDialogBuilder(this) + .setTitle("Oops! Invalid Seed Phrase") + .setMessage("That seed phrase appears to be invalid! Please double-check it and try again.\n\n${error?.message ?: ""}") + .setCancelable(false) + .setPositiveButton("Retry") { dialog, _ -> + dialog.dismiss() + onDismiss() + } + .show() +} + fun Context.showScanFailure(error: Throwable?, onCancel: () -> Unit = {}, onDismiss: () -> Unit = {}): Dialog { val message = if (error == null) { "Unknown error" diff --git a/app/src/main/java/cash/z/ecc/android/ui/setup/RestoreFragment.kt b/app/src/main/java/cash/z/ecc/android/ui/setup/RestoreFragment.kt index 389d4ad..40320e8 100644 --- a/app/src/main/java/cash/z/ecc/android/ui/setup/RestoreFragment.kt +++ b/app/src/main/java/cash/z/ecc/android/ui/setup/RestoreFragment.kt @@ -17,6 +17,7 @@ import cash.z.ecc.android.R import cash.z.ecc.android.databinding.FragmentRestoreBinding import cash.z.ecc.android.di.viewmodel.activityViewModel import cash.z.ecc.android.ext.goneIf +import cash.z.ecc.android.ext.showInvalidSeedPhraseError import cash.z.ecc.android.feedback.Report import cash.z.ecc.android.feedback.Report.Funnel.Restore import cash.z.ecc.android.feedback.Report.Tap.* @@ -118,7 +119,12 @@ class RestoreFragment : BaseFragment(), View.OnKeyListen if (birthdateString.isNullOrEmpty()) ZcashSdk.SAPLING_ACTIVATION_HEIGHT else birthdateString.toInt() }.coerceAtLeast(ZcashSdk.SAPLING_ACTIVATION_HEIGHT) - importWallet(seedPhrase, birthday) + try { + walletSetup.validatePhrase(seedPhrase) + importWallet(seedPhrase, birthday) + } catch (t: Throwable) { + mainActivity?.showInvalidSeedPhraseError(t) + } } private fun importWallet(seedPhrase: String, birthday: Int) { diff --git a/app/src/main/java/cash/z/ecc/android/ui/setup/WalletSetupViewModel.kt b/app/src/main/java/cash/z/ecc/android/ui/setup/WalletSetupViewModel.kt index 8d8a626..95c9a89 100644 --- a/app/src/main/java/cash/z/ecc/android/ui/setup/WalletSetupViewModel.kt +++ b/app/src/main/java/cash/z/ecc/android/ui/setup/WalletSetupViewModel.kt @@ -142,6 +142,13 @@ class WalletSetupViewModel @Inject constructor() : ViewModel() { } } + /** + * Throw an exception if the seed phrase is bad. + */ + fun validatePhrase(seedPhrase: String) { + mnemonics.validate(seedPhrase.toCharArray()) + } + object LockBoxKey { const val SEED = "cash.z.ecc.android.SEED" const val SEED_PHRASE = "cash.z.ecc.android.SEED_PHRASE" diff --git a/mnemonic/src/main/java/cash/z/ecc/kotlin/mnemonic/Mnemonics.kt b/mnemonic/src/main/java/cash/z/ecc/kotlin/mnemonic/Mnemonics.kt index 0ffbd86..2d8e10b 100644 --- a/mnemonic/src/main/java/cash/z/ecc/kotlin/mnemonic/Mnemonics.kt +++ b/mnemonic/src/main/java/cash/z/ecc/kotlin/mnemonic/Mnemonics.kt @@ -19,4 +19,8 @@ class Mnemonics @Inject constructor() : MnemonicPlugin { override fun nextMnemonicList(entropy: ByteArray): List = MnemonicCode(entropy).words override fun toSeed(mnemonic: CharArray): ByteArray = MnemonicCode(mnemonic).toSeed() override fun toWordList(mnemonic: CharArray): List = MnemonicCode(mnemonic).words + + fun validate(mnemonic: CharArray) { + MnemonicCode(mnemonic).validate() + } } \ No newline at end of file