Merge pull request #791 from PR0M3TH3AN/codex/fix-nip-46-connection-issues-cjhftt

Handle nip04 handshake payload arrays
This commit is contained in:
thePR0M3TH3AN authored and GitHub committed 2025-10-22 09:34:56 -04:00
commit d787c212f6
2 files changed
+118

No files matched your search

+72
View File
@@ -3857,6 +3857,61 @@ function normalizeNip46CiphertextPayload(payload) {
}
};
const extractScalarString = (value) => {
if (typeof value === "string") {
const trimmed = value.trim();
return trimmed ? trimmed : "";
}
if (typeof value === "number" || typeof value === "boolean") {
return String(value);
}
if (Array.isArray(value)) {
const decoded = decodeBytesToUtf8(value);
if (decoded) {
return decoded;
}
if (value.length === 1) {
return extractScalarString(value[0]);
}
return "";
}
if (!value || typeof value !== "object") {
return "";
}
const decoded = decodeBytesToUtf8(value);
if (decoded) {
return decoded;
}
const preferredKeys = [
"ciphertext",
"cipher_text",
"payload",
"content",
"result",
"value",
"data",
"nonce",
"iv",
"secret",
"message",
];
for (const key of preferredKeys) {
if (typeof value[key] === "string" && value[key].trim()) {
return value[key].trim();
}
}
return "";
};
const coerce = (value) => {
if (typeof value === "string") {
addCandidate(value);
@@ -3888,6 +3943,23 @@ function normalizeNip46CiphertextPayload(payload) {
return;
}
const scalarEntries = [];
for (const entry of value) {
const scalar = extractScalarString(entry);
if (scalar) {
scalarEntries.push(scalar);
}
}
if (scalarEntries.length >= 2) {
for (let i = 0; i < scalarEntries.length; i += 1) {
for (let j = i + 1; j < scalarEntries.length; j += 1) {
addCiphertextWithNonce(scalarEntries[i], scalarEntries[j]);
addCiphertextWithNonce(scalarEntries[j], scalarEntries[i]);
}
}
}
for (const entry of value) {
coerce(entry);
}
+46
View File
@@ -371,3 +371,49 @@ test(
);
},
);
test(
"attemptDecryptNip46HandshakePayload handles array-encoded nip04 payloads",
async () => {
const nostrTools = await loadNostrTools();
const { generateSecretKey, getPublicKey, nip04, utils } = nostrTools;
const clientSecret = utils.bytesToHex(generateSecretKey());
const clientPubkey = getPublicKey(clientSecret).toLowerCase();
const remoteSecret = utils.bytesToHex(generateSecretKey());
const remotePubkey = getPublicKey(remoteSecret).toLowerCase();
const payload = JSON.stringify({ id: "ack", result: "ack" });
const ciphertext = nip04.encrypt(remoteSecret, clientPubkey, payload);
const [ciphertextPart, ivPart] = ciphertext.split("?iv=");
assert.ok(ivPart, "nip04 encryption should emit an iv segment");
const encodedPayload = JSON.stringify([ciphertextPart, ivPart]);
const { __testExports } = await import("../js/nostr.js");
const { attemptDecryptNip46HandshakePayload } = __testExports;
const result = await attemptDecryptNip46HandshakePayload({
clientPrivateKey: clientSecret,
candidateRemotePubkeys: [remotePubkey],
ciphertext: encodedPayload,
});
assert.equal(
result.remotePubkey,
remotePubkey,
"helper should resolve the remote signer key for array payloads",
);
assert.equal(
result.plaintext,
payload,
"helper should decrypt nip04 payloads serialized as arrays",
);
assert.equal(
result.algorithm,
"nip04",
"helper should report the nip04 algorithm for nip04 ciphertext",
);
},
);