refactor: move out GPG identifier parser to BasePgpActivity

This commit is contained in:
Harsh Shandilya 2023-05-08 01:49:23 +05:30
parent 136f4e5caa
commit df58f484ac
No known key found for this signature in database
2 changed files with 54 additions and 44 deletions

View file

@ -18,7 +18,9 @@ import androidx.annotation.StringRes
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import app.passwordstore.R import app.passwordstore.R
import app.passwordstore.crypto.GpgIdentifier
import app.passwordstore.data.crypto.CryptoRepository import app.passwordstore.data.crypto.CryptoRepository
import app.passwordstore.data.repo.PasswordRepository
import app.passwordstore.injection.prefs.SettingsPreferences import app.passwordstore.injection.prefs.SettingsPreferences
import app.passwordstore.ui.pgp.PGPKeyImportActivity import app.passwordstore.ui.pgp.PGPKeyImportActivity
import app.passwordstore.util.coroutines.DispatcherProvider import app.passwordstore.util.coroutines.DispatcherProvider
@ -150,6 +152,57 @@ open class BasePgpActivity : AppCompatActivity() {
} }
} }
/**
* Get a list of available [GpgIdentifier]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>? {
val repoRoot = PasswordRepository.getRepositoryDirectory()
val gpgIdentifierFile =
File(repoRoot, subDir).findTillRoot(".gpg-id", repoRoot)
?: File(repoRoot, ".gpg-id").apply { createNewFile() }
val gpgIdentifiers =
gpgIdentifierFile
.readLines()
.filter { it.isNotBlank() }
.map { line ->
GpgIdentifier.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
// real ID.
if (line.isEmpty()) return@run
if (line.removePrefix("0x").matches("[a-fA-F0-9]{8}".toRegex()).not()) {
snackbar(message = resources.getString(R.string.invalid_gpg_id))
}
return null
}
}
.filterIsInstance<GpgIdentifier>()
if (gpgIdentifiers.isEmpty()) {
error("Failed to parse identifiers from .gpg-id: ${gpgIdentifierFile.readText()}")
}
return gpgIdentifiers
}
@Suppress("ReturnCount")
private fun File.findTillRoot(fileName: String, rootPath: File): File? {
val gpgFile = File(this, fileName)
if (gpgFile.exists()) return gpgFile
if (this.absolutePath == rootPath.absolutePath) {
return null
}
val parent = parentFile
return if (parent != null && parent.exists()) {
parent.findTillRoot(fileName, rootPath)
} else {
null
}
}
companion object { companion object {
const val EXTRA_FILE_PATH = "FILE_PATH" const val EXTRA_FILE_PATH = "FILE_PATH"

View file

@ -24,9 +24,7 @@ import androidx.core.view.isVisible
import androidx.core.widget.doAfterTextChanged import androidx.core.widget.doAfterTextChanged
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import app.passwordstore.R import app.passwordstore.R
import app.passwordstore.crypto.GpgIdentifier
import app.passwordstore.data.passfile.PasswordEntry import app.passwordstore.data.passfile.PasswordEntry
import app.passwordstore.data.repo.PasswordRepository
import app.passwordstore.databinding.PasswordCreationActivityBinding import app.passwordstore.databinding.PasswordCreationActivityBinding
import app.passwordstore.ui.dialogs.DicewarePasswordGeneratorDialogFragment import app.passwordstore.ui.dialogs.DicewarePasswordGeneratorDialogFragment
import app.passwordstore.ui.dialogs.OtpImportDialogFragment import app.passwordstore.ui.dialogs.OtpImportDialogFragment
@ -333,31 +331,7 @@ class PasswordCreationActivity : BasePgpActivity() {
} }
// pass enters the key ID into `.gpg-id`. // pass enters the key ID into `.gpg-id`.
val repoRoot = PasswordRepository.getRepositoryDirectory() val gpgIdentifiers = getGpgIdentifiers(directory.text.toString()) ?: return@with
val gpgIdentifierFile =
File(repoRoot, directory.text.toString()).findTillRoot(".gpg-id", repoRoot)
?: File(repoRoot, ".gpg-id").apply { createNewFile() }
val gpgIdentifiers =
gpgIdentifierFile
.readLines()
.filter { it.isNotBlank() }
.map { line ->
GpgIdentifier.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
// real ID.
if (line.isEmpty()) return@run
if (line.removePrefix("0x").matches("[a-fA-F0-9]{8}".toRegex()).not()) {
snackbar(message = resources.getString(R.string.invalid_gpg_id))
}
return@with
}
}
.filterIsInstance<GpgIdentifier>()
if (gpgIdentifiers.isEmpty()) {
error("Failed to parse identifiers from .gpg-id: ${gpgIdentifierFile.readText()}")
}
val content = "$editPass\n$editExtra" val content = "$editPass\n$editExtra"
val path = val path =
when { when {
@ -483,23 +457,6 @@ class PasswordCreationActivity : BasePgpActivity() {
} }
} }
@Suppress("ReturnCount")
private fun File.findTillRoot(fileName: String, rootPath: File): File? {
val gpgFile = File(this, fileName)
if (gpgFile.exists()) return gpgFile
if (this.absolutePath == rootPath.absolutePath) {
return null
}
val parent = parentFile
return if (parent != null && parent.exists()) {
parent.findTillRoot(fileName, rootPath)
} else {
null
}
}
companion object { companion object {
private const val KEY_PWGEN_TYPE_CLASSIC = "classic" private const val KEY_PWGEN_TYPE_CLASSIC = "classic"