aboutsummaryrefslogtreecommitdiffstats
path: root/app/src/main/java/com/zeapo/pwdstore/crypto/PgpActivity.kt
diff options
context:
space:
mode:
authorFabian Henneke <FabianHenneke@users.noreply.github.com>2020-03-24 14:03:40 +0100
committerGitHub <noreply@github.com>2020-03-24 14:03:40 +0100
commitbebe43468330f182ea35e01ace555ce8d0512aeb (patch)
tree85899eccd985b302183ee1551054ef54bdb0ada5 /app/src/main/java/com/zeapo/pwdstore/crypto/PgpActivity.kt
parent98e9f6734a00cfb1d8164227b2de07d2aea150d2 (diff)
downloadHardenedPass-bebe43468330f182ea35e01ace555ce8d0512aeb.tar.gz
HardenedPass-bebe43468330f182ea35e01ace555ce8d0512aeb.zip
Add support for Oreo Autofill (#653)
Adds support for the Autofill feature first available in Android Oreo. In compatible apps and browsers, login forms are automatically detected and the user is presented with options to fill or generate credentials. In most apps and certain browsers, the service will also offer to create new Password Store entries from credentials entered into login forms. Signed-off-by: Harsh Shandilya <me@msfjarvis.dev> Co-authored-by: Harsh Shandilya <me@msfjarvis.dev>
Diffstat (limited to 'app/src/main/java/com/zeapo/pwdstore/crypto/PgpActivity.kt')
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/crypto/PgpActivity.kt98
1 files changed, 85 insertions, 13 deletions
diff --git a/app/src/main/java/com/zeapo/pwdstore/crypto/PgpActivity.kt b/app/src/main/java/com/zeapo/pwdstore/crypto/PgpActivity.kt
index 6f09ca5a..90efd583 100644
--- a/app/src/main/java/com/zeapo/pwdstore/crypto/PgpActivity.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/crypto/PgpActivity.kt
@@ -16,6 +16,7 @@ import android.content.SharedPreferences
import android.graphics.Typeface
import android.os.Build
import android.os.Bundle
+import android.text.InputType
import android.text.TextUtils
import android.text.format.DateUtils
import android.text.method.PasswordTransformationMethod
@@ -30,6 +31,7 @@ import android.widget.CheckBox
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.constraintlayout.widget.ConstraintLayout
+import androidx.core.widget.doOnTextChanged
import androidx.lifecycle.lifecycleScope
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import androidx.preference.PreferenceManager
@@ -48,11 +50,7 @@ import java.io.File
import java.nio.charset.Charset
import java.util.Date
import kotlinx.android.synthetic.main.decrypt_layout.*
-import kotlinx.android.synthetic.main.encrypt_layout.crypto_extra_edit
-import kotlinx.android.synthetic.main.encrypt_layout.crypto_password_category
-import kotlinx.android.synthetic.main.encrypt_layout.crypto_password_edit
-import kotlinx.android.synthetic.main.encrypt_layout.crypto_password_file_edit
-import kotlinx.android.synthetic.main.encrypt_layout.generate_password
+import kotlinx.android.synthetic.main.encrypt_layout.*
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.launch
import me.msfjarvis.openpgpktx.util.OpenPgpApi
@@ -81,6 +79,11 @@ class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
private var editPass: String? = null
private var editExtra: String? = null
+ private val suggestedName by lazy { intent.getStringExtra("SUGGESTED_NAME") }
+ private val suggestedPass by lazy { intent.getStringExtra("SUGGESTED_PASS") }
+ private val suggestedExtra by lazy { intent.getStringExtra("SUGGESTED_EXTRA") }
+ private val shouldGeneratePassword by lazy { intent.getBooleanExtra("GENERATE_PASSWORD", false) }
+
private val operation: String by lazy { intent.getStringExtra("OPERATION") }
private val repoPath: String by lazy { intent.getStringExtra("REPO_PATH") }
@@ -150,25 +153,85 @@ class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
setContentView(R.layout.encrypt_layout)
generate_password?.setOnClickListener {
- when (settings.getString("pref_key_pwgen_type", KEY_PWGEN_TYPE_CLASSIC)) {
- KEY_PWGEN_TYPE_CLASSIC -> PasswordGeneratorDialogFragment()
- .show(supportFragmentManager, "generator")
- KEY_PWGEN_TYPE_XKPASSWD -> XkPasswordGeneratorDialogFragment()
- .show(supportFragmentManager, "xkpwgenerator")
- }
+ generatePassword()
}
title = getString(R.string.new_password_title)
crypto_password_category.text = getRelativePath(fullPath, repoPath)
+ suggestedName?.let {
+ crypto_password_file_edit.setText(it)
+ encrypt_username.apply {
+ visibility = View.VISIBLE
+ setOnClickListener {
+ if (isChecked) {
+ // User wants to enable username encryption, so we add it to the
+ // encrypted extras as the first line.
+ val username = crypto_password_file_edit.text!!.toString()
+ val extras = "username:$username\n${crypto_extra_edit.text!!}"
+
+ crypto_password_file_edit.setText("")
+ crypto_extra_edit.setText(extras)
+ } else {
+ // User wants to disable username encryption, so we extract the
+ // username from the encrypted extras and use it as the filename.
+ val entry = PasswordEntry("PASSWORD\n${crypto_extra_edit.text!!}")
+ val username = entry.username
+
+ // username should not be null here by the logic in
+ // updateEncryptUsernameState, but it could still happen due to
+ // input lag.
+ if (username != null) {
+ crypto_password_file_edit.setText(username)
+ crypto_extra_edit.setText(entry.extraContentWithoutUsername)
+ }
+ }
+ updateEncryptUsernameState()
+ }
+ }
+ crypto_password_file_edit.doOnTextChanged { _, _, _, _ -> updateEncryptUsernameState() }
+ crypto_extra_edit.doOnTextChanged { _, _, _, _ -> updateEncryptUsernameState() }
+ updateEncryptUsernameState()
+ }
+ suggestedPass?.let {
+ crypto_password_edit.setText(it)
+ crypto_password_edit.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD
+ }
+ suggestedExtra?.let { crypto_extra_edit.setText(it) }
+ if (shouldGeneratePassword) {
+ generatePassword()
+ crypto_password_edit.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD
+ }
}
}
}
+ fun updateEncryptUsernameState() {
+ encrypt_username.apply {
+ if (visibility != View.VISIBLE)
+ return
+ val hasUsernameInFileName = crypto_password_file_edit.text!!.toString().isNotBlank()
+ // Use PasswordEntry to parse extras for username
+ val entry = PasswordEntry("PLACEHOLDER\n${crypto_extra_edit.text!!}")
+ val hasUsernameInExtras = entry.hasUsername()
+ isEnabled = hasUsernameInFileName xor hasUsernameInExtras
+ isChecked = hasUsernameInExtras
+ }
+ }
+
override fun onResume() {
super.onResume()
LocalBroadcastManager.getInstance(this).registerReceiver(receiver, IntentFilter(ACTION_CLEAR))
}
+ private fun generatePassword() {
+ when (settings.getString("pref_key_pwgen_type", KEY_PWGEN_TYPE_CLASSIC)) {
+ KEY_PWGEN_TYPE_CLASSIC -> PasswordGeneratorDialogFragment()
+ .show(supportFragmentManager, "generator")
+ KEY_PWGEN_TYPE_XKPASSWD -> XkPasswordGeneratorDialogFragment()
+ .show(supportFragmentManager, "xkpwgenerator")
+ }
+ }
+
override fun onStop() {
LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver)
super.onStop()
@@ -482,7 +545,8 @@ class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
data.putExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true)
// TODO Check if we could use PasswordEntry to generate the file
- val iStream = ByteArrayInputStream("$editPass\n$editExtra".toByteArray(Charset.forName("UTF-8")))
+ val content = "$editPass\n$editExtra"
+ val iStream = ByteArrayInputStream(content.toByteArray(Charset.forName("UTF-8")))
val oStream = ByteArrayOutputStream()
val path = if (intent.getBooleanExtra("fromDecrypt", false)) fullPath else "$fullPath/$editName.gpg"
@@ -494,7 +558,8 @@ class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
RESULT_CODE_SUCCESS -> {
try {
// TODO This might fail, we should check that the write is successful
- val outputStream = FileUtils.openOutputStream(File(path))
+ val file = File(path)
+ val outputStream = FileUtils.openOutputStream(file)
outputStream.write(oStream.toByteArray())
outputStream.close()
@@ -508,6 +573,13 @@ class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
returnIntent.putExtra("OPERATION", "EDIT")
returnIntent.putExtra("needCommit", true)
}
+
+ if (shouldGeneratePassword) {
+ val entry = PasswordEntry(content)
+ returnIntent.putExtra("PASSWORD", entry.password)
+ returnIntent.putExtra("USERNAME", entry.username ?: file.nameWithoutExtension)
+ }
+
setResult(RESULT_OK, returnIntent)
finish()
} catch (e: Exception) {