crypto-pgpainless: allow updating existing keys automatically for specific cases
This commit is contained in:
parent
236c2719fa
commit
b9f4da71ea
2 changed files with 77 additions and 19 deletions
|
@ -21,6 +21,9 @@ import java.io.File
|
|||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.bouncycastle.openpgp.PGPPublicKeyRing
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRing
|
||||
import org.pgpainless.PGPainless
|
||||
import org.pgpainless.util.selection.userid.SelectUserId
|
||||
|
||||
public class PGPKeyManager
|
||||
|
@ -36,9 +39,24 @@ constructor(
|
|||
withContext(dispatcher) {
|
||||
runSuspendCatching {
|
||||
if (!keyDirExists()) throw KeyDirectoryUnavailableException
|
||||
if (tryParseKeyring(key) == null) throw InvalidKeyException
|
||||
val incomingKeyRing = tryParseKeyring(key) ?: throw InvalidKeyException
|
||||
val keyFile = File(keyDir, "${tryGetId(key)}.$KEY_EXTENSION")
|
||||
if (keyFile.exists()) {
|
||||
val existingKeyBytes = keyFile.readBytes()
|
||||
val existingKeyRing =
|
||||
tryParseKeyring(PGPKey(existingKeyBytes)) ?: throw InvalidKeyException
|
||||
when {
|
||||
existingKeyRing is PGPPublicKeyRing && incomingKeyRing is PGPSecretKeyRing -> {
|
||||
keyFile.writeBytes(key.contents)
|
||||
return@runSuspendCatching key
|
||||
}
|
||||
existingKeyRing is PGPPublicKeyRing && incomingKeyRing is PGPPublicKeyRing -> {
|
||||
val updatedPublicKey = PGPainless.mergeCertificate(existingKeyRing, incomingKeyRing)
|
||||
val keyBytes = PGPainless.asciiArmor(updatedPublicKey).encodeToByteArray()
|
||||
keyFile.writeBytes(keyBytes)
|
||||
return@runSuspendCatching key
|
||||
}
|
||||
}
|
||||
// Check for replace flag first and if it is false, throw an error
|
||||
if (!replace)
|
||||
throw KeyAlreadyExistsException(
|
||||
|
|
|
@ -6,6 +6,8 @@ import app.passwordstore.crypto.TestUtils.getArmoredPrivateKeyWithMultipleIdenti
|
|||
import app.passwordstore.crypto.errors.KeyAlreadyExistsException
|
||||
import app.passwordstore.crypto.errors.KeyNotFoundException
|
||||
import app.passwordstore.crypto.errors.NoKeysAvailableException
|
||||
import com.github.michaelbull.result.Err
|
||||
import com.github.michaelbull.result.Ok
|
||||
import com.github.michaelbull.result.unwrap
|
||||
import com.github.michaelbull.result.unwrapError
|
||||
import java.io.File
|
||||
|
@ -35,7 +37,8 @@ class PGPKeyManagerTest {
|
|||
private val dispatcher = StandardTestDispatcher()
|
||||
private val scope = TestScope(dispatcher)
|
||||
private val keyManager by unsafeLazy { PGPKeyManager(filesDir.absolutePath, dispatcher) }
|
||||
private val key = PGPKey(TestUtils.getArmoredPrivateKey())
|
||||
private val privateKey = PGPKey(TestUtils.getArmoredPrivateKey())
|
||||
private val publicKey = PGPKey(TestUtils.getArmoredPublicKey())
|
||||
|
||||
private fun <T> unsafeLazy(initializer: () -> T) =
|
||||
lazy(LazyThreadSafetyMode.NONE) { initializer.invoke() }
|
||||
|
@ -54,7 +57,7 @@ class PGPKeyManagerTest {
|
|||
fun addKey() =
|
||||
scope.runTest {
|
||||
// Check if the key id returned is correct
|
||||
val keyId = keyManager.getKeyId(keyManager.addKey(key).unwrap())
|
||||
val keyId = keyManager.getKeyId(keyManager.addKey(privateKey).unwrap())
|
||||
assertEquals(KeyId(CryptoConstants.KEY_ID), keyId)
|
||||
|
||||
// Check if the keys directory have one file
|
||||
|
@ -69,8 +72,8 @@ class PGPKeyManagerTest {
|
|||
fun addKeyWithoutReplaceFlag() =
|
||||
scope.runTest {
|
||||
// Check adding the keys twice
|
||||
keyManager.addKey(key, false).unwrap()
|
||||
val error = keyManager.addKey(key, false).unwrapError()
|
||||
keyManager.addKey(privateKey, false).unwrap()
|
||||
val error = keyManager.addKey(privateKey, false).unwrapError()
|
||||
|
||||
assertIs<KeyAlreadyExistsException>(error)
|
||||
}
|
||||
|
@ -79,8 +82,8 @@ class PGPKeyManagerTest {
|
|||
fun addKeyWithReplaceFlag() =
|
||||
scope.runTest {
|
||||
// Check adding the keys twice
|
||||
keyManager.addKey(key, true).unwrap()
|
||||
val keyId = keyManager.getKeyId(keyManager.addKey(key, true).unwrap())
|
||||
keyManager.addKey(privateKey, true).unwrap()
|
||||
val keyId = keyManager.getKeyId(keyManager.addKey(privateKey, true).unwrap())
|
||||
|
||||
assertEquals(KeyId(CryptoConstants.KEY_ID), keyId)
|
||||
}
|
||||
|
@ -89,10 +92,10 @@ class PGPKeyManagerTest {
|
|||
fun removeKey() =
|
||||
scope.runTest {
|
||||
// Add key using KeyManager
|
||||
keyManager.addKey(key).unwrap()
|
||||
keyManager.addKey(privateKey).unwrap()
|
||||
|
||||
// Check if the key id returned is correct
|
||||
val keyId = keyManager.getKeyId(keyManager.removeKey(key).unwrap())
|
||||
val keyId = keyManager.getKeyId(keyManager.removeKey(privateKey).unwrap())
|
||||
assertEquals(KeyId(CryptoConstants.KEY_ID), keyId)
|
||||
|
||||
// Check if the keys directory have 0 files
|
||||
|
@ -104,42 +107,42 @@ class PGPKeyManagerTest {
|
|||
fun getKeyById() =
|
||||
scope.runTest {
|
||||
// Add key using KeyManager
|
||||
keyManager.addKey(key).unwrap()
|
||||
keyManager.addKey(privateKey).unwrap()
|
||||
|
||||
val keyId = keyManager.getKeyId(key)
|
||||
val keyId = keyManager.getKeyId(privateKey)
|
||||
assertNotNull(keyId)
|
||||
assertEquals(KeyId(CryptoConstants.KEY_ID), keyManager.getKeyId(key))
|
||||
assertEquals(KeyId(CryptoConstants.KEY_ID), keyManager.getKeyId(privateKey))
|
||||
|
||||
// Check returned key id matches the expected id and the created key id
|
||||
val returnedKey = keyManager.getKeyById(keyId).unwrap()
|
||||
assertEquals(keyManager.getKeyId(key), keyManager.getKeyId(returnedKey))
|
||||
assertEquals(keyManager.getKeyId(privateKey), keyManager.getKeyId(returnedKey))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getKeyByFullUserId() =
|
||||
scope.runTest {
|
||||
keyManager.addKey(key).unwrap()
|
||||
keyManager.addKey(privateKey).unwrap()
|
||||
|
||||
val keyId = "${CryptoConstants.KEY_NAME} <${CryptoConstants.KEY_EMAIL}>"
|
||||
val returnedKey = keyManager.getKeyById(UserId(keyId)).unwrap()
|
||||
assertEquals(keyManager.getKeyId(key), keyManager.getKeyId(returnedKey))
|
||||
assertEquals(keyManager.getKeyId(privateKey), keyManager.getKeyId(returnedKey))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getKeyByEmailUserId() =
|
||||
scope.runTest {
|
||||
keyManager.addKey(key).unwrap()
|
||||
keyManager.addKey(privateKey).unwrap()
|
||||
|
||||
val keyId = CryptoConstants.KEY_EMAIL
|
||||
val returnedKey = keyManager.getKeyById(UserId(keyId)).unwrap()
|
||||
assertEquals(keyManager.getKeyId(key), keyManager.getKeyId(returnedKey))
|
||||
assertEquals(keyManager.getKeyId(privateKey), keyManager.getKeyId(returnedKey))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getNonExistentKey() =
|
||||
scope.runTest {
|
||||
// Add key using KeyManager
|
||||
keyManager.addKey(key).unwrap()
|
||||
keyManager.addKey(privateKey).unwrap()
|
||||
|
||||
val keyId = KeyId(0x08edf7567183ce44)
|
||||
|
||||
|
@ -166,7 +169,7 @@ class PGPKeyManagerTest {
|
|||
assertEquals(0, noKeyList.size)
|
||||
|
||||
// Add key using KeyManager
|
||||
keyManager.addKey(key).unwrap()
|
||||
keyManager.addKey(privateKey).unwrap()
|
||||
keyManager.addKey(PGPKey(getArmoredPrivateKeyWithMultipleIdentities())).unwrap()
|
||||
|
||||
// Check if KeyManager returns one key
|
||||
|
@ -186,4 +189,41 @@ class PGPKeyManagerTest {
|
|||
assertContentEquals(johnKey.contents, janeKey.contents)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun replacePrivateKeyWithPublicKey() {
|
||||
scope.runTest {
|
||||
assertIs<Ok<PGPKey>>(keyManager.addKey(privateKey))
|
||||
assertIs<Err<KeyAlreadyExistsException>>(keyManager.addKey(publicKey))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun replacePublicKeyWithSecretKey() {
|
||||
scope.runTest {
|
||||
assertIs<Ok<PGPKey>>(keyManager.addKey(publicKey))
|
||||
assertIs<Ok<PGPKey>>(keyManager.addKey(privateKey))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun replacePublicKeyWithPublicKey() {
|
||||
scope.runTest {
|
||||
assertIs<Ok<PGPKey>>(keyManager.addKey(publicKey))
|
||||
assertIs<Ok<PGPKey>>(keyManager.addKey(publicKey))
|
||||
val allKeys = keyManager.getAllKeys()
|
||||
assertIs<Ok<List<PGPKey>>>(allKeys)
|
||||
assertEquals(1, allKeys.value.size)
|
||||
val key = allKeys.value[0]
|
||||
assertContentEquals(publicKey.contents, key.contents)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun replaceSecretKeyWithSecretKey() {
|
||||
scope.runTest {
|
||||
assertIs<Ok<PGPKey>>(keyManager.addKey(privateKey))
|
||||
assertIs<Err<KeyAlreadyExistsException>>(keyManager.addKey(privateKey))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue