|
|
|
@@ -110,7 +110,26 @@ export async function bootstrapConvKey(
|
|
|
|
|
p_bundles: bundles,
|
|
|
|
|
});
|
|
|
|
|
if (error) throw error;
|
|
|
|
|
const handle = { conversationId, keyVersion, key: convKey };
|
|
|
|
|
|
|
|
|
|
// `share_conv_keys` uses `ON CONFLICT (conv, recipient_user_id, key_version)
|
|
|
|
|
// DO NOTHING`. If a concurrent peer bootstrapped first at the same version,
|
|
|
|
|
// OUR INSERTs were silently skipped server-side and the row on the server
|
|
|
|
|
// holds THEIR conv-key, not ours. Trusting the locally-generated key here
|
|
|
|
|
// would leave both clients with mutually un-decryptable bundles (each
|
|
|
|
|
// encrypting/decrypting with its own key — exactly the bug that broke
|
|
|
|
|
// conv aae12d84). Re-fetch our own bundle and unwrap to get the CANONICAL
|
|
|
|
|
// server key. Whoever wrote first wins; the loser converges.
|
|
|
|
|
const ownBundle = await fetchKeyBundle(client, conversationId, own.userId, keyVersion);
|
|
|
|
|
if (!ownBundle) {
|
|
|
|
|
throw new Error('bootstrapConvKey: own bundle missing after share_conv_keys');
|
|
|
|
|
}
|
|
|
|
|
const canonicalKey = await unwrapConvKey(
|
|
|
|
|
ownBundle.encryptedKey,
|
|
|
|
|
ownBundle.nonce,
|
|
|
|
|
ownBundle.sender.senderPublicKey,
|
|
|
|
|
own.privateKey,
|
|
|
|
|
);
|
|
|
|
|
const handle = { conversationId, keyVersion, key: canonicalKey };
|
|
|
|
|
cache.set(cacheKey(conversationId, keyVersion), handle);
|
|
|
|
|
return handle;
|
|
|
|
|
}
|
|
|
|
|