@konemono/nostr-login 1.7.35 → 1.7.37
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/index.esm.js +4 -4
- package/dist/index.esm.js.map +1 -1
- package/dist/modules/AuthNostrService.d.ts +3 -3
- package/dist/modules/BannerManager.d.ts +1 -1
- package/dist/modules/ModalManager.d.ts +1 -1
- package/dist/modules/Nip46.d.ts +0 -2
- package/dist/modules/Nostr.d.ts +1 -1
- package/dist/modules/NostrParams.d.ts +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/unpkg.js +2 -2
- package/dist/utils/index.d.ts +1 -1
- package/package.json +1 -1
- package/src/const/index.ts +0 -1
- package/src/iife-module.ts +2 -7
- package/src/index.ts +2 -7
- package/src/modules/AuthNostrService.ts +170 -56
- package/src/modules/BannerManager.ts +1 -1
- package/src/modules/ModalManager.ts +58 -51
- package/src/modules/Nip46.ts +70 -248
- package/src/modules/Nostr.ts +1 -1
- package/src/modules/NostrParams.ts +1 -1
- package/src/modules/ProcessManager.ts +18 -57
- package/src/types.ts +31 -1
- package/src/utils/index.ts +1 -1
package/src/modules/Nip46.ts
CHANGED
|
@@ -1,59 +1,34 @@
|
|
|
1
1
|
import NDK, { NDKEvent, NDKFilter, NDKNip46Signer, NDKNostrRpc, NDKRpcRequest, NDKRpcResponse, NDKSubscription, NDKSubscriptionCacheUsage, NostrEvent } from '@nostr-dev-kit/ndk';
|
|
2
2
|
import { validateEvent, verifySignature } from 'nostr-tools';
|
|
3
3
|
import { PrivateKeySigner } from './Signer';
|
|
4
|
-
import { NIP46_TIMEOUT } from '../const';
|
|
5
|
-
import ProcessManager from './ProcessManager';
|
|
6
4
|
|
|
7
5
|
class NostrRpc extends NDKNostrRpc {
|
|
8
|
-
protected processManager?: ProcessManager;
|
|
9
6
|
protected _ndk: NDK;
|
|
10
7
|
protected _signer: PrivateKeySigner;
|
|
11
8
|
protected requests: Set<string> = new Set();
|
|
12
|
-
protected requestTimeouts: Map<string, NodeJS.Timeout> = new Map();
|
|
13
9
|
private sub?: NDKSubscription;
|
|
14
10
|
protected _useNip44: boolean = false;
|
|
15
11
|
|
|
16
|
-
public
|
|
17
|
-
this.clearAllTimeouts(); // private/protected なメソッドを呼び出す
|
|
18
|
-
this.requests.clear(); // requests Setをクリア
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
public constructor(ndk: NDK, signer: PrivateKeySigner, processManager?: ProcessManager) {
|
|
12
|
+
public constructor(ndk: NDK, signer: PrivateKeySigner) {
|
|
22
13
|
super(ndk, signer, ndk.debug.extend('nip46:signer:rpc'));
|
|
23
14
|
this._ndk = ndk;
|
|
24
15
|
this._signer = signer;
|
|
25
|
-
this.processManager = processManager;
|
|
26
16
|
}
|
|
27
17
|
|
|
28
18
|
public async subscribe(filter: NDKFilter): Promise<NDKSubscription> {
|
|
19
|
+
// NOTE: fixing ndk
|
|
29
20
|
filter.kinds = filter.kinds?.filter(k => k === 24133);
|
|
30
21
|
this.sub = await super.subscribe(filter);
|
|
31
22
|
return this.sub;
|
|
32
23
|
}
|
|
33
24
|
|
|
34
25
|
public stop() {
|
|
35
|
-
this.clearAllTimeouts();
|
|
36
26
|
if (this.sub) {
|
|
37
27
|
this.sub.stop();
|
|
38
28
|
this.sub = undefined;
|
|
39
29
|
}
|
|
40
30
|
}
|
|
41
31
|
|
|
42
|
-
protected clearAllTimeouts() {
|
|
43
|
-
for (const timeout of this.requestTimeouts.values()) {
|
|
44
|
-
clearTimeout(timeout);
|
|
45
|
-
}
|
|
46
|
-
this.requestTimeouts.clear();
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
protected clearTimeout(id: string) {
|
|
50
|
-
const timeout = this.requestTimeouts.get(id);
|
|
51
|
-
if (timeout) {
|
|
52
|
-
clearTimeout(timeout);
|
|
53
|
-
this.requestTimeouts.delete(id);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
32
|
public setUseNip44(useNip44: boolean) {
|
|
58
33
|
this._useNip44 = useNip44;
|
|
59
34
|
}
|
|
@@ -64,6 +39,7 @@ class NostrRpc extends NDKNostrRpc {
|
|
|
64
39
|
return ciphertext[l - 28] === '?' && ciphertext[l - 27] === 'i' && ciphertext[l - 26] === 'v' && ciphertext[l - 25] === '=';
|
|
65
40
|
}
|
|
66
41
|
|
|
42
|
+
// override to auto-decrypt nip04/nip44
|
|
67
43
|
public async parseEvent(event: NDKEvent): Promise<NDKRpcRequest | NDKRpcResponse> {
|
|
68
44
|
const remoteUser = this._ndk.getUser({ pubkey: event.pubkey });
|
|
69
45
|
remoteUser.ndk = this._ndk;
|
|
@@ -92,6 +68,9 @@ class NostrRpc extends NDKNostrRpc {
|
|
|
92
68
|
}
|
|
93
69
|
}
|
|
94
70
|
|
|
71
|
+
// ndk doesn't support nostrconnect:
|
|
72
|
+
// we just listed to an unsolicited reply to
|
|
73
|
+
// our pubkey and if it's ack/secret - we're fine
|
|
95
74
|
public async listen(nostrConnectSecret: string): Promise<string> {
|
|
96
75
|
const pubkey = this._signer.pubkey;
|
|
97
76
|
console.log('nostr-login listening for conn to', pubkey);
|
|
@@ -100,45 +79,40 @@ class NostrRpc extends NDKNostrRpc {
|
|
|
100
79
|
'#p': [pubkey],
|
|
101
80
|
});
|
|
102
81
|
return new Promise<string>((ok, err) => {
|
|
103
|
-
const timeoutId = setTimeout(() => {
|
|
104
|
-
this.stop();
|
|
105
|
-
err(new Error('NIP46 listen timeout'));
|
|
106
|
-
}, NIP46_TIMEOUT);
|
|
107
|
-
|
|
108
82
|
sub.on('event', async (event: NDKEvent) => {
|
|
109
83
|
try {
|
|
110
84
|
const parsedEvent = await this.parseEvent(event);
|
|
85
|
+
// console.log('ack parsedEvent', parsedEvent);
|
|
111
86
|
if (!(parsedEvent as NDKRpcRequest).method) {
|
|
112
87
|
const response = parsedEvent as NDKRpcResponse;
|
|
113
88
|
|
|
89
|
+
// ignore
|
|
114
90
|
if (response.result === 'auth_url') return;
|
|
115
91
|
|
|
92
|
+
// FIXME for now accept 'ack' replies, later on only
|
|
93
|
+
// accept secrets
|
|
116
94
|
if (response.result === 'ack' || response.result === nostrConnectSecret) {
|
|
117
|
-
clearTimeout(timeoutId);
|
|
118
95
|
ok(event.pubkey);
|
|
119
96
|
} else {
|
|
120
|
-
clearTimeout(timeoutId);
|
|
121
97
|
err(response.error);
|
|
122
98
|
}
|
|
123
99
|
}
|
|
124
100
|
} catch (e) {
|
|
125
101
|
console.log('error parsing event', e, event.rawEvent());
|
|
126
102
|
}
|
|
103
|
+
// done
|
|
127
104
|
this.stop();
|
|
128
105
|
});
|
|
129
106
|
});
|
|
130
107
|
}
|
|
131
108
|
|
|
109
|
+
// since ndk doesn't yet support perms param
|
|
110
|
+
// we reimplement the 'connect' call here
|
|
111
|
+
// instead of await signer.blockUntilReady();
|
|
132
112
|
public async connect(pubkey: string, token?: string, perms?: string) {
|
|
133
113
|
return new Promise<void>((ok, err) => {
|
|
134
114
|
const connectParams = [pubkey!, token || '', perms || ''];
|
|
135
|
-
|
|
136
|
-
const timeoutId = setTimeout(() => {
|
|
137
|
-
err(new Error('NIP46 connect timeout'));
|
|
138
|
-
}, NIP46_TIMEOUT);
|
|
139
|
-
|
|
140
115
|
this.sendRequest(pubkey!, 'connect', connectParams, 24133, (response: NDKRpcResponse) => {
|
|
141
|
-
clearTimeout(timeoutId);
|
|
142
116
|
if (response.result === 'ack') {
|
|
143
117
|
ok();
|
|
144
118
|
} else {
|
|
@@ -152,112 +126,24 @@ class NostrRpc extends NDKNostrRpc {
|
|
|
152
126
|
return Math.random().toString(36).substring(7);
|
|
153
127
|
}
|
|
154
128
|
|
|
155
|
-
protected async ensureConnected(): Promise<void> {
|
|
156
|
-
const relays = Array.from(this._ndk.pool.relays.values());
|
|
157
|
-
console.log(
|
|
158
|
-
'Checking relay connections:',
|
|
159
|
-
relays.map(r => ({ url: r.url, status: r.status })),
|
|
160
|
-
);
|
|
161
|
-
|
|
162
|
-
const connectedRelays = relays.filter(r => r.status === 1);
|
|
163
|
-
console.log('connected relays', connectedRelays);
|
|
164
|
-
|
|
165
|
-
if (connectedRelays.length === 0) {
|
|
166
|
-
console.log('No connected relays, forcing reconnection...');
|
|
167
|
-
|
|
168
|
-
// 既存の接続を全てクリーンアップ
|
|
169
|
-
for (const relay of relays) {
|
|
170
|
-
try {
|
|
171
|
-
await relay.disconnect();
|
|
172
|
-
} catch (e) {
|
|
173
|
-
console.log('Error disconnecting relay:', relay.url, e);
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
// 再接続
|
|
178
|
-
await this._ndk.connect();
|
|
179
|
-
|
|
180
|
-
// 接続確立を待つ
|
|
181
|
-
await new Promise<void>((resolve, reject) => {
|
|
182
|
-
const timeout = setTimeout(() => {
|
|
183
|
-
const status = Array.from(this._ndk.pool.relays.values()).map(r => ({ url: r.url, status: r.status }));
|
|
184
|
-
console.error('Failed to reconnect to relays within 10s. Status:', status);
|
|
185
|
-
reject(new Error('Failed to reconnect to relays'));
|
|
186
|
-
}, 10000);
|
|
187
|
-
|
|
188
|
-
const checkConnection = () => {
|
|
189
|
-
const connected = Array.from(this._ndk.pool.relays.values()).filter(r => r.status === 1);
|
|
190
|
-
if (connected.length > 0) {
|
|
191
|
-
clearTimeout(timeout);
|
|
192
|
-
console.log(
|
|
193
|
-
'Successfully reconnected to',
|
|
194
|
-
connected.length,
|
|
195
|
-
'relays:',
|
|
196
|
-
connected.map(r => r.url),
|
|
197
|
-
);
|
|
198
|
-
resolve();
|
|
199
|
-
} else {
|
|
200
|
-
setTimeout(checkConnection, 200);
|
|
201
|
-
}
|
|
202
|
-
};
|
|
203
|
-
checkConnection();
|
|
204
|
-
});
|
|
205
|
-
} else {
|
|
206
|
-
console.log(
|
|
207
|
-
'Already connected to',
|
|
208
|
-
connectedRelays.length,
|
|
209
|
-
'relays:',
|
|
210
|
-
connectedRelays.map(r => r.url),
|
|
211
|
-
);
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
|
|
215
129
|
public async sendRequest(remotePubkey: string, method: string, params: string[] = [], kind = 24133, cb?: (res: NDKRpcResponse) => void): Promise<NDKRpcResponse> {
|
|
216
|
-
console.log('sendRequest called:', method, 'to', remotePubkey);
|
|
217
|
-
|
|
218
|
-
try {
|
|
219
|
-
this.processManager?.pause();
|
|
220
|
-
await this.ensureConnected();
|
|
221
|
-
} catch (e) {
|
|
222
|
-
console.error('Failed to ensure connection:', e);
|
|
223
|
-
if (cb) {
|
|
224
|
-
cb({
|
|
225
|
-
id: '',
|
|
226
|
-
result: '',
|
|
227
|
-
error: 'Failed to connect to relays: ' + (e as Error).message,
|
|
228
|
-
event: undefined as any,
|
|
229
|
-
});
|
|
230
|
-
}
|
|
231
|
-
throw e;
|
|
232
|
-
} finally {
|
|
233
|
-
this.processManager?.resume();
|
|
234
|
-
}
|
|
235
|
-
|
|
236
130
|
const id = this.getId();
|
|
237
131
|
|
|
132
|
+
// response handler will deduplicate auth urls and responses
|
|
238
133
|
this.setResponseHandler(id, cb);
|
|
239
134
|
|
|
135
|
+
// create and sign request
|
|
240
136
|
const event = await this.createRequestEvent(id, remotePubkey, method, params, kind);
|
|
241
|
-
console.log(
|
|
137
|
+
console.log("sendRequest", { event, method, remotePubkey, params });
|
|
242
138
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
console.log('sendRequest event published successfully');
|
|
246
|
-
} catch (e) {
|
|
247
|
-
console.error('Failed to publish event:', e);
|
|
248
|
-
this.clearTimeout(id);
|
|
249
|
-
this.requests.delete(id);
|
|
250
|
-
if (cb) {
|
|
251
|
-
cb({
|
|
252
|
-
id,
|
|
253
|
-
result: '',
|
|
254
|
-
error: 'Failed to publish event: ' + (e as Error).message,
|
|
255
|
-
event: undefined as any,
|
|
256
|
-
});
|
|
257
|
-
}
|
|
258
|
-
throw e;
|
|
259
|
-
}
|
|
139
|
+
// send to relays
|
|
140
|
+
await event.publish();
|
|
260
141
|
|
|
142
|
+
// NOTE: ndk returns a promise that never resolves and
|
|
143
|
+
// in fact REQUIRES cb to be provided (otherwise no way
|
|
144
|
+
// to consume the result), we've already stepped on the bug
|
|
145
|
+
// of waiting for this unresolvable result, so now we return
|
|
146
|
+
// undefined to make sure waiters fail, not hang.
|
|
261
147
|
// @ts-ignore
|
|
262
148
|
return undefined as NDKRpcResponse;
|
|
263
149
|
}
|
|
@@ -265,26 +151,6 @@ class NostrRpc extends NDKNostrRpc {
|
|
|
265
151
|
protected setResponseHandler(id: string, cb?: (res: NDKRpcResponse) => void) {
|
|
266
152
|
let authUrlSent = false;
|
|
267
153
|
const now = Date.now();
|
|
268
|
-
|
|
269
|
-
const timeoutId = setTimeout(() => {
|
|
270
|
-
if (this.requests.has(id)) {
|
|
271
|
-
clearTimeout(timeoutId);
|
|
272
|
-
this.requests.delete(id);
|
|
273
|
-
this.requestTimeouts.delete(id);
|
|
274
|
-
console.log('NIP46 request timeout for', id);
|
|
275
|
-
if (cb) {
|
|
276
|
-
cb({
|
|
277
|
-
id,
|
|
278
|
-
result: '',
|
|
279
|
-
error: 'NIP46 request timeout',
|
|
280
|
-
event: undefined as any,
|
|
281
|
-
});
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
}, NIP46_TIMEOUT);
|
|
285
|
-
|
|
286
|
-
this.requestTimeouts.set(id, timeoutId);
|
|
287
|
-
|
|
288
154
|
return new Promise<NDKRpcResponse>(() => {
|
|
289
155
|
const responseHandler = (response: NDKRpcResponse) => {
|
|
290
156
|
if (response.result === 'auth_url') {
|
|
@@ -295,7 +161,6 @@ class NostrRpc extends NDKNostrRpc {
|
|
|
295
161
|
}
|
|
296
162
|
} else if (cb) {
|
|
297
163
|
if (this.requests.has(id)) {
|
|
298
|
-
this.clearTimeout(id);
|
|
299
164
|
this.requests.delete(id);
|
|
300
165
|
console.log('nostr-login processed nip46 request in', Date.now() - now, 'ms');
|
|
301
166
|
cb(response);
|
|
@@ -310,14 +175,6 @@ class NostrRpc extends NDKNostrRpc {
|
|
|
310
175
|
protected async createRequestEvent(id: string, remotePubkey: string, method: string, params: string[] = [], kind = 24133) {
|
|
311
176
|
this.requests.add(id);
|
|
312
177
|
const localUser = await this._signer.user();
|
|
313
|
-
|
|
314
|
-
if (!localUser.pubkey) {
|
|
315
|
-
throw new Error('CORRUPTION: Missing local pubkey. Signer state compromised.');
|
|
316
|
-
}
|
|
317
|
-
if (!remotePubkey) {
|
|
318
|
-
throw new Error('CORRUPTION: Missing remote pubkey. Signer state compromised.');
|
|
319
|
-
}
|
|
320
|
-
|
|
321
178
|
const remoteUser = this._ndk.getUser({ pubkey: remotePubkey });
|
|
322
179
|
const request = { id, method, params };
|
|
323
180
|
|
|
@@ -354,6 +211,7 @@ export class IframeNostrRpc extends NostrRpc {
|
|
|
354
211
|
this._ndk,
|
|
355
212
|
{},
|
|
356
213
|
{
|
|
214
|
+
// don't send to relay
|
|
357
215
|
closeOnEose: true,
|
|
358
216
|
cacheUsage: NDKSubscriptionCacheUsage.ONLY_CACHE,
|
|
359
217
|
},
|
|
@@ -365,6 +223,7 @@ export class IframeNostrRpc extends NostrRpc {
|
|
|
365
223
|
|
|
366
224
|
this.iframePort = port;
|
|
367
225
|
|
|
226
|
+
// to make sure Chrome doesn't terminate the channel
|
|
368
227
|
setInterval(() => {
|
|
369
228
|
console.log('iframe-nip46 ping');
|
|
370
229
|
this.iframePort!.postMessage('ping');
|
|
@@ -379,6 +238,7 @@ export class IframeNostrRpc extends NostrRpc {
|
|
|
379
238
|
return;
|
|
380
239
|
}
|
|
381
240
|
|
|
241
|
+
// a copy-paste from rpc.subscribe
|
|
382
242
|
try {
|
|
383
243
|
const event = ev.data;
|
|
384
244
|
|
|
@@ -386,6 +246,7 @@ export class IframeNostrRpc extends NostrRpc {
|
|
|
386
246
|
if (!verifySignature(event)) throw new Error('Invalid event signature from iframe');
|
|
387
247
|
const nevent = new NDKEvent(this._ndk, event);
|
|
388
248
|
const parsedEvent = await this.parseEvent(nevent);
|
|
249
|
+
// we're only implementing client-side rpc
|
|
389
250
|
if (!(parsedEvent as NDKRpcRequest).method) {
|
|
390
251
|
console.log('parsed response', parsedEvent);
|
|
391
252
|
this.emit(`response-${parsedEvent.id}`, parsedEvent);
|
|
@@ -397,60 +258,31 @@ export class IframeNostrRpc extends NostrRpc {
|
|
|
397
258
|
}
|
|
398
259
|
|
|
399
260
|
public async sendRequest(remotePubkey: string, method: string, params: string[] = [], kind = 24133, cb?: (res: NDKRpcResponse) => void): Promise<NDKRpcResponse> {
|
|
400
|
-
console.log('IframeNostrRpc.sendRequest called:', method, 'iframePort:', !!this.iframePort);
|
|
401
|
-
|
|
402
|
-
if (!this.iframePort) {
|
|
403
|
-
try {
|
|
404
|
-
console.log(this.processManager);
|
|
405
|
-
this.processManager?.pause();
|
|
406
|
-
await this.ensureConnected();
|
|
407
|
-
} catch (e) {
|
|
408
|
-
console.error('Failed to ensure connection:', e);
|
|
409
|
-
if (cb) {
|
|
410
|
-
cb({
|
|
411
|
-
id: '',
|
|
412
|
-
result: '',
|
|
413
|
-
error: 'Failed to connect to relays: ' + (e as Error).message,
|
|
414
|
-
event: undefined as any,
|
|
415
|
-
});
|
|
416
|
-
}
|
|
417
|
-
throw e;
|
|
418
|
-
} finally {
|
|
419
|
-
this.processManager?.resume();
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
|
|
423
261
|
const id = this.getId();
|
|
424
262
|
|
|
263
|
+
// create and sign request event
|
|
425
264
|
const event = await this.createRequestEvent(id, remotePubkey, method, params, kind);
|
|
426
265
|
|
|
266
|
+
// set response handler, it will dedup auth urls,
|
|
267
|
+
// and also dedup response handlers - we're sending
|
|
268
|
+
// to relays and to iframe
|
|
427
269
|
this.setResponseHandler(id, cb);
|
|
428
270
|
|
|
429
271
|
if (this.iframePort) {
|
|
272
|
+
// map request event id to request id, if iframe
|
|
273
|
+
// has no key it will reply with error:event_id (it can't
|
|
274
|
+
// decrypt the request id without keys)
|
|
430
275
|
this.iframeRequests.set(event.id, { id, pubkey: remotePubkey });
|
|
431
276
|
|
|
277
|
+
// send to iframe
|
|
432
278
|
console.log('iframe-nip46 sending request to', this.peerOrigin, event.rawEvent());
|
|
433
279
|
this.iframePort.postMessage(event.rawEvent());
|
|
434
280
|
} else {
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
console.log('Request published to relays successfully');
|
|
438
|
-
} catch (e) {
|
|
439
|
-
console.error('Failed to publish event:', e);
|
|
440
|
-
this.clearTimeout(id);
|
|
441
|
-
this.requests.delete(id);
|
|
442
|
-
if (cb) {
|
|
443
|
-
cb({
|
|
444
|
-
id,
|
|
445
|
-
result: '',
|
|
446
|
-
error: 'Failed to publish event: ' + (e as Error).message,
|
|
447
|
-
event: undefined as any,
|
|
448
|
-
});
|
|
449
|
-
}
|
|
450
|
-
throw e;
|
|
451
|
-
}
|
|
281
|
+
// send to relays
|
|
282
|
+
await event.publish();
|
|
452
283
|
}
|
|
453
284
|
|
|
285
|
+
// see notes in 'super'
|
|
454
286
|
// @ts-ignore
|
|
455
287
|
return undefined as NDKRpcResponse;
|
|
456
288
|
}
|
|
@@ -467,11 +299,14 @@ export class ReadyListener {
|
|
|
467
299
|
this.promise = new Promise<any>(ok => {
|
|
468
300
|
console.log(new Date(), 'started listener for', this.messages);
|
|
469
301
|
|
|
302
|
+
// ready message handler
|
|
470
303
|
const onReady = async (e: MessageEvent) => {
|
|
471
304
|
const originHostname = new URL(origin!).hostname;
|
|
472
305
|
const messageHostname = new URL(e.origin).hostname;
|
|
306
|
+
// same host or subdomain
|
|
473
307
|
const validHost = messageHostname === originHostname || messageHostname.endsWith('.' + originHostname);
|
|
474
308
|
if (!validHost || !Array.isArray(e.data) || !e.data.length || !this.messages.includes(e.data[0])) {
|
|
309
|
+
// console.log(new Date(), 'got invalid ready message', e.origin, e.data);
|
|
475
310
|
return;
|
|
476
311
|
}
|
|
477
312
|
|
|
@@ -486,6 +321,17 @@ export class ReadyListener {
|
|
|
486
321
|
async wait(): Promise<any> {
|
|
487
322
|
console.log(new Date(), 'waiting for', this.messages);
|
|
488
323
|
const r = await this.promise;
|
|
324
|
+
// NOTE: timer here doesn't help bcs it must be activated when
|
|
325
|
+
// user "confirms", but that's happening on a different
|
|
326
|
+
// origin and we can't really know.
|
|
327
|
+
// await new Promise<any>((ok, err) => {
|
|
328
|
+
// // 10 sec should be more than enough
|
|
329
|
+
// setTimeout(() => err(new Date() + ' timeout for ' + this.message), 10000);
|
|
330
|
+
|
|
331
|
+
// // if promise already resolved or will resolve in the future
|
|
332
|
+
// this.promise.then(ok);
|
|
333
|
+
// });
|
|
334
|
+
|
|
489
335
|
console.log(new Date(), 'finished waiting for', this.messages, r);
|
|
490
336
|
return r;
|
|
491
337
|
}
|
|
@@ -498,8 +344,9 @@ export class Nip46Signer extends NDKNip46Signer {
|
|
|
498
344
|
constructor(ndk: NDK, localSigner: PrivateKeySigner, signerPubkey: string, iframeOrigin?: string) {
|
|
499
345
|
super(ndk, signerPubkey, localSigner);
|
|
500
346
|
|
|
347
|
+
// override with our own rpc implementation
|
|
501
348
|
this._rpc = new IframeNostrRpc(ndk, localSigner, iframeOrigin);
|
|
502
|
-
this._rpc.setUseNip44(true);
|
|
349
|
+
this._rpc.setUseNip44(true); // !!this.params.optionsModal.dev);
|
|
503
350
|
this._rpc.on('authUrl', (url: string) => {
|
|
504
351
|
this.emit('authUrl', url);
|
|
505
352
|
});
|
|
@@ -512,29 +359,20 @@ export class Nip46Signer extends NDKNip46Signer {
|
|
|
512
359
|
}
|
|
513
360
|
|
|
514
361
|
private async setSignerPubkey(signerPubkey: string, sameAsUser: boolean = false) {
|
|
515
|
-
console.log(
|
|
362
|
+
console.log("setSignerPubkey", signerPubkey);
|
|
516
363
|
|
|
364
|
+
// ensure it's set
|
|
517
365
|
this.remotePubkey = signerPubkey;
|
|
518
366
|
|
|
367
|
+
// when we're sure it's known
|
|
519
368
|
this._rpc.on(`iframeRestart-${signerPubkey}`, () => {
|
|
520
369
|
this.emit('iframeRestart');
|
|
521
370
|
});
|
|
522
371
|
|
|
372
|
+
// now call getPublicKey and swap remotePubkey w/ that
|
|
523
373
|
await this.initUserPubkey(sameAsUser ? signerPubkey : '');
|
|
524
374
|
}
|
|
525
375
|
|
|
526
|
-
public forceResetState() {
|
|
527
|
-
console.log('Nip46Signer state reset due to connection failure or timeout.');
|
|
528
|
-
|
|
529
|
-
// 1. ユーザー公開鍵をクリア
|
|
530
|
-
this._userPubkey = '';
|
|
531
|
-
|
|
532
|
-
// 2. リモート公開鍵をクリア
|
|
533
|
-
this.remotePubkey = ''; // 親クラスのプロパティをクリア
|
|
534
|
-
|
|
535
|
-
// 3. RPC側のタイマーとリクエストを、公開メソッド経由でクリア
|
|
536
|
-
(this._rpc as NostrRpc).cleanupTimersAndRequests();
|
|
537
|
-
}
|
|
538
376
|
public async initUserPubkey(hintPubkey?: string) {
|
|
539
377
|
if (this._userPubkey) throw new Error('Already called initUserPubkey');
|
|
540
378
|
|
|
@@ -546,19 +384,9 @@ export class Nip46Signer extends NDKNip46Signer {
|
|
|
546
384
|
this._userPubkey = await new Promise<string>((ok, err) => {
|
|
547
385
|
if (!this.remotePubkey) throw new Error('Signer pubkey not set');
|
|
548
386
|
|
|
549
|
-
console.log(
|
|
550
|
-
|
|
551
|
-
const timeoutId = setTimeout(() => {
|
|
552
|
-
err(new Error('NIP46 get_public_key timeout'));
|
|
553
|
-
}, NIP46_TIMEOUT);
|
|
554
|
-
|
|
387
|
+
console.log("get_public_key", this.remotePubkey);
|
|
555
388
|
this._rpc.sendRequest(this.remotePubkey, 'get_public_key', [], 24133, (response: NDKRpcResponse) => {
|
|
556
|
-
|
|
557
|
-
if (response.error) {
|
|
558
|
-
err(new Error(response.error));
|
|
559
|
-
} else {
|
|
560
|
-
ok(response.result);
|
|
561
|
-
}
|
|
389
|
+
ok(response.result);
|
|
562
390
|
});
|
|
563
391
|
});
|
|
564
392
|
}
|
|
@@ -580,21 +408,15 @@ export class Nip46Signer extends NDKNip46Signer {
|
|
|
580
408
|
}
|
|
581
409
|
|
|
582
410
|
public async createAccount2({ bunkerPubkey, name, domain, perms = '' }: { bunkerPubkey: string; name: string; domain: string; perms?: string }) {
|
|
583
|
-
const params = [
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
if (response.error) {
|
|
593
|
-
err(new Error(response.error));
|
|
594
|
-
} else {
|
|
595
|
-
ok(response);
|
|
596
|
-
}
|
|
597
|
-
});
|
|
411
|
+
const params = [
|
|
412
|
+
name,
|
|
413
|
+
domain,
|
|
414
|
+
'', // email
|
|
415
|
+
perms,
|
|
416
|
+
];
|
|
417
|
+
|
|
418
|
+
const r = await new Promise<NDKRpcResponse>(ok => {
|
|
419
|
+
this.rpc.sendRequest(bunkerPubkey, 'create_account', params, undefined, ok);
|
|
598
420
|
});
|
|
599
421
|
|
|
600
422
|
console.log('create_account pubkey', r);
|
package/src/modules/Nostr.ts
CHANGED
|
@@ -2,7 +2,6 @@ import { EventEmitter } from 'tseep';
|
|
|
2
2
|
import { CALL_TIMEOUT } from '../const';
|
|
3
3
|
|
|
4
4
|
class ProcessManager extends EventEmitter {
|
|
5
|
-
private paused = false;
|
|
6
5
|
private callCount: number = 0;
|
|
7
6
|
private callTimer: NodeJS.Timeout | undefined;
|
|
8
7
|
|
|
@@ -11,41 +10,22 @@ class ProcessManager extends EventEmitter {
|
|
|
11
10
|
}
|
|
12
11
|
|
|
13
12
|
public onAuthUrl() {
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
if (Boolean(this.callTimer)) {
|
|
14
|
+
clearTimeout(this.callTimer);
|
|
15
|
+
}
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
public onIframeUrl() {
|
|
19
|
-
|
|
20
|
-
this.resetTimer();
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
private resetTimer() {
|
|
24
|
-
// 既存のタイマーがあればクリア
|
|
25
|
-
if (this.callTimer) {
|
|
19
|
+
if (Boolean(this.callTimer)) {
|
|
26
20
|
clearTimeout(this.callTimer);
|
|
27
|
-
this.callTimer = undefined; // IDをクリア
|
|
28
|
-
console.log('ProcessManager: timer reset');
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// 監視対象が残っていて、かつ一時停止中でなければ、新しいタイマーを設定
|
|
32
|
-
if (this.callCount > 0 && !this.paused) {
|
|
33
|
-
this.callTimer = setTimeout(() => {
|
|
34
|
-
console.log('ProcessManager: timeout reached, emitting onCallTimeout');
|
|
35
|
-
this.callTimer = undefined; // タイムアウト時にIDをクリア
|
|
36
|
-
this.emit('onCallTimeout');
|
|
37
|
-
}, CALL_TIMEOUT);
|
|
38
|
-
console.log(`ProcessManager: new timer set for ${CALL_TIMEOUT} ms`);
|
|
39
21
|
}
|
|
40
22
|
}
|
|
41
23
|
|
|
42
24
|
public async wait<T>(cb: () => Promise<T>): Promise<T> {
|
|
43
|
-
|
|
25
|
+
// FIXME only allow 1 parallel req
|
|
44
26
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
// waitの最初の呼び出し時のみ、タイマーを初期設定
|
|
48
|
-
this.resetTimer();
|
|
27
|
+
if (!this.callTimer) {
|
|
28
|
+
this.callTimer = setTimeout(() => this.emit('onCallTimeout'), CALL_TIMEOUT);
|
|
49
29
|
}
|
|
50
30
|
|
|
51
31
|
if (!this.callCount) {
|
|
@@ -54,52 +34,33 @@ class ProcessManager extends EventEmitter {
|
|
|
54
34
|
|
|
55
35
|
this.callCount++;
|
|
56
36
|
|
|
57
|
-
let error
|
|
58
|
-
let result
|
|
37
|
+
let error;
|
|
38
|
+
let result;
|
|
59
39
|
|
|
60
|
-
// 非同期処理の実行
|
|
61
40
|
try {
|
|
62
41
|
result = await cb();
|
|
63
42
|
} catch (e) {
|
|
64
43
|
error = e;
|
|
65
44
|
}
|
|
66
45
|
|
|
67
|
-
// ★ 修正点: クリーンアップロジックを resetTimer に置き換え
|
|
68
|
-
// ProcessManagerの呼び出しカウントをデクリメント
|
|
69
46
|
this.callCount--;
|
|
70
|
-
this.emit('onCallEnd');
|
|
71
|
-
|
|
72
|
-
// リクエスト完了後、タイマーをリセットし、callCountに応じて再設定
|
|
73
|
-
this.resetTimer();
|
|
74
47
|
|
|
75
|
-
|
|
76
|
-
if (error) {
|
|
77
|
-
throw error;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// @ts-ignore
|
|
81
|
-
return result as T;
|
|
82
|
-
}
|
|
48
|
+
this.emit('onCallEnd');
|
|
83
49
|
|
|
84
|
-
public pause() {
|
|
85
|
-
console.log('ProcessManager: PAUSING timer...');
|
|
86
50
|
if (this.callTimer) {
|
|
87
51
|
clearTimeout(this.callTimer);
|
|
88
52
|
}
|
|
89
|
-
this.callTimer = undefined; // タイマーをクリア
|
|
90
|
-
this.paused = true;
|
|
91
|
-
this.emit('onCallPause');
|
|
92
|
-
}
|
|
93
53
|
|
|
94
|
-
|
|
95
|
-
console.log('ProcessManager: RESUMING timer...');
|
|
96
|
-
this.paused = false;
|
|
54
|
+
this.callTimer = undefined;
|
|
97
55
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
this.resetTimer();
|
|
56
|
+
if (error) {
|
|
57
|
+
throw error;
|
|
101
58
|
}
|
|
102
|
-
|
|
59
|
+
|
|
60
|
+
// we can't return undefined bcs an exception is
|
|
61
|
+
// thrown above on error
|
|
62
|
+
// @ts-ignore
|
|
63
|
+
return result;
|
|
103
64
|
}
|
|
104
65
|
}
|
|
105
66
|
|