applesauce-signers 2.0.0 → 3.1.0
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/dist/helpers/index.d.ts +1 -0
- package/dist/helpers/index.js +1 -0
- package/dist/helpers/nostr-connect.d.ts +92 -0
- package/dist/helpers/nostr-connect.js +93 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/interop.d.ts +49 -0
- package/dist/interop.js +19 -0
- package/dist/signers/amber-clipboard-signer.d.ts +6 -6
- package/dist/signers/extension-signer.d.ts +9 -16
- package/dist/signers/extension-signer.js +9 -20
- package/dist/signers/index.d.ts +1 -0
- package/dist/signers/index.js +1 -0
- package/dist/signers/nostr-connect-provider.d.ts +121 -0
- package/dist/signers/nostr-connect-provider.js +406 -0
- package/dist/signers/nostr-connect-signer.d.ts +23 -101
- package/dist/signers/nostr-connect-signer.js +52 -81
- package/dist/signers/password-signer.d.ts +6 -6
- package/dist/signers/password-signer.js +8 -3
- package/dist/signers/readonly-signer.d.ts +12 -13
- package/dist/signers/readonly-signer.js +6 -9
- package/dist/signers/serial-port-signer.d.ts +4 -4
- package/dist/signers/simple-signer.d.ts +2 -1
- package/package.json +8 -4
- package/dist/nip-07.d.ts +0 -20
- package/dist/nip-07.js +0 -1
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
import { logger } from "applesauce-core";
|
|
2
|
+
import { getEncryptedContentEncryptionMethods, getHiddenContent, isEvent, unixNow, unlockHiddenContent, } from "applesauce-core/helpers";
|
|
3
|
+
import { createDefer } from "applesauce-core/promise";
|
|
4
|
+
import { nanoid } from "nanoid";
|
|
5
|
+
import { kinds, verifyEvent } from "nostr-tools";
|
|
6
|
+
import { filter, from, repeat, retry } from "rxjs";
|
|
7
|
+
import { isNIP04 } from "../helpers/encryption.js";
|
|
8
|
+
import { createBunkerURI, NostrConnectMethod, parseNostrConnectURI, } from "../helpers/nostr-connect.js";
|
|
9
|
+
import { getConnectionMethods, } from "../interop.js";
|
|
10
|
+
import { SimpleSigner } from "./simple-signer.js";
|
|
11
|
+
export class NostrConnectProvider {
|
|
12
|
+
/** A fallback method to use for subscriptionMethod if none is passed in when creating the provider */
|
|
13
|
+
static subscriptionMethod = undefined;
|
|
14
|
+
/** A fallback method to use for publishMethod if none is passed in when creating the provider */
|
|
15
|
+
static publishMethod = undefined;
|
|
16
|
+
/** A fallback pool to use if none is pass in when creating the provider */
|
|
17
|
+
static pool = undefined;
|
|
18
|
+
/** A method that is called when an event needs to be published */
|
|
19
|
+
publishMethod;
|
|
20
|
+
/** The active nostr subscription */
|
|
21
|
+
subscriptionMethod;
|
|
22
|
+
/** Internal logger */
|
|
23
|
+
log = logger.extend("NostrConnectProvider");
|
|
24
|
+
/** A set of nostr requests that have been seen */
|
|
25
|
+
seen = new Set();
|
|
26
|
+
/** The main signer for the actual signing operations */
|
|
27
|
+
upstream;
|
|
28
|
+
/** The identity signer (provider's identity) */
|
|
29
|
+
signer;
|
|
30
|
+
/** Whether the provider is listening for events */
|
|
31
|
+
listening = false;
|
|
32
|
+
/** The connected client's public key */
|
|
33
|
+
client;
|
|
34
|
+
/** The secret used to authorize clients to connect */
|
|
35
|
+
secret;
|
|
36
|
+
/** Relays to communicate over */
|
|
37
|
+
relays;
|
|
38
|
+
/** Whether a client is connected (received a `connect` request) */
|
|
39
|
+
connected = false;
|
|
40
|
+
/** Callbacks */
|
|
41
|
+
onClientConnect;
|
|
42
|
+
onClientDisconnect;
|
|
43
|
+
/** A method used to accept or reject `connect` requests */
|
|
44
|
+
onConnect;
|
|
45
|
+
/** A method used to accept or reject `sign_event` requests */
|
|
46
|
+
onSignEvent;
|
|
47
|
+
/** A method used to accept or reject `nip04_encrypt` requests */
|
|
48
|
+
onNip04Encrypt;
|
|
49
|
+
/** A method used to accept or reject `nip04_decrypt` requests */
|
|
50
|
+
onNip04Decrypt;
|
|
51
|
+
/** A method used to accept or reject `nip44_encrypt` requests */
|
|
52
|
+
onNip44Encrypt;
|
|
53
|
+
/** A method used to accept or reject `nip44_decrypt` requests */
|
|
54
|
+
onNip44Decrypt;
|
|
55
|
+
constructor(options) {
|
|
56
|
+
this.relays = options.relays;
|
|
57
|
+
this.upstream = options.upstream;
|
|
58
|
+
this.signer = options.signer ?? new SimpleSigner();
|
|
59
|
+
this.secret = options.secret;
|
|
60
|
+
// Get the subscription and publish methods
|
|
61
|
+
const { subscriptionMethod, publishMethod } = getConnectionMethods(options, NostrConnectProvider);
|
|
62
|
+
// Use arrow functions so "this" isn't bound to the signer
|
|
63
|
+
this.subscriptionMethod = (relays, filters) => subscriptionMethod(relays, filters);
|
|
64
|
+
this.publishMethod = (relays, event) => publishMethod(relays, event);
|
|
65
|
+
// Set client connection callbacks
|
|
66
|
+
if (options.onClientConnect)
|
|
67
|
+
this.onClientConnect = options.onClientConnect;
|
|
68
|
+
if (options.onClientDisconnect)
|
|
69
|
+
this.onClientDisconnect = options.onClientDisconnect;
|
|
70
|
+
// Set authorization callbacks
|
|
71
|
+
if (options.onConnect)
|
|
72
|
+
this.onConnect = options.onConnect;
|
|
73
|
+
if (options.onSignEvent)
|
|
74
|
+
this.onSignEvent = options.onSignEvent;
|
|
75
|
+
if (options.onNip04Encrypt)
|
|
76
|
+
this.onNip04Encrypt = options.onNip04Encrypt;
|
|
77
|
+
if (options.onNip04Decrypt)
|
|
78
|
+
this.onNip04Decrypt = options.onNip04Decrypt;
|
|
79
|
+
if (options.onNip44Encrypt)
|
|
80
|
+
this.onNip44Encrypt = options.onNip44Encrypt;
|
|
81
|
+
if (options.onNip44Decrypt)
|
|
82
|
+
this.onNip44Decrypt = options.onNip44Decrypt;
|
|
83
|
+
}
|
|
84
|
+
/** The currently active REQ subscription */
|
|
85
|
+
req;
|
|
86
|
+
/** Updates the relay subscription to listen for request events */
|
|
87
|
+
async updateSubscription() {
|
|
88
|
+
if (this.req)
|
|
89
|
+
this.req.unsubscribe();
|
|
90
|
+
const pubkey = await this.signer.getPublicKey();
|
|
91
|
+
// Setup subscription to listen for requests
|
|
92
|
+
this.req = from(this.subscriptionMethod(this.relays, [
|
|
93
|
+
// If client is known, only listen for requests from the client
|
|
94
|
+
this.client
|
|
95
|
+
? {
|
|
96
|
+
kinds: [kinds.NostrConnect],
|
|
97
|
+
"#p": [pubkey],
|
|
98
|
+
authors: [this.client],
|
|
99
|
+
}
|
|
100
|
+
: // Otherwise listen for all requests (waiting for a `connect` request)
|
|
101
|
+
{
|
|
102
|
+
kinds: [kinds.NostrConnect],
|
|
103
|
+
"#p": [pubkey],
|
|
104
|
+
},
|
|
105
|
+
]))
|
|
106
|
+
.pipe(
|
|
107
|
+
// Keep the connection open indefinitely
|
|
108
|
+
repeat(),
|
|
109
|
+
// Retry on connection failure
|
|
110
|
+
retry(),
|
|
111
|
+
// Ignore strings (support for applesauce-relay)
|
|
112
|
+
filter((event) => typeof event !== "string"))
|
|
113
|
+
.subscribe(this.handleEvent.bind(this));
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Start the provider
|
|
117
|
+
* @param request - An inital `connect` request to respond to or a {@link NostrConnectURI}
|
|
118
|
+
*/
|
|
119
|
+
async start(request) {
|
|
120
|
+
if (this.listening)
|
|
121
|
+
return;
|
|
122
|
+
this.listening = true;
|
|
123
|
+
// Handle first request if provided (e.g. from a `connect` request)
|
|
124
|
+
if (isEvent(request))
|
|
125
|
+
await this.handleEvent(request);
|
|
126
|
+
// Handle NostrConnectURI
|
|
127
|
+
else if (request)
|
|
128
|
+
await this.handleNostrConnectURI(request);
|
|
129
|
+
// Start the subscription (if its not already started)
|
|
130
|
+
if (!this.req)
|
|
131
|
+
await this.updateSubscription();
|
|
132
|
+
this.log("Started", this.relays);
|
|
133
|
+
}
|
|
134
|
+
/** Stop the provider */
|
|
135
|
+
async stop() {
|
|
136
|
+
this.listening = false;
|
|
137
|
+
// Close the current subscription
|
|
138
|
+
if (this.req) {
|
|
139
|
+
this.req.unsubscribe();
|
|
140
|
+
this.req = undefined;
|
|
141
|
+
}
|
|
142
|
+
// Cancel waiting promise
|
|
143
|
+
if (this.waitingPromise) {
|
|
144
|
+
this.waitingPromise.reject(new Error("Closed"));
|
|
145
|
+
this.waitingPromise = null;
|
|
146
|
+
}
|
|
147
|
+
// Notify client disconnect
|
|
148
|
+
if (this.client && this.connected && this.onClientDisconnect)
|
|
149
|
+
this.onClientDisconnect(this.client);
|
|
150
|
+
// Forget all seen requests
|
|
151
|
+
this.seen.clear();
|
|
152
|
+
this.client = undefined;
|
|
153
|
+
this.connected = false;
|
|
154
|
+
this.log("Stopped");
|
|
155
|
+
}
|
|
156
|
+
waitingPromise = null;
|
|
157
|
+
/** Wait for a client to connect */
|
|
158
|
+
waitForClient(abort) {
|
|
159
|
+
if (this.client)
|
|
160
|
+
return Promise.resolve(this.client);
|
|
161
|
+
this.start();
|
|
162
|
+
this.waitingPromise = createDefer();
|
|
163
|
+
abort?.addEventListener("abort", () => {
|
|
164
|
+
this.waitingPromise?.reject(new Error("Aborted"));
|
|
165
|
+
this.waitingPromise = null;
|
|
166
|
+
this.stop();
|
|
167
|
+
}, true);
|
|
168
|
+
return this.waitingPromise;
|
|
169
|
+
}
|
|
170
|
+
/** Call this method with incoming events */
|
|
171
|
+
async handleEvent(event) {
|
|
172
|
+
if (!verifyEvent(event))
|
|
173
|
+
return;
|
|
174
|
+
// Do nothing if this request has already been seen
|
|
175
|
+
if (this.seen.has(event.id))
|
|
176
|
+
return;
|
|
177
|
+
this.seen.add(event.id);
|
|
178
|
+
try {
|
|
179
|
+
const content = getHiddenContent(event) ||
|
|
180
|
+
// Support legacy NIP-04 encryption
|
|
181
|
+
(isNIP04(event.content)
|
|
182
|
+
? await unlockHiddenContent(event, this.signer, "nip04")
|
|
183
|
+
: await unlockHiddenContent(event, this.signer, "nip44"));
|
|
184
|
+
const request = JSON.parse(content);
|
|
185
|
+
// If the client isn't known, reject the request
|
|
186
|
+
if (!this.client && request.method !== NostrConnectMethod.Connect)
|
|
187
|
+
throw new Error("Received request from unknown client");
|
|
188
|
+
else if (this.client && event.pubkey !== this.client)
|
|
189
|
+
throw new Error("Received request from wrong client");
|
|
190
|
+
// Process the request
|
|
191
|
+
this.log(`Processing ${request.method} from ${event.pubkey}`);
|
|
192
|
+
try {
|
|
193
|
+
let result;
|
|
194
|
+
switch (request.method) {
|
|
195
|
+
case NostrConnectMethod.Connect:
|
|
196
|
+
result = await this.handleConnect(event.pubkey, request.params);
|
|
197
|
+
break;
|
|
198
|
+
case NostrConnectMethod.GetPublicKey:
|
|
199
|
+
result = await this.upstream.getPublicKey();
|
|
200
|
+
break;
|
|
201
|
+
case NostrConnectMethod.SignEvent:
|
|
202
|
+
result = await this.handleSignEvent(request.params);
|
|
203
|
+
break;
|
|
204
|
+
case NostrConnectMethod.Nip04Encrypt:
|
|
205
|
+
result = await this.handleNip04Encrypt(request.params);
|
|
206
|
+
break;
|
|
207
|
+
case NostrConnectMethod.Nip04Decrypt:
|
|
208
|
+
result = await this.handleNip04Decrypt(request.params);
|
|
209
|
+
break;
|
|
210
|
+
case NostrConnectMethod.Nip44Encrypt:
|
|
211
|
+
result = await this.handleNip44Encrypt(request.params);
|
|
212
|
+
break;
|
|
213
|
+
case NostrConnectMethod.Nip44Decrypt:
|
|
214
|
+
result = await this.handleNip44Decrypt(request.params);
|
|
215
|
+
break;
|
|
216
|
+
default:
|
|
217
|
+
throw new Error(`Unsupported method: ${request.method}`);
|
|
218
|
+
}
|
|
219
|
+
// Send success response
|
|
220
|
+
await this.sendResponse(event, request.id, result);
|
|
221
|
+
}
|
|
222
|
+
catch (error) {
|
|
223
|
+
this.log(`Error processing ${request.method}:`, error);
|
|
224
|
+
await this.sendErrorResponse(event, request.id, error instanceof Error ? error.message : "Unknown error");
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
catch (err) {
|
|
228
|
+
this.log("Error handling request:", err);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
/** Handle an initial NostrConnectURI */
|
|
232
|
+
async handleNostrConnectURI(uri) {
|
|
233
|
+
if (this.client)
|
|
234
|
+
throw new Error("Already connected to a client");
|
|
235
|
+
// Parse the URI
|
|
236
|
+
if (typeof uri === "string")
|
|
237
|
+
uri = parseNostrConnectURI(uri);
|
|
238
|
+
// Get a response to a fake initial `connect` request
|
|
239
|
+
const response = await this.handleConnect(uri.client, [
|
|
240
|
+
await this.signer.getPublicKey(),
|
|
241
|
+
uri.secret,
|
|
242
|
+
uri.metadata?.permissions?.join(",") ?? "",
|
|
243
|
+
]);
|
|
244
|
+
// Send `connect` response with random id
|
|
245
|
+
await this.sendResponse(uri.client, nanoid(8), response);
|
|
246
|
+
}
|
|
247
|
+
/** Handle connect request */
|
|
248
|
+
async handleConnect(client, [target, secret, permissionsStr]) {
|
|
249
|
+
const permissions = permissionsStr ? permissionsStr.split(",") : [];
|
|
250
|
+
// Check if this is a connection to our provider
|
|
251
|
+
const providerPubkey = await this.signer.getPublicKey();
|
|
252
|
+
if (target !== providerPubkey)
|
|
253
|
+
throw new Error("Invalid target pubkey");
|
|
254
|
+
// If the client is already known, ensure that it matches the new client
|
|
255
|
+
if (this.client && this.client !== client)
|
|
256
|
+
throw new Error("Only one client can connect at a time");
|
|
257
|
+
// If this is the first `connect` request, check that the secret matches
|
|
258
|
+
if (this.secret && !this.client && this.secret !== secret)
|
|
259
|
+
throw new Error("Invalid connection secret");
|
|
260
|
+
// Handle authorization if callback is provided
|
|
261
|
+
if (this.onConnect) {
|
|
262
|
+
const authorized = await this.onConnect(client, permissions);
|
|
263
|
+
if (authorized === false)
|
|
264
|
+
throw new Error("Authorization denied");
|
|
265
|
+
}
|
|
266
|
+
// If the client isn't set yet, this if the first `connect` request
|
|
267
|
+
const isFirstRequest = !this.client;
|
|
268
|
+
// Establish connection
|
|
269
|
+
this.client = client;
|
|
270
|
+
this.connected = true;
|
|
271
|
+
if (!this.secret)
|
|
272
|
+
this.secret = secret;
|
|
273
|
+
// Update the subscription since we now know the client pubkey
|
|
274
|
+
if (isFirstRequest)
|
|
275
|
+
await this.updateSubscription();
|
|
276
|
+
// Notify connection
|
|
277
|
+
if (this.onClientConnect)
|
|
278
|
+
this.onClientConnect(client);
|
|
279
|
+
// Resolve waiting promise
|
|
280
|
+
if (this.waitingPromise) {
|
|
281
|
+
this.waitingPromise.resolve(client);
|
|
282
|
+
this.waitingPromise = null;
|
|
283
|
+
}
|
|
284
|
+
// Return ack or the secret if provided
|
|
285
|
+
return secret || "ack";
|
|
286
|
+
}
|
|
287
|
+
/** Handle sign event request */
|
|
288
|
+
async handleSignEvent([eventJson]) {
|
|
289
|
+
const template = JSON.parse(eventJson);
|
|
290
|
+
// Check if the sign event is allowed
|
|
291
|
+
if (this.onSignEvent) {
|
|
292
|
+
const result = await this.onSignEvent(template, this.client);
|
|
293
|
+
if (result === false)
|
|
294
|
+
throw new Error("Sign event denied");
|
|
295
|
+
}
|
|
296
|
+
const signedEvent = await this.upstream.signEvent(template);
|
|
297
|
+
return JSON.stringify(signedEvent);
|
|
298
|
+
}
|
|
299
|
+
/** Handle NIP-04 encryption */
|
|
300
|
+
async handleNip04Encrypt([pubkey, plaintext,]) {
|
|
301
|
+
if (!this.upstream.nip04)
|
|
302
|
+
throw new Error("NIP-04 not supported");
|
|
303
|
+
// Check if the nip04 encryption is allowed
|
|
304
|
+
if (this.onNip04Encrypt) {
|
|
305
|
+
const result = await this.onNip04Encrypt(pubkey, plaintext, this.client);
|
|
306
|
+
if (result === false)
|
|
307
|
+
throw new Error("NIP-04 encryption denied");
|
|
308
|
+
}
|
|
309
|
+
return await this.upstream.nip04.encrypt(pubkey, plaintext);
|
|
310
|
+
}
|
|
311
|
+
/** Handle NIP-04 decryption */
|
|
312
|
+
async handleNip04Decrypt([pubkey, ciphertext,]) {
|
|
313
|
+
if (!this.upstream.nip04)
|
|
314
|
+
throw new Error("NIP-04 not supported");
|
|
315
|
+
// Check if the nip04 decryption is allowed
|
|
316
|
+
if (this.onNip04Decrypt) {
|
|
317
|
+
const result = await this.onNip04Decrypt(pubkey, ciphertext, this.client);
|
|
318
|
+
if (result === false)
|
|
319
|
+
throw new Error("NIP-04 decryption denied");
|
|
320
|
+
}
|
|
321
|
+
return await this.upstream.nip04.decrypt(pubkey, ciphertext);
|
|
322
|
+
}
|
|
323
|
+
/** Handle NIP-44 encryption */
|
|
324
|
+
async handleNip44Encrypt([pubkey, plaintext,]) {
|
|
325
|
+
if (!this.upstream.nip44)
|
|
326
|
+
throw new Error("NIP-44 not supported");
|
|
327
|
+
// Check if the nip44 encryption is allowed
|
|
328
|
+
if (this.onNip44Encrypt) {
|
|
329
|
+
const result = await this.onNip44Encrypt(pubkey, plaintext, this.client);
|
|
330
|
+
if (result === false)
|
|
331
|
+
throw new Error("NIP-44 encryption denied");
|
|
332
|
+
}
|
|
333
|
+
return await this.upstream.nip44.encrypt(pubkey, plaintext);
|
|
334
|
+
}
|
|
335
|
+
/** Handle NIP-44 decryption */
|
|
336
|
+
async handleNip44Decrypt([pubkey, ciphertext,]) {
|
|
337
|
+
if (!this.upstream.nip44)
|
|
338
|
+
throw new Error("NIP-44 not supported");
|
|
339
|
+
// Check if the nip44 decryption is allowed
|
|
340
|
+
if (this.onNip44Decrypt) {
|
|
341
|
+
const result = await this.onNip44Decrypt(pubkey, ciphertext, this.client);
|
|
342
|
+
if (result === false)
|
|
343
|
+
throw new Error("NIP-44 decryption denied");
|
|
344
|
+
}
|
|
345
|
+
return await this.upstream.nip44.decrypt(pubkey, ciphertext);
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
* Send a response to the client
|
|
349
|
+
* @param clientOrRequest - The client pubkey or request event
|
|
350
|
+
* @param requestId - The id of the request
|
|
351
|
+
* @param result - The result of the request
|
|
352
|
+
*/
|
|
353
|
+
async sendResponse(clientOrRequest, requestId, result) {
|
|
354
|
+
const response = {
|
|
355
|
+
id: requestId,
|
|
356
|
+
result,
|
|
357
|
+
};
|
|
358
|
+
await this.sendMessage(clientOrRequest, response);
|
|
359
|
+
}
|
|
360
|
+
/** Send an error response to the client */
|
|
361
|
+
async sendErrorResponse(event, requestId, error) {
|
|
362
|
+
const response = {
|
|
363
|
+
id: requestId,
|
|
364
|
+
result: "",
|
|
365
|
+
error,
|
|
366
|
+
};
|
|
367
|
+
await this.sendMessage(event, response);
|
|
368
|
+
}
|
|
369
|
+
/** Send an encrypted message to the client */
|
|
370
|
+
async sendMessage(clientOrRequest, message) {
|
|
371
|
+
// Get the pubkey of the client
|
|
372
|
+
const client = typeof clientOrRequest === "string" ? clientOrRequest : clientOrRequest.pubkey;
|
|
373
|
+
// Try NIP-44 first, fallback to NIP-04
|
|
374
|
+
let encryption;
|
|
375
|
+
// If responding to a request, try to use the same encryption
|
|
376
|
+
if (typeof clientOrRequest !== "string")
|
|
377
|
+
encryption = getEncryptedContentEncryptionMethods(clientOrRequest.kind, this.signer, isNIP04(clientOrRequest.content) ? "nip04" : "nip44");
|
|
378
|
+
// Get default encryption method (nip44)
|
|
379
|
+
else
|
|
380
|
+
encryption = getEncryptedContentEncryptionMethods(kinds.NostrConnect, this.signer);
|
|
381
|
+
const content = JSON.stringify(message);
|
|
382
|
+
const event = await this.signer.signEvent({
|
|
383
|
+
kind: kinds.NostrConnect,
|
|
384
|
+
created_at: unixNow(),
|
|
385
|
+
tags: [["p", client]],
|
|
386
|
+
content: await encryption.encrypt(client, content),
|
|
387
|
+
});
|
|
388
|
+
// Publish the event
|
|
389
|
+
const result = this.publishMethod(this.relays, event);
|
|
390
|
+
// Handle returned Promise or Observable
|
|
391
|
+
if (result instanceof Promise) {
|
|
392
|
+
await result;
|
|
393
|
+
}
|
|
394
|
+
else if ("subscribe" in result) {
|
|
395
|
+
await new Promise((res) => result.subscribe({ complete: res }));
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
/** Get the connection string that clients can use to connect */
|
|
399
|
+
async getBunkerURI() {
|
|
400
|
+
return createBunkerURI({
|
|
401
|
+
remote: await this.signer.getPublicKey(),
|
|
402
|
+
relays: this.relays,
|
|
403
|
+
secret: this.secret,
|
|
404
|
+
});
|
|
405
|
+
}
|
|
406
|
+
}
|
|
@@ -1,61 +1,9 @@
|
|
|
1
|
-
import { EventTemplate, Filter, NostrEvent, verifyEvent } from "nostr-tools";
|
|
2
|
-
import { Nip07Interface, SimpleSigner } from "applesauce-signers";
|
|
3
1
|
import { Deferred } from "applesauce-core/promise";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
Nip04Decrypt = "nip04_decrypt",
|
|
10
|
-
Nip44Encrypt = "nip44_encrypt",
|
|
11
|
-
Nip44Decrypt = "nip44_decrypt"
|
|
12
|
-
}
|
|
13
|
-
export declare enum NostrConnectMethod {
|
|
14
|
-
Connect = "connect",
|
|
15
|
-
CreateAccount = "create_account",
|
|
16
|
-
GetPublicKey = "get_public_key",
|
|
17
|
-
SignEvent = "sign_event",
|
|
18
|
-
Nip04Encrypt = "nip04_encrypt",
|
|
19
|
-
Nip04Decrypt = "nip04_decrypt",
|
|
20
|
-
Nip44Encrypt = "nip44_encrypt",
|
|
21
|
-
Nip44Decrypt = "nip44_decrypt"
|
|
22
|
-
}
|
|
23
|
-
type RequestParams = {
|
|
24
|
-
[NostrConnectMethod.Connect]: [string] | [string, string] | [string, string, string];
|
|
25
|
-
[NostrConnectMethod.CreateAccount]: [string, string] | [string, string, string] | [string, string, string, string];
|
|
26
|
-
[NostrConnectMethod.GetPublicKey]: [];
|
|
27
|
-
[NostrConnectMethod.SignEvent]: [string];
|
|
28
|
-
[NostrConnectMethod.Nip04Encrypt]: [string, string];
|
|
29
|
-
[NostrConnectMethod.Nip04Decrypt]: [string, string];
|
|
30
|
-
[NostrConnectMethod.Nip44Encrypt]: [string, string];
|
|
31
|
-
[NostrConnectMethod.Nip44Decrypt]: [string, string];
|
|
32
|
-
};
|
|
33
|
-
type ResponseResults = {
|
|
34
|
-
[NostrConnectMethod.Connect]: "ack";
|
|
35
|
-
[NostrConnectMethod.CreateAccount]: string;
|
|
36
|
-
[NostrConnectMethod.GetPublicKey]: string;
|
|
37
|
-
[NostrConnectMethod.SignEvent]: string;
|
|
38
|
-
[NostrConnectMethod.Nip04Encrypt]: string;
|
|
39
|
-
[NostrConnectMethod.Nip04Decrypt]: string;
|
|
40
|
-
[NostrConnectMethod.Nip44Encrypt]: string;
|
|
41
|
-
[NostrConnectMethod.Nip44Decrypt]: string;
|
|
42
|
-
};
|
|
43
|
-
export type NostrConnectRequest<N extends NostrConnectMethod> = {
|
|
44
|
-
id: string;
|
|
45
|
-
method: N;
|
|
46
|
-
params: RequestParams[N];
|
|
47
|
-
};
|
|
48
|
-
export type NostrConnectResponse<N extends NostrConnectMethod> = {
|
|
49
|
-
id: string;
|
|
50
|
-
result: ResponseResults[N];
|
|
51
|
-
error?: string;
|
|
52
|
-
};
|
|
53
|
-
export type NostrConnectErrorResponse = {
|
|
54
|
-
id: string;
|
|
55
|
-
result: string;
|
|
56
|
-
error: string;
|
|
57
|
-
};
|
|
58
|
-
export type NostrConnectSignerOptions = {
|
|
2
|
+
import { ISigner, NostrConnectionMethodsOptions, NostrPool, NostrPublishMethod, NostrSubscriptionMethod, SimpleSigner } from "applesauce-signers";
|
|
3
|
+
import { EventTemplate, NostrEvent, verifyEvent } from "nostr-tools";
|
|
4
|
+
import { Subscription } from "rxjs";
|
|
5
|
+
import { BunkerURI, NostrConnectAppMetadata } from "../helpers/nostr-connect.js";
|
|
6
|
+
export type NostrConnectSignerOptions = NostrConnectionMethodsOptions & {
|
|
59
7
|
/** The relays to communicate over */
|
|
60
8
|
relays: string[];
|
|
61
9
|
/** A {@link SimpleSigner} for this client */
|
|
@@ -64,35 +12,18 @@ export type NostrConnectSignerOptions = {
|
|
|
64
12
|
remote?: string;
|
|
65
13
|
/** Users pubkey */
|
|
66
14
|
pubkey?: string;
|
|
15
|
+
/** A secret used when initalizing the connection from the client side */
|
|
16
|
+
secret?: string;
|
|
67
17
|
/** A method for handling "auth" requests */
|
|
68
18
|
onAuth?: (url: string) => Promise<void>;
|
|
69
|
-
/** A method for subscribing to relays */
|
|
70
|
-
subscriptionMethod?: NostrSubscriptionMethod;
|
|
71
|
-
/** A method for publishing events */
|
|
72
|
-
publishMethod?: NostrPublishMethod;
|
|
73
|
-
};
|
|
74
|
-
interface Unsubscribable {
|
|
75
|
-
unsubscribe(): void;
|
|
76
|
-
}
|
|
77
|
-
interface Observer<T> {
|
|
78
|
-
next: (value: T) => void;
|
|
79
|
-
error: (err: any) => void;
|
|
80
|
-
complete: () => void;
|
|
81
|
-
}
|
|
82
|
-
type Subscribable<T extends unknown> = {
|
|
83
|
-
subscribe: (observer: Partial<Observer<T>>) => Unsubscribable;
|
|
84
19
|
};
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
url?: string | URL;
|
|
93
|
-
permissions?: string[];
|
|
94
|
-
};
|
|
95
|
-
export declare class NostrConnectSigner implements Nip07Interface {
|
|
20
|
+
export declare class NostrConnectSigner implements ISigner {
|
|
21
|
+
/** A fallback method to use for subscriptionMethod if none is pass in when creating the signer */
|
|
22
|
+
static subscriptionMethod: NostrSubscriptionMethod | undefined;
|
|
23
|
+
/** A fallback method to use for publishMethod if none is pass in when creating the signer */
|
|
24
|
+
static publishMethod: NostrPublishMethod | undefined;
|
|
25
|
+
/** A fallback pool to use if none is pass in when creating the signer */
|
|
26
|
+
static pool: NostrPool | undefined;
|
|
96
27
|
/** A method that is called when an event needs to be published */
|
|
97
28
|
protected publishMethod: NostrPublishMethod;
|
|
98
29
|
/** The active nostr subscription */
|
|
@@ -116,22 +47,18 @@ export declare class NostrConnectSigner implements Nip07Interface {
|
|
|
116
47
|
onAuth: (url: string) => Promise<void>;
|
|
117
48
|
verifyEvent: typeof verifyEvent;
|
|
118
49
|
/** A secret used when initiating a connection from the client side */
|
|
119
|
-
|
|
50
|
+
secret: string;
|
|
120
51
|
nip04?: {
|
|
121
|
-
encrypt: (pubkey: string, plaintext: string) => Promise<string
|
|
122
|
-
decrypt: (pubkey: string, ciphertext: string) => Promise<string
|
|
52
|
+
encrypt: (pubkey: string, plaintext: string) => Promise<string>;
|
|
53
|
+
decrypt: (pubkey: string, ciphertext: string) => Promise<string>;
|
|
123
54
|
} | undefined;
|
|
124
55
|
nip44?: {
|
|
125
|
-
encrypt: (pubkey: string, plaintext: string) => Promise<string
|
|
126
|
-
decrypt: (pubkey: string, ciphertext: string) => Promise<string
|
|
56
|
+
encrypt: (pubkey: string, plaintext: string) => Promise<string>;
|
|
57
|
+
decrypt: (pubkey: string, ciphertext: string) => Promise<string>;
|
|
127
58
|
} | undefined;
|
|
128
|
-
|
|
129
|
-
static subscriptionMethod: NostrSubscriptionMethod | undefined;
|
|
130
|
-
/** A fallback method to use for publishMethod if none is pass in when creating the signer */
|
|
131
|
-
static publishMethod: NostrPublishMethod | undefined;
|
|
132
|
-
constructor(opts: NostrConnectSignerOptions);
|
|
59
|
+
constructor(options: NostrConnectSignerOptions);
|
|
133
60
|
/** The currently active REQ subscription */
|
|
134
|
-
protected req?:
|
|
61
|
+
protected req?: Subscription;
|
|
135
62
|
/** Open the connection */
|
|
136
63
|
open(): Promise<void>;
|
|
137
64
|
/** Close the connection */
|
|
@@ -143,7 +70,7 @@ export declare class NostrConnectSigner implements Nip07Interface {
|
|
|
143
70
|
protected createRequestEvent(content: string, target?: string | undefined, kind?: number): Promise<import("nostr-tools").VerifiedEvent>;
|
|
144
71
|
private makeRequest;
|
|
145
72
|
/** Connect to remote signer */
|
|
146
|
-
connect(secret?: string | undefined, permissions?: string[]): Promise<
|
|
73
|
+
connect(secret?: string | undefined, permissions?: string[]): Promise<string>;
|
|
147
74
|
private waitingPromise;
|
|
148
75
|
/** Wait for a remote signer to connect */
|
|
149
76
|
waitForSigner(abort?: AbortSignal): Promise<void>;
|
|
@@ -164,11 +91,7 @@ export declare class NostrConnectSigner implements Nip07Interface {
|
|
|
164
91
|
/** Returns the nostrconnect:// URI for this signer */
|
|
165
92
|
getNostrConnectURI(metadata?: NostrConnectAppMetadata): string;
|
|
166
93
|
/** Parses a bunker:// URI */
|
|
167
|
-
static parseBunkerURI(uri: string):
|
|
168
|
-
remote: string;
|
|
169
|
-
relays: string[];
|
|
170
|
-
secret?: string;
|
|
171
|
-
};
|
|
94
|
+
static parseBunkerURI(uri: string): BunkerURI;
|
|
172
95
|
/** Builds an array of signing permissions for event kinds */
|
|
173
96
|
static buildSigningPermissions(kinds: number[]): string[];
|
|
174
97
|
/** Create a {@link NostrConnectSigner} from a bunker:// URI */
|
|
@@ -177,4 +100,3 @@ export declare class NostrConnectSigner implements Nip07Interface {
|
|
|
177
100
|
signer?: SimpleSigner;
|
|
178
101
|
}): Promise<NostrConnectSigner>;
|
|
179
102
|
}
|
|
180
|
-
export {};
|