summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHarsh Shandilya <me@msfjarvis.dev>2022-01-09 17:50:22 +0530
committerGitHub <noreply@github.com>2022-01-09 17:50:22 +0530
commit35155e55841bc87b2c0e0dc577e1433041b44bc5 (patch)
treec9cf58da55e5876b4fe5676a415b9299881e83ef
parent1738879fb3ba1b2c2d0ca7933c861bf99ae32535 (diff)
Make PGPainless backend feature flag runtime configurable (#1654)
* Make feature flags runtime configurable * Add a settings entry for PGPainless feature flag * Add changelog entry
-rw-r--r--CHANGELOG.md1
-rw-r--r--app/src/main/java/dev/msfjarvis/aps/ui/autofill/AutofillFilterView.kt9
-rw-r--r--app/src/main/java/dev/msfjarvis/aps/ui/autofill/AutofillSaveActivity.kt11
-rw-r--r--app/src/main/java/dev/msfjarvis/aps/ui/crypto/BasePgpActivity.kt7
-rw-r--r--app/src/main/java/dev/msfjarvis/aps/ui/passwords/PasswordStore.kt9
-rw-r--r--app/src/main/java/dev/msfjarvis/aps/ui/settings/PGPSettings.kt6
-rw-r--r--app/src/main/java/dev/msfjarvis/aps/util/autofill/Api30AutofillResponseBuilder.kt20
-rw-r--r--app/src/main/java/dev/msfjarvis/aps/util/autofill/AutofillResponseBuilder.kt20
-rw-r--r--app/src/main/java/dev/msfjarvis/aps/util/features/Feature.kt18
-rw-r--r--app/src/main/java/dev/msfjarvis/aps/util/features/Features.kt21
-rw-r--r--app/src/main/java/dev/msfjarvis/aps/util/services/OreoAutofillService.kt11
11 files changed, 116 insertions, 17 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2d61673c..9ade72cb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -14,6 +14,7 @@ All notable changes to this project will be documented in this file.
- Allow pinning shortcuts directly to the launcher home screen
- Another workaround for SteamGuard's non-standard OTP format
- Allow importing QR code from images
+- Introduce a new opt-in PGP backend powered by [PGPainless](https://github.com/pgpainless/pgpainless) that does not require OpenKeychain
### Fixed
diff --git a/app/src/main/java/dev/msfjarvis/aps/ui/autofill/AutofillFilterView.kt b/app/src/main/java/dev/msfjarvis/aps/ui/autofill/AutofillFilterView.kt
index bb6d1056..55f3fc11 100644
--- a/app/src/main/java/dev/msfjarvis/aps/ui/autofill/AutofillFilterView.kt
+++ b/app/src/main/java/dev/msfjarvis/aps/ui/autofill/AutofillFilterView.kt
@@ -25,23 +25,27 @@ import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import com.github.androidpasswordstore.autofillparser.FormOrigin
+import dagger.hilt.android.AndroidEntryPoint
import dev.msfjarvis.aps.R
import dev.msfjarvis.aps.data.password.PasswordItem
import dev.msfjarvis.aps.databinding.ActivityOreoAutofillFilterBinding
-import dev.msfjarvis.aps.util.FeatureFlags
import dev.msfjarvis.aps.util.autofill.AutofillMatcher
import dev.msfjarvis.aps.util.autofill.AutofillPreferences
import dev.msfjarvis.aps.util.autofill.DirectoryStructure
import dev.msfjarvis.aps.util.extensions.viewBinding
+import dev.msfjarvis.aps.util.features.Feature
+import dev.msfjarvis.aps.util.features.Features
import dev.msfjarvis.aps.util.viewmodel.FilterMode
import dev.msfjarvis.aps.util.viewmodel.ListMode
import dev.msfjarvis.aps.util.viewmodel.SearchMode
import dev.msfjarvis.aps.util.viewmodel.SearchableRepositoryAdapter
import dev.msfjarvis.aps.util.viewmodel.SearchableRepositoryViewModel
+import javax.inject.Inject
import logcat.LogPriority.ERROR
import logcat.logcat
@TargetApi(Build.VERSION_CODES.O)
+@AndroidEntryPoint
class AutofillFilterView : AppCompatActivity() {
companion object {
@@ -76,6 +80,7 @@ class AutofillFilterView : AppCompatActivity() {
}
}
+ @Inject lateinit var features: Features
private lateinit var formOrigin: FormOrigin
private lateinit var directoryStructure: DirectoryStructure
private val binding by viewBinding(ActivityOreoAutofillFilterBinding::inflate)
@@ -222,7 +227,7 @@ class AutofillFilterView : AppCompatActivity() {
AutofillMatcher.addMatchFor(applicationContext, formOrigin, item.file)
// intent?.extras? is checked to be non-null in onCreate
decryptAction.launch(
- if (FeatureFlags.ENABLE_PGP_V2_BACKEND) {
+ if (features.isEnabled(Feature.EnablePGPainlessBackend)) {
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/AutofillSaveActivity.kt b/app/src/main/java/dev/msfjarvis/aps/ui/autofill/AutofillSaveActivity.kt
index 49b14ea4..f79ad6a8 100644
--- a/app/src/main/java/dev/msfjarvis/aps/ui/autofill/AutofillSaveActivity.kt
+++ b/app/src/main/java/dev/msfjarvis/aps/ui/autofill/AutofillSaveActivity.kt
@@ -18,19 +18,23 @@ import androidx.core.os.bundleOf
import com.github.androidpasswordstore.autofillparser.AutofillAction
import com.github.androidpasswordstore.autofillparser.Credentials
import com.github.androidpasswordstore.autofillparser.FormOrigin
+import dagger.hilt.android.AndroidEntryPoint
import dev.msfjarvis.aps.data.repo.PasswordRepository
import dev.msfjarvis.aps.ui.crypto.PasswordCreationActivity
import dev.msfjarvis.aps.ui.crypto.PasswordCreationActivityV2
-import dev.msfjarvis.aps.util.FeatureFlags
import dev.msfjarvis.aps.util.autofill.AutofillMatcher
import dev.msfjarvis.aps.util.autofill.AutofillPreferences
import dev.msfjarvis.aps.util.autofill.AutofillResponseBuilder
import dev.msfjarvis.aps.util.extensions.unsafeLazy
+import dev.msfjarvis.aps.util.features.Feature
+import dev.msfjarvis.aps.util.features.Features
import java.io.File
+import javax.inject.Inject
import logcat.LogPriority.ERROR
import logcat.logcat
@RequiresApi(Build.VERSION_CODES.O)
+@AndroidEntryPoint
class AutofillSaveActivity : AppCompatActivity() {
companion object {
@@ -105,11 +109,14 @@ class AutofillSaveActivity : AppCompatActivity() {
}
}
+ @Inject lateinit var features: Features
+
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val repo = PasswordRepository.getRepositoryDirectory()
val creationActivity =
- if (FeatureFlags.ENABLE_PGP_V2_BACKEND) PasswordCreationActivityV2::class.java
+ if (features.isEnabled(Feature.EnablePGPainlessBackend))
+ PasswordCreationActivityV2::class.java
else PasswordCreationActivity::class.java
val saveIntent =
Intent(this, creationActivity).apply {
diff --git a/app/src/main/java/dev/msfjarvis/aps/ui/crypto/BasePgpActivity.kt b/app/src/main/java/dev/msfjarvis/aps/ui/crypto/BasePgpActivity.kt
index 7c74a621..6ce1c057 100644
--- a/app/src/main/java/dev/msfjarvis/aps/ui/crypto/BasePgpActivity.kt
+++ b/app/src/main/java/dev/msfjarvis/aps/ui/crypto/BasePgpActivity.kt
@@ -24,13 +24,14 @@ import com.google.android.material.snackbar.Snackbar
import dagger.hilt.android.AndroidEntryPoint
import dev.msfjarvis.aps.R
import dev.msfjarvis.aps.injection.prefs.SettingsPreferences
-import dev.msfjarvis.aps.util.FeatureFlags
import dev.msfjarvis.aps.util.extensions.OPENPGP_PROVIDER
import dev.msfjarvis.aps.util.extensions.asLog
import dev.msfjarvis.aps.util.extensions.clipboard
import dev.msfjarvis.aps.util.extensions.getString
import dev.msfjarvis.aps.util.extensions.snackbar
import dev.msfjarvis.aps.util.extensions.unsafeLazy
+import dev.msfjarvis.aps.util.features.Feature
+import dev.msfjarvis.aps.util.features.Features
import dev.msfjarvis.aps.util.services.ClipboardService
import dev.msfjarvis.aps.util.settings.PreferenceKeys
import java.io.File
@@ -63,6 +64,8 @@ open class BasePgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBou
/** [SharedPreferences] instance used by subclasses to persist settings */
@SettingsPreferences @Inject lateinit var settings: SharedPreferences
+ @Inject lateinit var features: Features
+
/**
* Handle to the [OpenPgpApi] instance that is used by subclasses to interface with OpenKeychain.
*/
@@ -127,7 +130,7 @@ open class BasePgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBou
/** Method for subclasses to initiate binding with [OpenPgpServiceConnection]. */
fun bindToOpenKeychain(onBoundListener: OpenPgpServiceConnection.OnBound) {
- if (FeatureFlags.ENABLE_PGP_V2_BACKEND) return
+ if (features.isEnabled(Feature.EnablePGPainlessBackend)) return
val installed =
runCatching {
packageManager.getPackageInfo(OPENPGP_PROVIDER, 0)
diff --git a/app/src/main/java/dev/msfjarvis/aps/ui/passwords/PasswordStore.kt b/app/src/main/java/dev/msfjarvis/aps/ui/passwords/PasswordStore.kt
index b42c30e9..d80959b8 100644
--- a/app/src/main/java/dev/msfjarvis/aps/ui/passwords/PasswordStore.kt
+++ b/app/src/main/java/dev/msfjarvis/aps/ui/passwords/PasswordStore.kt
@@ -47,7 +47,6 @@ import dev.msfjarvis.aps.ui.git.base.BaseGitActivity
import dev.msfjarvis.aps.ui.onboarding.activity.OnboardingActivity
import dev.msfjarvis.aps.ui.settings.DirectorySelectionActivity
import dev.msfjarvis.aps.ui.settings.SettingsActivity
-import dev.msfjarvis.aps.util.FeatureFlags
import dev.msfjarvis.aps.util.autofill.AutofillMatcher
import dev.msfjarvis.aps.util.extensions.base64
import dev.msfjarvis.aps.util.extensions.commitChange
@@ -57,6 +56,8 @@ import dev.msfjarvis.aps.util.extensions.isInsideRepository
import dev.msfjarvis.aps.util.extensions.isPermissionGranted
import dev.msfjarvis.aps.util.extensions.listFilesRecursively
import dev.msfjarvis.aps.util.extensions.sharedPrefs
+import dev.msfjarvis.aps.util.features.Feature
+import dev.msfjarvis.aps.util.features.Features
import dev.msfjarvis.aps.util.settings.AuthMode
import dev.msfjarvis.aps.util.settings.PreferenceKeys
import dev.msfjarvis.aps.util.shortcuts.ShortcutHandler
@@ -76,6 +77,7 @@ const val PASSWORD_FRAGMENT_TAG = "PasswordsList"
@AndroidEntryPoint
class PasswordStore : BaseGitActivity() {
+ @Inject lateinit var features: Features
@Inject lateinit var shortcutHandler: ShortcutHandler
private lateinit var searchItem: MenuItem
private val settings by lazy { sharedPrefs }
@@ -428,7 +430,7 @@ class PasswordStore : BaseGitActivity() {
(authDecryptIntent.clone() as Intent).setComponent(
ComponentName(
this,
- if (FeatureFlags.ENABLE_PGP_V2_BACKEND) {
+ if (features.isEnabled(Feature.EnablePGPainlessBackend)) {
DecryptActivityV2::class.java
} else {
DecryptActivity::class.java
@@ -458,7 +460,8 @@ class PasswordStore : BaseGitActivity() {
val currentDir = currentDir
logcat(INFO) { "Adding file to : ${currentDir.absolutePath}" }
val creationActivity =
- if (FeatureFlags.ENABLE_PGP_V2_BACKEND) PasswordCreationActivityV2::class.java
+ if (features.isEnabled(Feature.EnablePGPainlessBackend))
+ PasswordCreationActivityV2::class.java
else PasswordCreationActivity::class.java
val intent = Intent(this, creationActivity)
intent.putExtra(BasePgpActivity.EXTRA_FILE_PATH, currentDir.absolutePath)
diff --git a/app/src/main/java/dev/msfjarvis/aps/ui/settings/PGPSettings.kt b/app/src/main/java/dev/msfjarvis/aps/ui/settings/PGPSettings.kt
index 81418ccb..86f23c32 100644
--- a/app/src/main/java/dev/msfjarvis/aps/ui/settings/PGPSettings.kt
+++ b/app/src/main/java/dev/msfjarvis/aps/ui/settings/PGPSettings.kt
@@ -7,15 +7,21 @@ package dev.msfjarvis.aps.ui.settings
import androidx.fragment.app.FragmentActivity
import de.Maxr1998.modernpreferences.PreferenceScreen
+import de.Maxr1998.modernpreferences.helpers.checkBox
import de.Maxr1998.modernpreferences.helpers.onClick
import de.Maxr1998.modernpreferences.helpers.pref
import dev.msfjarvis.aps.ui.pgp.PGPKeyImportActivity
import dev.msfjarvis.aps.util.extensions.launchActivity
+import dev.msfjarvis.aps.util.features.Feature
class PGPSettings(private val activity: FragmentActivity) : SettingsProvider {
override fun provideSettings(builder: PreferenceScreen.Builder) {
builder.apply {
+ checkBox(Feature.EnablePGPainlessBackend.configKey) {
+ title = "Enable new PGP backend"
+ persistent = true
+ }
pref("_") {
title = "Import PGP key"
persistent = false
diff --git a/app/src/main/java/dev/msfjarvis/aps/util/autofill/Api30AutofillResponseBuilder.kt b/app/src/main/java/dev/msfjarvis/aps/util/autofill/Api30AutofillResponseBuilder.kt
index fd8faa7f..22f2db85 100644
--- a/app/src/main/java/dev/msfjarvis/aps/util/autofill/Api30AutofillResponseBuilder.kt
+++ b/app/src/main/java/dev/msfjarvis/aps/util/autofill/Api30AutofillResponseBuilder.kt
@@ -19,13 +19,17 @@ import com.github.androidpasswordstore.autofillparser.AutofillAction
import com.github.androidpasswordstore.autofillparser.FillableForm
import com.github.androidpasswordstore.autofillparser.fillWith
import com.github.michaelbull.result.fold
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
import dev.msfjarvis.aps.autofill.oreo.ui.AutofillSmsActivity
import dev.msfjarvis.aps.ui.autofill.AutofillDecryptActivity
import dev.msfjarvis.aps.ui.autofill.AutofillDecryptActivityV2
import dev.msfjarvis.aps.ui.autofill.AutofillFilterView
import dev.msfjarvis.aps.ui.autofill.AutofillPublisherChangedActivity
import dev.msfjarvis.aps.ui.autofill.AutofillSaveActivity
-import dev.msfjarvis.aps.util.FeatureFlags
+import dev.msfjarvis.aps.util.features.Feature
+import dev.msfjarvis.aps.util.features.Features
import java.io.File
import logcat.LogPriority.ERROR
import logcat.asLog
@@ -33,7 +37,17 @@ import logcat.logcat
/** Implements [AutofillResponseBuilder]'s methods for API 30 and above */
@RequiresApi(Build.VERSION_CODES.R)
-class Api30AutofillResponseBuilder(form: FillableForm) {
+class Api30AutofillResponseBuilder
+@AssistedInject
+constructor(
+ @Assisted form: FillableForm,
+ private val features: Features,
+) {
+
+ @AssistedFactory
+ interface Factory {
+ fun create(form: FillableForm): Api30AutofillResponseBuilder
+ }
private val formOrigin = form.formOrigin
private val scenario = form.scenario
@@ -73,7 +87,7 @@ class Api30AutofillResponseBuilder(form: FillableForm) {
if (!scenario.hasFieldsToFillOn(AutofillAction.Match)) return null
val metadata = makeFillMatchMetadata(context, file)
val intentSender =
- if (FeatureFlags.ENABLE_PGP_V2_BACKEND) {
+ if (features.isEnabled(Feature.EnablePGPainlessBackend)) {
AutofillDecryptActivityV2.makeDecryptFileIntentSender(file, context)
} else {
AutofillDecryptActivity.makeDecryptFileIntentSender(file, context)
diff --git a/app/src/main/java/dev/msfjarvis/aps/util/autofill/AutofillResponseBuilder.kt b/app/src/main/java/dev/msfjarvis/aps/util/autofill/AutofillResponseBuilder.kt
index 723347f2..5c1c91d6 100644
--- a/app/src/main/java/dev/msfjarvis/aps/util/autofill/AutofillResponseBuilder.kt
+++ b/app/src/main/java/dev/msfjarvis/aps/util/autofill/AutofillResponseBuilder.kt
@@ -19,20 +19,34 @@ import com.github.androidpasswordstore.autofillparser.Credentials
import com.github.androidpasswordstore.autofillparser.FillableForm
import com.github.androidpasswordstore.autofillparser.fillWith
import com.github.michaelbull.result.fold
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
import dev.msfjarvis.aps.autofill.oreo.ui.AutofillSmsActivity
import dev.msfjarvis.aps.ui.autofill.AutofillDecryptActivity
import dev.msfjarvis.aps.ui.autofill.AutofillDecryptActivityV2
import dev.msfjarvis.aps.ui.autofill.AutofillFilterView
import dev.msfjarvis.aps.ui.autofill.AutofillPublisherChangedActivity
import dev.msfjarvis.aps.ui.autofill.AutofillSaveActivity
-import dev.msfjarvis.aps.util.FeatureFlags
+import dev.msfjarvis.aps.util.features.Feature
+import dev.msfjarvis.aps.util.features.Features
import java.io.File
import logcat.LogPriority.ERROR
import logcat.asLog
import logcat.logcat
@RequiresApi(Build.VERSION_CODES.O)
-class AutofillResponseBuilder(form: FillableForm) {
+class AutofillResponseBuilder
+@AssistedInject
+constructor(
+ @Assisted form: FillableForm,
+ private val features: Features,
+) {
+
+ @AssistedFactory
+ interface Factory {
+ fun create(form: FillableForm): AutofillResponseBuilder
+ }
private val formOrigin = form.formOrigin
private val scenario = form.scenario
@@ -61,7 +75,7 @@ class AutofillResponseBuilder(form: FillableForm) {
if (!scenario.hasFieldsToFillOn(AutofillAction.Match)) return null
val metadata = makeFillMatchMetadata(context, file)
val intentSender =
- if (FeatureFlags.ENABLE_PGP_V2_BACKEND) {
+ if (features.isEnabled(Feature.EnablePGPainlessBackend)) {
AutofillDecryptActivityV2.makeDecryptFileIntentSender(file, context)
} else {
AutofillDecryptActivity.makeDecryptFileIntentSender(file, context)
diff --git a/app/src/main/java/dev/msfjarvis/aps/util/features/Feature.kt b/app/src/main/java/dev/msfjarvis/aps/util/features/Feature.kt
new file mode 100644
index 00000000..7ae2e642
--- /dev/null
+++ b/app/src/main/java/dev/msfjarvis/aps/util/features/Feature.kt
@@ -0,0 +1,18 @@
+/*
+ * Copyright © 2014-2022 The Android Password Store Authors. All Rights Reserved.
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+package dev.msfjarvis.aps.util.features
+
+/** List of all feature flags for the app. */
+enum class Feature(
+ /** Default value for the flag. */
+ val defaultValue: Boolean,
+ /** Key to retrieve the current value for the flag. */
+ val configKey: String,
+) {
+
+ /** Opt into the new PGP backend powered by the PGPainless library. */
+ EnablePGPainlessBackend(false, "enable_pgp_v2_backend"),
+}
diff --git a/app/src/main/java/dev/msfjarvis/aps/util/features/Features.kt b/app/src/main/java/dev/msfjarvis/aps/util/features/Features.kt
new file mode 100644
index 00000000..39b2c3a8
--- /dev/null
+++ b/app/src/main/java/dev/msfjarvis/aps/util/features/Features.kt
@@ -0,0 +1,21 @@
+/*
+ * Copyright © 2014-2022 The Android Password Store Authors. All Rights Reserved.
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+package dev.msfjarvis.aps.util.features
+
+import android.content.SharedPreferences
+import dev.msfjarvis.aps.injection.prefs.SettingsPreferences
+import javax.inject.Inject
+
+class Features
+@Inject
+constructor(
+ @SettingsPreferences private val preferences: SharedPreferences,
+) {
+
+ fun isEnabled(feature: Feature): Boolean {
+ return preferences.getBoolean(feature.configKey, feature.defaultValue)
+ }
+}
diff --git a/app/src/main/java/dev/msfjarvis/aps/util/services/OreoAutofillService.kt b/app/src/main/java/dev/msfjarvis/aps/util/services/OreoAutofillService.kt
index a52caff0..7b804f3e 100644
--- a/app/src/main/java/dev/msfjarvis/aps/util/services/OreoAutofillService.kt
+++ b/app/src/main/java/dev/msfjarvis/aps/util/services/OreoAutofillService.kt
@@ -23,6 +23,7 @@ import com.github.androidpasswordstore.autofillparser.cachePublicSuffixList
import com.github.androidpasswordstore.autofillparser.passwordValue
import com.github.androidpasswordstore.autofillparser.recoverNodes
import com.github.androidpasswordstore.autofillparser.usernameValue
+import dagger.hilt.android.AndroidEntryPoint
import dev.msfjarvis.aps.BuildConfig
import dev.msfjarvis.aps.R
import dev.msfjarvis.aps.ui.autofill.AutofillSaveActivity
@@ -32,10 +33,12 @@ import dev.msfjarvis.aps.util.extensions.getString
import dev.msfjarvis.aps.util.extensions.hasFlag
import dev.msfjarvis.aps.util.extensions.sharedPrefs
import dev.msfjarvis.aps.util.settings.PreferenceKeys
+import javax.inject.Inject
import logcat.LogPriority.ERROR
import logcat.logcat
@RequiresApi(Build.VERSION_CODES.O)
+@AndroidEntryPoint
class OreoAutofillService : AutofillService() {
companion object {
@@ -55,6 +58,9 @@ class OreoAutofillService : AutofillService() {
private const val DISABLE_AUTOFILL_DURATION_MS = 1000 * 60 * 60 * 24L
}
+ @Inject lateinit var api30ResponseBuilderFactory: Api30AutofillResponseBuilder.Factory
+ @Inject lateinit var responseBuilderFactory: AutofillResponseBuilder.Factory
+
override fun onCreate() {
super.onCreate()
cachePublicSuffixList(applicationContext)
@@ -97,10 +103,11 @@ class OreoAutofillService : AutofillService() {
return
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
- Api30AutofillResponseBuilder(formToFill)
+ api30ResponseBuilderFactory
+ .create(formToFill)
.fillCredentials(this, request.inlineSuggestionsRequest, callback)
} else {
- AutofillResponseBuilder(formToFill).fillCredentials(this, callback)
+ responseBuilderFactory.create(formToFill).fillCredentials(this, callback)
}
}