Split up validating, verifying and storing of recovery code

This commit is contained in:
Torsten Grote 2021-08-11 10:32:53 +02:00 committed by Chirayu Desai
parent 26516d72a2
commit e0f728205d
2 changed files with 38 additions and 17 deletions

View file

@ -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)
} }
} }

View file

@ -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 { */
val verified = crypto.verifyBackupKey(seed) fun verifyExistingCode(input: List<CharSequence>) {
if (verified && !keyManager.hasMainKey()) keyManager.storeMainKey(seed) // we validate the code again, just in case
mExistingCodeChecked.setEvent(verified) val seed = validateCode(input).toSeed()
} val verified = crypto.verifyBackupKey(seed)
// store main key at this opportunity if it is still missing
if (verified && !keyManager.hasMainKey()) keyManager.storeMainKey(seed)
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)
} }
/** /**