| author | Eric Roberts
<eric@devl.me> 2026-08-26 18:14:47 UTC |
| committer | Stephen Paul Weber
<singpolyma@singpolyma.net> 2026-08-26 18:16:17 UTC |
| parent | 3c345fec4332ad385568b3693cc0793c1bd88834 |
| borogove/Persistence.hx | +2 | -2 |
| borogove/persistence/Dummy.hx | +5 | -3 |
| borogove/persistence/IDB.js | +7 | -3 |
| borogove/persistence/Sqlite.hx | +29 | -3 |
| test/TestSqlite.hx | +35 | -0 |
| test/persistence-tests.ts | +49 | -0 |
diff --git a/borogove/Persistence.hx b/borogove/Persistence.hx index c1722c2..03d7834 100644 --- a/borogove/Persistence.hx +++ b/borogove/Persistence.hx @@ -350,12 +350,12 @@ interface Persistence { /** Store the local OMEMO identity key pair for an account **/ - public function storeOmemoIdentityKey(login:String, keypair:IdentityKeyPair):Void; + public function storeOmemoIdentityKey(login:String, keypair:IdentityKeyPair):Promise<IdentityKeyPair>; /** Load the local OMEMO identity key pair for an account **/ - public function getOmemoIdentityKey(login:String): Promise<IdentityKeyPair>; + public function getOmemoIdentityKey(login:String): Promise<Null<IdentityKeyPair>>; /** Load the known OMEMO device list for a contact or account diff --git a/borogove/persistence/Dummy.hx b/borogove/persistence/Dummy.hx index fe93725..46c56ab 100644 --- a/borogove/persistence/Dummy.hx +++ b/borogove/persistence/Dummy.hx @@ -194,11 +194,13 @@ class Dummy implements Persistence { } @HaxeCBridge.noemit - public function storeOmemoIdentityKey(login:String, keypair:IdentityKeyPair):Void { } + public function storeOmemoIdentityKey(login:String, keypair:IdentityKeyPair):Promise<IdentityKeyPair> { + return Promise.resolve(keypair); + } @HaxeCBridge.noemit - public function getOmemoIdentityKey(login:String): Promise<IdentityKeyPair> { - return Promise.reject("Not found"); + public function getOmemoIdentityKey(login:String): Promise<Null<IdentityKeyPair>> { + return Promise.resolve(null); } @HaxeCBridge.noemit diff --git a/borogove/persistence/IDB.js b/borogove/persistence/IDB.js index 2b686ca..07ae61b 100644 --- a/borogove/persistence/IDB.js +++ b/borogove/persistence/IDB.js @@ -1149,10 +1149,12 @@ tx.onerror = console.error; return omemoId; }, - storeOmemoIdentityKey(account, keypair) { + async storeOmemoIdentityKey(account, keypair) { const tx = db.transaction(["keyvaluepairs"], "readwrite"); const store = tx.objectStore("keyvaluepairs"); - store.put(keypair, "omemo:key:" + account).onerror = console.error; + await promisifyRequest(store.put(keypair, "omemo:key:" + account)); + + return keypair; }, storeOmemoDeviceList(chatId, deviceIds) { @@ -1293,7 +1295,9 @@ tx.onerror = console.error; getOmemoIdentityKey(account) { const tx = db.transaction(["keyvaluepairs"], "readonly"); const store = tx.objectStore("keyvaluepairs"); - return promisifyRequest(store.get("omemo:key:"+account)); + return promisifyRequest(store.get("omemo:key:"+account)).then( + (result) => result ?? null, + ); }, async getOmemoSignedPreKey(account, keyId) { diff --git a/borogove/persistence/Sqlite.hx b/borogove/persistence/Sqlite.hx index 164953d..38807c0 100644 --- a/borogove/persistence/Sqlite.hx +++ b/borogove/persistence/Sqlite.hx @@ -268,6 +268,16 @@ class Sqlite implements Persistence implements KeyValueStore { "PRAGMA user_version = 13"]); } return Promise.resolve(null); + }).then(_ -> { + if (version < 14) { + return exec(["CREATE TABLE omemo_identity_keys ( + account_id TEXT NOT NULL PRIMARY KEY, + private_key BLOB NOT NULL, + public_key BLOB NOT NULL + ) STRICT", + "PRAGMA user_version = 14"]); + } + return Promise.resolve(null); }); }); }); @@ -1386,11 +1396,27 @@ class Sqlite implements Persistence implements KeyValueStore { } @HaxeCBridge.noemit - public function storeOmemoIdentityKey(login:String, keypair:IdentityKeyPair):Void { } + public function storeOmemoIdentityKey(login:String, keypair:IdentityKeyPair):Promise<IdentityKeyPair> { + return db.exec( + "INSERT OR REPLACE INTO omemo_identity_keys VALUES (?,?,?)", + [login, keypair.privKey, keypair.pubKey], + ).then(_ -> keypair); + } @HaxeCBridge.noemit - public function getOmemoIdentityKey(login:String): Promise<IdentityKeyPair> { - return Promise.reject("TODO"); + public function getOmemoIdentityKey(login:String): Promise<Null<IdentityKeyPair>> { + return db.exec( + "SELECT private_key, public_key FROM omemo_identity_keys WHERE account_id=? LIMIT 1", + [login], + ).then(result -> { + for (row in result) { + return { + privKey: row.private_key, + pubKey: row.public_key, + }; + } + return null; + }); } @HaxeCBridge.noemit diff --git a/test/TestSqlite.hx b/test/TestSqlite.hx index 28f5e55..d9a9fd3 100644 --- a/test/TestSqlite.hx +++ b/test/TestSqlite.hx @@ -1331,4 +1331,39 @@ class TestSqlite extends utest.Test { async.done(); }); } + + public function testGetOmemoIdentityKeyNotFound(async: Async) { + persistence + .getOmemoIdentityKey("identity-notfound@example.com") + .then(result -> { + Assert.equals(null, result); + async.done(); + }) + .catchError(e -> { + Assert.fail(Std.string(e)); + async.done(); + }); + } + + public function testOmemoIdentityKey(async: Async) { + final login = "identity-existing@example.com"; + final keyPair = { + privKey: Bytes.ofHex("0001027f80ff").getData(), + pubKey: Bytes.ofHex("ff807f020100").getData(), + }; + + persistence + .storeOmemoIdentityKey(login, keyPair) + .then(_ -> persistence.getOmemoIdentityKey(login)) + .then(result -> { + Assert.equals("0001027f80ff", Bytes.ofData(result.privKey).toHex()); + Assert.equals("ff807f020100", Bytes.ofData(result.pubKey).toHex()); + async.done(); + }) + .catchError(e -> { + Assert.fail(Std.string(e)); + async.done(); + }); + } + } diff --git a/test/persistence-tests.ts b/test/persistence-tests.ts index 7185789..8e74c03 100644 --- a/test/persistence-tests.ts +++ b/test/persistence-tests.ts @@ -1493,4 +1493,53 @@ export function sharedPersistenceTests(test: PersistenceTest) { expect(result).toBe(omemoId); }); + + test("getOmemoIdentityKey returns null when none is stored", async ({ + page, + persistence, + }) => { + const result = await page.evaluate( + async (persistence) => + persistence.getOmemoIdentityKey( + "omemo-identity-not-found@example.com", + ), + persistence, + ); + + expect(result).toBeNull(); + }); + + test("storeOmemoIdentityKey stores the key pair", async ({ + page, + persistence, + }) => { + const keyPair = { + privKey: [0, 1, 2, 127, 128, 255], + pubKey: [255, 128, 127, 2, 1, 0], + }; + + const result = await page.evaluate( + async ({ persistence, keyPair }) => { + await persistence.storeOmemoIdentityKey( + "omemo-identity-existing@example.com", + { + privKey: new Uint8Array(keyPair.privKey).buffer, + pubKey: new Uint8Array(keyPair.pubKey).buffer, + }, + ); + const loadedKeyPair = await persistence.getOmemoIdentityKey( + "omemo-identity-existing@example.com", + ); + + return { + loadedPrivKey: [...new Uint8Array(loadedKeyPair.privKey)], + loadedPubKey: [...new Uint8Array(loadedKeyPair.pubKey)], + }; + }, + { persistence, keyPair }, + ); + + expect(result.loadedPrivKey).toEqual([0, 1, 2, 127, 128, 255]); + expect(result.loadedPubKey).toEqual([255, 128, 127, 2, 1, 0]); + }); }