aboutsummaryrefslogtreecommitdiff
path: root/app/src/main/java/com/zeapo
diff options
context:
space:
mode:
authorHarsh Shandilya <msfjarvis@gmail.com>2020-06-30 19:21:49 +0530
committerGitHub <noreply@github.com>2020-06-30 19:21:49 +0530
commit5e74507d5b3f3de8a4f0881fa14f87058e9a63fc (patch)
treeccab0b45fb642074bbe6691c82a7e2f3eedc0c10 /app/src/main/java/com/zeapo
parent57f125a4da9f8bad69c2b2e2e6540d245bdd44c4 (diff)
Allow importing TOTP configuration through QR codes (#903)
Co-authored-by: Fabian Henneke <fabian@henneke.me>
Diffstat (limited to 'app/src/main/java/com/zeapo')
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/crypto/PasswordCreationActivity.kt46
1 files changed, 38 insertions, 8 deletions
diff --git a/app/src/main/java/com/zeapo/pwdstore/crypto/PasswordCreationActivity.kt b/app/src/main/java/com/zeapo/pwdstore/crypto/PasswordCreationActivity.kt
index 81a73988..a9b1219d 100644
--- a/app/src/main/java/com/zeapo/pwdstore/crypto/PasswordCreationActivity.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/crypto/PasswordCreationActivity.kt
@@ -17,6 +17,8 @@ import androidx.core.widget.doOnTextChanged
import androidx.lifecycle.lifecycleScope
import com.github.ajalt.timberkt.e
import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import com.google.zxing.integration.android.IntentIntegrator
+import com.google.zxing.integration.android.IntentIntegrator.QR_CODE
import com.zeapo.pwdstore.R
import com.zeapo.pwdstore.autofill.oreo.AutofillPreferences
import com.zeapo.pwdstore.autofill.oreo.DirectoryStructure
@@ -62,6 +64,33 @@ class PasswordCreationActivity : BasePgpActivity(), OpenPgpServiceConnection.OnB
with(binding) {
setContentView(root)
generatePassword.setOnClickListener { generatePassword() }
+ otpImportButton.setOnClickListener {
+ registerForActivityResult(StartActivityForResult()) { result ->
+ if (result.resultCode == RESULT_OK) {
+ otpImportButton.isVisible = false
+ val intentResult = IntentIntegrator.parseActivityResult(RESULT_OK, result.data)
+ val contents = if (intentResult.contents.startsWith("otpauth://")) {
+ "${intentResult.contents}\n"
+ } else {
+ "totp: ${intentResult.contents}\n"
+ }
+ val currentExtras = extraContent.text.toString()
+ if (currentExtras.isNotEmpty() && currentExtras.last() != '\n')
+ extraContent.append("\n$contents")
+ else
+ extraContent.append(contents)
+ snackbar(message = getString(R.string.otp_import_success))
+ } else {
+ snackbar(message = getString(R.string.otp_import_failure))
+ }
+ }.launch(
+ IntentIntegrator(this@PasswordCreationActivity)
+ .setOrientationLocked(false)
+ .setBeepEnabled(false)
+ .setDesiredBarcodeFormats(QR_CODE)
+ .createScanIntent()
+ )
+ }
category.apply {
if (suggestedName != null || suggestedPass != null || shouldGeneratePassword) {
@@ -95,7 +124,7 @@ class PasswordCreationActivity : BasePgpActivity(), OpenPgpServiceConnection.OnB
val username = filename.text.toString()
val extras = "username:$username\n${extraContent.text}"
- filename.setText("")
+ filename.text?.clear()
extraContent.setText(extras)
} else {
// User wants to disable username encryption, so we extract the
@@ -104,20 +133,20 @@ class PasswordCreationActivity : BasePgpActivity(), OpenPgpServiceConnection.OnB
val username = entry.username
// username should not be null here by the logic in
- // updateEncryptUsernameState, but it could still happen due to
+ // updateViewState, but it could still happen due to
// input lag.
if (username != null) {
filename.setText(username)
extraContent.setText(entry.extraContentWithoutAuthData)
}
}
- updateEncryptUsernameState()
+ updateViewState()
}
}
listOf(filename, extraContent).forEach {
- it.doOnTextChanged { _, _, _, _ -> updateEncryptUsernameState() }
+ it.doOnTextChanged { _, _, _, _ -> updateViewState() }
}
- updateEncryptUsernameState()
+ updateViewState()
}
suggestedPass?.let {
password.setText(it)
@@ -158,17 +187,18 @@ class PasswordCreationActivity : BasePgpActivity(), OpenPgpServiceConnection.OnB
}
}
- private fun updateEncryptUsernameState() = with(binding) {
+ private fun updateViewState() = with(binding) {
+ // Use PasswordEntry to parse extras for username
+ val entry = PasswordEntry("PLACEHOLDER\n${extraContent.text}")
encryptUsername.apply {
if (visibility != View.VISIBLE)
return@with
val hasUsernameInFileName = filename.text.toString().isNotBlank()
- // Use PasswordEntry to parse extras for username
- val entry = PasswordEntry("PLACEHOLDER\n${extraContent.text}")
val hasUsernameInExtras = entry.hasUsername()
isEnabled = hasUsernameInFileName xor hasUsernameInExtras
isChecked = hasUsernameInExtras
}
+ otpImportButton.isVisible = !entry.hasTotp()
}
/**