inject.mjs raw
1 // Test NIP-07 signer — injected into MAIN world.
2 // Implements window.nostr with hardcoded test keys.
3 // Uses secp256k1 WASM for BIP-340 Schnorr signing.
4
5 const TEST_SK = '328615b6c92aa6527fc175a67670222daabc69fa2b84c2ded5f6907f78f2b0f8';
6 const TEST_PK = '5dbeb1d7e84d0a4fb3fac47868438dc9135b35f25e27ae933e306e3584bf69a8';
7
8 const extUrl = new URL('./', import.meta.url).href;
9
10 function hexToBytes(hex) {
11 const b = new Uint8Array(hex.length / 2);
12 for (let i = 0; i < b.length; i++) b[i] = parseInt(hex.substr(i * 2, 2), 16);
13 return b;
14 }
15
16 function bytesToHex(bytes) {
17 return Array.from(bytes, b => b.toString(16).padStart(2, '0')).join('');
18 }
19
20 const skBytes = hexToBytes(TEST_SK);
21
22 let secp = null;
23
24 async function getSecp() {
25 if (secp) return secp;
26 const { initSecp256k1 } = await import(extUrl + 'secp256k1.mjs');
27 secp = await initSecp256k1(extUrl + 'secp256k1.wasm');
28 return secp;
29 }
30
31 // NIP-01 canonical serialization for event ID computation.
32 function serializeEvent(ev) {
33 return JSON.stringify([
34 0,
35 ev.pubkey,
36 ev.created_at,
37 ev.kind,
38 ev.tags,
39 ev.content,
40 ]);
41 }
42
43 async function sha256hex(str) {
44 const data = new TextEncoder().encode(str);
45 const hash = await crypto.subtle.digest('SHA-256', data);
46 return bytesToHex(new Uint8Array(hash));
47 }
48
49 window.nostr = {
50 async getPublicKey() {
51 return TEST_PK;
52 },
53
54 async signEvent(event) {
55 const s = await getSecp();
56 // Compute event ID per NIP-01.
57 event.pubkey = TEST_PK;
58 const id = await sha256hex(serializeEvent(event));
59 event.id = id;
60 // BIP-340 Schnorr sign the ID hash.
61 const sig = s.sign(skBytes, hexToBytes(id));
62 event.sig = bytesToHex(sig);
63 return event;
64 },
65
66 nip04: {
67 async encrypt(pubkey, plaintext) {
68 return Promise.reject(new Error('nip04 not implemented in test signer'));
69 },
70 async decrypt(pubkey, ciphertext) {
71 return Promise.reject(new Error('nip04 not implemented in test signer'));
72 },
73 },
74
75 nip44: {
76 async encrypt(pubkey, plaintext) {
77 // NIP-44 requires ECDH which the secp256k1 WASM doesn't expose.
78 // For tests that need NIP-44, use nsec auth mode instead.
79 return Promise.reject(new Error('nip44 not implemented in test signer'));
80 },
81 async decrypt(pubkey, ciphertext) {
82 return Promise.reject(new Error('nip44 not implemented in test signer'));
83 },
84 },
85 };
86
87 console.log('[test-signer] window.nostr installed (pk: ' + TEST_PK.slice(0, 8) + '...)');
88