mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-31 01:42:27 +00:00
Merge pull request #775 from PR0M3TH3AN/codex/refactor-nip46rpcclient.ensurecipher
Refactor Nip46 RPC cipher handling
This commit is contained in:
2 files changed
+108
-11
No files matched your search
+52
-11
@@ -3555,15 +3555,56 @@ class Nip46RpcClient {
|
||||
let encrypt = null;
|
||||
let decrypt = null;
|
||||
|
||||
if (tools?.nip44?.v2?.encrypt && tools?.nip44?.v2?.decrypt) {
|
||||
encrypt = (priv, pub, payload) => tools.nip44.v2.encrypt(priv, pub, payload);
|
||||
decrypt = (priv, pub, payload) => tools.nip44.v2.decrypt(priv, pub, payload);
|
||||
} else if (tools?.nip44?.encrypt && tools?.nip44?.decrypt) {
|
||||
encrypt = (priv, pub, payload) => tools.nip44.encrypt(priv, pub, payload);
|
||||
decrypt = (priv, pub, payload) => tools.nip44.decrypt(priv, pub, payload);
|
||||
const nip44v2GetConversationKey =
|
||||
typeof tools?.nip44?.v2?.getConversationKey === "function"
|
||||
? tools.nip44.v2.getConversationKey
|
||||
: typeof tools?.nip44?.v2?.utils?.getConversationKey === "function"
|
||||
? tools.nip44.v2.utils.getConversationKey
|
||||
: null;
|
||||
|
||||
if (
|
||||
tools?.nip44?.v2?.encrypt &&
|
||||
tools?.nip44?.v2?.decrypt &&
|
||||
nip44v2GetConversationKey
|
||||
) {
|
||||
const conversationKey = nip44v2GetConversationKey(
|
||||
this.clientPrivateKey,
|
||||
this.remotePubkey,
|
||||
);
|
||||
|
||||
if (!conversationKey) {
|
||||
throw new Error("Failed to derive a nip44 conversation key for remote signing.");
|
||||
}
|
||||
|
||||
encrypt = (plaintext, nonce) =>
|
||||
typeof nonce === "string"
|
||||
? tools.nip44.v2.encrypt(plaintext, conversationKey, nonce)
|
||||
: tools.nip44.v2.encrypt(plaintext, conversationKey);
|
||||
decrypt = (ciphertext) => tools.nip44.v2.decrypt(ciphertext, conversationKey);
|
||||
} else if (
|
||||
tools?.nip44?.encrypt &&
|
||||
tools?.nip44?.decrypt &&
|
||||
typeof tools?.nip44?.getConversationKey === "function"
|
||||
) {
|
||||
const conversationKey = tools.nip44.getConversationKey(
|
||||
this.clientPrivateKey,
|
||||
this.remotePubkey,
|
||||
);
|
||||
|
||||
if (!conversationKey) {
|
||||
throw new Error("Failed to derive a nip44 conversation key for remote signing.");
|
||||
}
|
||||
|
||||
encrypt = (plaintext, nonce) =>
|
||||
typeof nonce === "string"
|
||||
? tools.nip44.encrypt(plaintext, conversationKey, nonce)
|
||||
: tools.nip44.encrypt(plaintext, conversationKey);
|
||||
decrypt = (ciphertext) => tools.nip44.decrypt(ciphertext, conversationKey);
|
||||
} else if (tools?.nip04?.encrypt && tools?.nip04?.decrypt) {
|
||||
encrypt = (priv, pub, payload) => tools.nip04.encrypt(priv, pub, payload);
|
||||
decrypt = (priv, pub, payload) => tools.nip04.decrypt(priv, pub, payload);
|
||||
const privateKey = this.clientPrivateKey;
|
||||
const remotePubkey = this.remotePubkey;
|
||||
encrypt = (plaintext) => tools.nip04.encrypt(privateKey, remotePubkey, plaintext);
|
||||
decrypt = (ciphertext) => tools.nip04.decrypt(privateKey, remotePubkey, ciphertext);
|
||||
}
|
||||
|
||||
if (!encrypt || !decrypt) {
|
||||
@@ -3577,12 +3618,12 @@ class Nip46RpcClient {
|
||||
async encryptPayload(payload) {
|
||||
const { encrypt } = await this.ensureCipher();
|
||||
const serialized = typeof payload === "string" ? payload : JSON.stringify(payload);
|
||||
return encrypt(this.clientPrivateKey, this.remotePubkey, serialized);
|
||||
return encrypt(serialized);
|
||||
}
|
||||
|
||||
async decryptPayload(ciphertext) {
|
||||
const { decrypt } = await this.ensureCipher();
|
||||
return decrypt(this.clientPrivateKey, this.remotePubkey, ciphertext);
|
||||
return decrypt(ciphertext);
|
||||
}
|
||||
|
||||
async ensureSubscription() {
|
||||
@@ -4433,7 +4474,7 @@ function getActiveKey(video) {
|
||||
return `LEGACY:${video.id}`;
|
||||
}
|
||||
|
||||
export { convertEventToVideo };
|
||||
export { convertEventToVideo, Nip46RpcClient };
|
||||
|
||||
export class NostrClient {
|
||||
constructor() {
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
import assert from "node:assert/strict";
|
||||
import test from "node:test";
|
||||
|
||||
const PAYLOAD = { message: "hello", count: 42 };
|
||||
|
||||
const loadNostrTools = async () => {
|
||||
const nostrTools = await import("nostr-tools");
|
||||
globalThis.nostrToolsReady = Promise.resolve(nostrTools);
|
||||
return nostrTools;
|
||||
};
|
||||
|
||||
test("Nip46RpcClient encrypts payloads with nip44 conversation keys", async () => {
|
||||
const nostrTools = await loadNostrTools();
|
||||
const { generateSecretKey, getPublicKey, nip44, utils } = nostrTools;
|
||||
|
||||
const clientSecret = utils.bytesToHex(generateSecretKey());
|
||||
const remoteSecret = utils.bytesToHex(generateSecretKey());
|
||||
const clientPublicKey = getPublicKey(clientSecret);
|
||||
const remotePubkey = getPublicKey(remoteSecret);
|
||||
|
||||
const { Nip46RpcClient } = await import("../js/nostr.js");
|
||||
|
||||
const rpcClient = new Nip46RpcClient({
|
||||
nostrClient: { relays: [] },
|
||||
clientPrivateKey: clientSecret,
|
||||
clientPublicKey,
|
||||
remotePubkey,
|
||||
});
|
||||
|
||||
const serialized = JSON.stringify(PAYLOAD);
|
||||
const ciphertext = await rpcClient.encryptPayload(PAYLOAD);
|
||||
|
||||
assert.equal(typeof ciphertext, "string", "ciphertext should be encoded as a string");
|
||||
|
||||
const conversationKey =
|
||||
typeof nip44.v2.getConversationKey === "function"
|
||||
? nip44.v2.getConversationKey(clientSecret, remotePubkey)
|
||||
: nip44.v2.utils.getConversationKey(clientSecret, remotePubkey);
|
||||
const decryptedWithTools = nip44.v2.decrypt(ciphertext, conversationKey);
|
||||
assert.equal(
|
||||
decryptedWithTools,
|
||||
serialized,
|
||||
"nip44 decrypt should recover the serialized payload",
|
||||
);
|
||||
|
||||
const roundTrip = await rpcClient.decryptPayload(ciphertext);
|
||||
assert.equal(roundTrip, serialized, "client should decrypt its own ciphertext");
|
||||
|
||||
const externalCiphertext = nip44.v2.encrypt(serialized, conversationKey);
|
||||
const externalRoundTrip = await rpcClient.decryptPayload(externalCiphertext);
|
||||
assert.equal(
|
||||
externalRoundTrip,
|
||||
serialized,
|
||||
"client should decrypt ciphertext produced by nostr-tools",
|
||||
);
|
||||
});
|
||||
Reference in new issue
Block a user