@konemono/nostr-login 1.7.13 → 1.7.15
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/package.json +1 -1
- package/src/index.ts +2 -0
- package/src/modules/AuthNostrService.ts +15 -2
- package/src/modules/Nip46.ts +40 -15
- package/src/utils/index.ts +29 -15
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -94,7 +94,9 @@ export class NostrLoginInitializer {
|
|
|
94
94
|
});
|
|
95
95
|
|
|
96
96
|
this.authNostrService.on('timeout', () => {
|
|
97
|
+
console.log('nostr-login: timeout event received, calling cancelNostrConnect');
|
|
97
98
|
this.bannerManager.onCallTimeout();
|
|
99
|
+
this.authNostrService.cancelNostrConnect();
|
|
98
100
|
});
|
|
99
101
|
|
|
100
102
|
this.modalManager.on('onAuthUrlClick', url => {
|
|
@@ -323,6 +323,14 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
323
323
|
}
|
|
324
324
|
|
|
325
325
|
private releaseSigner() {
|
|
326
|
+
// cleanup iframe ping interval if using IframeNostrRpc
|
|
327
|
+
if (this.signer && '_rpc' in this.signer) {
|
|
328
|
+
const rpc = (this.signer as any)._rpc;
|
|
329
|
+
if (rpc && typeof rpc.cleanup === 'function') {
|
|
330
|
+
rpc.cleanup();
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
326
334
|
this.signer = null;
|
|
327
335
|
this.signerErrCallback?.('cancelled');
|
|
328
336
|
this.localSigner = null;
|
|
@@ -465,8 +473,12 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
465
473
|
// with 'load' event below
|
|
466
474
|
const ready = new ReadyListener(['workerReady', 'workerError'], url.origin);
|
|
467
475
|
|
|
468
|
-
await new Promise(ok => {
|
|
469
|
-
|
|
476
|
+
await new Promise((ok, err) => {
|
|
477
|
+
const timeoutId = setTimeout(() => err('Iframe load timeout'), 30000);
|
|
478
|
+
iframe!.addEventListener('load', () => {
|
|
479
|
+
clearTimeout(timeoutId);
|
|
480
|
+
ok(undefined);
|
|
481
|
+
});
|
|
470
482
|
});
|
|
471
483
|
|
|
472
484
|
// now make sure the iframe is ready,
|
|
@@ -584,6 +596,7 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
584
596
|
setTimeout(() => {
|
|
585
597
|
if (!finished) {
|
|
586
598
|
finished = true
|
|
599
|
+
console.log('nostr-login: relay connection timeout, emitting timeout event');
|
|
587
600
|
this.emit('timeout');
|
|
588
601
|
reject('Connection timed out')
|
|
589
602
|
}
|
package/src/modules/Nip46.ts
CHANGED
|
@@ -78,8 +78,24 @@ class NostrRpc extends NDKNostrRpc {
|
|
|
78
78
|
'kinds': [24133],
|
|
79
79
|
'#p': [pubkey],
|
|
80
80
|
});
|
|
81
|
+
|
|
81
82
|
return new Promise<string>((ok, err) => {
|
|
83
|
+
let finished = false;
|
|
84
|
+
|
|
85
|
+
// 30 sec timeout
|
|
86
|
+
const timeoutId = setTimeout(() => {
|
|
87
|
+
if (!finished) {
|
|
88
|
+
finished = true;
|
|
89
|
+
this.stop();
|
|
90
|
+
console.log('nostr-login: listen timeout, emitting timeout event');
|
|
91
|
+
this.emit('timeout');
|
|
92
|
+
err('Listen timed out');
|
|
93
|
+
}
|
|
94
|
+
}, 30000);
|
|
95
|
+
|
|
82
96
|
sub.on('event', async (event: NDKEvent) => {
|
|
97
|
+
if (finished) return;
|
|
98
|
+
|
|
83
99
|
try {
|
|
84
100
|
const parsedEvent = await this.parseEvent(event);
|
|
85
101
|
// console.log('ack parsedEvent', parsedEvent);
|
|
@@ -92,16 +108,20 @@ class NostrRpc extends NDKNostrRpc {
|
|
|
92
108
|
// FIXME for now accept 'ack' replies, later on only
|
|
93
109
|
// accept secrets
|
|
94
110
|
if (response.result === 'ack' || response.result === nostrConnectSecret) {
|
|
111
|
+
finished = true;
|
|
112
|
+
clearTimeout(timeoutId);
|
|
113
|
+
this.stop();
|
|
95
114
|
ok(event.pubkey);
|
|
96
115
|
} else {
|
|
116
|
+
finished = true;
|
|
117
|
+
clearTimeout(timeoutId);
|
|
118
|
+
this.stop();
|
|
97
119
|
err(response.error);
|
|
98
120
|
}
|
|
99
121
|
}
|
|
100
122
|
} catch (e) {
|
|
101
123
|
console.log('error parsing event', e, event.rawEvent());
|
|
102
124
|
}
|
|
103
|
-
// done
|
|
104
|
-
this.stop();
|
|
105
125
|
});
|
|
106
126
|
});
|
|
107
127
|
}
|
|
@@ -177,6 +197,7 @@ class NostrRpc extends NDKNostrRpc {
|
|
|
177
197
|
if (this.requests.has(id)) {
|
|
178
198
|
this.requests.delete(id);
|
|
179
199
|
this.removeListener(`response-${id}`, responseHandler);
|
|
200
|
+
console.log('nostr-login: NIP-46 request timeout, emitting timeout event');
|
|
180
201
|
this.emit('timeout');
|
|
181
202
|
reject('Request timed out');
|
|
182
203
|
}
|
|
@@ -211,6 +232,7 @@ export class IframeNostrRpc extends NostrRpc {
|
|
|
211
232
|
private peerOrigin?: string;
|
|
212
233
|
private iframePort?: MessagePort;
|
|
213
234
|
private iframeRequests = new Map<string, { id: string; pubkey: string }>();
|
|
235
|
+
private iframePingInterval?: NodeJS.Timeout;
|
|
214
236
|
|
|
215
237
|
public constructor(ndk: NDK, localSigner: PrivateKeySigner, iframePeerOrigin?: string) {
|
|
216
238
|
super(ndk, localSigner);
|
|
@@ -237,7 +259,7 @@ export class IframeNostrRpc extends NostrRpc {
|
|
|
237
259
|
this.iframePort = port;
|
|
238
260
|
|
|
239
261
|
// to make sure Chrome doesn't terminate the channel
|
|
240
|
-
setInterval(() => {
|
|
262
|
+
this.iframePingInterval = setInterval(() => {
|
|
241
263
|
console.log('iframe-nip46 ping');
|
|
242
264
|
this.iframePort!.postMessage('ping');
|
|
243
265
|
}, 5000);
|
|
@@ -270,6 +292,13 @@ export class IframeNostrRpc extends NostrRpc {
|
|
|
270
292
|
};
|
|
271
293
|
}
|
|
272
294
|
|
|
295
|
+
public cleanup() {
|
|
296
|
+
if (this.iframePingInterval) {
|
|
297
|
+
clearInterval(this.iframePingInterval);
|
|
298
|
+
this.iframePingInterval = undefined;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
273
302
|
public async sendRequest(remotePubkey: string, method: string, params: string[] = [], kind = 24133, cb?: (res: NDKRpcResponse) => void): Promise<NDKRpcResponse> {
|
|
274
303
|
const id = this.getId();
|
|
275
304
|
|
|
@@ -333,18 +362,14 @@ export class ReadyListener {
|
|
|
333
362
|
|
|
334
363
|
async wait(): Promise<any> {
|
|
335
364
|
console.log(new Date(), 'waiting for', this.messages);
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
// // if promise already resolved or will resolve in the future
|
|
345
|
-
// this.promise.then(ok);
|
|
346
|
-
// });
|
|
347
|
-
|
|
365
|
+
|
|
366
|
+
const r = await new Promise<any>((ok, err) => {
|
|
367
|
+
// 30 sec timeout for iframe ready
|
|
368
|
+
setTimeout(() => err(new Date() + ' timeout for ' + this.messages), 30000);
|
|
369
|
+
|
|
370
|
+
this.promise.then(ok).catch(err);
|
|
371
|
+
});
|
|
372
|
+
|
|
348
373
|
console.log(new Date(), 'finished waiting for', this.messages, r);
|
|
349
374
|
return r;
|
|
350
375
|
}
|
package/src/utils/index.ts
CHANGED
|
@@ -115,22 +115,36 @@ export const getBunkerUrl = async (value: string, optionsModal: NostrLoginOption
|
|
|
115
115
|
const origin = optionsModal.devOverrideBunkerOrigin || `https://${domain}`;
|
|
116
116
|
const bunkerUrl = `${origin}/.well-known/nostr.json?name=_`;
|
|
117
117
|
const userUrl = `${origin}/.well-known/nostr.json?name=${name}`;
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
const
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
118
|
+
|
|
119
|
+
// 10 sec timeout for fetch
|
|
120
|
+
const controller = new AbortController();
|
|
121
|
+
const timeoutId = setTimeout(() => controller.abort(), 10000);
|
|
122
|
+
|
|
123
|
+
try {
|
|
124
|
+
const bunker = await fetch(bunkerUrl, { signal: controller.signal });
|
|
125
|
+
const bunkerData = await bunker.json();
|
|
126
|
+
const bunkerPubkey = bunkerData.names['_'];
|
|
127
|
+
const bunkerRelays = bunkerData.nip46[bunkerPubkey];
|
|
128
|
+
const user = await fetch(userUrl, { signal: controller.signal });
|
|
129
|
+
const userData = await user.json();
|
|
130
|
+
const userPubkey = userData.names[name];
|
|
131
|
+
// console.log({
|
|
132
|
+
// bunkerData, userData, bunkerPubkey, bunkerRelays, userPubkey,
|
|
133
|
+
// name, domain, origin
|
|
134
|
+
// })
|
|
135
|
+
if (!bunkerRelays.length) {
|
|
136
|
+
throw new Error('Bunker relay not provided');
|
|
137
|
+
}
|
|
132
138
|
|
|
133
|
-
|
|
139
|
+
return `bunker://${userPubkey}?relay=${bunkerRelays[0]}`;
|
|
140
|
+
} catch (e: any) {
|
|
141
|
+
if (e.name === 'AbortError') {
|
|
142
|
+
throw new Error('Request timed out');
|
|
143
|
+
}
|
|
144
|
+
throw e;
|
|
145
|
+
} finally {
|
|
146
|
+
clearTimeout(timeoutId);
|
|
147
|
+
}
|
|
134
148
|
}
|
|
135
149
|
|
|
136
150
|
throw new Error('Invalid user name or bunker url');
|