git » sdk » commit 163762d

Implement get/storeOmemoSignedPreKey

author Eric Roberts
2026-08-26 18:14:50 UTC
committer Stephen Paul Weber
2026-08-26 18:16:17 UTC
parent 6d15389a5aae89d15e95de474417d794f96909aa

Implement get/storeOmemoSignedPreKey

There were some things in OMEMO.hx just firing and forgetting so they also got
changed to await. This seems more correct, even if it likely wasn't a problem
in practice.

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();
+	});
 }