check if the identity key pair exists before creation

sometimes we create the identity key pair although it already exists
we try to avoid that by checking the group again right before sending the request.
we do not force reloading the cache as this is done outside by the caller already or the group is new. so it should not be necessary.
This commit is contained in:
vaf 2025-10-15 13:13:22 +02:00
parent fc895d87a2
commit bce2ca909f
No known key found for this signature in database
GPG key ID: 2AE9A7F02CCE35DC
2 changed files with 24 additions and 23 deletions

View file

@ -37,9 +37,9 @@ export class IdentityKeyCreator {
/**
* Creates an identity key pair for the given group.
* Encrypts the private key with the passed encryptingKey or the group key and tags the public key with the group key.
* @param groupId
* @param currentKeyPairToBeSigned MUST be an RSA+ECC or TutaCrypt key pair
* @param formerKeyPairsToBeSigned the former key pairs may include RSA key pairs
* @param groupId the caller is responsible to make sure the group is updated in the cache
* @param encryptingKey the key to encrypt the private key. by default the current group key is used.
* this is useful in case group members must not have access to the private key.
*/
@ -99,6 +99,13 @@ export class IdentityKeyCreator {
}),
)
}
// Do not try to re-create the key pair in case it already exists
// We check down here to make race conditions less likely.
const group = await this.entityClient.load(GroupTypeRef, groupId)
if (group.identityKeyPair != null) {
console.log(`Identity key pair already exists. Did not create it again for group: ${groupId}`)
return
}
await this.serviceExecutor.post(
IdentityKeyService,
createIdentityKeyPostIn({

View file

@ -96,14 +96,20 @@ o.spec("IdentityKeyCreatorTest", function () {
object: object(),
}
const adminEncPrivateKey: VersionedEncryptedKey = { encryptingKeyVersion: adminKeyVersion, key: object() }
const userGroup: Group = object()
userGroup.currentKeys = object()
userGroup.groupKeyVersion = "1"
let userGroup: Group
const publicKeySignature: PublicKeySignature = object()
o.beforeEach(function () {
userGroupKeyPair = object()
userGroup = createTestEntity(GroupTypeRef, {
_id: userGroupId,
currentKeys: object(),
groupKeyVersion: currentUserGroupKeyVersion.toString(),
identityKeyPair: null,
adminGroupKeyVersion: adminKeyVersion.toString(),
adminGroupEncGKey: adminGroupEncGKey,
admin: adminGroupId,
})
when(cryptoWrapper.ed25519PublicKeyToBytes(identityKeyPair.public_key)).thenReturn(encodedPubIdentityKey)
when(ed25519Facade.generateKeypair()).thenResolve(identityKeyPair)
@ -165,17 +171,14 @@ o.spec("IdentityKeyCreatorTest", function () {
await assertThrows(ProgrammingError, async () => identityKeyCreator.createIdentityKeyPair(userGroupId, userGroupKeyPair, []))
})
o("no service invocation if the identity key pair exists", async function () {
userGroup.identityKeyPair = object()
await identityKeyCreator.createIdentityKeyPair(userGroupId, userGroupKeyPair, [])
verify(serviceExecutor.post(IdentityKeyService, anything()), { times: 0 })
})
o("success admin creates new user", async function () {
when(cryptoWrapper.decryptKey(adminGroupKey.object, adminGroupEncGKey)).thenReturn(userGroupKey.object)
when(cacheManagementFacade.reloadGroup(userGroupId)).thenResolve(
createTestEntity(GroupTypeRef, {
_id: userGroupId,
groupKeyVersion: userGroupKey.version.toString(),
adminGroupKeyVersion: adminKeyVersion.toString(),
adminGroupEncGKey: adminGroupEncGKey,
admin: adminGroupId,
}),
)
await identityKeyCreator.createIdentityKeyPair(userGroupId, userGroupKeyPair, [])
verify(
@ -206,15 +209,6 @@ o.spec("IdentityKeyCreatorTest", function () {
when(cryptoWrapper.decryptKey(adminGroupKey.object, adminGroupEncGKey)).thenReturn(userGroupKey.object)
when(cryptoWrapper.encryptEd25519Key(userGroupKey, identityKeyPair.private_key)).thenThrow(new Error("should not happen"))
when(cryptoWrapper.encryptEd25519Key(adminGroupKey, identityKeyPair.private_key)).thenReturn(adminEncPrivateKey)
when(cacheManagementFacade.reloadGroup(userGroupId)).thenResolve(
createTestEntity(GroupTypeRef, {
_id: userGroupId,
groupKeyVersion: userGroupKey.version.toString(),
adminGroupKeyVersion: adminKeyVersion.toString(),
adminGroupEncGKey: adminGroupEncGKey,
admin: adminGroupId,
}),
)
await identityKeyCreator.createIdentityKeyPair(userGroupId, userGroupKeyPair, [], adminGroupKey)
verify(