Skip to content

Commit 7859678

Browse files
authored
Update nostr-tools so NIP-44 accepts payloads over 64 KiB (#153)
Deploying a site with a few hundred files fails at the last step: Creating site manifest event with: Files: 1117 ✗ Failed to create/publish manifest: invalid plaintext size: must be between 1 and 65535 bytes NIP-46 wraps each request to a remote signer in a NIP-44 payload, so the largest event a bunker can sign is bounded by NIP-44's plaintext limit. NIP-44 v2 raised that limit to 2^32-1 bytes using a 6-byte extended length prefix for anything >= 65536; nostr-tools implements it from 2.23.8, but the lockfile pinned 2.19.4, which still enforces the old 65535 cap. A manifest carries one path tag per file, so a 1117-file site produces a ~141 KB event and cannot be signed at all -- after its blobs have already been uploaded. Deploys signed with a local key were unaffected, since nothing is encrypted in that path. nostr-tools 2.24.1 brings @noble/curves 2.x, which no longer accepts a hex string where a Uint8Array is expected. Two tests constructed SimpleSigner that way; src/ already passes bytes.
1 parent 1699257 commit 7859678

4 files changed

Lines changed: 73 additions & 43 deletions

File tree

deno.lock

Lines changed: 34 additions & 39 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { assertEquals } from "@std/assert";
2+
import * as nip44 from "npm:nostr-tools/nip44";
3+
import { generateSecretKey, getPublicKey } from "npm:nostr-tools/pure";
4+
5+
/**
6+
* NIP-46 wraps every request to a remote signer in a NIP-44 payload, so the
7+
* largest event nsyte can have a bunker sign is bounded by NIP-44's plaintext
8+
* limit. NIP-44 v2 raised that to 2^32-1 bytes with a 6-byte extended length
9+
* prefix (`[0x00, 0x00][u32]`) for anything >= 65536; before that it was
10+
* capped at 65535.
11+
*
12+
* A site manifest (kind 35128) carries one `path` tag per file, so a site of a
13+
* few hundred files clears 64 KiB easily -- a 1117-file site produces a
14+
* ~141 KB event. Against an implementation that still enforces the old cap,
15+
* every such deploy fails at the last step with "invalid plaintext size: must
16+
* be between 1 and 65535 bytes", after the upload has already happened.
17+
*
18+
* This guards the resolved nostr-tools version rather than code in this repo:
19+
* a lockfile that drifts back to a pre-extended-prefix release reintroduces
20+
* the failure silently.
21+
*/
22+
Deno.test("NIP-44 round-trips payloads larger than the old 65535-byte cap", () => {
23+
const conversationKey = nip44.getConversationKey(
24+
generateSecretKey(),
25+
getPublicKey(generateSecretKey()),
26+
);
27+
28+
// 65535 is the last size the 2-byte u16 prefix covers; 65536 is the first
29+
// that needs the extended prefix, and is where the old implementation threw.
30+
// 141397 is the size of a real 1117-file manifest.
31+
for (const size of [65535, 65536, 141397]) {
32+
const plaintext = "a".repeat(size);
33+
const decrypted = nip44.decrypt(nip44.encrypt(plaintext, conversationKey), conversationKey);
34+
assertEquals(decrypted.length, size, `NIP-44 failed to round-trip ${size} bytes`);
35+
assertEquals(decrypted, plaintext);
36+
}
37+
});

tests/unit/timestamp_exclusion_test.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
import { assertEquals } from "@std/assert";
22
import { beforeAll, describe, it } from "@std/testing/bdd";
33
import { SimpleSigner } from "applesauce-signers";
4-
import { encodeHex } from "@std/encoding/hex";
54
import { createDeleteEvent } from "../../src/lib/nostr.ts";
65

76
let signer: SimpleSigner;
87

98
beforeAll(async () => {
109
const privKeyBytes = new Uint8Array(32);
1110
crypto.getRandomValues(privKeyBytes);
12-
signer = new SimpleSigner(encodeHex(privKeyBytes));
11+
signer = new SimpleSigner(privKeyBytes);
1312
await signer.getPublicKey();
1413
});
1514

tests/unit/timestamp_propagation_test.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { assertEquals } from "@std/assert";
22
import { beforeAll, describe, it } from "@std/testing/bdd";
33
import { SimpleSigner } from "applesauce-signers";
4-
import { encodeHex } from "@std/encoding/hex";
54
import {
65
createAppHandlerEvent,
76
createAppRecommendationEvent,
@@ -21,7 +20,7 @@ let pubkey: string;
2120
beforeAll(async () => {
2221
const privKeyBytes = new Uint8Array(32);
2322
crypto.getRandomValues(privKeyBytes);
24-
signer = new SimpleSigner(encodeHex(privKeyBytes));
23+
signer = new SimpleSigner(privKeyBytes);
2524
pubkey = await signer.getPublicKey();
2625
});
2726

0 commit comments

Comments
 (0)