@qntx/nostr 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +25 -0
- package/dist/builder-BphJa-Y-.d.mts +67 -0
- package/dist/builder-q0VsvnYE.mjs +158 -0
- package/dist/builder-q0VsvnYE.mjs.map +1 -0
- package/dist/client-Bd8B1mYm.mjs +835 -0
- package/dist/client-Bd8B1mYm.mjs.map +1 -0
- package/dist/client.d.mts +2 -0
- package/dist/client.mjs +2 -0
- package/dist/core.d.mts +8 -0
- package/dist/core.mjs +9 -0
- package/dist/error-B49rbDzT.d.mts +7 -0
- package/dist/error-CwBxle6N.mjs +13 -0
- package/dist/error-CwBxle6N.mjs.map +1 -0
- package/dist/error-DZEs5OuZ.mjs +24 -0
- package/dist/error-DZEs5OuZ.mjs.map +1 -0
- package/dist/error-WEFS-R-4.d.mts +20 -0
- package/dist/event-B5D2jxt_.d.mts +108 -0
- package/dist/event-CzoQEFMF.mjs +188 -0
- package/dist/event-CzoQEFMF.mjs.map +1 -0
- package/dist/filter-BxwjEkZp.mjs +113 -0
- package/dist/filter-BxwjEkZp.mjs.map +1 -0
- package/dist/filter-DUEKP3q1.d.mts +40 -0
- package/dist/gossip-3xkRRCm_.mjs +220 -0
- package/dist/gossip-3xkRRCm_.mjs.map +1 -0
- package/dist/gossip-C5RVB1UB.d.mts +71 -0
- package/dist/gossip.d.mts +3 -0
- package/dist/gossip.mjs +2 -0
- package/dist/http-6vevbBlu.d.mts +22 -0
- package/dist/http-D2rhokZo.mjs +24 -0
- package/dist/http-D2rhokZo.mjs.map +1 -0
- package/dist/index-BYMnhRIC.d.mts +161 -0
- package/dist/index-C0C4e-Gn.d.mts +55 -0
- package/dist/index-CaxrMD1A.d.mts +1 -0
- package/dist/index-DaRyjo7O.d.mts +77 -0
- package/dist/index-DgOugrpF.d.mts +275 -0
- package/dist/index-EwL6fHLo.d.mts +267 -0
- package/dist/index-k2YhCgsh.d.mts +57 -0
- package/dist/index.d.mts +22 -0
- package/dist/index.mjs +23 -0
- package/dist/key-BiGxGLhg.d.mts +37 -0
- package/dist/key-Dn-aX4x4.mjs +130 -0
- package/dist/key-Dn-aX4x4.mjs.map +1 -0
- package/dist/kind-BLl4cLOc.mjs +59 -0
- package/dist/kind-BLl4cLOc.mjs.map +1 -0
- package/dist/loaders-BNQszDAn.mjs +767 -0
- package/dist/loaders-BNQszDAn.mjs.map +1 -0
- package/dist/loaders.d.mts +3 -0
- package/dist/loaders.mjs +2 -0
- package/dist/memory-BCmhZPek.mjs +461 -0
- package/dist/memory-BCmhZPek.mjs.map +1 -0
- package/dist/message-C_Uj-Y-c.mjs +179 -0
- package/dist/message-C_Uj-Y-c.mjs.map +1 -0
- package/dist/message-DJC-Jz6T.d.mts +32 -0
- package/dist/nip17-BWq-Kfq5.d.mts +38 -0
- package/dist/nip19-D7905oIv.d.mts +63 -0
- package/dist/nip46-C_DoxiS_.d.mts +51 -0
- package/dist/nip59-DljW_sYh.d.mts +76 -0
- package/dist/nip65-Di5hZRuV.d.mts +21 -0
- package/dist/nip77-ByxlgoQO.d.mts +55 -0
- package/dist/nips/blossom.d.mts +93 -0
- package/dist/nips/blossom.mjs +325 -0
- package/dist/nips/blossom.mjs.map +1 -0
- package/dist/nips/nip04.d.mts +8 -0
- package/dist/nips/nip04.mjs +41 -0
- package/dist/nips/nip04.mjs.map +1 -0
- package/dist/nips/nip05.d.mts +89 -0
- package/dist/nips/nip05.mjs +147 -0
- package/dist/nips/nip05.mjs.map +1 -0
- package/dist/nips/nip10.d.mts +43 -0
- package/dist/nips/nip10.mjs +194 -0
- package/dist/nips/nip10.mjs.map +1 -0
- package/dist/nips/nip11.d.mts +43 -0
- package/dist/nips/nip11.mjs +99 -0
- package/dist/nips/nip11.mjs.map +1 -0
- package/dist/nips/nip13.d.mts +23 -0
- package/dist/nips/nip13.mjs +88 -0
- package/dist/nips/nip13.mjs.map +1 -0
- package/dist/nips/nip17.d.mts +2 -0
- package/dist/nips/nip17.mjs +138 -0
- package/dist/nips/nip17.mjs.map +1 -0
- package/dist/nips/nip19.d.mts +2 -0
- package/dist/nips/nip19.mjs +174 -0
- package/dist/nips/nip19.mjs.map +1 -0
- package/dist/nips/nip21.d.mts +17 -0
- package/dist/nips/nip21.mjs +29 -0
- package/dist/nips/nip21.mjs.map +1 -0
- package/dist/nips/nip27.d.mts +42 -0
- package/dist/nips/nip27.mjs +175 -0
- package/dist/nips/nip27.mjs.map +1 -0
- package/dist/nips/nip42.d.mts +12 -0
- package/dist/nips/nip42.mjs +22 -0
- package/dist/nips/nip42.mjs.map +1 -0
- package/dist/nips/nip44.d.mts +12 -0
- package/dist/nips/nip44.mjs +125 -0
- package/dist/nips/nip44.mjs.map +1 -0
- package/dist/nips/nip46.d.mts +2 -0
- package/dist/nips/nip46.mjs +132 -0
- package/dist/nips/nip46.mjs.map +1 -0
- package/dist/nips/nip49.d.mts +12 -0
- package/dist/nips/nip49.mjs +80 -0
- package/dist/nips/nip49.mjs.map +1 -0
- package/dist/nips/nip51.d.mts +88 -0
- package/dist/nips/nip51.mjs +246 -0
- package/dist/nips/nip51.mjs.map +1 -0
- package/dist/nips/nip57.d.mts +43 -0
- package/dist/nips/nip57.mjs +230 -0
- package/dist/nips/nip57.mjs.map +1 -0
- package/dist/nips/nip59.d.mts +2 -0
- package/dist/nips/nip59.mjs +171 -0
- package/dist/nips/nip59.mjs.map +1 -0
- package/dist/nips/nip65.d.mts +2 -0
- package/dist/nips/nip65.mjs +76 -0
- package/dist/nips/nip65.mjs.map +1 -0
- package/dist/nips/nip77.d.mts +2 -0
- package/dist/nips/nip77.mjs +421 -0
- package/dist/nips/nip77.mjs.map +1 -0
- package/dist/nips/nip96.d.mts +31 -0
- package/dist/nips/nip96.mjs +95 -0
- package/dist/nips/nip96.mjs.map +1 -0
- package/dist/nips/nip98.d.mts +28 -0
- package/dist/nips/nip98.mjs +91 -0
- package/dist/nips/nip98.mjs.map +1 -0
- package/dist/nostr_crypto_wasm_bg-hi5aXi5P.mjs +4 -0
- package/dist/nostr_crypto_wasm_bg.wasm +0 -0
- package/dist/pool-C_j1OmBB.mjs +1881 -0
- package/dist/pool-C_j1OmBB.mjs.map +1 -0
- package/dist/pool-DhRi7l-b.d.mts +297 -0
- package/dist/relay.d.mts +4 -0
- package/dist/relay.mjs +2 -0
- package/dist/signer-CZ6K6FUc.mjs +473 -0
- package/dist/signer-CZ6K6FUc.mjs.map +1 -0
- package/dist/signer.d.mts +3 -0
- package/dist/signer.mjs +2 -0
- package/dist/storage-DOy0iLRE.mjs +870 -0
- package/dist/storage-DOy0iLRE.mjs.map +1 -0
- package/dist/storage.d.mts +4 -0
- package/dist/storage.mjs +4 -0
- package/dist/types-BzyADqnw.d.mts +19 -0
- package/dist/types-Dn24TPFs.d.mts +43 -0
- package/dist/util-6tfLQ9JF.mjs +73 -0
- package/dist/util-6tfLQ9JF.mjs.map +1 -0
- package/dist/wasm.d.mts +19 -0
- package/dist/wasm.mjs +237 -0
- package/dist/wasm.mjs.map +1 -0
- package/package.json +204 -0
|
@@ -0,0 +1,473 @@
|
|
|
1
|
+
import { a as isHex32 } from "./util-6tfLQ9JF.mjs";
|
|
2
|
+
import { t as CryptoError } from "./error-DZEs5OuZ.mjs";
|
|
3
|
+
import { t as Kind } from "./kind-BLl4cLOc.mjs";
|
|
4
|
+
import { l as signedMatchesUnsigned, m as Tag, p as validateSignedEvent } from "./event-CzoQEFMF.mjs";
|
|
5
|
+
import { i as getPublicKey, n as SecretKey, o as signEvent, r as finalizeEvent, s as verifyEvent, t as Keys } from "./key-Dn-aX4x4.mjs";
|
|
6
|
+
import { decrypt, encrypt } from "./nips/nip04.mjs";
|
|
7
|
+
import { decrypt as decrypt$1, encrypt as encrypt$1, getConversationKey } from "./nips/nip44.mjs";
|
|
8
|
+
import { Nip46Error, decodeNip46Response, encodeNip46Request, parseBunkerURL, parseNostrConnectURI } from "./nips/nip46.mjs";
|
|
9
|
+
//#region src/signer/keys.ts
|
|
10
|
+
/** Local secret-key signer with NIP-04 (legacy) and NIP-44 support. */
|
|
11
|
+
var KeysSigner = class {
|
|
12
|
+
#keys;
|
|
13
|
+
#convKeys = /* @__PURE__ */ new Map();
|
|
14
|
+
constructor(secretKey) {
|
|
15
|
+
this.#keys = secretKey instanceof Keys ? secretKey : Keys.fromSecretKey(secretKey);
|
|
16
|
+
}
|
|
17
|
+
get keys() {
|
|
18
|
+
return this.#keys;
|
|
19
|
+
}
|
|
20
|
+
async getPublicKey() {
|
|
21
|
+
return this.#keys.publicKey;
|
|
22
|
+
}
|
|
23
|
+
async signEvent(unsigned) {
|
|
24
|
+
const expected = getPublicKey(this.#keys.secretKey);
|
|
25
|
+
if (unsigned.pubkey.toLowerCase() !== expected) throw new CryptoError("unsigned event pubkey does not match signer");
|
|
26
|
+
return signEvent(unsigned, this.#keys.secretKey);
|
|
27
|
+
}
|
|
28
|
+
async nip04Encrypt(peer, plaintext) {
|
|
29
|
+
return encrypt(this.#keys.secretKey.bytes, peer, plaintext);
|
|
30
|
+
}
|
|
31
|
+
async nip04Decrypt(peer, ciphertext) {
|
|
32
|
+
return decrypt(this.#keys.secretKey.bytes, peer, ciphertext);
|
|
33
|
+
}
|
|
34
|
+
#conversationKey(peer) {
|
|
35
|
+
const pk = peer.toLowerCase();
|
|
36
|
+
let key = this.#convKeys.get(pk);
|
|
37
|
+
if (!key) {
|
|
38
|
+
key = getConversationKey(this.#keys.secretKey.bytes, pk);
|
|
39
|
+
this.#convKeys.set(pk, key);
|
|
40
|
+
}
|
|
41
|
+
return key;
|
|
42
|
+
}
|
|
43
|
+
async nip44Encrypt(peer, plaintext) {
|
|
44
|
+
return encrypt$1(plaintext, this.#conversationKey(peer));
|
|
45
|
+
}
|
|
46
|
+
async nip44Decrypt(peer, payload) {
|
|
47
|
+
return decrypt$1(payload, this.#conversationKey(peer));
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
//#endregion
|
|
51
|
+
//#region src/signer/nip07.ts
|
|
52
|
+
/** Resolve `window.nostr` / `globalThis.nostr` when present. */
|
|
53
|
+
function getWindowNostr() {
|
|
54
|
+
const g = globalThis;
|
|
55
|
+
return g.nostr ?? g.window?.nostr;
|
|
56
|
+
}
|
|
57
|
+
/** True when a NIP-07 provider is injected in the current environment. */
|
|
58
|
+
function isNip07Available() {
|
|
59
|
+
const n = getWindowNostr();
|
|
60
|
+
return Boolean(n && typeof n.getPublicKey === "function" && typeof n.signEvent === "function");
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Signer backed by a NIP-07 browser extension (or any injected provider).
|
|
64
|
+
* Never holds secret keys in-process.
|
|
65
|
+
*/
|
|
66
|
+
var Nip07Signer = class {
|
|
67
|
+
#provider;
|
|
68
|
+
constructor(provider) {
|
|
69
|
+
this.#provider = provider;
|
|
70
|
+
}
|
|
71
|
+
#resolve() {
|
|
72
|
+
const provider = this.#provider ?? getWindowNostr();
|
|
73
|
+
if (!provider) throw new CryptoError("NIP-07 provider not available (window.nostr missing)");
|
|
74
|
+
return provider;
|
|
75
|
+
}
|
|
76
|
+
async getPublicKey() {
|
|
77
|
+
const pk = await this.#resolve().getPublicKey();
|
|
78
|
+
if (typeof pk !== "string" || pk.length !== 64) throw new CryptoError("NIP-07 getPublicKey returned an invalid pubkey");
|
|
79
|
+
return pk.toLowerCase();
|
|
80
|
+
}
|
|
81
|
+
async signEvent(unsigned) {
|
|
82
|
+
const provider = this.#resolve();
|
|
83
|
+
const template = {
|
|
84
|
+
kind: unsigned.kind,
|
|
85
|
+
tags: unsigned.tags.map((t) => [...t]),
|
|
86
|
+
content: unsigned.content,
|
|
87
|
+
created_at: unsigned.created_at
|
|
88
|
+
};
|
|
89
|
+
const signed = await provider.signEvent(template);
|
|
90
|
+
if (!validateSignedEvent(signed)) throw new CryptoError("NIP-07 signEvent returned an invalid event");
|
|
91
|
+
if (!verifyEvent(signed)) throw new CryptoError("NIP-07 signed event failed signature verification");
|
|
92
|
+
if (!signedMatchesUnsigned(signed, unsigned)) throw new CryptoError("NIP-07 signed event does not match unsigned template");
|
|
93
|
+
return signed;
|
|
94
|
+
}
|
|
95
|
+
async nip04Encrypt(peer, plaintext) {
|
|
96
|
+
const nip04 = this.#resolve().nip04;
|
|
97
|
+
if (!nip04?.encrypt) throw new CryptoError("NIP-07 provider does not support nip04.encrypt");
|
|
98
|
+
return nip04.encrypt(peer, plaintext);
|
|
99
|
+
}
|
|
100
|
+
async nip04Decrypt(peer, ciphertext) {
|
|
101
|
+
const nip04 = this.#resolve().nip04;
|
|
102
|
+
if (!nip04?.decrypt) throw new CryptoError("NIP-07 provider does not support nip04.decrypt");
|
|
103
|
+
return nip04.decrypt(peer, ciphertext);
|
|
104
|
+
}
|
|
105
|
+
async nip44Encrypt(peer, plaintext) {
|
|
106
|
+
const nip44 = this.#resolve().nip44;
|
|
107
|
+
if (!nip44?.encrypt) throw new CryptoError("NIP-07 provider does not support nip44.encrypt");
|
|
108
|
+
return nip44.encrypt(peer, plaintext);
|
|
109
|
+
}
|
|
110
|
+
async nip44Decrypt(peer, payload) {
|
|
111
|
+
const nip44 = this.#resolve().nip44;
|
|
112
|
+
if (!nip44?.decrypt) throw new CryptoError("NIP-07 provider does not support nip44.decrypt");
|
|
113
|
+
return nip44.decrypt(peer, payload);
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
//#endregion
|
|
117
|
+
//#region src/signer/nip46.ts
|
|
118
|
+
function resolveClientSecret(key) {
|
|
119
|
+
if (key === void 0) return SecretKey.generate();
|
|
120
|
+
if (key instanceof SecretKey) return key;
|
|
121
|
+
if (typeof key === "string") return SecretKey.fromHex(key);
|
|
122
|
+
return SecretKey.fromBytes(key);
|
|
123
|
+
}
|
|
124
|
+
function resolveTransport(opts) {
|
|
125
|
+
if (opts.pool) return {
|
|
126
|
+
pool: opts.pool,
|
|
127
|
+
ownsPool: false
|
|
128
|
+
};
|
|
129
|
+
if (opts.createPool) return {
|
|
130
|
+
pool: opts.createPool(),
|
|
131
|
+
ownsPool: true
|
|
132
|
+
};
|
|
133
|
+
throw new Nip46Error("Nip46Signer requires pool or createPool (inject Pool from @qntx/nostr/relay)");
|
|
134
|
+
}
|
|
135
|
+
function applyPointerOpts(pointer, opts) {
|
|
136
|
+
let next = {
|
|
137
|
+
pubkey: pointer.pubkey.toLowerCase(),
|
|
138
|
+
relays: [...pointer.relays],
|
|
139
|
+
secret: pointer.secret
|
|
140
|
+
};
|
|
141
|
+
if (opts.secret !== void 0 && next.secret == null) next = {
|
|
142
|
+
...next,
|
|
143
|
+
secret: opts.secret
|
|
144
|
+
};
|
|
145
|
+
const relays = next.relays.length > 0 ? next.relays : [...opts.relays ?? []];
|
|
146
|
+
if (relays.length === 0) throw new Nip46Error("no relays for bunker connection");
|
|
147
|
+
if (next.relays.length > 0 && opts.relays?.length) {
|
|
148
|
+
const merged = [...next.relays];
|
|
149
|
+
for (const r of opts.relays) if (!merged.includes(r)) merged.push(r);
|
|
150
|
+
return {
|
|
151
|
+
...next,
|
|
152
|
+
relays: merged
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
return {
|
|
156
|
+
...next,
|
|
157
|
+
relays
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
function resolveBunkerPointer(input) {
|
|
161
|
+
if (typeof input !== "string") return {
|
|
162
|
+
pubkey: input.pubkey.toLowerCase(),
|
|
163
|
+
relays: [...input.relays],
|
|
164
|
+
secret: input.secret
|
|
165
|
+
};
|
|
166
|
+
const bunker = parseBunkerURL(input);
|
|
167
|
+
if (bunker) return bunker;
|
|
168
|
+
throw new Nip46Error("invalid bunker input (expected bunker:// URL or BunkerPointer)");
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* NIP-46 remote signer (bunker / nostrconnect).
|
|
172
|
+
* Implements {@link NostrSigner}; never holds the remote user's secret key.
|
|
173
|
+
* Network I/O is injected via {@link Nip46Transport} (no relay import).
|
|
174
|
+
*/
|
|
175
|
+
var Nip46Signer = class Nip46Signer {
|
|
176
|
+
#pool;
|
|
177
|
+
#ownsPool;
|
|
178
|
+
#clientSecret;
|
|
179
|
+
#clientPubkey;
|
|
180
|
+
#pointer;
|
|
181
|
+
#conversationKey;
|
|
182
|
+
#onAuthUrl;
|
|
183
|
+
#timeoutMs;
|
|
184
|
+
#perms;
|
|
185
|
+
#metadata;
|
|
186
|
+
#relays;
|
|
187
|
+
#listeners = /* @__PURE__ */ new Map();
|
|
188
|
+
#waitingAuth = /* @__PURE__ */ new Set();
|
|
189
|
+
#sub;
|
|
190
|
+
#open = false;
|
|
191
|
+
#serial = 0;
|
|
192
|
+
#idPrefix = Math.random().toString(36).slice(2, 9);
|
|
193
|
+
#cachedRemotePubkey;
|
|
194
|
+
constructor(clientSecret, pointer, pool, ownsPool, opts) {
|
|
195
|
+
if (pointer.relays.length === 0) throw new Nip46Error("bunker pointer has no relays");
|
|
196
|
+
this.#clientSecret = clientSecret;
|
|
197
|
+
this.#clientPubkey = getPublicKey(clientSecret);
|
|
198
|
+
this.#pointer = {
|
|
199
|
+
pubkey: pointer.pubkey.toLowerCase(),
|
|
200
|
+
relays: [...pointer.relays],
|
|
201
|
+
secret: pointer.secret
|
|
202
|
+
};
|
|
203
|
+
this.#relays = [...pointer.relays];
|
|
204
|
+
this.#pool = pool;
|
|
205
|
+
this.#ownsPool = ownsPool;
|
|
206
|
+
this.#conversationKey = getConversationKey(clientSecret.bytes, this.#pointer.pubkey);
|
|
207
|
+
this.#onAuthUrl = opts.onAuthUrl;
|
|
208
|
+
this.#timeoutMs = opts.timeoutMs ?? 3e4;
|
|
209
|
+
this.#perms = opts.perms;
|
|
210
|
+
this.#metadata = opts.metadata;
|
|
211
|
+
}
|
|
212
|
+
get bunker() {
|
|
213
|
+
return {
|
|
214
|
+
pubkey: this.#pointer.pubkey,
|
|
215
|
+
relays: [...this.#relays],
|
|
216
|
+
secret: this.#pointer.secret
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
get clientPublicKey() {
|
|
220
|
+
return this.#clientPubkey;
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Subscribe to an already-known bunker pointer. Does not send the `connect` RPC
|
|
224
|
+
* (reconnect without a new handshake).
|
|
225
|
+
* Requires `clientSecretKey` — reconnect must reuse the original client identity.
|
|
226
|
+
*/
|
|
227
|
+
static fromBunker(pointer, opts) {
|
|
228
|
+
if (opts.clientSecretKey === void 0) throw new Nip46Error("fromBunker requires clientSecretKey");
|
|
229
|
+
const resolved = applyPointerOpts(pointer, opts);
|
|
230
|
+
const sk = resolveClientSecret(opts.clientSecretKey);
|
|
231
|
+
const { pool, ownsPool } = resolveTransport(opts);
|
|
232
|
+
const signer = new Nip46Signer(sk, resolved, pool, ownsPool, opts);
|
|
233
|
+
signer.#startSubscription();
|
|
234
|
+
return signer;
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Connect using a `bunker://` URL or pre-parsed pointer.
|
|
238
|
+
* Invalid strings throw. A NIP-05 identifier is not a bunker pointer.
|
|
239
|
+
* When both pointer and `opts.relays` are nonempty, unique `opts.relays` are appended.
|
|
240
|
+
*/
|
|
241
|
+
static async connect(input, opts = {}) {
|
|
242
|
+
const pointer = resolveBunkerPointer(input);
|
|
243
|
+
const signer = Nip46Signer.fromBunker(pointer, {
|
|
244
|
+
...opts,
|
|
245
|
+
clientSecretKey: resolveClientSecret(opts.clientSecretKey)
|
|
246
|
+
});
|
|
247
|
+
try {
|
|
248
|
+
await signer.connectRemote();
|
|
249
|
+
try {
|
|
250
|
+
await signer.switchRelays();
|
|
251
|
+
} catch {}
|
|
252
|
+
await signer.getPublicKey();
|
|
253
|
+
return signer;
|
|
254
|
+
} catch (err) {
|
|
255
|
+
await signer.close();
|
|
256
|
+
throw err;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Wait for a bunker to complete a client-initiated `nostrconnect://` handshake.
|
|
261
|
+
* Requires `clientSecretKey` whose pubkey matches the URI client pubkey
|
|
262
|
+
* (build the URI with {@link createNostrConnectURI} after generating keys).
|
|
263
|
+
*/
|
|
264
|
+
static async fromNostrConnectURI(connectionURI, opts) {
|
|
265
|
+
const params = parseNostrConnectURI(connectionURI);
|
|
266
|
+
const sk = resolveClientSecret(opts.clientSecretKey);
|
|
267
|
+
const clientPubkey = getPublicKey(sk);
|
|
268
|
+
if (clientPubkey !== params.clientPubkey) throw new Nip46Error("client secret key does not match nostrconnect client pubkey");
|
|
269
|
+
const { pool, ownsPool } = resolveTransport(opts);
|
|
270
|
+
const handshakeTimeoutMs = opts.handshakeTimeoutMs ?? 3e5;
|
|
271
|
+
return new Promise((resolve, reject) => {
|
|
272
|
+
let settled = false;
|
|
273
|
+
const finish = (err, signer) => {
|
|
274
|
+
if (settled) return;
|
|
275
|
+
settled = true;
|
|
276
|
+
clearTimeout(timer);
|
|
277
|
+
sub.close(err ? "failed" : "connected");
|
|
278
|
+
if (err) {
|
|
279
|
+
if (ownsPool) pool.close();
|
|
280
|
+
reject(err);
|
|
281
|
+
} else if (signer) resolve(signer);
|
|
282
|
+
};
|
|
283
|
+
const timer = setTimeout(() => {
|
|
284
|
+
finish(new Nip46Error("nostrconnect handshake timed out"));
|
|
285
|
+
}, handshakeTimeoutMs);
|
|
286
|
+
const sub = pool.subscribe(params.relays, [{
|
|
287
|
+
kinds: [Kind.NostrConnect],
|
|
288
|
+
"#p": [clientPubkey],
|
|
289
|
+
limit: 0
|
|
290
|
+
}], {
|
|
291
|
+
signal: opts.signal,
|
|
292
|
+
onevent: (event) => {
|
|
293
|
+
try {
|
|
294
|
+
const convKey = getConversationKey(sk.bytes, event.pubkey);
|
|
295
|
+
const payload = decrypt$1(event.content, convKey);
|
|
296
|
+
if (decodeNip46Response(payload).result !== params.secret) return;
|
|
297
|
+
const pointer = {
|
|
298
|
+
pubkey: event.pubkey.toLowerCase(),
|
|
299
|
+
relays: params.relays,
|
|
300
|
+
secret: params.secret
|
|
301
|
+
};
|
|
302
|
+
const signer = new Nip46Signer(sk, pointer, pool, ownsPool, opts);
|
|
303
|
+
signer.#startSubscription();
|
|
304
|
+
signer.switchRelays().catch(() => void 0).then(() => signer.getPublicKey()).then(() => finish(void 0, signer)).catch((e) => finish(e instanceof Error ? e : new Nip46Error(String(e))));
|
|
305
|
+
} catch {}
|
|
306
|
+
},
|
|
307
|
+
onclose: (reason) => {
|
|
308
|
+
if (reason !== "connected" && reason !== "failed") finish(new Nip46Error(`nostrconnect subscription closed: ${reason}`));
|
|
309
|
+
}
|
|
310
|
+
});
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
#startSubscription() {
|
|
314
|
+
this.#sub?.close();
|
|
315
|
+
this.#sub = this.#pool.subscribe(this.#relays, [{
|
|
316
|
+
kinds: [Kind.NostrConnect],
|
|
317
|
+
authors: [this.#pointer.pubkey],
|
|
318
|
+
"#p": [this.#clientPubkey],
|
|
319
|
+
limit: 0
|
|
320
|
+
}], {
|
|
321
|
+
onevent: (event) => {
|
|
322
|
+
try {
|
|
323
|
+
const payload = decrypt$1(event.content, this.#conversationKey);
|
|
324
|
+
const { id, result, error } = decodeNip46Response(payload);
|
|
325
|
+
if (result === "auth_url" && this.#waitingAuth.has(id)) {
|
|
326
|
+
this.#waitingAuth.delete(id);
|
|
327
|
+
if (error) this.#onAuthUrl?.(error);
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
const listener = this.#listeners.get(id);
|
|
331
|
+
if (!listener) return;
|
|
332
|
+
clearTimeout(listener.timer);
|
|
333
|
+
this.#listeners.delete(id);
|
|
334
|
+
this.#waitingAuth.delete(id);
|
|
335
|
+
if (error) listener.reject(new Nip46Error(error));
|
|
336
|
+
else if (result !== void 0) listener.resolve(result);
|
|
337
|
+
else listener.reject(new Nip46Error("empty NIP-46 response"));
|
|
338
|
+
} catch {}
|
|
339
|
+
},
|
|
340
|
+
onclose: () => {
|
|
341
|
+
this.#sub = void 0;
|
|
342
|
+
}
|
|
343
|
+
});
|
|
344
|
+
this.#open = true;
|
|
345
|
+
}
|
|
346
|
+
async connectRemote(overrides) {
|
|
347
|
+
const metadata = overrides?.metadata ?? this.#metadata;
|
|
348
|
+
const perms = overrides?.perms ?? this.#perms;
|
|
349
|
+
const params = [this.#pointer.pubkey, this.#pointer.secret ?? ""];
|
|
350
|
+
if (perms?.length || metadata) params.push(perms?.length ? perms.join(",") : "");
|
|
351
|
+
if (metadata) params.push(JSON.stringify(metadata));
|
|
352
|
+
const result = await this.#sendRequest("connect", params);
|
|
353
|
+
if (result === "ack") return;
|
|
354
|
+
if (this.#pointer.secret && result === this.#pointer.secret) return;
|
|
355
|
+
throw new Nip46Error(`connect result is not ack or secret: ${result}`);
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Ask the bunker for its preferred relay list and resubscribe when it changes.
|
|
359
|
+
* Spec result is a JSON array of URLs, or `null` when nothing changes.
|
|
360
|
+
*/
|
|
361
|
+
async switchRelays() {
|
|
362
|
+
const resp = await this.#sendRequest("switch_relays", []);
|
|
363
|
+
if (resp === "null") return null;
|
|
364
|
+
let parsed;
|
|
365
|
+
try {
|
|
366
|
+
parsed = JSON.parse(resp);
|
|
367
|
+
} catch (cause) {
|
|
368
|
+
throw new Nip46Error("invalid switch_relays JSON", { cause: cause instanceof Error ? cause : void 0 });
|
|
369
|
+
}
|
|
370
|
+
if (!Array.isArray(parsed) || parsed.length === 0 || !parsed.every((x) => typeof x === "string")) throw new Nip46Error("invalid switch_relays result");
|
|
371
|
+
this.#relays = parsed;
|
|
372
|
+
this.#startSubscription();
|
|
373
|
+
return parsed;
|
|
374
|
+
}
|
|
375
|
+
/** Courtesy session teardown. Always closes the local signer afterwards. */
|
|
376
|
+
async logout() {
|
|
377
|
+
try {
|
|
378
|
+
const resp = await this.#sendRequest("logout", []);
|
|
379
|
+
if (resp !== "ack") throw new Nip46Error(`logout result is not ack: ${resp}`);
|
|
380
|
+
} finally {
|
|
381
|
+
await this.close();
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
async ping() {
|
|
385
|
+
const resp = await this.#sendRequest("ping", []);
|
|
386
|
+
if (resp !== "pong") throw new Nip46Error(`ping result is not pong: ${resp}`);
|
|
387
|
+
}
|
|
388
|
+
async getPublicKey() {
|
|
389
|
+
if (!this.#cachedRemotePubkey) {
|
|
390
|
+
const pk = await this.#sendRequest("get_public_key", []);
|
|
391
|
+
if (!isHex32(pk)) throw new Nip46Error("bunker returned invalid pubkey");
|
|
392
|
+
this.#cachedRemotePubkey = pk.toLowerCase();
|
|
393
|
+
}
|
|
394
|
+
return this.#cachedRemotePubkey;
|
|
395
|
+
}
|
|
396
|
+
async signEvent(unsigned) {
|
|
397
|
+
const template = {
|
|
398
|
+
kind: unsigned.kind,
|
|
399
|
+
tags: unsigned.tags,
|
|
400
|
+
content: unsigned.content,
|
|
401
|
+
created_at: unsigned.created_at
|
|
402
|
+
};
|
|
403
|
+
const resp = await this.#sendRequest("sign_event", [JSON.stringify(template)]);
|
|
404
|
+
let signed;
|
|
405
|
+
try {
|
|
406
|
+
signed = JSON.parse(resp);
|
|
407
|
+
} catch (cause) {
|
|
408
|
+
throw new Nip46Error("bunker returned invalid sign_event JSON", { cause: cause instanceof Error ? cause : void 0 });
|
|
409
|
+
}
|
|
410
|
+
if (!validateSignedEvent(signed) || !verifyEvent(signed)) throw new Nip46Error("bunker returned improperly signed event");
|
|
411
|
+
if (!signedMatchesUnsigned(signed, unsigned)) throw new Nip46Error("signed event does not match unsigned template");
|
|
412
|
+
return signed;
|
|
413
|
+
}
|
|
414
|
+
async nip04Encrypt(peer, plaintext) {
|
|
415
|
+
return this.#sendRequest("nip04_encrypt", [peer, plaintext]);
|
|
416
|
+
}
|
|
417
|
+
async nip04Decrypt(peer, ciphertext) {
|
|
418
|
+
return this.#sendRequest("nip04_decrypt", [peer, ciphertext]);
|
|
419
|
+
}
|
|
420
|
+
async nip44Encrypt(peer, plaintext) {
|
|
421
|
+
return this.#sendRequest("nip44_encrypt", [peer, plaintext]);
|
|
422
|
+
}
|
|
423
|
+
async nip44Decrypt(peer, payload) {
|
|
424
|
+
return this.#sendRequest("nip44_decrypt", [peer, payload]);
|
|
425
|
+
}
|
|
426
|
+
async close() {
|
|
427
|
+
this.#open = false;
|
|
428
|
+
for (const [, listener] of this.#listeners) {
|
|
429
|
+
clearTimeout(listener.timer);
|
|
430
|
+
listener.reject(new Nip46Error("signer closed"));
|
|
431
|
+
}
|
|
432
|
+
this.#listeners.clear();
|
|
433
|
+
this.#sub?.close("signer closed");
|
|
434
|
+
this.#sub = void 0;
|
|
435
|
+
if (this.#ownsPool) this.#pool.close();
|
|
436
|
+
}
|
|
437
|
+
async #sendRequest(method, params) {
|
|
438
|
+
if (!this.#open) throw new Nip46Error("signer is closed");
|
|
439
|
+
if (!this.#sub) this.#startSubscription();
|
|
440
|
+
this.#serial += 1;
|
|
441
|
+
const id = `${this.#idPrefix}-${this.#serial}`;
|
|
442
|
+
const encrypted = encrypt$1(encodeNip46Request({
|
|
443
|
+
id,
|
|
444
|
+
method,
|
|
445
|
+
params
|
|
446
|
+
}), this.#conversationKey);
|
|
447
|
+
const event = finalizeEvent({
|
|
448
|
+
kind: Kind.NostrConnect,
|
|
449
|
+
tags: [Tag.p(this.#pointer.pubkey)],
|
|
450
|
+
content: encrypted,
|
|
451
|
+
created_at: Math.floor(Date.now() / 1e3)
|
|
452
|
+
}, this.#clientSecret);
|
|
453
|
+
const resultPromise = new Promise((resolve, reject) => {
|
|
454
|
+
const timer = setTimeout(() => {
|
|
455
|
+
this.#listeners.delete(id);
|
|
456
|
+
this.#waitingAuth.delete(id);
|
|
457
|
+
reject(new Nip46Error(`NIP-46 request timed out: ${method}`));
|
|
458
|
+
}, this.#timeoutMs);
|
|
459
|
+
this.#listeners.set(id, {
|
|
460
|
+
resolve,
|
|
461
|
+
reject,
|
|
462
|
+
timer
|
|
463
|
+
});
|
|
464
|
+
this.#waitingAuth.add(id);
|
|
465
|
+
});
|
|
466
|
+
await this.#pool.publish(this.#relays, event);
|
|
467
|
+
return resultPromise;
|
|
468
|
+
}
|
|
469
|
+
};
|
|
470
|
+
//#endregion
|
|
471
|
+
export { KeysSigner as a, isNip07Available as i, Nip07Signer as n, getWindowNostr as r, Nip46Signer as t };
|
|
472
|
+
|
|
473
|
+
//# sourceMappingURL=signer-CZ6K6FUc.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signer-CZ6K6FUc.mjs","names":["#keys","#convKeys","nip04.encrypt","nip04.decrypt","nip44.getConversationKey","nip44.encrypt","#conversationKey","nip44.decrypt","#provider","#resolve","#pool","#ownsPool","#clientSecret","#clientPubkey","#pointer","#conversationKey","#onAuthUrl","#timeoutMs","#perms","#metadata","#listeners","#waitingAuth","#relays","#startSubscription","decrypt","#sub","#open","#sendRequest","#cachedRemotePubkey","#serial","#idPrefix","encrypt"],"sources":["../src/signer/keys.ts","../src/signer/nip07.ts","../src/signer/nip46.ts"],"sourcesContent":["import type { Event, UnsignedEvent } from \"../core/event.ts\";\nimport { CryptoError } from \"../core/error.ts\";\nimport { Keys, SecretKey, getPublicKey, signEvent } from \"../core/key.ts\";\nimport * as nip04 from \"../nips/nip04.ts\";\nimport * as nip44 from \"../nips/nip44.ts\";\nimport type { NostrSigner } from \"./types.ts\";\n\n/** Local secret-key signer with NIP-04 (legacy) and NIP-44 support. */\nexport class KeysSigner implements NostrSigner {\n readonly #keys: Keys;\n readonly #convKeys = new Map<string, Uint8Array>();\n\n constructor(secretKey: SecretKey | Uint8Array | string | Keys) {\n this.#keys = secretKey instanceof Keys ? secretKey : Keys.fromSecretKey(secretKey);\n }\n\n get keys(): Keys {\n return this.#keys;\n }\n\n async getPublicKey(): Promise<string> {\n return this.#keys.publicKey;\n }\n\n async signEvent(unsigned: UnsignedEvent): Promise<Event> {\n const expected = getPublicKey(this.#keys.secretKey);\n if (unsigned.pubkey.toLowerCase() !== expected) {\n throw new CryptoError(\"unsigned event pubkey does not match signer\");\n }\n return signEvent(unsigned, this.#keys.secretKey);\n }\n\n async nip04Encrypt(peer: string, plaintext: string): Promise<string> {\n return nip04.encrypt(this.#keys.secretKey.bytes, peer, plaintext);\n }\n\n async nip04Decrypt(peer: string, ciphertext: string): Promise<string> {\n return nip04.decrypt(this.#keys.secretKey.bytes, peer, ciphertext);\n }\n\n #conversationKey(peer: string): Uint8Array {\n const pk = peer.toLowerCase();\n let key = this.#convKeys.get(pk);\n if (!key) {\n key = nip44.getConversationKey(this.#keys.secretKey.bytes, pk);\n this.#convKeys.set(pk, key);\n }\n return key;\n }\n\n async nip44Encrypt(peer: string, plaintext: string): Promise<string> {\n return nip44.encrypt(plaintext, this.#conversationKey(peer));\n }\n\n async nip44Decrypt(peer: string, payload: string): Promise<string> {\n return nip44.decrypt(payload, this.#conversationKey(peer));\n }\n}\n","import type { Event, EventTemplate, UnsignedEvent } from \"../core/event.ts\";\nimport { signedMatchesUnsigned, validateSignedEvent } from \"../core/event.ts\";\nimport { CryptoError } from \"../core/error.ts\";\nimport { verifyEvent } from \"../core/key.ts\";\nimport type { NostrSigner } from \"./types.ts\";\n\n/**\n * Minimal NIP-07 provider surface (browser extension `window.nostr`).\n * @see https://github.com/nostr-protocol/nips/blob/master/07.md\n */\nexport type WindowNostr = {\n getPublicKey(): Promise<string>;\n signEvent(event: EventTemplate): Promise<Event>;\n nip04?: {\n encrypt(pubkey: string, plaintext: string): Promise<string>;\n decrypt(pubkey: string, ciphertext: string): Promise<string>;\n };\n nip44?: {\n encrypt(pubkey: string, plaintext: string): Promise<string>;\n decrypt(pubkey: string, ciphertext: string): Promise<string>;\n };\n};\n\ntype GlobalWithNostr = typeof globalThis & {\n nostr?: WindowNostr;\n window?: { nostr?: WindowNostr };\n};\n\n/** Resolve `window.nostr` / `globalThis.nostr` when present. */\nexport function getWindowNostr(): WindowNostr | undefined {\n const g = globalThis as GlobalWithNostr;\n return g.nostr ?? g.window?.nostr;\n}\n\n/** True when a NIP-07 provider is injected in the current environment. */\nexport function isNip07Available(): boolean {\n const n = getWindowNostr();\n return Boolean(n && typeof n.getPublicKey === \"function\" && typeof n.signEvent === \"function\");\n}\n\n/**\n * Signer backed by a NIP-07 browser extension (or any injected provider).\n * Never holds secret keys in-process.\n */\nexport class Nip07Signer implements NostrSigner {\n readonly #provider: WindowNostr | undefined;\n\n constructor(provider?: WindowNostr) {\n this.#provider = provider;\n }\n\n #resolve(): WindowNostr {\n const provider = this.#provider ?? getWindowNostr();\n if (!provider) {\n throw new CryptoError(\"NIP-07 provider not available (window.nostr missing)\");\n }\n return provider;\n }\n\n async getPublicKey(): Promise<string> {\n const pk = await this.#resolve().getPublicKey();\n if (typeof pk !== \"string\" || pk.length !== 64) {\n throw new CryptoError(\"NIP-07 getPublicKey returned an invalid pubkey\");\n }\n return pk.toLowerCase();\n }\n\n async signEvent(unsigned: UnsignedEvent): Promise<Event> {\n const provider = this.#resolve();\n const template: EventTemplate = {\n kind: unsigned.kind,\n tags: unsigned.tags.map((t) => [...t] as [string, ...string[]]),\n content: unsigned.content,\n created_at: unsigned.created_at,\n };\n\n const signed = await provider.signEvent(template);\n if (!validateSignedEvent(signed)) {\n throw new CryptoError(\"NIP-07 signEvent returned an invalid event\");\n }\n if (!verifyEvent(signed)) {\n throw new CryptoError(\"NIP-07 signed event failed signature verification\");\n }\n if (!signedMatchesUnsigned(signed, unsigned)) {\n throw new CryptoError(\"NIP-07 signed event does not match unsigned template\");\n }\n return signed;\n }\n\n async nip04Encrypt(peer: string, plaintext: string): Promise<string> {\n const nip04 = this.#resolve().nip04;\n if (!nip04?.encrypt) throw new CryptoError(\"NIP-07 provider does not support nip04.encrypt\");\n return nip04.encrypt(peer, plaintext);\n }\n\n async nip04Decrypt(peer: string, ciphertext: string): Promise<string> {\n const nip04 = this.#resolve().nip04;\n if (!nip04?.decrypt) throw new CryptoError(\"NIP-07 provider does not support nip04.decrypt\");\n return nip04.decrypt(peer, ciphertext);\n }\n\n async nip44Encrypt(peer: string, plaintext: string): Promise<string> {\n const nip44 = this.#resolve().nip44;\n if (!nip44?.encrypt) throw new CryptoError(\"NIP-07 provider does not support nip44.encrypt\");\n return nip44.encrypt(peer, plaintext);\n }\n\n async nip44Decrypt(peer: string, payload: string): Promise<string> {\n const nip44 = this.#resolve().nip44;\n if (!nip44?.decrypt) throw new CryptoError(\"NIP-07 provider does not support nip44.decrypt\");\n return nip44.decrypt(peer, payload);\n }\n}\n","import type { Event, EventTemplate, UnsignedEvent } from \"../core/event.ts\";\nimport { signedMatchesUnsigned, validateSignedEvent } from \"../core/event.ts\";\nimport type { Filter } from \"../core/filter.ts\";\nimport { Kind } from \"../core/kind.ts\";\nimport { SecretKey, finalizeEvent, getPublicKey, verifyEvent } from \"../core/key.ts\";\nimport { Tag } from \"../core/tag.ts\";\nimport { isHex32 } from \"../core/util.ts\";\nimport { decrypt, encrypt, getConversationKey } from \"../nips/nip44.ts\";\nimport {\n Nip46Error,\n decodeNip46Response,\n encodeNip46Request,\n parseBunkerURL,\n parseNostrConnectURI,\n type BunkerPointer,\n type ClientMetadata,\n type Nip46Request,\n} from \"../nips/nip46.ts\";\nimport type { NostrSigner } from \"./types.ts\";\n\n/** Subscribe options used by NIP-46 transport (structural subset of Pool). */\nexport type Nip46SubscribeOptions = {\n signal?: AbortSignal;\n onevent?: (event: Event) => void;\n onclose?: (reason: string) => void;\n};\n\n/**\n * Structural relay transport for NIP-46 RPC.\n * Satisfied by {@link import(\"../relay/pool.ts\").Pool}; constructed above the signer layer\n * so `signer` never imports `relay` (ADR-0001).\n */\nexport type Nip46Transport = {\n subscribe(\n relays: string[],\n filters: Filter[],\n opts?: Nip46SubscribeOptions,\n ): { close: (reason?: string) => void };\n publish(relays: string[], event: Event): Promise<unknown>;\n close(urls?: string[]): void;\n};\n\nexport type Nip46SignerOptions = {\n /**\n * Shared transport. When set, the signer does not close it on {@link Nip46Signer.close}.\n */\n pool?: Nip46Transport;\n /**\n * Factory for a private transport when `pool` is omitted.\n * Typical: `() => new Pool({ websocketImplementation, enableReconnect: true })`.\n */\n createPool?: () => Nip46Transport;\n /**\n * Relays used when the bunker pointer has none, and merged uniquely onto a\n * nonempty pointer (pointer first).\n */\n relays?: string[];\n /**\n * Bunker connection secret when the pointer or bunker:// URL has none.\n */\n secret?: string | null;\n /** Local client key used to encrypt RPC (not the remote user key). */\n clientSecretKey?: SecretKey | Uint8Array | string;\n /** Called when bunker returns `auth_url` for a pending request. */\n onAuthUrl?: (url: string) => void;\n /** Per-request timeout in ms. Default 30s. */\n timeoutMs?: number;\n /** Requested permissions sent with `connect` (`method[:kind]` list). */\n perms?: string[];\n /** Client metadata sent with bunker-initiated `connect`. */\n metadata?: ClientMetadata;\n};\n\nfunction resolveClientSecret(key?: SecretKey | Uint8Array | string): SecretKey {\n if (key === undefined) return SecretKey.generate();\n if (key instanceof SecretKey) return key;\n if (typeof key === \"string\") return SecretKey.fromHex(key);\n return SecretKey.fromBytes(key);\n}\n\nfunction resolveTransport(opts: Nip46SignerOptions): { pool: Nip46Transport; ownsPool: boolean } {\n if (opts.pool) return { pool: opts.pool, ownsPool: false };\n if (opts.createPool) return { pool: opts.createPool(), ownsPool: true };\n throw new Nip46Error(\n \"Nip46Signer requires pool or createPool (inject Pool from @qntx/nostr/relay)\",\n );\n}\n\nfunction applyPointerOpts(pointer: BunkerPointer, opts: Nip46SignerOptions): BunkerPointer {\n let next: BunkerPointer = {\n pubkey: pointer.pubkey.toLowerCase(),\n relays: [...pointer.relays],\n secret: pointer.secret,\n };\n if (opts.secret !== undefined && next.secret == null) {\n next = { ...next, secret: opts.secret };\n }\n\n const relays = next.relays.length > 0 ? next.relays : [...(opts.relays ?? [])];\n if (relays.length === 0) {\n throw new Nip46Error(\"no relays for bunker connection\");\n }\n if (next.relays.length > 0 && opts.relays?.length) {\n const merged = [...next.relays];\n for (const r of opts.relays) {\n if (!merged.includes(r)) merged.push(r);\n }\n return { ...next, relays: merged };\n }\n return { ...next, relays };\n}\n\nfunction resolveBunkerPointer(input: string | BunkerPointer): BunkerPointer {\n if (typeof input !== \"string\") {\n return {\n pubkey: input.pubkey.toLowerCase(),\n relays: [...input.relays],\n secret: input.secret,\n };\n }\n\n const bunker = parseBunkerURL(input);\n if (bunker) return bunker;\n\n throw new Nip46Error(\"invalid bunker input (expected bunker:// URL or BunkerPointer)\");\n}\n\n/**\n * NIP-46 remote signer (bunker / nostrconnect).\n * Implements {@link NostrSigner}; never holds the remote user's secret key.\n * Network I/O is injected via {@link Nip46Transport} (no relay import).\n */\nexport class Nip46Signer implements NostrSigner {\n readonly #pool: Nip46Transport;\n readonly #ownsPool: boolean;\n readonly #clientSecret: SecretKey;\n readonly #clientPubkey: string;\n readonly #pointer: BunkerPointer;\n readonly #conversationKey: Uint8Array;\n readonly #onAuthUrl: ((url: string) => void) | undefined;\n readonly #timeoutMs: number;\n readonly #perms: string[] | undefined;\n readonly #metadata: ClientMetadata | undefined;\n #relays: string[];\n readonly #listeners = new Map<\n string,\n {\n resolve: (v: string) => void;\n reject: (e: Error) => void;\n timer: ReturnType<typeof setTimeout>;\n }\n >();\n readonly #waitingAuth = new Set<string>();\n #sub: { close: (reason?: string) => void } | undefined;\n #open = false;\n #serial = 0;\n #idPrefix = Math.random().toString(36).slice(2, 9);\n #cachedRemotePubkey: string | undefined;\n\n private constructor(\n clientSecret: SecretKey,\n pointer: BunkerPointer,\n pool: Nip46Transport,\n ownsPool: boolean,\n opts: Nip46SignerOptions,\n ) {\n if (pointer.relays.length === 0) {\n throw new Nip46Error(\"bunker pointer has no relays\");\n }\n this.#clientSecret = clientSecret;\n this.#clientPubkey = getPublicKey(clientSecret);\n this.#pointer = {\n pubkey: pointer.pubkey.toLowerCase(),\n relays: [...pointer.relays],\n secret: pointer.secret,\n };\n this.#relays = [...pointer.relays];\n this.#pool = pool;\n this.#ownsPool = ownsPool;\n this.#conversationKey = getConversationKey(clientSecret.bytes, this.#pointer.pubkey);\n this.#onAuthUrl = opts.onAuthUrl;\n this.#timeoutMs = opts.timeoutMs ?? 30_000;\n this.#perms = opts.perms;\n this.#metadata = opts.metadata;\n }\n\n get bunker(): Readonly<BunkerPointer> {\n return {\n pubkey: this.#pointer.pubkey,\n relays: [...this.#relays],\n secret: this.#pointer.secret,\n };\n }\n\n get clientPublicKey(): string {\n return this.#clientPubkey;\n }\n\n /**\n * Subscribe to an already-known bunker pointer. Does not send the `connect` RPC\n * (reconnect without a new handshake).\n * Requires `clientSecretKey` — reconnect must reuse the original client identity.\n */\n static fromBunker(\n pointer: BunkerPointer,\n opts: Nip46SignerOptions & { clientSecretKey: SecretKey | Uint8Array | string },\n ): Nip46Signer {\n if (opts.clientSecretKey === undefined) {\n throw new Nip46Error(\"fromBunker requires clientSecretKey\");\n }\n const resolved = applyPointerOpts(pointer, opts);\n const sk = resolveClientSecret(opts.clientSecretKey);\n const { pool, ownsPool } = resolveTransport(opts);\n const signer = new Nip46Signer(sk, resolved, pool, ownsPool, opts);\n signer.#startSubscription();\n return signer;\n }\n\n /**\n * Connect using a `bunker://` URL or pre-parsed pointer.\n * Invalid strings throw. A NIP-05 identifier is not a bunker pointer.\n * When both pointer and `opts.relays` are nonempty, unique `opts.relays` are appended.\n */\n static async connect(\n input: string | BunkerPointer,\n opts: Nip46SignerOptions = {},\n ): Promise<Nip46Signer> {\n const pointer = resolveBunkerPointer(input);\n const signer = Nip46Signer.fromBunker(pointer, {\n ...opts,\n clientSecretKey: resolveClientSecret(opts.clientSecretKey),\n });\n try {\n await signer.connectRemote();\n try {\n await signer.switchRelays();\n } catch {\n // Bunker may not implement switch_relays.\n }\n await signer.getPublicKey();\n return signer;\n } catch (err) {\n await signer.close();\n throw err;\n }\n }\n\n /**\n * Wait for a bunker to complete a client-initiated `nostrconnect://` handshake.\n * Requires `clientSecretKey` whose pubkey matches the URI client pubkey\n * (build the URI with {@link createNostrConnectURI} after generating keys).\n */\n static async fromNostrConnectURI(\n connectionURI: string,\n opts: Nip46SignerOptions & {\n clientSecretKey: SecretKey | Uint8Array | string;\n signal?: AbortSignal;\n handshakeTimeoutMs?: number;\n },\n ): Promise<Nip46Signer> {\n const params = parseNostrConnectURI(connectionURI);\n const sk = resolveClientSecret(opts.clientSecretKey);\n const clientPubkey = getPublicKey(sk);\n\n if (clientPubkey !== params.clientPubkey) {\n throw new Nip46Error(\"client secret key does not match nostrconnect client pubkey\");\n }\n\n const { pool, ownsPool } = resolveTransport(opts);\n const handshakeTimeoutMs = opts.handshakeTimeoutMs ?? 300_000;\n\n return new Promise((resolve, reject) => {\n let settled = false;\n const finish = (err?: Error, signer?: Nip46Signer) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n sub.close(err ? \"failed\" : \"connected\");\n if (err) {\n if (ownsPool) pool.close();\n reject(err);\n } else if (signer) {\n resolve(signer);\n }\n };\n\n const timer = setTimeout(() => {\n finish(new Nip46Error(\"nostrconnect handshake timed out\"));\n }, handshakeTimeoutMs);\n\n const sub = pool.subscribe(\n params.relays,\n [{ kinds: [Kind.NostrConnect], \"#p\": [clientPubkey], limit: 0 }],\n {\n signal: opts.signal,\n onevent: (event) => {\n try {\n const convKey = getConversationKey(sk.bytes, event.pubkey);\n const payload = decrypt(event.content, convKey);\n const response = decodeNip46Response(payload);\n if (response.result !== params.secret) return;\n\n const pointer: BunkerPointer = {\n pubkey: event.pubkey.toLowerCase(),\n relays: params.relays,\n secret: params.secret,\n };\n const signer = new Nip46Signer(sk, pointer, pool, ownsPool, opts);\n signer.#startSubscription();\n void signer\n .switchRelays()\n .catch(() => undefined)\n .then(() => signer.getPublicKey())\n .then(() => finish(undefined, signer))\n .catch((e) => finish(e instanceof Error ? e : new Nip46Error(String(e))));\n } catch {\n // ignore non-matching events\n }\n },\n onclose: (reason) => {\n if (reason !== \"connected\" && reason !== \"failed\") {\n finish(new Nip46Error(`nostrconnect subscription closed: ${reason}`));\n }\n },\n },\n );\n });\n }\n\n #startSubscription(): void {\n this.#sub?.close();\n this.#sub = this.#pool.subscribe(\n this.#relays,\n [\n {\n kinds: [Kind.NostrConnect],\n authors: [this.#pointer.pubkey],\n \"#p\": [this.#clientPubkey],\n limit: 0,\n },\n ],\n {\n onevent: (event) => {\n try {\n const payload = decrypt(event.content, this.#conversationKey);\n const { id, result, error } = decodeNip46Response(payload);\n\n if (result === \"auth_url\" && this.#waitingAuth.has(id)) {\n this.#waitingAuth.delete(id);\n if (error) this.#onAuthUrl?.(error);\n return;\n }\n\n const listener = this.#listeners.get(id);\n if (!listener) return;\n clearTimeout(listener.timer);\n this.#listeners.delete(id);\n this.#waitingAuth.delete(id);\n if (error) listener.reject(new Nip46Error(error));\n else if (result !== undefined) listener.resolve(result);\n else listener.reject(new Nip46Error(\"empty NIP-46 response\"));\n } catch {\n // ignore decrypt failures from unrelated events\n }\n },\n onclose: () => {\n this.#sub = undefined;\n },\n },\n );\n this.#open = true;\n }\n\n async connectRemote(overrides?: { metadata?: ClientMetadata; perms?: string[] }): Promise<void> {\n const metadata = overrides?.metadata ?? this.#metadata;\n const perms = overrides?.perms ?? this.#perms;\n const params = [this.#pointer.pubkey, this.#pointer.secret ?? \"\"];\n if (perms?.length || metadata) {\n params.push(perms?.length ? perms.join(\",\") : \"\");\n }\n if (metadata) {\n params.push(JSON.stringify(metadata));\n }\n const result = await this.#sendRequest(\"connect\", params);\n if (result === \"ack\") return;\n if (this.#pointer.secret && result === this.#pointer.secret) return;\n throw new Nip46Error(`connect result is not ack or secret: ${result}`);\n }\n\n /**\n * Ask the bunker for its preferred relay list and resubscribe when it changes.\n * Spec result is a JSON array of URLs, or `null` when nothing changes.\n */\n async switchRelays(): Promise<string[] | null> {\n const resp = await this.#sendRequest(\"switch_relays\", []);\n if (resp === \"null\") return null;\n let parsed: unknown;\n try {\n parsed = JSON.parse(resp);\n } catch (cause) {\n throw new Nip46Error(\"invalid switch_relays JSON\", {\n cause: cause instanceof Error ? cause : undefined,\n });\n }\n if (\n !Array.isArray(parsed) ||\n parsed.length === 0 ||\n !parsed.every((x) => typeof x === \"string\")\n ) {\n throw new Nip46Error(\"invalid switch_relays result\");\n }\n this.#relays = parsed;\n this.#startSubscription();\n return parsed;\n }\n\n /** Courtesy session teardown. Always closes the local signer afterwards. */\n async logout(): Promise<void> {\n try {\n const resp = await this.#sendRequest(\"logout\", []);\n if (resp !== \"ack\") throw new Nip46Error(`logout result is not ack: ${resp}`);\n } finally {\n await this.close();\n }\n }\n\n async ping(): Promise<void> {\n const resp = await this.#sendRequest(\"ping\", []);\n if (resp !== \"pong\") throw new Nip46Error(`ping result is not pong: ${resp}`);\n }\n\n async getPublicKey(): Promise<string> {\n if (!this.#cachedRemotePubkey) {\n const pk = await this.#sendRequest(\"get_public_key\", []);\n if (!isHex32(pk)) throw new Nip46Error(\"bunker returned invalid pubkey\");\n this.#cachedRemotePubkey = pk.toLowerCase();\n }\n return this.#cachedRemotePubkey;\n }\n\n async signEvent(unsigned: UnsignedEvent): Promise<Event> {\n const template: EventTemplate = {\n kind: unsigned.kind,\n tags: unsigned.tags,\n content: unsigned.content,\n created_at: unsigned.created_at,\n };\n const resp = await this.#sendRequest(\"sign_event\", [JSON.stringify(template)]);\n let signed: unknown;\n try {\n signed = JSON.parse(resp);\n } catch (cause) {\n throw new Nip46Error(\"bunker returned invalid sign_event JSON\", {\n cause: cause instanceof Error ? cause : undefined,\n });\n }\n if (!validateSignedEvent(signed) || !verifyEvent(signed)) {\n throw new Nip46Error(\"bunker returned improperly signed event\");\n }\n if (!signedMatchesUnsigned(signed, unsigned)) {\n throw new Nip46Error(\"signed event does not match unsigned template\");\n }\n return signed;\n }\n\n async nip04Encrypt(peer: string, plaintext: string): Promise<string> {\n return this.#sendRequest(\"nip04_encrypt\", [peer, plaintext]);\n }\n\n async nip04Decrypt(peer: string, ciphertext: string): Promise<string> {\n return this.#sendRequest(\"nip04_decrypt\", [peer, ciphertext]);\n }\n\n async nip44Encrypt(peer: string, plaintext: string): Promise<string> {\n return this.#sendRequest(\"nip44_encrypt\", [peer, plaintext]);\n }\n\n async nip44Decrypt(peer: string, payload: string): Promise<string> {\n return this.#sendRequest(\"nip44_decrypt\", [peer, payload]);\n }\n\n async close(): Promise<void> {\n this.#open = false;\n for (const [, listener] of this.#listeners) {\n clearTimeout(listener.timer);\n listener.reject(new Nip46Error(\"signer closed\"));\n }\n this.#listeners.clear();\n this.#sub?.close(\"signer closed\");\n this.#sub = undefined;\n if (this.#ownsPool) this.#pool.close();\n }\n\n async #sendRequest(method: string, params: string[]): Promise<string> {\n if (!this.#open) throw new Nip46Error(\"signer is closed\");\n if (!this.#sub) this.#startSubscription();\n\n this.#serial += 1;\n const id = `${this.#idPrefix}-${this.#serial}`;\n const req: Nip46Request = { id, method, params };\n const encrypted = encrypt(encodeNip46Request(req), this.#conversationKey);\n\n const event = finalizeEvent(\n {\n kind: Kind.NostrConnect,\n tags: [Tag.p(this.#pointer.pubkey)],\n content: encrypted,\n created_at: Math.floor(Date.now() / 1000),\n },\n this.#clientSecret,\n );\n\n const resultPromise = new Promise<string>((resolve, reject) => {\n const timer = setTimeout(() => {\n this.#listeners.delete(id);\n this.#waitingAuth.delete(id);\n reject(new Nip46Error(`NIP-46 request timed out: ${method}`));\n }, this.#timeoutMs);\n this.#listeners.set(id, { resolve, reject, timer });\n this.#waitingAuth.add(id);\n });\n\n await this.#pool.publish(this.#relays, event);\n return resultPromise;\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { t as NostrSigner } from "./types-BzyADqnw.mjs";
|
|
2
|
+
import { a as Nip07Signer, c as isNip07Available, i as Nip46Transport, l as KeysSigner, n as Nip46SignerOptions, o as WindowNostr, r as Nip46SubscribeOptions, s as getWindowNostr, t as Nip46Signer } from "./index-BYMnhRIC.mjs";
|
|
3
|
+
export { KeysSigner, Nip07Signer, Nip46Signer, type Nip46SignerOptions, type Nip46SubscribeOptions, type Nip46Transport, type NostrSigner, type WindowNostr, getWindowNostr, isNip07Available };
|
package/dist/signer.mjs
ADDED