Wire in fallback key selection flow (#958)

Co-authored-by: Fabian Henneke <fabian@henneke.me>
(cherry picked from commit 084b833fa4)
This commit is contained in:
Harsh Shandilya
2020-07-23 21:29:04 +05:30
committed by Harsh Shandilya
parent 859da9d914
commit 1546f862c5
5 changed files with 245 additions and 138 deletions

View File

@@ -81,6 +81,11 @@
android:parentActivityName=".PasswordStore"
android:windowSoftInputMode="adjustResize" />
<activity
android:name=".crypto.GetKeyIdsActivity"
android:parentActivityName=".PasswordStore"
android:theme="@style/NoBackgroundTheme" />
<service
android:name=".autofill.AutofillService"
android:enabled="@bool/enable_accessibility_autofill"

View File

@@ -0,0 +1,74 @@
/*
* Copyright © 2014-2020 The Android Password Store Authors. All Rights Reserved.
* SPDX-License-Identifier: GPL-3.0-only
*/
package com.zeapo.pwdstore.crypto
import android.content.Intent
import android.os.Bundle
import androidx.activity.result.IntentSenderRequest
import androidx.activity.result.contract.ActivityResultContracts.StartIntentSenderForResult
import androidx.lifecycle.lifecycleScope
import com.github.ajalt.timberkt.e
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import me.msfjarvis.openpgpktx.util.OpenPgpApi
import me.msfjarvis.openpgpktx.util.OpenPgpUtils
import org.openintents.openpgp.IOpenPgpService2
class GetKeyIdsActivity : BasePgpActivity() {
private val userInteractionRequiredResult = registerForActivityResult(StartIntentSenderForResult()) { result ->
if (result.data == null || result.resultCode == RESULT_CANCELED) {
setResult(RESULT_CANCELED, result.data)
finish()
return@registerForActivityResult
}
getKeyIds(result.data!!)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
bindToOpenKeychain(this)
}
override fun onBound(service: IOpenPgpService2) {
super.onBound(service)
getKeyIds()
}
override fun onError(e: Exception) {
e(e)
}
/**
* Get the Key ids from OpenKeychain
*/
private fun getKeyIds(data: Intent = Intent()) {
data.action = OpenPgpApi.ACTION_GET_KEY_IDS
lifecycleScope.launch(Dispatchers.IO) {
api?.executeApiAsync(data, null, null) { result ->
when (result?.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR)) {
OpenPgpApi.RESULT_CODE_SUCCESS -> {
try {
val ids = result.getLongArrayExtra(OpenPgpApi.RESULT_KEY_IDS)?.map {
OpenPgpUtils.convertKeyIdToHex(it)
} ?: emptyList()
val keyResult = Intent().putExtra(OpenPgpApi.EXTRA_KEY_IDS, ids.toTypedArray())
setResult(RESULT_OK, keyResult)
finish()
} catch (e: Exception) {
e(e)
}
}
OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED -> {
val sender = getUserInteractionRequestIntent(result)
userInteractionRequiredResult.launch(IntentSenderRequest.Builder(sender).build())
}
OpenPgpApi.RESULT_CODE_ERROR -> handleError(result)
}
}
}
}
}

View File

