| author | Eric Roberts
<eric@devl.me> 2026-08-26 18:14:50 UTC |
| committer | Stephen Paul Weber
<singpolyma@singpolyma.net> 2026-08-26 18:16:17 UTC |
| parent | 6d15389a5aae89d15e95de474417d794f96909aa |
| borogove/OMEMO.hx | +3 | -5 |
| borogove/Persistence.hx | +2 | -2 |
| borogove/persistence/Dummy.hx | +5 | -3 |
| borogove/persistence/IDB.js | +4 | -2 |
| borogove/persistence/Sqlite.hx | +36 | -3 |
| test/TestSqlite.hx | +40 | -0 |
| test/persistence-tests.ts | +61 | -0 |
diff --git a/borogove/OMEMO.hx b/borogove/OMEMO.hx index b8be3fd..4fe407a 100644 --- a/borogove/OMEMO.hx +++ b/borogove/OMEMO.hx @@ -157,8 +157,7 @@ class OMEMOStore extends SignalProtocolStore { public function storeSignedPreKey(keyId:Int, keyPair:SignedPreKey):Promise<Bool> { trace("OMEMO: Storing signed prekey "+keyId); - persistence.storeOmemoSignedPreKey(accountId, keyPair); - return Promise.resolve(true); + return persistence.storeOmemoSignedPreKey(accountId, keyPair).then(_ -> true); } public function removeSignedPreKey(keyId:Int):Promise<Bool> { @@ -673,9 +672,8 @@ class OMEMO { prekeys = prekeys_; return KeyHelper.generateSignedPreKey(identityKeyPair, 0); - }).then(cast function (signedPreKey:SignedPreKey):Bool { + }).then(signedPreKey -> { trace("OMEMO: Built bundle"); - persistence.storeOmemoSignedPreKey(client.accountId(), signedPreKey); final public_signed_prekey = OMEMOBundleSignedPreKey.fromSignedPreKeyPair(signedPreKey); this.bundle = { @@ -684,7 +682,7 @@ class OMEMO { prekeys: prekeys, signed_prekey: public_signed_prekey, }; - return true; + return persistence.storeOmemoSignedPreKey(client.accountId(), signedPreKey).then(_ -> true); }); } diff --git a/borogove/Persistence.hx b/borogove/Persistence.hx index dabed42..4f6058c 100644 --- a/borogove/Persistence.hx +++ b/borogove/Persistence.hx @@ -385,12 +385,12 @@ interface Persistence { /** Store an OMEMO signed pre-key **/ - public function storeOmemoSignedPreKey(login:String, signedPreKey:SignedPreKey):Void; + public function storeOmemoSignedPreKey(login:String, signedPreKey:SignedPreKey):Promise<SignedPreKey>; /** Load an OMEMO signed pre-key **/ - public function getOmemoSignedPreKey(login:String, keyId:Int): Promise<SignedPreKey>; + public function getOmemoSignedPreKey(login:String, keyId:Int): Promise<Null<SignedPreKey>>; /** List available OMEMO pre-keys for an account diff --git a/borogove/persistence/Dummy.hx b/borogove/persistence/Dummy.hx index d2d21fa..edbfcd2 100644 --- a/borogove/persistence/Dummy.hx +++ b/borogove/persistence/Dummy.hx @@ -229,11 +229,13 @@ class Dummy implements Persistence { } @HaxeCBridge.noemit - public function storeOmemoSignedPreKey(login:String, signedPreKey:SignedPreKey):Void { } + public function storeOmemoSignedPreKey(login:String, signedPreKey:SignedPreKey):Promise<SignedPreKey> { + return Promise.resolve(signedPreKey); + } @HaxeCBridge.noemit - public function getOmemoSignedPreKey(login:String, keyId:Int): Promise<SignedPreKey> { - return Promise.reject("Not found"); + public function getOmemoSignedPreKey(login:String, keyId:Int): Promise<Null<SignedPreKey>> { + return Promise.resolve(null); } @HaxeCBridge.noemit diff --git a/borogove/persistence/IDB.js b/borogove/persistence/IDB.js index 14b3546..709608d 100644 --- a/borogove/persistence/IDB.js +++ b/borogove/persistence/IDB.js @@ -1325,7 +1325,7 @@ tx.onerror = console.error; } }, - storeOmemoSignedPreKey(account, signedKey) { + async storeOmemoSignedPreKey(account, signedKey) { const tx = db.transaction(["keyvaluepairs"], "readwrite"); const store = tx.objectStore("keyvaluepairs"); const dbKey = "omemo:signed-prekey:"+account+":"+signedKey.keyId.toString(); @@ -1334,7 +1334,9 @@ tx.onerror = console.error; pubKey: arrayBufferToBase64(signedKey.keyPair.pubKey), signature: arrayBufferToBase64(signedKey.signature), }; - store.put(storedKey, dbKey); + await promisifyRequest(store.put(storedKey, dbKey)); + + return signedKey; }, async removeAccount(account, completely) { diff --git a/borogove/persistence/Sqlite.hx b/borogove/persistence/Sqlite.hx index b38cfb7..fc0995f 100644 --- a/borogove/persistence/Sqlite.hx +++ b/borogove/persistence/Sqlite.hx @@ -300,6 +300,19 @@ class Sqlite implements Persistence implements KeyValueStore { "PRAGMA user_version = 16"]); } return Promise.resolve(null); + }).then(_ -> { + if (version < 17) { + return exec(["CREATE TABLE omemo_signed_prekeys ( + account_id TEXT NOT NULL, + key_id INTEGER NOT NULL, + private_key BLOB NOT NULL, + public_key BLOB NOT NULL, + signature BLOB NOT NULL, + PRIMARY KEY (account_id, key_id) + ) STRICT", + "PRAGMA user_version = 17"]); + } + return Promise.resolve(null); }); }); }); @@ -1505,11 +1518,31 @@ class Sqlite implements Persistence implements KeyValueStore { } @HaxeCBridge.noemit - public function storeOmemoSignedPreKey(login:String, signedPreKey:SignedPreKey):Void { } + public function storeOmemoSignedPreKey(login:String, signedPreKey:SignedPreKey):Promise<SignedPreKey> { + return db.exec( + "INSERT OR REPLACE INTO omemo_signed_prekeys VALUES (?,?,?,?,?)", + [login, signedPreKey.keyId, signedPreKey.keyPair.privKey, signedPreKey.keyPair.pubKey, signedPreKey.signature], + ).then(_ -> signedPreKey); + } @HaxeCBridge.noemit - public function getOmemoSignedPreKey(login:String, keyId:Int): Promise<SignedPreKey> { - return Promise.reject("TODO"); + public function getOmemoSignedPreKey(login:String, keyId:Int):Promise<Null<SignedPreKey>> { + return db.exec( + "SELECT private_key, public_key, signature FROM omemo_signed_prekeys WHERE account_id=? AND key_id=? LIMIT 1", + [login, keyId], + ).then(result -> { + for (row in result) { + return { + keyId: keyId, + keyPair: { + privKey: row.private_key, + pubKey: row.public_key, + }, + signature: row.signature, + }; + } + return null; + }); } @HaxeCBridge.noemit diff --git a/test/TestSqlite.hx b/test/TestSqlite.hx index a78e59a..c1f6c8f 100644 --- a/test/TestSqlite.hx +++ b/test/TestSqlite.hx @@ -1444,4 +1444,44 @@ class TestSqlite extends utest.Test { }); } + public function testOmemoSignedPreKey(async: Async) { + final login = "signed-prekey@example.com"; + final signedPreKey = { + keyId: 42, + keyPair: { + privKey: Bytes.ofHex("0001027f80ff").getData(), + pubKey: Bytes.ofHex("ff807f020100").getData(), + }, + signature: Bytes.ofHex("090807060504").getData(), + }; + + persistence + .storeOmemoSignedPreKey(login, signedPreKey) + .then(_ -> persistence.getOmemoSignedPreKey(login, signedPreKey.keyId)) + .then(result -> { + Assert.equals(signedPreKey.keyId, result.keyId); + Assert.equals("0001027f80ff", Bytes.ofData(result.keyPair.privKey).toHex()); + Assert.equals("ff807f020100", Bytes.ofData(result.keyPair.pubKey).toHex()); + Assert.equals("090807060504", Bytes.ofData(result.signature).toHex()); + async.done(); + }) + .catchError(e -> { + Assert.fail(Std.string(e)); + async.done(); + }); + } + + public function testGetOmemoSignedPreKeyNotFound(async: Async) { + persistence + .getOmemoSignedPreKey("signed-prekey-notfound@example.com", 1) + .then(result -> { + Assert.equals(null, result); + async.done(); + }) + .catchError(e -> { + Assert.fail(Std.string(e)); + async.done(); + }); + } + } diff --git a/test/persistence-tests.ts b/test/persistence-tests.ts index 06fa4c9..8a32158 100644 --- a/test/persistence-tests.ts +++ b/test/persistence-tests.ts @@ -1648,4 +1648,65 @@ export function sharedPersistenceTests(test: PersistenceTest) { expect(result.loadedPubKey).toEqual(keyPair.pubKey); expect(result.afterRemove).toBeNull(); }); + + test("storeOmemoSignedPreKey and getOmemoSignedPreKey", async ({ + page, + persistence, + }) => { + const identifier = "omemo-signed-prekey-existing@example.com"; + const keyId = 42; + const signedPreKey = { + keyId, + keyPair: { + privKey: [0, 1, 2, 127, 128, 255], + pubKey: [255, 128, 127, 2, 1, 0], + }, + signature: [9, 8, 7, 6, 5, 4], + }; + const result = await page.evaluate( + async ({ persistence, identifier, signedPreKey }) => { + await persistence.storeOmemoSignedPreKey(identifier, { + keyId: signedPreKey.keyId, + keyPair: { + privKey: new Uint8Array(signedPreKey.keyPair.privKey).buffer, + pubKey: new Uint8Array(signedPreKey.keyPair.pubKey).buffer, + }, + signature: new Uint8Array(signedPreKey.signature).buffer, + }); + const loaded = await persistence.getOmemoSignedPreKey( + identifier, + signedPreKey.keyId, + ); + + return { + keyId: loaded.keyId, + loadedPrivKey: [...new Uint8Array(loaded.keyPair.privKey)], + loadedPubKey: [...new Uint8Array(loaded.keyPair.pubKey)], + loadedSignature: [...new Uint8Array(loaded.signature)], + }; + }, + { persistence, identifier, signedPreKey }, + ); + + expect(result.keyId).toBe(keyId); + expect(result.loadedPrivKey).toEqual(signedPreKey.keyPair.privKey); + expect(result.loadedPubKey).toEqual(signedPreKey.keyPair.pubKey); + expect(result.loadedSignature).toEqual(signedPreKey.signature); + }); + + test("getOmemoSignedPreKey returns null when none is stored", async ({ + page, + persistence, + }) => { + const result = await page.evaluate( + async ({ persistence }) => + persistence.getOmemoSignedPreKey( + "omemo-signed-prekey-not-found@example.com", + 1, + ), + { persistence }, + ); + + expect(result).toBeNull(); + }); }