Do not generate new 12-word code when restoring

Also allow auto-completion when entering the 12-word code.
This makes testing and entering the code easier
and does not compromise security as the word list is public anyway.
This commit is contained in:
Torsten Grote 2019-09-06 13:32:49 -03:00
parent 1a7fdfa59a
commit 044ef01ba1
No known key found for this signature in database
GPG key ID: 3E5F77D92CF891FF
7 changed files with 75 additions and 24 deletions

View file

@ -15,6 +15,8 @@ class RestoreActivity : BackupActivity() {
override fun getInitialFragment() = RestoreSetFragment()
override fun isRestoreOperation() = true
override fun onCreate(savedInstanceState: Bundle?) {
viewModel = ViewModelProviders.of(this).get(RestoreViewModel::class.java)
super.onCreate(savedInstanceState)

View file

@ -14,6 +14,8 @@ class SettingsActivity : BackupActivity() {
override fun getInitialFragment() = SettingsFragment()
override fun isRestoreOperation() = false
override fun onCreate(savedInstanceState: Bundle?) {
viewModel = ViewModelProviders.of(this).get(SettingsViewModel::class.java)
super.onCreate(savedInstanceState)

View file

@ -27,6 +27,8 @@ abstract class BackupActivity : AppCompatActivity() {
protected abstract fun getInitialFragment(): Fragment
protected abstract fun isRestoreOperation(): Boolean
@CallSuper
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -80,6 +82,7 @@ abstract class BackupActivity : AppCompatActivity() {
private fun showRecoveryCodeActivity() {
val intent = Intent(this, RecoveryCodeActivity::class.java)
intent.putExtra(INTENT_EXTRA_IS_RESTORE, isRestoreOperation())
startActivityForResult(intent, REQUEST_CODE_RECOVERY_CODE)
}

View file

@ -6,6 +6,8 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.ViewModelProviders
import com.stevesoltys.backup.R
internal const val INTENT_EXTRA_IS_RESTORE = "isRestore"
class RecoveryCodeActivity : AppCompatActivity() {
private lateinit var viewModel: RecoveryCodeViewModel
@ -16,14 +18,9 @@ class RecoveryCodeActivity : AppCompatActivity() {
setContentView(R.layout.activity_recovery_code)
viewModel = ViewModelProviders.of(this).get(RecoveryCodeViewModel::class.java)
viewModel.isRestore = isRestore()
viewModel.confirmButtonClicked.observeEvent(this, LiveEventHandler { clicked ->
if (clicked) {
val tag = "Confirm"
supportFragmentManager.beginTransaction()
.replace(R.id.fragment, RecoveryCodeInputFragment(), tag)
.addToBackStack(tag)
.commit()
}
if (clicked) showInput(true)
})
viewModel.recoveryCodeSaved.observeEvent(this, LiveEventHandler { saved ->
if (saved) {
@ -35,9 +32,8 @@ class RecoveryCodeActivity : AppCompatActivity() {
supportActionBar!!.setDisplayHomeAsUpEnabled(true)
if (savedInstanceState == null) {
supportFragmentManager.beginTransaction()
.add(R.id.fragment, RecoveryCodeOutputFragment(), "Code")
.commit()
if (viewModel.isRestore) showInput(false)
else showOutput()
}
}
@ -51,4 +47,22 @@ class RecoveryCodeActivity : AppCompatActivity() {
}
}
private fun showOutput() {
supportFragmentManager.beginTransaction()
.add(R.id.fragment, RecoveryCodeOutputFragment(), "Code")
.commit()
}
private fun showInput(addToBackStack: Boolean) {
val tag = "Confirm"
val fragmentTransaction = supportFragmentManager.beginTransaction()
.replace(R.id.fragment, RecoveryCodeInputFragment(), tag)
if (addToBackStack) fragmentTransaction.addToBackStack(tag)
fragmentTransaction.commit()
}
private fun isRestore(): Boolean {
return intent?.getBooleanExtra(INTENT_EXTRA_IS_RESTORE, false) ?: false
}
}

View file

@ -5,6 +5,8 @@ import android.view.LayoutInflater
import android.view.View
import android.view.View.OnFocusChangeListener
import android.view.ViewGroup
import android.widget.ArrayAdapter
import android.widget.AutoCompleteTextView
import android.widget.Toast
import android.widget.Toast.LENGTH_LONG
import androidx.fragment.app.Fragment
@ -13,6 +15,7 @@ import com.stevesoltys.backup.R
import com.stevesoltys.backup.isDebugBuild
import io.github.novacrypto.bip39.Validation.InvalidChecksumException
import io.github.novacrypto.bip39.Validation.WordNotFoundException
import io.github.novacrypto.bip39.wordlists.English
import kotlinx.android.synthetic.main.fragment_recovery_code_input.*
import kotlinx.android.synthetic.main.recovery_code_input.*
@ -29,15 +32,27 @@ class RecoveryCodeInputFragment : Fragment() {
super.onActivityCreated(savedInstanceState)
viewModel = ViewModelProviders.of(requireActivity()).get(RecoveryCodeViewModel::class.java)
val adapter = getAdapter()
for (i in 0 until WORD_NUM) {
val wordLayout = getWordLayout(i)
wordLayout.editText!!.onFocusChangeListener = OnFocusChangeListener { _, focus ->
val editText = wordLayout.editText as AutoCompleteTextView
editText.onFocusChangeListener = OnFocusChangeListener { _, focus ->
if (!focus) wordLayout.isErrorEnabled = false
}
editText.setAdapter(adapter)
}
doneButton.setOnClickListener { done() }
if (isDebugBuild()) debugPreFill()
if (isDebugBuild() && !viewModel.isRestore) debugPreFill()
}
private fun getAdapter(): ArrayAdapter<String> {
val adapter = ArrayAdapter<String>(requireContext(), android.R.layout.simple_list_item_1)
for (i in 0 until WORD_LIST_SIZE) {
adapter.add(English.INSTANCE.getWord(i))
}
return adapter
}
private fun getInput(): List<CharSequence> = ArrayList<String>(WORD_NUM).apply {

View file

@ -13,6 +13,7 @@ import java.security.SecureRandom
import java.util.*
internal const val WORD_NUM = 12
internal const val WORD_LIST_SIZE = 2048
class RecoveryCodeViewModel(application: Application) : AndroidViewModel(application) {
@ -33,6 +34,8 @@ class RecoveryCodeViewModel(application: Application) : AndroidViewModel(applica
private val mRecoveryCodeSaved = MutableLiveEvent<Boolean>()
internal val recoveryCodeSaved: LiveEvent<Boolean> = mRecoveryCodeSaved
internal var isRestore: Boolean = false
@Throws(WordNotFoundException::class, InvalidChecksumException::class)
fun validateAndContinue(input: List<CharSequence>) {
try {

View file

@ -19,10 +19,11 @@
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="spread_inside">
<com.google.android.material.textfield.TextInputEditText
<androidx.appcompat.widget.AppCompatAutoCompleteTextView
android:id="@+id/wordInput1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:completionThreshold="1"
android:imeOptions="actionNext|flagNavigateNext|flagNoPersonalizedLearning"
android:inputType="textAutoComplete"
android:nextFocusForward="@+id/wordInput2" />
@ -40,10 +41,11 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/wordLayout1">
<com.google.android.material.textfield.TextInputEditText
<androidx.appcompat.widget.AppCompatAutoCompleteTextView
android:id="@+id/wordInput2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:completionThreshold="1"
android:imeOptions="actionNext|flagNavigateNext|flagNoPersonalizedLearning"
android:inputType="textAutoComplete"
android:nextFocusForward="@+id/wordInput3" />
@ -61,10 +63,11 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/wordLayout2">
<com.google.android.material.textfield.TextInputEditText
<androidx.appcompat.widget.AppCompatAutoCompleteTextView
android:id="@+id/wordInput3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:completionThreshold="1"
android:imeOptions="actionNext|flagNavigateNext|flagNoPersonalizedLearning"
android:inputType="textAutoComplete"
android:nextFocusForward="@+id/wordInput4" />
@ -82,10 +85,11 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/wordLayout3">
<com.google.android.material.textfield.TextInputEditText
<androidx.appcompat.widget.AppCompatAutoCompleteTextView
android:id="@+id/wordInput4"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:completionThreshold="1"
android:imeOptions="actionNext|flagNavigateNext|flagNoPersonalizedLearning"
android:inputType="textAutoComplete"
android:nextFocusForward="@+id/wordInput5" />
@ -103,10 +107,11 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/wordLayout4">
<com.google.android.material.textfield.TextInputEditText
<androidx.appcompat.widget.AppCompatAutoCompleteTextView
android:id="@+id/wordInput5"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:completionThreshold="1"
android:imeOptions="actionNext|flagNavigateNext|flagNoPersonalizedLearning"
android:inputType="textAutoComplete"
android:nextFocusForward="@+id/wordInput6" />
@ -124,10 +129,11 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/wordLayout5">
<com.google.android.material.textfield.TextInputEditText
<androidx.appcompat.widget.AppCompatAutoCompleteTextView
android:id="@+id/wordInput6"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:completionThreshold="1"
android:imeOptions="actionNext|flagNavigateNext|flagNoPersonalizedLearning"
android:inputType="textAutoComplete"
android:nextFocusForward="@+id/wordInput7" />
@ -146,10 +152,11 @@
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="spread_inside">
<com.google.android.material.textfield.TextInputEditText
<androidx.appcompat.widget.AppCompatAutoCompleteTextView
android:id="@+id/wordInput7"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:completionThreshold="1"
android:imeOptions="actionNext|flagNavigateNext|flagNoPersonalizedLearning"
android:inputType="textAutoComplete"
android:nextFocusForward="@+id/wordInput8" />
@ -167,10 +174,11 @@
app:layout_constraintStart_toEndOf="@+id/wordLayout1"
app:layout_constraintTop_toBottomOf="@+id/wordLayout7">
<com.google.android.material.textfield.TextInputEditText
<androidx.appcompat.widget.AppCompatAutoCompleteTextView
android:id="@+id/wordInput8"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:completionThreshold="1"
android:imeOptions="actionNext|flagNavigateNext|flagNoPersonalizedLearning"
android:inputType="textAutoComplete"
android:nextFocusForward="@+id/wordInput9" />
@ -188,10 +196,11 @@
app:layout_constraintStart_toEndOf="@+id/wordLayout1"
app:layout_constraintTop_toBottomOf="@+id/wordLayout8">
<com.google.android.material.textfield.TextInputEditText
<androidx.appcompat.widget.AppCompatAutoCompleteTextView
android:id="@+id/wordInput9"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:completionThreshold="1"
android:imeOptions="actionNext|flagNavigateNext|flagNoPersonalizedLearning"
android:inputType="textAutoComplete"
android:nextFocusForward="@+id/wordInput10" />
@ -209,10 +218,11 @@
app:layout_constraintStart_toEndOf="@+id/wordLayout1"
app:layout_constraintTop_toBottomOf="@+id/wordLayout9">
<com.google.android.material.textfield.TextInputEditText
<androidx.appcompat.widget.AppCompatAutoCompleteTextView
android:id="@+id/wordInput10"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:completionThreshold="1"
android:imeOptions="actionNext|flagNavigateNext|flagNoPersonalizedLearning"
android:inputType="textAutoComplete"
android:nextFocusForward="@+id/wordInput11" />
@ -230,10 +240,11 @@
app:layout_constraintStart_toEndOf="@+id/wordLayout1"
app:layout_constraintTop_toBottomOf="@+id/wordLayout10">
<com.google.android.material.textfield.TextInputEditText
<androidx.appcompat.widget.AppCompatAutoCompleteTextView
android:id="@+id/wordInput11"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:completionThreshold="1"
android:imeOptions="actionNext|flagNavigateNext|flagNoPersonalizedLearning"
android:inputType="textAutoComplete"
android:nextFocusForward="@+id/wordInput12" />
@ -251,10 +262,11 @@
app:layout_constraintStart_toEndOf="@+id/wordLayout1"
app:layout_constraintTop_toBottomOf="@+id/wordLayout11">
<com.google.android.material.textfield.TextInputEditText
<androidx.appcompat.widget.AppCompatAutoCompleteTextView
android:id="@+id/wordInput12"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:completionThreshold="1"
android:imeOptions="actionDone|flagNoPersonalizedLearning"
android:inputType="textAutoComplete" />