Handle remote signer key hints for NIP-46

This commit is contained in:
thePR0M3TH3AN committed 2025-10-22 08:58:31 -04:00
1 parent 37a7ecfaf9
commit eb9b97bcae
3 files changed
+236 -35

No files matched your search

+83
View File
@@ -288,3 +288,86 @@ test("decryptNip46PayloadWithKeys supports nip04-style ciphertext wrappers", asy
"nip04 decrypt should succeed for structured payload candidates",
);
});
test("parseNip46ConnectionString handles remote signer key hints", async () => {
const nostrTools = await loadNostrTools();
const { generateSecretKey, getPublicKey, nip19, utils } = nostrTools;
const signerSecret = utils.bytesToHex(generateSecretKey());
const userSecret = utils.bytesToHex(generateSecretKey());
const signerPubkey = getPublicKey(signerSecret).toLowerCase();
const userPubkey = getPublicKey(userSecret).toLowerCase();
const signerNpub = nip19.npubEncode(signerPubkey);
const userNpub = nip19.npubEncode(userPubkey);
const uri =
`bunker://${userNpub}?remote-signer-key=${encodeURIComponent(signerNpub)}` +
`&relay=${encodeURIComponent("wss://relay.example.com")}`;
const { __testExports } = await import("../js/nostr.js");
const { parseNip46ConnectionString } = __testExports;
const parsed = parseNip46ConnectionString(uri);
assert.ok(parsed, "parser should return a payload");
assert.equal(
parsed.remotePubkey,
signerPubkey,
"remote signer pubkey should come from the remote-signer-key parameter",
);
assert.equal(
parsed.userPubkeyHint,
userPubkey,
"user pubkey hint should reflect the bunker URI hostname",
);
assert.deepEqual(
parsed.relays,
["wss://relay.example.com"],
"relay parameters should be decoded",
);
});
test(
"attemptDecryptNip46HandshakePayload falls back to expected remote signer key",
async () => {
const nostrTools = await loadNostrTools();
const { generateSecretKey, getPublicKey, nip44, utils } = nostrTools;
const clientSecret = utils.bytesToHex(generateSecretKey());
const remoteSignerSecret = utils.bytesToHex(generateSecretKey());
const userSecret = utils.bytesToHex(generateSecretKey());
const remoteSignerPubkey = getPublicKey(remoteSignerSecret).toLowerCase();
const userPubkey = getPublicKey(userSecret).toLowerCase();
const conversationKey =
typeof nip44.v2.getConversationKey === "function"
? nip44.v2.getConversationKey(clientSecret, remoteSignerPubkey)
: nip44.v2.utils.getConversationKey(clientSecret, remoteSignerPubkey);
const payload = JSON.stringify({ id: "ack", result: "ok" });
const ciphertext = nip44.v2.encrypt(payload, conversationKey);
const { __testExports } = await import("../js/nostr.js");
const { attemptDecryptNip46HandshakePayload } = __testExports;
const result = await attemptDecryptNip46HandshakePayload({
clientPrivateKey: clientSecret,
candidateRemotePubkeys: [userPubkey, remoteSignerPubkey],
ciphertext,
});
assert.equal(
result.remotePubkey,
remoteSignerPubkey,
"helper should return the remote signer key that successfully decrypted the payload",
);
assert.equal(
result.plaintext,
payload,
"helper should yield the handshake plaintext",
);
},
);