Split up validating, verifying and storing of recovery code
This commit is contained in:
parent
26516d72a2
commit
e0f728205d
2 changed files with 38 additions and 17 deletions
|
@ -30,7 +30,7 @@ import com.stevesoltys.seedvault.ui.LiveEventHandler
|
||||||
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
|
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
internal const val ARG_FOR_NEW_CODE = "forVerifyingNewCode"
|
internal const val ARG_FOR_NEW_CODE = "forStoringNewCode"
|
||||||
|
|
||||||
class RecoveryCodeInputFragment : Fragment() {
|
class RecoveryCodeInputFragment : Fragment() {
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ class RecoveryCodeInputFragment : Fragment() {
|
||||||
/**
|
/**
|
||||||
* True if this is for verifying a new recovery code, false for verifying an existing one.
|
* True if this is for verifying a new recovery code, false for verifying an existing one.
|
||||||
*/
|
*/
|
||||||
private var forVerifyingNewCode: Boolean = true
|
private var forStoringNewCode: Boolean = true
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater,
|
inflater: LayoutInflater,
|
||||||
|
@ -85,7 +85,7 @@ class RecoveryCodeInputFragment : Fragment() {
|
||||||
wordList = v.findViewById(R.id.wordList)
|
wordList = v.findViewById(R.id.wordList)
|
||||||
|
|
||||||
arguments?.getBoolean(ARG_FOR_NEW_CODE, true)?.let {
|
arguments?.getBoolean(ARG_FOR_NEW_CODE, true)?.let {
|
||||||
forVerifyingNewCode = it
|
forStoringNewCode = it
|
||||||
}
|
}
|
||||||
|
|
||||||
return v
|
return v
|
||||||
|
@ -116,14 +116,14 @@ class RecoveryCodeInputFragment : Fragment() {
|
||||||
editText.setAdapter(adapter)
|
editText.setAdapter(adapter)
|
||||||
}
|
}
|
||||||
doneButton.setOnClickListener { done() }
|
doneButton.setOnClickListener { done() }
|
||||||
newCodeButton.visibility = if (forVerifyingNewCode) GONE else VISIBLE
|
newCodeButton.visibility = if (forStoringNewCode) GONE else VISIBLE
|
||||||
newCodeButton.setOnClickListener { generateNewCode() }
|
newCodeButton.setOnClickListener { generateNewCode() }
|
||||||
|
|
||||||
viewModel.existingCodeChecked.observeEvent(viewLifecycleOwner,
|
viewModel.existingCodeChecked.observeEvent(viewLifecycleOwner,
|
||||||
LiveEventHandler { verified -> onExistingCodeChecked(verified) }
|
LiveEventHandler { verified -> onExistingCodeChecked(verified) }
|
||||||
)
|
)
|
||||||
|
|
||||||
if (forVerifyingNewCode && isDebugBuild() && !viewModel.isRestore) debugPreFill()
|
if (forStoringNewCode && isDebugBuild() && !viewModel.isRestore) debugPreFill()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getInput(): List<CharSequence> = ArrayList<String>(WORD_NUM).apply {
|
private fun getInput(): List<CharSequence> = ArrayList<String>(WORD_NUM).apply {
|
||||||
|
@ -134,11 +134,18 @@ class RecoveryCodeInputFragment : Fragment() {
|
||||||
val input = getInput()
|
val input = getInput()
|
||||||
if (!allFilledOut(input)) return
|
if (!allFilledOut(input)) return
|
||||||
try {
|
try {
|
||||||
viewModel.validateAndContinue(input, forVerifyingNewCode)
|
viewModel.validateCode(input)
|
||||||
} catch (e: ChecksumException) {
|
} catch (e: ChecksumException) {
|
||||||
Toast.makeText(context, R.string.recovery_code_error_checksum_word, LENGTH_LONG).show()
|
Toast.makeText(context, R.string.recovery_code_error_checksum_word, LENGTH_LONG).show()
|
||||||
|
return
|
||||||
} catch (e: InvalidWordException) {
|
} catch (e: InvalidWordException) {
|
||||||
showWrongWordError(input)
|
showWrongWordError(input)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (forStoringNewCode) {
|
||||||
|
viewModel.storeNewCode(input)
|
||||||
|
} else {
|
||||||
|
viewModel.verifyExistingCode(input)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -57,23 +57,37 @@ internal class RecoveryCodeViewModel(
|
||||||
internal var isRestore: Boolean = false
|
internal var isRestore: Boolean = false
|
||||||
|
|
||||||
@Throws(InvalidWordException::class, ChecksumException::class)
|
@Throws(InvalidWordException::class, ChecksumException::class)
|
||||||
fun validateAndContinue(input: List<CharSequence>, forVerifyingNewCode: Boolean) {
|
fun validateCode(input: List<CharSequence>): Mnemonics.MnemonicCode {
|
||||||
val code = Mnemonics.MnemonicCode(input.toMnemonicChars())
|
val code = Mnemonics.MnemonicCode(input.toMnemonicChars())
|
||||||
try {
|
try {
|
||||||
code.validate()
|
code.validate()
|
||||||
} catch (e: WordCountException) {
|
} catch (e: WordCountException) {
|
||||||
throw AssertionError(e)
|
throw AssertionError(e)
|
||||||
}
|
}
|
||||||
val seed = code.toSeed()
|
return code
|
||||||
if (forVerifyingNewCode) {
|
}
|
||||||
keyManager.storeBackupKey(seed)
|
|
||||||
keyManager.storeMainKey(seed)
|
/**
|
||||||
mRecoveryCodeSaved.setEvent(true)
|
* Verifies existing recovery code and returns result via [existingCodeChecked].
|
||||||
} else {
|
*/
|
||||||
|
fun verifyExistingCode(input: List<CharSequence>) {
|
||||||
|
// we validate the code again, just in case
|
||||||
|
val seed = validateCode(input).toSeed()
|
||||||
val verified = crypto.verifyBackupKey(seed)
|
val verified = crypto.verifyBackupKey(seed)
|
||||||
|
// store main key at this opportunity if it is still missing
|
||||||
if (verified && !keyManager.hasMainKey()) keyManager.storeMainKey(seed)
|
if (verified && !keyManager.hasMainKey()) keyManager.storeMainKey(seed)
|
||||||
mExistingCodeChecked.setEvent(verified)
|
mExistingCodeChecked.setEvent(verified)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores a new recovery code and returns result via [recoveryCodeSaved].
|
||||||
|
*/
|
||||||
|
fun storeNewCode(input: List<CharSequence>) {
|
||||||
|
// we validate the code again, just in case
|
||||||
|
val seed = validateCode(input).toSeed()
|
||||||
|
keyManager.storeBackupKey(seed)
|
||||||
|
keyManager.storeMainKey(seed)
|
||||||
|
mRecoveryCodeSaved.setEvent(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in a new issue