Skip to content
This repository was archived by the owner on Oct 15, 2024. It is now read-only.

Commit 2d74bda

Browse files
committed
crypto-pgp: make key lookups more robust
1 parent 78a6e37 commit 2d74bda

File tree

1 file changed

+44
-12
lines changed

1 file changed

+44
-12
lines changed

crypto-pgp/src/main/kotlin/dev/msfjarvis/aps/data/crypto/GPGKeyManager.kt

Lines changed: 44 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package dev.msfjarvis.aps.data.crypto
22

33
import com.github.michaelbull.result.Err
44
import com.github.michaelbull.result.Result
5+
import com.github.michaelbull.result.expect
56
import com.github.michaelbull.result.map
67
import com.github.michaelbull.result.runCatching
78
import com.proton.Gopenpgp.crypto.Crypto
@@ -62,15 +63,13 @@ public class GPGKeyManager(
6263
if (!keyDirExists())
6364
return@withContext Err(IllegalStateException("Key directory does not exist"))
6465

65-
return@withContext runCatching {
66-
keyDir.listFiles()?.forEach { file ->
67-
if (file.isFile && file.nameWithoutExtension.lowercase() == id.lowercase()) {
68-
val fileContent = file.readText()
69-
return@runCatching keyFactory.create(Key(fileContent))
66+
runCatching {
67+
val keys = getGopenpgpKeys().expect { "Failed to get PGP keys" }
68+
return@runCatching keyFactory.create(
69+
keys.first { key ->
70+
return@first getKeyIdentities(key).matches(id)
7071
}
71-
}
72-
73-
error("Key with id: $id not found in directory")
72+
)
7473
}
7574
}
7675

@@ -94,19 +93,52 @@ public class GPGKeyManager(
9493
}
9594

9695
override suspend fun getAllKeyIds(): Result<List<String>, Throwable> =
97-
withContext(dispatcher) {
98-
getAllKeys().map { keys -> keys.map { it.getKeyId() } }
99-
}
96+
withContext(dispatcher) { getAllKeys().map { keys -> keys.map { it.getKeyId() } } }
10097

10198
override fun canHandle(fileName: String): Boolean {
102-
println("Checking in " + javaClass.simpleName)
10399
return fileName.split('.').last() == "gpg"
104100
}
105101

102+
private suspend fun getGopenpgpKeys(): Result<List<Key>, Throwable> = runCatching {
103+
withContext(dispatcher) {
104+
(keyDir.listFiles() ?: emptyArray()).map { file -> Crypto.newKeyFromArmored(file.readText()) }
105+
}
106+
}
107+
108+
private fun getKeyIdentities(key: Key): KeyIdentities {
109+
val keyId = key.hexKeyID
110+
val fingerprint = key.fingerprint
111+
val email = key.userEmail
112+
return KeyIdentities.create(keyId, fingerprint, email)
113+
}
114+
106115
private fun keyDirExists(): Boolean {
107116
return keyDir.exists() || keyDir.mkdir()
108117
}
109118

119+
/** Container class for identifying properties of a GPG key */
120+
private class KeyIdentities
121+
private constructor(val keyId: String, val fingerprint: String, val email: String) {
122+
fun matches(identifier: String): Boolean {
123+
val ident = identifier.lowercase()
124+
return ident == keyId || ident == fingerprint || ident == email || ident == "<$email>"
125+
}
126+
127+
companion object {
128+
fun create(
129+
keyId: String,
130+
fingerprint: String,
131+
email: String,
132+
): KeyIdentities {
133+
return KeyIdentities(
134+
keyId.lowercase(),
135+
fingerprint.lowercase(),
136+
email.lowercase(),
137+
)
138+
}
139+
}
140+
}
141+
110142
private companion object {
111143

112144
private const val KeyDir = "gpg-keys"

0 commit comments

Comments
 (0)