refactor: consistently adopt PGP over GPG for naming
PGP is the standard, GPG is an implementation of it. We're adhering to PGP, and not using GPG.
This commit is contained in:
parent
c168ce2e86
commit
5dac84c3c8
19 changed files with 94 additions and 95 deletions
|
@ -6,9 +6,9 @@
|
|||
package app.passwordstore.data.crypto
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import app.passwordstore.crypto.GpgIdentifier
|
||||
import app.passwordstore.crypto.PGPDecryptOptions
|
||||
import app.passwordstore.crypto.PGPEncryptOptions
|
||||
import app.passwordstore.crypto.PGPIdentifier
|
||||
import app.passwordstore.crypto.PGPKeyManager
|
||||
import app.passwordstore.crypto.PGPainlessCryptoHandler
|
||||
import app.passwordstore.crypto.errors.CryptoHandlerException
|
||||
|
@ -40,20 +40,20 @@ constructor(
|
|||
|
||||
suspend fun decrypt(
|
||||
password: String,
|
||||
identities: List<GpgIdentifier>,
|
||||
identities: List<PGPIdentifier>,
|
||||
message: ByteArrayInputStream,
|
||||
out: ByteArrayOutputStream,
|
||||
) = withContext(dispatcherProvider.io()) { decryptPgp(password, identities, message, out) }
|
||||
|
||||
suspend fun encrypt(
|
||||
identities: List<GpgIdentifier>,
|
||||
identities: List<PGPIdentifier>,
|
||||
content: ByteArrayInputStream,
|
||||
out: ByteArrayOutputStream,
|
||||
) = withContext(dispatcherProvider.io()) { encryptPgp(identities, content, out) }
|
||||
|
||||
private suspend fun decryptPgp(
|
||||
password: String,
|
||||
identities: List<GpgIdentifier>,
|
||||
identities: List<PGPIdentifier>,
|
||||
message: ByteArrayInputStream,
|
||||
out: ByteArrayOutputStream,
|
||||
): Result<Unit, CryptoHandlerException> {
|
||||
|
@ -63,7 +63,7 @@ constructor(
|
|||
}
|
||||
|
||||
private suspend fun encryptPgp(
|
||||
identities: List<GpgIdentifier>,
|
||||
identities: List<PGPIdentifier>,
|
||||
content: ByteArrayInputStream,
|
||||
out: ByteArrayOutputStream,
|
||||
): Result<Unit, CryptoHandlerException> {
|
||||
|
|
|
@ -4,15 +4,14 @@ import android.content.Context
|
|||
import androidx.core.content.edit
|
||||
import androidx.security.crypto.EncryptedSharedPreferences
|
||||
import androidx.security.crypto.MasterKey
|
||||
import app.passwordstore.crypto.GpgIdentifier
|
||||
import app.passwordstore.crypto.PGPIdentifier
|
||||
import app.passwordstore.util.coroutines.DispatcherProvider
|
||||
import app.passwordstore.util.extensions.getString
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
/** Implements a rudimentary [EncryptedSharedPreferences]-backed cache for GPG passphrases. */
|
||||
@Suppress("Unused") // Soon
|
||||
class GPGPassphraseCache
|
||||
class PGPPassphraseCache
|
||||
@Inject
|
||||
constructor(
|
||||
private val dispatcherProvider: DispatcherProvider,
|
||||
|
@ -20,7 +19,7 @@ constructor(
|
|||
|
||||
suspend fun cachePassphrase(
|
||||
context: Context,
|
||||
identifier: GpgIdentifier,
|
||||
identifier: PGPIdentifier,
|
||||
passphrase: String,
|
||||
) {
|
||||
withContext(dispatcherProvider.io()) {
|
||||
|
@ -30,7 +29,7 @@ constructor(
|
|||
|
||||
suspend fun retrieveCachedPassphrase(
|
||||
context: Context,
|
||||
identifier: GpgIdentifier,
|
||||
identifier: PGPIdentifier,
|
||||
): String? {
|
||||
return withContext(dispatcherProvider.io()) {
|
||||
getPreferences(context).getString(identifier.toString())
|
||||
|
@ -39,7 +38,7 @@ constructor(
|
|||
|
||||
suspend fun clearCachedPassphrase(
|
||||
context: Context,
|
||||
identifier: GpgIdentifier,
|
||||
identifier: PGPIdentifier,
|
||||
) {
|
||||
withContext(dispatcherProvider.io()) {
|
||||
getPreferences(context).edit { remove(identifier.toString()) }
|
|
@ -7,7 +7,7 @@ package app.passwordstore.data.password
|
|||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import app.passwordstore.data.repo.PasswordRepository
|
||||
import app.passwordstore.ui.crypto.BasePgpActivity
|
||||
import app.passwordstore.ui.crypto.BasePGPActivity
|
||||
import app.passwordstore.ui.main.LaunchActivity
|
||||
import java.io.File
|
||||
|
||||
|
@ -21,7 +21,7 @@ data class PasswordItem(
|
|||
|
||||
val fullPathToParent = file.absolutePath.replace(rootDir.absolutePath, "").replace(file.name, "")
|
||||
|
||||
val longName = BasePgpActivity.getLongName(fullPathToParent, rootDir.absolutePath, toString())
|
||||
val longName = BasePGPActivity.getLongName(fullPathToParent, rootDir.absolutePath, toString())
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
return (other is PasswordItem) && (other.file == file)
|
||||
|
|
|
@ -13,16 +13,16 @@ import android.os.Bundle
|
|||
import android.view.autofill.AutofillManager
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import app.passwordstore.R
|
||||
import app.passwordstore.data.crypto.GPGPassphraseCache
|
||||
import app.passwordstore.data.crypto.PGPPassphraseCache
|
||||
import app.passwordstore.data.passfile.PasswordEntry
|
||||
import app.passwordstore.ui.crypto.BasePgpActivity
|
||||
import app.passwordstore.ui.crypto.BasePGPActivity
|
||||
import app.passwordstore.ui.crypto.PasswordDialog
|
||||
import app.passwordstore.util.auth.BiometricAuthenticator
|
||||
import app.passwordstore.util.autofill.AutofillPreferences
|
||||
import app.passwordstore.util.autofill.AutofillResponseBuilder
|
||||
import app.passwordstore.util.autofill.DirectoryStructure
|
||||
import app.passwordstore.util.extensions.asLog
|
||||
import app.passwordstore.util.features.Feature.EnableGPGPassphraseCache
|
||||
import app.passwordstore.util.features.Feature.EnablePGPPassphraseCache
|
||||
import app.passwordstore.util.features.Features
|
||||
import com.github.androidpasswordstore.autofillparser.AutofillAction
|
||||
import com.github.androidpasswordstore.autofillparser.Credentials
|
||||
|
@ -41,11 +41,11 @@ import logcat.LogPriority.ERROR
|
|||
import logcat.logcat
|
||||
|
||||
@AndroidEntryPoint
|
||||
class AutofillDecryptActivity : BasePgpActivity() {
|
||||
class AutofillDecryptActivity : BasePGPActivity() {
|
||||
|
||||
@Inject lateinit var passwordEntryFactory: PasswordEntry.Factory
|
||||
@Inject lateinit var features: Features
|
||||
@Inject lateinit var passphraseCache: GPGPassphraseCache
|
||||
@Inject lateinit var passphraseCache: PGPPassphraseCache
|
||||
|
||||
private lateinit var directoryStructure: DirectoryStructure
|
||||
|
||||
|
@ -70,9 +70,9 @@ class AutofillDecryptActivity : BasePgpActivity() {
|
|||
directoryStructure = AutofillPreferences.directoryStructure(this)
|
||||
logcat { action.toString() }
|
||||
requireKeysExist {
|
||||
val gpgIdentifiers = getGpgIdentifiers("") ?: return@requireKeysExist
|
||||
val gpgIdentifiers = getPGPIdentifiers("") ?: return@requireKeysExist
|
||||
if (
|
||||
features.isEnabled(EnableGPGPassphraseCache) && BiometricAuthenticator.canAuthenticate(this)
|
||||
features.isEnabled(EnablePGPPassphraseCache) && BiometricAuthenticator.canAuthenticate(this)
|
||||
) {
|
||||
BiometricAuthenticator.authenticate(
|
||||
this,
|
||||
|
@ -143,7 +143,7 @@ class AutofillDecryptActivity : BasePgpActivity() {
|
|||
}
|
||||
|
||||
private suspend fun decryptCredential(file: File, password: String): Credentials? {
|
||||
val gpgIdentifiers = getGpgIdentifiers("") ?: return null
|
||||
val gpgIdentifiers = getPGPIdentifiers("") ?: return null
|
||||
runCatching { file.readBytes().inputStream() }
|
||||
.onFailure { e ->
|
||||
logcat(ERROR) { e.asLog("File to decrypt not found") }
|
||||
|
|
|
@ -18,7 +18,7 @@ import androidx.annotation.StringRes
|
|||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import app.passwordstore.R
|
||||
import app.passwordstore.crypto.GpgIdentifier
|
||||
import app.passwordstore.crypto.PGPIdentifier
|
||||
import app.passwordstore.data.crypto.CryptoRepository
|
||||
import app.passwordstore.data.repo.PasswordRepository
|
||||
import app.passwordstore.injection.prefs.SettingsPreferences
|
||||
|
@ -41,7 +41,7 @@ import kotlinx.coroutines.withContext
|
|||
|
||||
@Suppress("Registered")
|
||||
@AndroidEntryPoint
|
||||
open class BasePgpActivity : AppCompatActivity() {
|
||||
open class BasePGPActivity : AppCompatActivity() {
|
||||
|
||||
/** Full path to the repository */
|
||||
val repoPath by unsafeLazy { intent.getStringExtra("REPO_PATH")!! }
|
||||
|
@ -110,12 +110,12 @@ open class BasePgpActivity : AppCompatActivity() {
|
|||
val hasKeys = repository.hasKeys()
|
||||
if (!hasKeys) {
|
||||
withContext(dispatcherProvider.main()) {
|
||||
MaterialAlertDialogBuilder(this@BasePgpActivity)
|
||||
MaterialAlertDialogBuilder(this@BasePGPActivity)
|
||||
.setTitle(resources.getString(R.string.no_keys_imported_dialog_title))
|
||||
.setMessage(resources.getString(R.string.no_keys_imported_dialog_message))
|
||||
.setPositiveButton(resources.getString(R.string.button_label_import)) { _, _ ->
|
||||
onKeyImport = onKeysExist
|
||||
keyImportAction.launch(Intent(this@BasePgpActivity, PGPKeyImportActivity::class.java))
|
||||
keyImportAction.launch(Intent(this@BasePGPActivity, PGPKeyImportActivity::class.java))
|
||||
}
|
||||
.show()
|
||||
}
|
||||
|
@ -147,12 +147,12 @@ open class BasePgpActivity : AppCompatActivity() {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get a list of available [GpgIdentifier]s for the current password repository. This method
|
||||
* Get a list of available [PGPIdentifier]s for the current password repository. This method
|
||||
* throws when no identifiers were able to be parsed. If this method returns null, it means that
|
||||
* an invalid identifier was encountered and further execution must stop to let the user correct
|
||||
* the problem.
|
||||
*/
|
||||
fun getGpgIdentifiers(subDir: String): List<GpgIdentifier>? {
|
||||
fun getPGPIdentifiers(subDir: String): List<PGPIdentifier>? {
|
||||
val repoRoot = PasswordRepository.getRepositoryDirectory()
|
||||
val gpgIdentifierFile =
|
||||
File(repoRoot, subDir).findTillRoot(".gpg-id", repoRoot)
|
||||
|
@ -162,7 +162,7 @@ open class BasePgpActivity : AppCompatActivity() {
|
|||
.readLines()
|
||||
.filter { it.isNotBlank() }
|
||||
.map { line ->
|
||||
GpgIdentifier.fromString(line)
|
||||
PGPIdentifier.fromString(line)
|
||||
?: run {
|
||||
// The line being empty means this is most likely an empty `.gpg-id`
|
||||
// file we created. Skip the validation so we can make the user add a
|
||||
|
@ -176,7 +176,7 @@ open class BasePgpActivity : AppCompatActivity() {
|
|||
return null
|
||||
}
|
||||
}
|
||||
.filterIsInstance<GpgIdentifier>()
|
||||
.filterIsInstance<PGPIdentifier>()
|
||||
if (gpgIdentifiers.isEmpty()) {
|
||||
error("Failed to parse identifiers from .gpg-id: ${gpgIdentifierFile.readText()}")
|
||||
}
|
|
@ -11,8 +11,8 @@ import android.view.Menu
|
|||
import android.view.MenuItem
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import app.passwordstore.R
|
||||
import app.passwordstore.crypto.GpgIdentifier
|
||||
import app.passwordstore.data.crypto.GPGPassphraseCache
|
||||
import app.passwordstore.crypto.PGPIdentifier
|
||||
import app.passwordstore.data.crypto.PGPPassphraseCache
|
||||
import app.passwordstore.data.passfile.PasswordEntry
|
||||
import app.passwordstore.data.password.FieldItem
|
||||
import app.passwordstore.databinding.DecryptLayoutBinding
|
||||
|
@ -21,7 +21,7 @@ import app.passwordstore.util.auth.BiometricAuthenticator
|
|||
import app.passwordstore.util.extensions.getString
|
||||
import app.passwordstore.util.extensions.unsafeLazy
|
||||
import app.passwordstore.util.extensions.viewBinding
|
||||
import app.passwordstore.util.features.Feature.EnableGPGPassphraseCache
|
||||
import app.passwordstore.util.features.Feature.EnablePGPPassphraseCache
|
||||
import app.passwordstore.util.features.Features
|
||||
import app.passwordstore.util.settings.Constants
|
||||
import app.passwordstore.util.settings.PreferenceKeys
|
||||
|
@ -42,10 +42,10 @@ import logcat.LogPriority.ERROR
|
|||
import logcat.logcat
|
||||
|
||||
@AndroidEntryPoint
|
||||
class DecryptActivity : BasePgpActivity() {
|
||||
class DecryptActivity : BasePGPActivity() {
|
||||
|
||||
@Inject lateinit var passwordEntryFactory: PasswordEntry.Factory
|
||||
@Inject lateinit var passphraseCache: GPGPassphraseCache
|
||||
@Inject lateinit var passphraseCache: PGPPassphraseCache
|
||||
@Inject lateinit var features: Features
|
||||
|
||||
private val binding by viewBinding(DecryptLayoutBinding::inflate)
|
||||
|
@ -67,7 +67,7 @@ class DecryptActivity : BasePgpActivity() {
|
|||
}
|
||||
}
|
||||
if (
|
||||
features.isEnabled(EnableGPGPassphraseCache) &&
|
||||
features.isEnabled(EnablePGPPassphraseCache) &&
|
||||
BiometricAuthenticator.canAuthenticate(this@DecryptActivity)
|
||||
) {
|
||||
BiometricAuthenticator.authenticate(
|
||||
|
@ -150,7 +150,7 @@ class DecryptActivity : BasePgpActivity() {
|
|||
}
|
||||
|
||||
private fun decrypt(isError: Boolean, authResult: BiometricAuthenticator.Result) {
|
||||
val gpgIdentifiers = getGpgIdentifiers("") ?: return
|
||||
val gpgIdentifiers = getPGPIdentifiers("") ?: return
|
||||
lifecycleScope.launch(dispatcherProvider.main()) {
|
||||
if (authResult is BiometricAuthenticator.Result.Success) {
|
||||
val cachedPassphrase =
|
||||
|
@ -168,7 +168,7 @@ class DecryptActivity : BasePgpActivity() {
|
|||
|
||||
private fun askPassphrase(
|
||||
isError: Boolean,
|
||||
gpgIdentifiers: List<GpgIdentifier>,
|
||||
gpgIdentifiers: List<PGPIdentifier>,
|
||||
authResult: BiometricAuthenticator.Result,
|
||||
) {
|
||||
if (retries < MAX_RETRIES) {
|
||||
|
@ -206,7 +206,7 @@ class DecryptActivity : BasePgpActivity() {
|
|||
|
||||
private suspend fun decryptWithCachedPassphrase(
|
||||
passphrase: String,
|
||||
identifiers: List<GpgIdentifier>,
|
||||
identifiers: List<PGPIdentifier>,
|
||||
authResult: BiometricAuthenticator.Result,
|
||||
) {
|
||||
when (val result = decryptWithPassphrase(passphrase, identifiers)) {
|
||||
|
@ -225,7 +225,7 @@ class DecryptActivity : BasePgpActivity() {
|
|||
|
||||
private suspend fun decryptWithPassphrase(
|
||||
password: String,
|
||||
gpgIdentifiers: List<GpgIdentifier>,
|
||||
gpgIdentifiers: List<PGPIdentifier>,
|
||||
) = runCatching {
|
||||
val message = withContext(dispatcherProvider.io()) { File(fullPath).readBytes().inputStream() }
|
||||
val outputStream = ByteArrayOutputStream()
|
||||
|
|
|
@ -63,7 +63,7 @@ import logcat.asLog
|
|||
import logcat.logcat
|
||||
|
||||
@AndroidEntryPoint
|
||||
class PasswordCreationActivity : BasePgpActivity() {
|
||||
class PasswordCreationActivity : BasePGPActivity() {
|
||||
|
||||
private val binding by viewBinding(PasswordCreationActivityBinding::inflate)
|
||||
@Inject lateinit var passwordEntryFactory: PasswordEntry.Factory
|
||||
|
@ -330,7 +330,7 @@ class PasswordCreationActivity : BasePgpActivity() {
|
|||
}
|
||||
|
||||
// pass enters the key ID into `.gpg-id`.
|
||||
val gpgIdentifiers = getGpgIdentifiers(directory.text.toString()) ?: return@with
|
||||
val gpgIdentifiers = getPGPIdentifiers(directory.text.toString()) ?: return@with
|
||||
val content = "$editPass\n$editExtra"
|
||||
val path =
|
||||
when {
|
||||
|
|
|
@ -11,7 +11,7 @@ import android.os.Handler
|
|||
import android.os.Looper
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.edit
|
||||
import app.passwordstore.ui.crypto.BasePgpActivity
|
||||
import app.passwordstore.ui.crypto.BasePGPActivity
|
||||
import app.passwordstore.ui.crypto.DecryptActivity
|
||||
import app.passwordstore.ui.passwords.PasswordStore
|
||||
import app.passwordstore.util.auth.BiometricAuthenticator
|
||||
|
@ -56,12 +56,12 @@ class LaunchActivity : AppCompatActivity() {
|
|||
if (intent.action == ACTION_DECRYPT_PASS)
|
||||
getDecryptIntent().apply {
|
||||
putExtra(
|
||||
BasePgpActivity.EXTRA_FILE_PATH,
|
||||
intent.getStringExtra(BasePgpActivity.EXTRA_FILE_PATH)
|
||||
BasePGPActivity.EXTRA_FILE_PATH,
|
||||
intent.getStringExtra(BasePGPActivity.EXTRA_FILE_PATH)
|
||||
)
|
||||
putExtra(
|
||||
BasePgpActivity.EXTRA_REPO_PATH,
|
||||
intent.getStringExtra(BasePgpActivity.EXTRA_REPO_PATH)
|
||||
BasePGPActivity.EXTRA_REPO_PATH,
|
||||
intent.getStringExtra(BasePGPActivity.EXTRA_REPO_PATH)
|
||||
)
|
||||
}
|
||||
else Intent(this, PasswordStore::class.java)
|
||||
|
|
|
@ -25,8 +25,8 @@ import androidx.lifecycle.lifecycleScope
|
|||
import app.passwordstore.R
|
||||
import app.passwordstore.data.password.PasswordItem
|
||||
import app.passwordstore.data.repo.PasswordRepository
|
||||
import app.passwordstore.ui.crypto.BasePgpActivity
|
||||
import app.passwordstore.ui.crypto.BasePgpActivity.Companion.getLongName
|
||||
import app.passwordstore.ui.crypto.BasePGPActivity
|
||||
import app.passwordstore.ui.crypto.BasePGPActivity.Companion.getLongName
|
||||
import app.passwordstore.ui.crypto.DecryptActivity
|
||||
import app.passwordstore.ui.crypto.PasswordCreationActivity
|
||||
import app.passwordstore.ui.dialogs.FolderCreationDialogFragment
|
||||
|
@ -393,9 +393,9 @@ class PasswordStore : BaseGitActivity() {
|
|||
val currentDir = currentDir
|
||||
logcat(INFO) { "Adding file to : ${currentDir.absolutePath}" }
|
||||
val intent = Intent(this, PasswordCreationActivity::class.java)
|
||||
intent.putExtra(BasePgpActivity.EXTRA_FILE_PATH, currentDir.absolutePath)
|
||||
intent.putExtra(BasePGPActivity.EXTRA_FILE_PATH, currentDir.absolutePath)
|
||||
intent.putExtra(
|
||||
BasePgpActivity.EXTRA_REPO_PATH,
|
||||
BasePGPActivity.EXTRA_REPO_PATH,
|
||||
PasswordRepository.getRepositoryDirectory().absolutePath
|
||||
)
|
||||
listRefreshAction.launch(intent)
|
||||
|
|
|
@ -32,7 +32,7 @@ import androidx.compose.ui.text.style.TextOverflow
|
|||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import app.passwordstore.R
|
||||
import app.passwordstore.crypto.GpgIdentifier
|
||||
import app.passwordstore.crypto.PGPIdentifier
|
||||
import app.passwordstore.ui.compose.theme.APSThemePreview
|
||||
import app.passwordstore.util.extensions.conditional
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
@ -41,10 +41,10 @@ import kotlinx.collections.immutable.toPersistentList
|
|||
|
||||
@Composable
|
||||
fun KeyList(
|
||||
identifiers: ImmutableList<GpgIdentifier>,
|
||||
onItemClick: (identifier: GpgIdentifier) -> Unit,
|
||||
identifiers: ImmutableList<PGPIdentifier>,
|
||||
onItemClick: (identifier: PGPIdentifier) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
onKeySelected: ((identifier: GpgIdentifier) -> Unit)? = null,
|
||||
onKeySelected: ((identifier: PGPIdentifier) -> Unit)? = null,
|
||||
) {
|
||||
if (identifiers.isEmpty()) {
|
||||
Column(
|
||||
|
@ -69,10 +69,10 @@ fun KeyList(
|
|||
|
||||
@Composable
|
||||
private fun KeyItem(
|
||||
identifier: GpgIdentifier,
|
||||
onItemClick: (identifier: GpgIdentifier) -> Unit,
|
||||
identifier: PGPIdentifier,
|
||||
onItemClick: (identifier: PGPIdentifier) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
onKeySelected: ((identifier: GpgIdentifier) -> Unit)? = null,
|
||||
onKeySelected: ((identifier: PGPIdentifier) -> Unit)? = null,
|
||||
) {
|
||||
var isDeleting by remember { mutableStateOf(false) }
|
||||
DeleteConfirmationDialog(
|
||||
|
@ -85,8 +85,8 @@ private fun KeyItem(
|
|||
)
|
||||
val label =
|
||||
when (identifier) {
|
||||
is GpgIdentifier.KeyId -> identifier.id.toString()
|
||||
is GpgIdentifier.UserId -> identifier.email
|
||||
is PGPIdentifier.KeyId -> identifier.id.toString()
|
||||
is PGPIdentifier.UserId -> identifier.email
|
||||
}
|
||||
Row(
|
||||
modifier =
|
||||
|
@ -144,8 +144,8 @@ private fun KeyListPreview() {
|
|||
KeyList(
|
||||
identifiers =
|
||||
listOfNotNull(
|
||||
GpgIdentifier.fromString("ultramicroscopicsilicovolcanoconiosis@example.com"),
|
||||
GpgIdentifier.fromString("0xB950AE2813841585"),
|
||||
PGPIdentifier.fromString("ultramicroscopicsilicovolcanoconiosis@example.com"),
|
||||
PGPIdentifier.fromString("0xB950AE2813841585"),
|
||||
)
|
||||
.toPersistentList(),
|
||||
onItemClick = {}
|
||||
|
|
|
@ -32,7 +32,7 @@ class PGPSettings(private val activity: FragmentActivity) : SettingsProvider {
|
|||
titleRes = R.string.pref_pgp_ascii_armor_title
|
||||
persistent = true
|
||||
}
|
||||
switch(Feature.EnableGPGPassphraseCache.configKey) {
|
||||
switch(Feature.EnablePGPPassphraseCache.configKey) {
|
||||
titleRes = R.string.pref_passphrase_cache_title
|
||||
summaryRes = R.string.pref_passphrase_cache_summary
|
||||
defaultValue = false
|
||||
|
|
|
@ -23,8 +23,8 @@ enum class Feature(
|
|||
/** Opt into the new SSH layer implemented as a freestanding module. */
|
||||
EnableNewSSHLayer(false, "enable_new_ssh"),
|
||||
|
||||
/** Opt into a cache layer for GPG passphrases. */
|
||||
EnableGPGPassphraseCache(false, "enable_gpg_passphrase_cache"),
|
||||
/** Opt into a cache layer for PGP passphrases. */
|
||||
EnablePGPPassphraseCache(false, "enable_gpg_passphrase_cache"),
|
||||
;
|
||||
|
||||
companion object {
|
||||
|
|
|
@ -5,8 +5,8 @@ import androidx.compose.runtime.mutableStateOf
|
|||
import androidx.compose.runtime.setValue
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import app.passwordstore.crypto.GpgIdentifier
|
||||
import app.passwordstore.crypto.KeyUtils
|
||||
import app.passwordstore.crypto.PGPIdentifier
|
||||
import app.passwordstore.crypto.PGPKeyManager
|
||||
import com.github.michaelbull.result.Err
|
||||
import com.github.michaelbull.result.Ok
|
||||
|
@ -20,7 +20,7 @@ import kotlinx.coroutines.launch
|
|||
|
||||
@HiltViewModel
|
||||
class PGPKeyListViewModel @Inject constructor(private val keyManager: PGPKeyManager) : ViewModel() {
|
||||
var keys: ImmutableList<GpgIdentifier> by mutableStateOf(persistentListOf())
|
||||
var keys: ImmutableList<PGPIdentifier> by mutableStateOf(persistentListOf())
|
||||
|
||||
init {
|
||||
updateKeySet()
|
||||
|
@ -40,7 +40,7 @@ class PGPKeyListViewModel @Inject constructor(private val keyManager: PGPKeyMana
|
|||
}
|
||||
}
|
||||
|
||||
fun deleteKey(identifier: GpgIdentifier) {
|
||||
fun deleteKey(identifier: PGPIdentifier) {
|
||||
viewModelScope.launch {
|
||||
keyManager.removeKey(identifier)
|
||||
updateKeySet()
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
|
||||
package app.passwordstore.crypto
|
||||
|
||||
import app.passwordstore.crypto.GpgIdentifier.KeyId
|
||||
import app.passwordstore.crypto.GpgIdentifier.UserId
|
||||
import app.passwordstore.crypto.PGPIdentifier.KeyId
|
||||
import app.passwordstore.crypto.PGPIdentifier.UserId
|
||||
import com.github.michaelbull.result.get
|
||||
import com.github.michaelbull.result.runCatching
|
||||
import org.bouncycastle.openpgp.PGPKeyRing
|
||||
|
|
|
@ -8,11 +8,11 @@ package app.passwordstore.crypto
|
|||
import java.util.Locale
|
||||
import java.util.regex.Pattern
|
||||
|
||||
/** Supertype for valid identifiers of GPG keys. */
|
||||
public sealed class GpgIdentifier {
|
||||
/** Supertype for valid identifiers of PGP keys. */
|
||||
public sealed class PGPIdentifier {
|
||||
|
||||
/** A [GpgIdentifier] that represents either a long key ID or a fingerprint. */
|
||||
public data class KeyId(val id: Long) : GpgIdentifier() {
|
||||
/** A [PGPIdentifier] that represents either a long key ID or a fingerprint. */
|
||||
public data class KeyId(val id: Long) : PGPIdentifier() {
|
||||
override fun toString(): String {
|
||||
return convertKeyIdToHex(id)
|
||||
}
|
||||
|
@ -36,10 +36,10 @@ public sealed class GpgIdentifier {
|
|||
}
|
||||
|
||||
/**
|
||||
* A [GpgIdentifier] that represents the textual name/email combination corresponding to a key.
|
||||
* A [PGPIdentifier] that represents the textual name/email combination corresponding to a key.
|
||||
* Despite the [email] property in this class, the value is not guaranteed to be a valid email.
|
||||
*/
|
||||
public data class UserId(val email: String) : GpgIdentifier() {
|
||||
public data class UserId(val email: String) : PGPIdentifier() {
|
||||
override fun toString(): String {
|
||||
return email
|
||||
}
|
||||
|
@ -53,10 +53,10 @@ public sealed class GpgIdentifier {
|
|||
private const val TRUNCATED_FINGERPRINT_LENGTH = 16
|
||||
|
||||
/**
|
||||
* Attempts to parse an untyped String identifier into a concrete subtype of [GpgIdentifier].
|
||||
* Attempts to parse an untyped String identifier into a concrete subtype of [PGPIdentifier].
|
||||
*/
|
||||
@Suppress("ReturnCount")
|
||||
public fun fromString(identifier: String): GpgIdentifier? {
|
||||
public fun fromString(identifier: String): PGPIdentifier? {
|
||||
if (identifier.isEmpty()) return null
|
||||
// Match long key IDs:
|
||||
// FF22334455667788 or 0xFF22334455667788
|
|
@ -32,7 +32,7 @@ public class PGPKeyManager
|
|||
constructor(
|
||||
filesDir: String,
|
||||
private val dispatcher: CoroutineDispatcher,
|
||||
) : KeyManager<PGPKey, GpgIdentifier> {
|
||||
) : KeyManager<PGPKey, PGPIdentifier> {
|
||||
|
||||
private val keyDir = File(filesDir, KEY_DIR_NAME)
|
||||
|
||||
|
@ -74,7 +74,7 @@ constructor(
|
|||
}
|
||||
|
||||
/** @see KeyManager.removeKey */
|
||||
override suspend fun removeKey(identifier: GpgIdentifier): Result<Unit, Throwable> =
|
||||
override suspend fun removeKey(identifier: PGPIdentifier): Result<Unit, Throwable> =
|
||||
withContext(dispatcher) {
|
||||
runSuspendCatching {
|
||||
if (!keyDirExists()) throw KeyDirectoryUnavailableException
|
||||
|
@ -87,7 +87,7 @@ constructor(
|
|||
}
|
||||
|
||||
/** @see KeyManager.getKeyById */
|
||||
override suspend fun getKeyById(id: GpgIdentifier): Result<PGPKey, Throwable> =
|
||||
override suspend fun getKeyById(id: PGPIdentifier): Result<PGPKey, Throwable> =
|
||||
withContext(dispatcher) {
|
||||
runSuspendCatching {
|
||||
if (!keyDirExists()) throw KeyDirectoryUnavailableException
|
||||
|
@ -97,14 +97,14 @@ constructor(
|
|||
|
||||
val matchResult =
|
||||
when (id) {
|
||||
is GpgIdentifier.KeyId -> {
|
||||
is PGPIdentifier.KeyId -> {
|
||||
val keyIdMatch =
|
||||
keys
|
||||
.map { key -> key to tryGetId(key) }
|
||||
.firstOrNull { (_, keyId) -> keyId?.id == id.id }
|
||||
keyIdMatch?.first
|
||||
}
|
||||
is GpgIdentifier.UserId -> {
|
||||
is PGPIdentifier.UserId -> {
|
||||
val selector = SelectUserId.byEmail(id.email)
|
||||
val userIdMatch =
|
||||
keys
|
||||
|
@ -134,7 +134,7 @@ constructor(
|
|||
}
|
||||
|
||||
/** @see KeyManager.getKeyById */
|
||||
override suspend fun getKeyId(key: PGPKey): GpgIdentifier? = tryGetId(key)
|
||||
override suspend fun getKeyId(key: PGPKey): PGPIdentifier? = tryGetId(key)
|
||||
|
||||
/** Checks if [keyDir] exists and attempts to create it if not. */
|
||||
private fun keyDirExists(): Boolean {
|
||||
|
|
|
@ -18,7 +18,7 @@ class KeyUtilsTest {
|
|||
assertIs<PGPSecretKeyRing>(keyring)
|
||||
val keyId = tryGetId(key)
|
||||
assertNotNull(keyId)
|
||||
assertIs<GpgIdentifier.KeyId>(keyId)
|
||||
assertIs<PGPIdentifier.KeyId>(keyId)
|
||||
assertEquals("b950ae2813841585", keyId.toString())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,33 +9,33 @@ import kotlin.test.Test
|
|||
import kotlin.test.assertNotNull
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class GpgIdentifierTest {
|
||||
class PGPIdentifierTest {
|
||||
|
||||
@Test
|
||||
fun parseHexKeyIdWithout0xPrefix() {
|
||||
val identifier = GpgIdentifier.fromString("79E8208280490C77")
|
||||
val identifier = PGPIdentifier.fromString("79E8208280490C77")
|
||||
assertNotNull(identifier)
|
||||
assertTrue { identifier is GpgIdentifier.KeyId }
|
||||
assertTrue { identifier is PGPIdentifier.KeyId }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun parseHexKeyId() {
|
||||
val identifier = GpgIdentifier.fromString("0x79E8208280490C77")
|
||||
val identifier = PGPIdentifier.fromString("0x79E8208280490C77")
|
||||
assertNotNull(identifier)
|
||||
assertTrue { identifier is GpgIdentifier.KeyId }
|
||||
assertTrue { identifier is PGPIdentifier.KeyId }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun parseValidEmail() {
|
||||
val identifier = GpgIdentifier.fromString("john.doe@example.org")
|
||||
val identifier = PGPIdentifier.fromString("john.doe@example.org")
|
||||
assertNotNull(identifier)
|
||||
assertTrue { identifier is GpgIdentifier.UserId }
|
||||
assertTrue { identifier is PGPIdentifier.UserId }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun parseEmailWithoutTLD() {
|
||||
val identifier = GpgIdentifier.fromString("john.doe@example")
|
||||
val identifier = PGPIdentifier.fromString("john.doe@example")
|
||||
assertNotNull(identifier)
|
||||
assertTrue { identifier is GpgIdentifier.UserId }
|
||||
assertTrue { identifier is PGPIdentifier.UserId }
|
||||
}
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
package app.passwordstore.crypto
|
||||
|
||||
import app.passwordstore.crypto.GpgIdentifier.KeyId
|
||||
import app.passwordstore.crypto.GpgIdentifier.UserId
|
||||
import app.passwordstore.crypto.KeyUtils.tryGetId
|
||||
import app.passwordstore.crypto.PGPIdentifier.KeyId
|
||||
import app.passwordstore.crypto.PGPIdentifier.UserId
|
||||
import app.passwordstore.crypto.errors.KeyAlreadyExistsException
|
||||
import app.passwordstore.crypto.errors.KeyNotFoundException
|
||||
import app.passwordstore.crypto.errors.NoKeysAvailableException
|
||||
|
|
Loading…
Reference in a new issue