@@ -279,7 +279,8 @@ class PasswordCreationActivity : BasePgpActivity(), OpenPgpServiceConnection.OnB
/**
* Encrypts the password and the extra content
*/
private fun encrypt(receivedIntent: Intent? = null) = with(binding) {
private fun encrypt(receivedIntent: Intent? = null) {
with(binding) {
val editName = filename.text.toString().trim()
val editPass = password.text.toString()
val editExtra = extraContent.text.toString()
@@ -311,15 +312,43 @@ class PasswordCreationActivity : BasePgpActivity(), OpenPgpServiceConnection.OnB
snackbar(message = resources.getString(R.string.failed_to_find_key_id))
return@with
}
val gpgIdentifierFileContent = gpgIdentifierFile.useLines { it.firstOrNull() } ?: ""
when (val identifier = parseGpgIdentifier(gpgIdentifierFileContent)) {
is GpgIdentifier.KeyId -> data.putExtra(OpenPgpApi.EXTRA_KEY_IDS, arrayOf(identifier.id).toLongArray())
is GpgIdentifier.UserId -> data.putExtra(OpenPgpApi.EXTRA_USER_IDS, arrayOf(identifier.email))
null -> {
val gpgIdentifiers = gpgIdentifierFile.readLines()
.filter { it.isNotBlank() }
.map { line ->
parseGpgIdentifier(line) ?: run {
snackbar(message = resources.getString(R.string.invalid_gpg_id))
return@with
}
}
if (gpgIdentifiers.isEmpty()) {
registerForActivityResult(StartActivityForResult()) { result ->
if (result.resultCode == RESULT_OK) {
result.data?.getStringArrayExtra(OpenPgpApi.EXTRA_KEY_IDS)?.let { keyIds ->
gpgIdentifierFile.writeText(keyIds.joinToString("\n"))
val repo = PasswordRepository.getRepository(null)
if (repo != null) {
commitChange(
getString(
R.string.git_commit_gpg_id,
getLongName(gpgIdentifierFile.parentFile!!.absolutePath, repoPath, gpgIdentifierFile.name)
)
)
}
encrypt(data)
}
}
}.launch(Intent(this@PasswordCreationActivity, GetKeyIdsActivity::class.java))
return@with
}
val keyIds = gpgIdentifiers.filterIsInstance<GpgIdentifier.KeyId>().map { it.id }.toLongArray()
if (keyIds.isNotEmpty()) {
data.putExtra(OpenPgpApi.EXTRA_KEY_IDS, keyIds)
}
val userIds = gpgIdentifiers.filterIsInstance<GpgIdentifier.UserId>().map { it.email }.toTypedArray()
if (userIds.isNotEmpty()) {
data.putExtra(OpenPgpApi.EXTRA_USER_IDS, userIds)
}
data.putExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true)
val content = "$editPass\n$editExtra"
@@ -443,6 +472,7 @@ class PasswordCreationActivity : BasePgpActivity(), OpenPgpServiceConnection.OnB
}
}
}
}
companion object {

View File

@@ -37,9 +37,6 @@ object PreferenceKeys {
const val GIT_SERVER_INFO = "git_server_info"
const val HTTPS_PASSWORD = "https_password"
const val LENGTH = "length"
const val OPENPGP_KEY_IDS_SET = "openpgp_key_ids_set"
const val OPENPGP_KEY_ID_PREF = "openpgp_key_id_pref"
const val OPENPGP_PROVIDER_LIST = "openpgp_provider_list"
const val OREO_AUTOFILL_CUSTOM_PUBLIC_SUFFIXES = "oreo_autofill_custom_public_suffixes"
const val OREO_AUTOFILL_DEFAULT_USERNAME = "oreo_autofill_default_username"
const val OREO_AUTOFILL_DIRECTORY_STRUCTURE = "oreo_autofill_directory_structure"

View File

@@ -45,6 +45,7 @@
<string name="git_commit_remove_text">Remove %1$s from store.</string>
<string name="git_commit_move_text">Rename %1$s to %2$s.</string>
<string name="git_commit_move_multiple_text">Move multiple passwords to %1$s.</string>
<string name="git_commit_gpg_id">Initialize GPG IDs in %1$s.</string>
<!-- PGPHandler -->
<string name="clipboard_password_toast_text">Password copied to clipboard, you have %d seconds to paste it somewhere.</string>
@@ -366,7 +367,7 @@
<string name="otp_import_failure">Failed to import TOTP configuration</string>
<string name="exporting_passwords">Exporting passwords…</string>
<string name="failed_to_find_key_id">Failed to locate .gpg-id, is your store set up correctly?</string>
<string name="invalid_gpg_id">Found .gpg-id, but it did not contain a key ID, fingerprint or user ID</string>
<string name="invalid_gpg_id">Found .gpg-id, but it contains an invalid key ID, fingerprint or user ID</string>
<string name="invalid_filename_text">File name must not contain \'/\', set directory above</string>
<string name="directory_hint">Directory</string>
</resources>