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:
parent
1a7fdfa59a
commit
044ef01ba1
7 changed files with 75 additions and 24 deletions
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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" />
|
||||
|
||||
|
|
Loading…
Reference in a new issue