Merge pull request #2948 from dlvoy/changed-masterpwd
Add additional prompt for old master password
This commit is contained in:
commit
8271f1fc64
5 changed files with 122 additions and 20 deletions
|
@ -130,6 +130,15 @@ class ImportExportPrefs @Inject constructor(
|
|||
})
|
||||
}
|
||||
|
||||
private fun askForEncryptionPass(activity: Activity, @StringRes canceledMsg: Int, @StringRes passwordName: Int, @StringRes passwordExplanation: Int?,
|
||||
@StringRes passwordWarning: Int?, then: ((password: String) -> Unit)) {
|
||||
passwordCheck.queryAnyPassword(activity, passwordName, R.string.key_master_password, passwordExplanation, passwordWarning, { password ->
|
||||
then(password)
|
||||
}, {
|
||||
ToastUtils.warnToast(activity, resourceHelper.gs(canceledMsg))
|
||||
})
|
||||
}
|
||||
|
||||
private fun askForMasterPassIfNeeded(activity: Activity, @StringRes canceledMsg: Int, then: ((password: String) -> Unit)) {
|
||||
if (prefsEncryptionIsDisabled()) {
|
||||
then("")
|
||||
|
@ -182,6 +191,28 @@ class ImportExportPrefs @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun promptForDecryptionPasswordIfNeeded(activity: Activity, prefs: Prefs, importOk: Boolean,
|
||||
format: PrefsFormat, importFile: PrefsFile, then: ((prefs: Prefs, importOk: Boolean) -> Unit)) {
|
||||
|
||||
// current master password was not the one used for decryption, so we prompt for old password...
|
||||
if (!importOk && (prefs.metadata[PrefsMetadataKey.ENCRYPTION]?.status == PrefsStatus.ERROR)) {
|
||||
askForEncryptionPass(activity, R.string.preferences_import_canceled, R.string.old_master_password,
|
||||
R.string.different_password_used, R.string.master_password_will_be_replaced) { password ->
|
||||
|
||||
// ...and use it to load & decrypt file again
|
||||
val prefsReloaded = format.loadPreferences(importFile.file, password)
|
||||
prefsReloaded.metadata = prefFileList.checkMetadata(prefsReloaded.metadata)
|
||||
|
||||
// import is OK when we do not have errors (warnings are allowed)
|
||||
val importOkCheckedAgain = checkIfImportIsOk(prefsReloaded)
|
||||
|
||||
then(prefsReloaded, importOkCheckedAgain);
|
||||
}
|
||||
} else {
|
||||
then(prefs, importOk);
|
||||
}
|
||||
}
|
||||
|
||||
private fun exportSharedPreferences(activity: Activity) {
|
||||
|
||||
prefFileList.ensureExportDirExists()
|
||||
|
@ -258,32 +289,36 @@ class ImportExportPrefs @Inject constructor(
|
|||
|
||||
try {
|
||||
|
||||
val prefs = format.loadPreferences(importFile.file, password)
|
||||
prefs.metadata = prefFileList.checkMetadata(prefs.metadata)
|
||||
val prefsAttempted = format.loadPreferences(importFile.file, password)
|
||||
prefsAttempted.metadata = prefFileList.checkMetadata(prefsAttempted.metadata)
|
||||
|
||||
// import is OK when we do not have errors (warnings are allowed)
|
||||
val importOk = checkIfImportIsOk(prefs)
|
||||
val importOkAttempted = checkIfImportIsOk(prefsAttempted)
|
||||
|
||||
// if at end we allow to import preferences
|
||||
val importPossible = (importOk || buildHelper.isEngineeringMode()) && (prefs.values.size > 0)
|
||||
promptForDecryptionPasswordIfNeeded(activity, prefsAttempted, importOkAttempted, format, importFile) { prefs, importOk ->
|
||||
|
||||
PrefImportSummaryDialog.showSummary(activity, importOk, importPossible, prefs, {
|
||||
if (importPossible) {
|
||||
sp.clear()
|
||||
for ((key, value) in prefs.values) {
|
||||
if (value == "true" || value == "false") {
|
||||
sp.putBoolean(key, value.toBoolean())
|
||||
} else {
|
||||
sp.putString(key, value)
|
||||
// if at end we allow to import preferences
|
||||
val importPossible = (importOk || buildHelper.isEngineeringMode()) && (prefs.values.size > 0)
|
||||
|
||||
PrefImportSummaryDialog.showSummary(activity, importOk, importPossible, prefs, {
|
||||
if (importPossible) {
|
||||
sp.clear()
|
||||
for ((key, value) in prefs.values) {
|
||||
if (value == "true" || value == "false") {
|
||||
sp.putBoolean(key, value.toBoolean())
|
||||
} else {
|
||||
sp.putString(key, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
restartAppAfterImport(activity)
|
||||
} else {
|
||||
// for impossible imports it should not be called
|
||||
ToastUtils.errorToast(activity, resourceHelper.gs(R.string.preferences_import_impossible))
|
||||
}
|
||||
})
|
||||
restartAppAfterImport(activity)
|
||||
} else {
|
||||
// for impossible imports it should not be called
|
||||
ToastUtils.errorToast(activity, resourceHelper.gs(R.string.preferences_import_impossible))
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
} catch (e: PrefFileNotFoundError) {
|
||||
ToastUtils.errorToast(activity, resourceHelper.gs(R.string.filenotfound) + " " + importFile)
|
||||
|
|
|
@ -208,6 +208,9 @@
|
|||
<string name="preferences_import_canceled">Import canceled! Preferences were NOT imported!</string>
|
||||
<string name="preferences_import_impossible">Cannot import preferences!</string>
|
||||
<string name="goto_main_try_again">Please go back to main screen and try again.</string>
|
||||
<string name="old_master_password">Old Master Password</string>
|
||||
<string name="different_password_used">This file was exported and encrypted with different master password. Provide old master password to decrypt file.</string>
|
||||
<string name="master_password_will_be_replaced">As a result of successful import current master password WILL BE REPLACED with that old master password!</string>
|
||||
|
||||
<string name="preferences_import_list_title">Select file to import</string>
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ import android.os.Build
|
|||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.widget.EditText
|
||||
import android.widget.TextView
|
||||
import androidx.annotation.StringRes
|
||||
import info.nightscout.androidaps.core.R
|
||||
import info.nightscout.androidaps.utils.CryptoUtil
|
||||
|
@ -24,6 +25,9 @@ class PasswordCheck @Inject constructor(
|
|||
private val cryptoUtil: CryptoUtil
|
||||
) {
|
||||
|
||||
/**
|
||||
Asks for "managed" kind of password, checking if it is valid.
|
||||
*/
|
||||
@SuppressLint("InflateParams")
|
||||
fun queryPassword(context: Context, @StringRes labelId: Int, @StringRes preference: Int, ok: ((String) -> Unit)?, cancel: (() -> Unit)? = null, fail: (() -> Unit)? = null) {
|
||||
val password = sp.getString(preference, "")
|
||||
|
@ -115,4 +119,51 @@ class PasswordCheck @Inject constructor(
|
|||
|
||||
alertDialogBuilder.create().show()
|
||||
}
|
||||
|
||||
/**
|
||||
Prompt free-form password, with additional help and warning messages.
|
||||
Preference ID (preference) is used only to generate ID for password managers,
|
||||
since this query does NOT check validity of password.
|
||||
*/
|
||||
@SuppressLint("InflateParams")
|
||||
fun queryAnyPassword(context: Context, @StringRes labelId: Int, @StringRes preference: Int, @StringRes passwordExplanation: Int?,
|
||||
@StringRes passwordWarning: Int?, ok: ((String) -> Unit)?, cancel: (() -> Unit)? = null) {
|
||||
|
||||
val promptsView = LayoutInflater.from(context).inflate(R.layout.passwordprompt, null)
|
||||
val alertDialogBuilder = AlertDialogHelper.Builder(context)
|
||||
alertDialogBuilder.setView(promptsView)
|
||||
passwordExplanation?.let { alertDialogBuilder.setMessage(it) }
|
||||
|
||||
passwordWarning?.let {
|
||||
val extraWarning: TextView = promptsView.findViewById<View>(R.id.password_prompt_extra_message) as TextView;
|
||||
extraWarning.text = context.getString(it);
|
||||
extraWarning.visibility = View.VISIBLE;
|
||||
}
|
||||
|
||||
val userInput = promptsView.findViewById<View>(R.id.password_prompt_pass) as EditText
|
||||
val userInput2 = promptsView.findViewById<View>(R.id.password_prompt_pass_confirm) as EditText
|
||||
|
||||
userInput2.visibility = View.GONE
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val autoFillHintPasswordKind = context.getString(preference)
|
||||
userInput.setAutofillHints(View.AUTOFILL_HINT_PASSWORD, "aaps_${autoFillHintPasswordKind}")
|
||||
userInput.importantForAutofill = View.IMPORTANT_FOR_AUTOFILL_YES
|
||||
}
|
||||
|
||||
alertDialogBuilder
|
||||
.setCancelable(false)
|
||||
.setCustomTitle(AlertDialogHelper.buildCustomTitle(context, context.getString(labelId), R.drawable.ic_header_key))
|
||||
.setPositiveButton(context.getString(R.string.ok)) { _, _ ->
|
||||
val enteredPassword = userInput.text.toString()
|
||||
ok?.invoke(enteredPassword)
|
||||
}
|
||||
.setNegativeButton(context.getString(R.string.cancel)
|
||||
) { dialog, _ ->
|
||||
cancel?.invoke()
|
||||
dialog.cancel()
|
||||
}
|
||||
|
||||
alertDialogBuilder.create().show()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,18 @@
|
|||
android:orientation="vertical"
|
||||
android:padding="10dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/password_prompt_extra_message"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:paddingStart="10dp"
|
||||
android:paddingEnd="10dp"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:textColor="@color/warningAccentText"
|
||||
android:visibility="gone"
|
||||
/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/password_prompt_pass"
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
<color name="dialog_title_icon_tint">#FFFFFF</color>
|
||||
<color name="warningAlertBackground">#FFFB8C00</color>
|
||||
<color name="warningAlertHeaderText">#FF000000</color>
|
||||
<color name="warningAccentText">#FFFB8C00</color>
|
||||
<color name="errorAlertBackground">#FFFF5555</color>
|
||||
<color name="errorAlertHeaderText">#FF000000</color>
|
||||
<color name="examinedProfile">#FFFF5555</color>
|
||||
|
|
Loading…
Reference in a new issue