From 571ab4e78e022ba7c9f0b8e20d3dd81f371d1b3c Mon Sep 17 00:00:00 2001 From: Harsh Shandilya Date: Tue, 14 Sep 2021 22:37:55 +0530 Subject: Gopenpgp related fixes (#1503) * app: rename new crypto activities (cherry picked from commit 89be012f995b878affb7e7a592750e130c7f0f2c) * app: allow alt backends to work without OpenKeychain (cherry picked from commit 7bf9f01e5ef7bb24700ce3f242e5aabbabbff09e) * app: rename ENABLE_GOPENPGP to ENABLE_PGP_V2_BACKEND --- .../aps/ui/autofill/AutofillDecryptActivityV2.kt | 155 +++++++++++++++++++++ .../aps/ui/autofill/AutofillFilterActivity.kt | 4 +- .../ui/autofill/GopenpgpAutofillDecryptActivity.kt | 155 --------------------- 3 files changed, 157 insertions(+), 157 deletions(-) create mode 100644 app/src/main/java/dev/msfjarvis/aps/ui/autofill/AutofillDecryptActivityV2.kt delete mode 100644 app/src/main/java/dev/msfjarvis/aps/ui/autofill/GopenpgpAutofillDecryptActivity.kt (limited to 'app/src/main/java/dev/msfjarvis/aps/ui/autofill') diff --git a/app/src/main/java/dev/msfjarvis/aps/ui/autofill/AutofillDecryptActivityV2.kt b/app/src/main/java/dev/msfjarvis/aps/ui/autofill/AutofillDecryptActivityV2.kt new file mode 100644 index 00000000..27a12867 --- /dev/null +++ b/app/src/main/java/dev/msfjarvis/aps/ui/autofill/AutofillDecryptActivityV2.kt @@ -0,0 +1,155 @@ +/* + * Copyright © 2014-2021 The Android Password Store Authors. All Rights Reserved. + * SPDX-License-Identifier: GPL-3.0-only + */ +package dev.msfjarvis.aps.ui.autofill + +import android.app.PendingIntent +import android.content.Context +import android.content.Intent +import android.content.IntentSender +import android.os.Build +import android.os.Bundle +import android.view.autofill.AutofillManager +import androidx.annotation.RequiresApi +import androidx.appcompat.app.AppCompatActivity +import androidx.lifecycle.lifecycleScope +import com.github.ajalt.timberkt.d +import com.github.ajalt.timberkt.e +import com.github.androidpasswordstore.autofillparser.AutofillAction +import com.github.androidpasswordstore.autofillparser.Credentials +import com.github.michaelbull.result.getOrElse +import com.github.michaelbull.result.onFailure +import com.github.michaelbull.result.onSuccess +import com.github.michaelbull.result.runCatching +import dagger.hilt.android.AndroidEntryPoint +import dev.msfjarvis.aps.injection.crypto.CryptoSet +import dev.msfjarvis.aps.injection.password.PasswordEntryFactory +import dev.msfjarvis.aps.ui.crypto.DecryptActivityV2 +import dev.msfjarvis.aps.util.autofill.AutofillPreferences +import dev.msfjarvis.aps.util.autofill.AutofillResponseBuilder +import dev.msfjarvis.aps.util.autofill.DirectoryStructure +import java.io.File +import javax.inject.Inject +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext + +@RequiresApi(Build.VERSION_CODES.O) +@AndroidEntryPoint +class AutofillDecryptActivityV2 : AppCompatActivity() { + + companion object { + + private const val EXTRA_FILE_PATH = "dev.msfjarvis.aps.autofill.oreo.EXTRA_FILE_PATH" + private const val EXTRA_SEARCH_ACTION = "dev.msfjarvis.aps.autofill.oreo.EXTRA_SEARCH_ACTION" + + private var decryptFileRequestCode = 1 + + fun makeDecryptFileIntent(file: File, forwardedExtras: Bundle, context: Context): Intent { + return Intent(context, AutofillDecryptActivityV2::class.java).apply { + putExtras(forwardedExtras) + putExtra(EXTRA_SEARCH_ACTION, true) + putExtra(EXTRA_FILE_PATH, file.absolutePath) + } + } + + fun makeDecryptFileIntentSender(file: File, context: Context): IntentSender { + val intent = + Intent(context, AutofillDecryptActivityV2::class.java).apply { + putExtra(EXTRA_SEARCH_ACTION, false) + putExtra(EXTRA_FILE_PATH, file.absolutePath) + } + return PendingIntent.getActivity( + context, + decryptFileRequestCode++, + intent, + PendingIntent.FLAG_CANCEL_CURRENT + ) + .intentSender + } + } + + @Inject lateinit var passwordEntryFactory: PasswordEntryFactory + @Inject lateinit var cryptos: CryptoSet + + private lateinit var directoryStructure: DirectoryStructure + + override fun onStart() { + super.onStart() + val filePath = + intent?.getStringExtra(EXTRA_FILE_PATH) + ?: run { + e { "AutofillDecryptActivityV2 started without EXTRA_FILE_PATH" } + finish() + return + } + val clientState = + intent?.getBundleExtra(AutofillManager.EXTRA_CLIENT_STATE) + ?: run { + e { "AutofillDecryptActivityV2 started without EXTRA_CLIENT_STATE" } + finish() + return + } + val isSearchAction = intent?.getBooleanExtra(EXTRA_SEARCH_ACTION, true)!! + val action = if (isSearchAction) AutofillAction.Search else AutofillAction.Match + directoryStructure = AutofillPreferences.directoryStructure(this) + d { action.toString() } + lifecycleScope.launch { + val credentials = decryptCredential(File(filePath)) + if (credentials == null) { + setResult(RESULT_CANCELED) + } else { + val fillInDataset = + AutofillResponseBuilder.makeFillInDataset( + this@AutofillDecryptActivityV2, + credentials, + clientState, + action + ) + withContext(Dispatchers.Main) { + setResult( + RESULT_OK, + Intent().apply { putExtra(AutofillManager.EXTRA_AUTHENTICATION_RESULT, fillInDataset) } + ) + } + } + withContext(Dispatchers.Main) { finish() } + } + } + + private suspend fun decryptCredential(file: File): Credentials? { + runCatching { file.inputStream() } + .onFailure { e -> + e(e) { "File to decrypt not found" } + return null + } + .onSuccess { encryptedInput -> + runCatching { + val crypto = cryptos.first { it.canHandle(file.absolutePath) } + withContext(Dispatchers.IO) { + crypto.decrypt( + DecryptActivityV2.PRIV_KEY, + DecryptActivityV2.PASS.toByteArray(charset = Charsets.UTF_8), + encryptedInput.readBytes() + ) + } + } + .onFailure { e -> + e(e) { "Decryption failed" } + return null + } + .onSuccess { result -> + return runCatching { + val entry = passwordEntryFactory.create(lifecycleScope, result) + AutofillPreferences.credentialsFromStoreEntry(this, file, entry, directoryStructure) + } + .getOrElse { e -> + e(e) { "Failed to parse password entry" } + return null + } + } + } + return null + } +} diff --git a/app/src/main/java/dev/msfjarvis/aps/ui/autofill/AutofillFilterActivity.kt b/app/src/main/java/dev/msfjarvis/aps/ui/autofill/AutofillFilterActivity.kt index 1d5160e2..04fb83d5 100644 --- a/app/src/main/java/dev/msfjarvis/aps/ui/autofill/AutofillFilterActivity.kt +++ b/app/src/main/java/dev/msfjarvis/aps/ui/autofill/AutofillFilterActivity.kt @@ -221,8 +221,8 @@ class AutofillFilterView : AppCompatActivity() { AutofillMatcher.addMatchFor(applicationContext, formOrigin, item.file) // intent?.extras? is checked to be non-null in onCreate decryptAction.launch( - if (FeatureFlags.ENABLE_GOPENPGP) { - GopenpgpAutofillDecryptActivity.makeDecryptFileIntent(item.file, intent!!.extras!!, this) + if (FeatureFlags.ENABLE_PGP_V2_BACKEND) { + AutofillDecryptActivityV2.makeDecryptFileIntent(item.file, intent!!.extras!!, this) } else { AutofillDecryptActivity.makeDecryptFileIntent(item.file, intent!!.extras!!, this) } diff --git a/app/src/main/java/dev/msfjarvis/aps/ui/autofill/GopenpgpAutofillDecryptActivity.kt b/app/src/main/java/dev/msfjarvis/aps/ui/autofill/GopenpgpAutofillDecryptActivity.kt deleted file mode 100644 index 1c9f19d7..00000000 --- a/app/src/main/java/dev/msfjarvis/aps/ui/autofill/GopenpgpAutofillDecryptActivity.kt +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright © 2014-2021 The Android Password Store Authors. All Rights Reserved. - * SPDX-License-Identifier: GPL-3.0-only - */ -package dev.msfjarvis.aps.ui.autofill - -import android.app.PendingIntent -import android.content.Context -import android.content.Intent -import android.content.IntentSender -import android.os.Build -import android.os.Bundle -import android.view.autofill.AutofillManager -import androidx.annotation.RequiresApi -import androidx.appcompat.app.AppCompatActivity -import androidx.lifecycle.lifecycleScope -import com.github.ajalt.timberkt.d -import com.github.ajalt.timberkt.e -import com.github.androidpasswordstore.autofillparser.AutofillAction -import com.github.androidpasswordstore.autofillparser.Credentials -import com.github.michaelbull.result.getOrElse -import com.github.michaelbull.result.onFailure -import com.github.michaelbull.result.onSuccess -import com.github.michaelbull.result.runCatching -import dagger.hilt.android.AndroidEntryPoint -import dev.msfjarvis.aps.injection.crypto.CryptoSet -import dev.msfjarvis.aps.injection.password.PasswordEntryFactory -import dev.msfjarvis.aps.ui.crypto.GopenpgpDecryptActivity -import dev.msfjarvis.aps.util.autofill.AutofillPreferences -import dev.msfjarvis.aps.util.autofill.AutofillResponseBuilder -import dev.msfjarvis.aps.util.autofill.DirectoryStructure -import java.io.File -import javax.inject.Inject -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext - -@RequiresApi(Build.VERSION_CODES.O) -@AndroidEntryPoint -class GopenpgpAutofillDecryptActivity : AppCompatActivity() { - - companion object { - - private const val EXTRA_FILE_PATH = "dev.msfjarvis.aps.autofill.oreo.EXTRA_FILE_PATH" - private const val EXTRA_SEARCH_ACTION = "dev.msfjarvis.aps.autofill.oreo.EXTRA_SEARCH_ACTION" - - private var decryptFileRequestCode = 1 - - fun makeDecryptFileIntent(file: File, forwardedExtras: Bundle, context: Context): Intent { - return Intent(context, GopenpgpAutofillDecryptActivity::class.java).apply { - putExtras(forwardedExtras) - putExtra(EXTRA_SEARCH_ACTION, true) - putExtra(EXTRA_FILE_PATH, file.absolutePath) - } - } - - fun makeDecryptFileIntentSender(file: File, context: Context): IntentSender { - val intent = - Intent(context, GopenpgpAutofillDecryptActivity::class.java).apply { - putExtra(EXTRA_SEARCH_ACTION, false) - putExtra(EXTRA_FILE_PATH, file.absolutePath) - } - return PendingIntent.getActivity( - context, - decryptFileRequestCode++, - intent, - PendingIntent.FLAG_CANCEL_CURRENT - ) - .intentSender - } - } - - @Inject lateinit var passwordEntryFactory: PasswordEntryFactory - @Inject lateinit var cryptos: CryptoSet - - private lateinit var directoryStructure: DirectoryStructure - - override fun onStart() { - super.onStart() - val filePath = - intent?.getStringExtra(EXTRA_FILE_PATH) - ?: run { - e { "GopenpgpAutofillDecryptActivity started without EXTRA_FILE_PATH" } - finish() - return - } - val clientState = - intent?.getBundleExtra(AutofillManager.EXTRA_CLIENT_STATE) - ?: run { - e { "GopenpgpAutofillDecryptActivity started without EXTRA_CLIENT_STATE" } - finish() - return - } - val isSearchAction = intent?.getBooleanExtra(EXTRA_SEARCH_ACTION, true)!! - val action = if (isSearchAction) AutofillAction.Search else AutofillAction.Match - directoryStructure = AutofillPreferences.directoryStructure(this) - d { action.toString() } - lifecycleScope.launch { - val credentials = decryptCredential(File(filePath)) - if (credentials == null) { - setResult(RESULT_CANCELED) - } else { - val fillInDataset = - AutofillResponseBuilder.makeFillInDataset( - this@GopenpgpAutofillDecryptActivity, - credentials, - clientState, - action - ) - withContext(Dispatchers.Main) { - setResult( - RESULT_OK, - Intent().apply { putExtra(AutofillManager.EXTRA_AUTHENTICATION_RESULT, fillInDataset) } - ) - } - } - withContext(Dispatchers.Main) { finish() } - } - } - - private suspend fun decryptCredential(file: File): Credentials? { - runCatching { file.inputStream() } - .onFailure { e -> - e(e) { "File to decrypt not found" } - return null - } - .onSuccess { encryptedInput -> - runCatching { - val crypto = cryptos.first { it.canHandle(file.absolutePath) } - withContext(Dispatchers.IO) { - crypto.decrypt( - GopenpgpDecryptActivity.PRIV_KEY, - GopenpgpDecryptActivity.PASS.toByteArray(charset = Charsets.UTF_8), - encryptedInput.readBytes() - ) - } - } - .onFailure { e -> - e(e) { "Decryption with Gopenpgp failed" } - return null - } - .onSuccess { result -> - return runCatching { - val entry = passwordEntryFactory.create(lifecycleScope, result) - AutofillPreferences.credentialsFromStoreEntry(this, file, entry, directoryStructure) - } - .getOrElse { e -> - e(e) { "Failed to parse password entry" } - return null - } - } - } - return null - } -} -- cgit v1.2.3