diff options
| author | Fabian Henneke <FabianHenneke@users.noreply.github.com> | 2020-03-24 14:03:40 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-03-24 14:03:40 +0100 |
| commit | bebe43468330f182ea35e01ace555ce8d0512aeb (patch) | |
| tree | 85899eccd985b302183ee1551054ef54bdb0ada5 /app/src/main/java/com/zeapo/pwdstore/crypto/PgpActivity.kt | |
| parent | 98e9f6734a00cfb1d8164227b2de07d2aea150d2 (diff) | |
| download | HardenedPass-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.kt | 98 |
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) { |
