git » sdk » commit 6d15389

Implement get/storeOmemoPreKey

author Eric Roberts
2026-08-26 18:14:49 UTC
committer Stephen Paul Weber
2026-08-26 18:16:17 UTC
parent b2f33f25bd0ab05f9133b15445fed2f2b23384d0

Implement get/storeOmemoPreKey

borogove/Persistence.hx +3 -3
borogove/persistence/Dummy.hx +8 -4
borogove/persistence/IDB.js +8 -4
borogove/persistence/Sqlite.hx +37 -4
test/TestSqlite.hx +40 -0
test/persistence-tests.ts +52 -0

diff --git a/borogove/Persistence.hx b/borogove/Persistence.hx
index 4ea7dec..dabed42 100644
--- a/borogove/Persistence.hx
+++ b/borogove/Persistence.hx
@@ -370,17 +370,17 @@ interface Persistence {
 	/**
 		Store an OMEMO pre-key
 	**/
-	public function storeOmemoPreKey(identifier:String, keyId:Int, keyPair:PreKeyPair):Void;
+	public function storeOmemoPreKey(accountId:String, keyId:Int, keyPair:PreKeyPair):Promise<PreKeyPair>;
 
 	/**
 		Load an OMEMO pre-key
 	**/
-	public function getOmemoPreKey(identifier:String, keyId:Int): Promise<PreKeyPair>;
+	public function getOmemoPreKey(accountId:String, keyId:Int): Promise<Null<PreKeyPair>>;
 
 	/**
 		Remove an OMEMO pre-key
 	**/
-	public function removeOmemoPreKey(identifier:String, keyId:Int):Void;
+	public function removeOmemoPreKey(accountId:String, keyId:Int):Promise<Bool>;
 
 	/**
 		Store an OMEMO signed pre-key
diff --git a/borogove/persistence/Dummy.hx b/borogove/persistence/Dummy.hx
index bed3908..d2d21fa 100644
--- a/borogove/persistence/Dummy.hx
+++ b/borogove/persistence/Dummy.hx
@@ -214,15 +214,19 @@ class Dummy implements Persistence {
 	}
 
 	@HaxeCBridge.noemit
-	public function storeOmemoPreKey(identifier:String, keyId:Int, keyPair:PreKeyPair):Void { }
+	public function storeOmemoPreKey(accountId:String, keyId:Int, keyPair:PreKeyPair):Promise<PreKeyPair> {
+		return Promise.resolve(keyPair);
+	}
 
 	@HaxeCBridge.noemit
-	public function getOmemoPreKey(identifier:String, keyId:Int): Promise<PreKeyPair> {
-		return Promise.reject("Not found");
+	public function getOmemoPreKey(accountId:String, keyId:Int): Promise<Null<PreKeyPair>> {
+		return Promise.resolve(null);
 	}
 
 	@HaxeCBridge.noemit
-	public function removeOmemoPreKey(identifier:String, keyId:Int):Void { }
+	public function removeOmemoPreKey(accountId:String, keyId:Int):Promise<Bool> {
+		return Promise.resolve(true);
+	}
 
 	@HaxeCBridge.noemit
 	public function storeOmemoSignedPreKey(login:String, signedPreKey:SignedPreKey):Void { }
diff --git a/borogove/persistence/IDB.js b/borogove/persistence/IDB.js
index 90b3c62..14b3546 100644
--- a/borogove/persistence/IDB.js
+++ b/borogove/persistence/IDB.js
@@ -1177,21 +1177,25 @@ tx.onerror = console.error;
 			return result || [];
 		},
 
-		storeOmemoPreKey(account, keyId, keyPair) {
+		async storeOmemoPreKey(account, keyId, keyPair) {
 			const tx = db.transaction(["keyvaluepairs"], "readwrite");
 			const store = tx.objectStore("keyvaluepairs");
 			const storedKeyPair = {
 				"privKey": arrayBufferToBase64(keyPair.privKey),
 				"pubKey": arrayBufferToBase64(keyPair.pubKey),
 			};
-			store.put(storedKeyPair, "omemo:prekeys:"+account+":"+keyId.toString());
+			await promisifyRequest(store.put(storedKeyPair, "omemo:prekeys:"+account+":"+keyId.toString()));
+
+			return keyPair;
 		},
 
-		removeOmemoPreKey(account, keyId) {
+		async removeOmemoPreKey(account, keyId) {
 			const tx = db.transaction(["keyvaluepairs"], "readwrite");
 			const store = tx.objectStore("keyvaluepairs");
 			const keyName = "omemo:prekeys:"+account+":"+keyId.toString();
-			store.delete(keyName);
+			await promisifyRequest(store.delete(keyName));
+
+			return true;
 		},
 
 		async getOmemoPreKey(account, keyId) {
diff --git a/borogove/persistence/Sqlite.hx b/borogove/persistence/Sqlite.hx
index 5016c94..b38cfb7 100644
--- a/borogove/persistence/Sqlite.hx
+++ b/borogove/persistence/Sqlite.hx
@@ -288,6 +288,18 @@ class Sqlite implements Persistence implements KeyValueStore {
 						"PRAGMA user_version = 15"]);
 					}
 					return Promise.resolve(null);
+				}).then(_ -> {
+					if (version < 16) {
+						return exec(["CREATE TABLE omemo_prekeys (
+							account_id TEXT NOT NULL,
+							key_id INTEGER NOT NULL,
+							private_key BLOB NOT NULL,
+							public_key BLOB NOT NULL,
+							PRIMARY KEY (account_id, key_id)
+						) STRICT",
+						"PRAGMA user_version = 16"]);
+					}
+					return Promise.resolve(null);
 				});
 			});
 		});
@@ -1461,15 +1473,36 @@ class Sqlite implements Persistence implements KeyValueStore {
 	}
 
 	@HaxeCBridge.noemit
-	public function storeOmemoPreKey(identifier:String, keyId:Int, keyPair:PreKeyPair):Void { }
+	public function storeOmemoPreKey(accountId:String, keyId:Int, keyPair:PreKeyPair):Promise<PreKeyPair> {
+		return db.exec(
+			"INSERT OR REPLACE INTO omemo_prekeys VALUES (?,?,?,?)",
+			[accountId, keyId, keyPair.privKey, keyPair.pubKey],
+		).then(_ -> keyPair);
+	}
 
 	@HaxeCBridge.noemit
-	public function getOmemoPreKey(identifier:String, keyId:Int): Promise<PreKeyPair> {
-		return Promise.reject("TODO");
+	public function getOmemoPreKey(accountId:String, keyId:Int): Promise<Null<PreKeyPair>> {
+		return db.exec(
+			"SELECT private_key, public_key FROM omemo_prekeys WHERE account_id=? AND key_id=? LIMIT 1",
+			[accountId, keyId],
+		).then(result -> {
+			for (row in result) {
+				return {
+					privKey: row.private_key,
+					pubKey: row.public_key,
+				};
+			}
+			return null;
+		});
 	}
 
 	@HaxeCBridge.noemit
-	public function removeOmemoPreKey(identifier:String, keyId:Int):Void { }
+	public function removeOmemoPreKey(accountId:String, keyId:Int):Promise<Bool> {
+		return db.exec(
+			"DELETE FROM omemo_prekeys WHERE account_id=? AND key_id=?",
+			[accountId, keyId],
+		).then(_ -> true);
+	}
 
 	@HaxeCBridge.noemit
 	public function storeOmemoSignedPreKey(login:String, signedPreKey:SignedPreKey):Void { }
diff --git a/test/TestSqlite.hx b/test/TestSqlite.hx
index 6db1098..a78e59a 100644
--- a/test/TestSqlite.hx
+++ b/test/TestSqlite.hx
@@ -1404,4 +1404,44 @@ class TestSqlite extends utest.Test {
 			});
 	}
 
+	public function testGetOmemoPreKeyNotFound(async: Async) {
+		persistence
+			.getOmemoPreKey("prekey-notfound@example.com", 1)
+			.then(result -> {
+				Assert.equals(null, result);
+				async.done();
+			})
+			.catchError(e -> {
+				Assert.fail(Std.string(e));
+				async.done();
+			});
+	}
+
+	public function testOmemoPreKey(async: Async) {
+		final login = "prekey-existing@example.com";
+		final keyId = 42;
+		final keyPair = {
+			privKey: Bytes.ofHex("0001027f80ff").getData(),
+			pubKey: Bytes.ofHex("ff807f020100").getData(),
+		};
+
+		persistence
+			.storeOmemoPreKey(login, keyId, keyPair)
+			.then(_ -> persistence.getOmemoPreKey(login, keyId))
+			.then(result -> {
+				Assert.equals("0001027f80ff", Bytes.ofData(result.privKey).toHex());
+				Assert.equals("ff807f020100", Bytes.ofData(result.pubKey).toHex());
+				return persistence.removeOmemoPreKey(login, keyId);
+			})
+			.then(_ -> persistence.getOmemoPreKey(login, keyId))
+			.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 61387af..06fa4c9 100644
--- a/test/persistence-tests.ts
+++ b/test/persistence-tests.ts
@@ -1596,4 +1596,56 @@ export function sharedPersistenceTests(test: PersistenceTest) {
 		expect(result.afterReplace).toEqual(replacementDeviceIds);
 		expect(result.afterClear).toEqual([]);
 	});
+
+	test("getOmemoPreKey returns null when none is stored", async ({
+		page,
+		persistence,
+	}) => {
+		const identifier = "omemo-prekey-not-found@example.com";
+		const keyId = 1;
+		const result = await page.evaluate(
+			async ({ persistence, identifier, keyId }) =>
+				persistence.getOmemoPreKey(identifier, keyId),
+			{ persistence, identifier, keyId },
+		);
+
+		expect(result).toBeNull();
+	});
+
+	test("storeOmemoPreKey stores a removable pre-key", async ({
+		page,
+		persistence,
+	}) => {
+		const identifier = "omemo-prekey-existing@example.com";
+		const keyId = 42;
+		const keyPair = {
+			privKey: [0, 1, 2, 127, 128, 255],
+			pubKey: [255, 128, 127, 2, 1, 0],
+		};
+		const result = await page.evaluate(
+			async ({ persistence, identifier, keyId, keyPair }) => {
+				await persistence.storeOmemoPreKey(identifier, keyId, {
+					privKey: new Uint8Array(keyPair.privKey).buffer,
+					pubKey: new Uint8Array(keyPair.pubKey).buffer,
+				});
+				const loadedKeyPair = await persistence.getOmemoPreKey(
+					identifier,
+					keyId,
+				);
+				await persistence.removeOmemoPreKey(identifier, keyId);
+				const afterRemove = await persistence.getOmemoPreKey(identifier, keyId);
+
+				return {
+					loadedPrivKey: [...new Uint8Array(loadedKeyPair.privKey)],
+					loadedPubKey: [...new Uint8Array(loadedKeyPair.pubKey)],
+					afterRemove,
+				};
+			},
+			{ persistence, identifier, keyId, keyPair },
+		);
+
+		expect(result.loadedPrivKey).toEqual(keyPair.privKey);
+		expect(result.loadedPubKey).toEqual(keyPair.pubKey);
+		expect(result.afterRemove).toBeNull();
+	});
 }