@konemono/nostr-login 1.7.36 → 1.7.38
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.d.ts +2 -2
- package/dist/index.esm.js +41 -12
- 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 +8 -10
- package/dist/modules/Nostr.d.ts +1 -1
- package/dist/modules/NostrParams.d.ts +1 -1
- package/dist/modules/Signer.d.ts +0 -9
- package/dist/types.d.ts +1 -1
- package/dist/unpkg.js +41 -12
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/nip44.d.ts +1 -1
- package/package.json +7 -7
- package/src/const/index.ts +1 -2
- package/src/iife-module.ts +2 -7
- package/src/index.ts +2 -7
- package/src/modules/AuthNostrService.ts +168 -57
- package/src/modules/BannerManager.ts +1 -1
- package/src/modules/ModalManager.ts +58 -51
- package/src/modules/Nip46.ts +92 -263
- package/src/modules/Nostr.ts +1 -1
- package/src/modules/NostrParams.ts +1 -1
- package/src/modules/ProcessManager.ts +18 -57
- package/src/modules/Signer.ts +2 -1
- package/src/types.ts +31 -1
- package/src/utils/index.ts +1 -1
package/src/modules/Nip46.ts
CHANGED
|
@@ -1,59 +1,45 @@
|
|
|
1
|
-
import NDK, {
|
|
1
|
+
import NDK, {
|
|
2
|
+
NDKEvent,
|
|
3
|
+
NDKFilter,
|
|
4
|
+
NDKNip46Signer,
|
|
5
|
+
NDKNostrRpc,
|
|
6
|
+
NDKPrivateKeySigner,
|
|
7
|
+
NDKRpcRequest,
|
|
8
|
+
NDKRpcResponse,
|
|
9
|
+
NDKSubscription,
|
|
10
|
+
NDKSubscriptionCacheUsage,
|
|
11
|
+
NostrEvent,
|
|
12
|
+
} from '@nostr-dev-kit/ndk';
|
|
2
13
|
import { validateEvent, verifySignature } from 'nostr-tools';
|
|
3
|
-
import { PrivateKeySigner } from './Signer';
|
|
4
|
-
import { NIP46_TIMEOUT } from '../const';
|
|
5
|
-
import ProcessManager from './ProcessManager';
|
|
14
|
+
//import { PrivateKeySigner } from './Signer';
|
|
6
15
|
|
|
7
16
|
class NostrRpc extends NDKNostrRpc {
|
|
8
|
-
protected processManager?: ProcessManager;
|
|
9
17
|
protected _ndk: NDK;
|
|
10
|
-
protected _signer:
|
|
18
|
+
protected _signer: NDKPrivateKeySigner;
|
|
11
19
|
protected requests: Set<string> = new Set();
|
|
12
|
-
protected requestTimeouts: Map<string, NodeJS.Timeout> = new Map();
|
|
13
20
|
private sub?: NDKSubscription;
|
|
14
21
|
protected _useNip44: boolean = false;
|
|
15
22
|
|
|
16
|
-
public
|
|
17
|
-
this.clearAllTimeouts(); // private/protected なメソッドを呼び出す
|
|
18
|
-
this.requests.clear(); // requests Setをクリア
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
public constructor(ndk: NDK, signer: PrivateKeySigner, processManager?: ProcessManager) {
|
|
23
|
+
public constructor(ndk: NDK, signer: NDKPrivateKeySigner) {
|
|
22
24
|
super(ndk, signer, ndk.debug.extend('nip46:signer:rpc'));
|
|
23
25
|
this._ndk = ndk;
|
|
24
26
|
this._signer = signer;
|
|
25
|
-
this.processManager = processManager;
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
public async subscribe(filter: NDKFilter): Promise<NDKSubscription> {
|
|
30
|
+
// NOTE: fixing ndk
|
|
29
31
|
filter.kinds = filter.kinds?.filter(k => k === 24133);
|
|
30
32
|
this.sub = await super.subscribe(filter);
|
|
31
33
|
return this.sub;
|
|
32
34
|
}
|
|
33
35
|
|
|
34
36
|
public stop() {
|
|
35
|
-
this.clearAllTimeouts();
|
|
36
37
|
if (this.sub) {
|
|
37
38
|
this.sub.stop();
|
|
38
39
|
this.sub = undefined;
|
|
39
40
|
}
|
|
40
41
|
}
|
|
41
42
|
|
|
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
43
|
public setUseNip44(useNip44: boolean) {
|
|
58
44
|
this._useNip44 = useNip44;
|
|
59
45
|
}
|
|
@@ -64,11 +50,14 @@ class NostrRpc extends NDKNostrRpc {
|
|
|
64
50
|
return ciphertext[l - 28] === '?' && ciphertext[l - 27] === 'i' && ciphertext[l - 26] === 'v' && ciphertext[l - 25] === '=';
|
|
65
51
|
}
|
|
66
52
|
|
|
53
|
+
// override to auto-decrypt nip04/nip44
|
|
67
54
|
public async parseEvent(event: NDKEvent): Promise<NDKRpcRequest | NDKRpcResponse> {
|
|
68
55
|
const remoteUser = this._ndk.getUser({ pubkey: event.pubkey });
|
|
69
56
|
remoteUser.ndk = this._ndk;
|
|
70
|
-
const
|
|
71
|
-
|
|
57
|
+
const decryptedContent = this.isNip04(event.content)
|
|
58
|
+
? await this._signer.decrypt(remoteUser, event.content, 'nip04')
|
|
59
|
+
: await this._signer.decrypt(remoteUser, event.content, 'nip44');
|
|
60
|
+
//const decryptedContent = await decrypt.call(this._signer, remoteUser, event.content);
|
|
72
61
|
const parsedContent = JSON.parse(decryptedContent);
|
|
73
62
|
const { id, method, params, result, error } = parsedContent;
|
|
74
63
|
|
|
@@ -92,6 +81,9 @@ class NostrRpc extends NDKNostrRpc {
|
|
|
92
81
|
}
|
|
93
82
|
}
|
|
94
83
|
|
|
84
|
+
// ndk doesn't support nostrconnect:
|
|
85
|
+
// we just listed to an unsolicited reply to
|
|
86
|
+
// our pubkey and if it's ack/secret - we're fine
|
|
95
87
|
public async listen(nostrConnectSecret: string): Promise<string> {
|
|
96
88
|
const pubkey = this._signer.pubkey;
|
|
97
89
|
console.log('nostr-login listening for conn to', pubkey);
|
|
@@ -100,45 +92,40 @@ class NostrRpc extends NDKNostrRpc {
|
|
|
100
92
|
'#p': [pubkey],
|
|
101
93
|
});
|
|
102
94
|
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
95
|
sub.on('event', async (event: NDKEvent) => {
|
|
109
96
|
try {
|
|
110
97
|
const parsedEvent = await this.parseEvent(event);
|
|
98
|
+
// console.log('ack parsedEvent', parsedEvent);
|
|
111
99
|
if (!(parsedEvent as NDKRpcRequest).method) {
|
|
112
100
|
const response = parsedEvent as NDKRpcResponse;
|
|
113
101
|
|
|
102
|
+
// ignore
|
|
114
103
|
if (response.result === 'auth_url') return;
|
|
115
104
|
|
|
105
|
+
// FIXME for now accept 'ack' replies, later on only
|
|
106
|
+
// accept secrets
|
|
116
107
|
if (response.result === 'ack' || response.result === nostrConnectSecret) {
|
|
117
|
-
clearTimeout(timeoutId);
|
|
118
108
|
ok(event.pubkey);
|
|
119
109
|
} else {
|
|
120
|
-
clearTimeout(timeoutId);
|
|
121
110
|
err(response.error);
|
|
122
111
|
}
|
|
123
112
|
}
|
|
124
113
|
} catch (e) {
|
|
125
114
|
console.log('error parsing event', e, event.rawEvent());
|
|
126
115
|
}
|
|
116
|
+
// done
|
|
127
117
|
this.stop();
|
|
128
118
|
});
|
|
129
119
|
});
|
|
130
120
|
}
|
|
131
121
|
|
|
122
|
+
// since ndk doesn't yet support perms param
|
|
123
|
+
// we reimplement the 'connect' call here
|
|
124
|
+
// instead of await signer.blockUntilReady();
|
|
132
125
|
public async connect(pubkey: string, token?: string, perms?: string) {
|
|
133
126
|
return new Promise<void>((ok, err) => {
|
|
134
127
|
const connectParams = [pubkey!, token || '', perms || ''];
|
|
135
|
-
|
|
136
|
-
const timeoutId = setTimeout(() => {
|
|
137
|
-
err(new Error('NIP46 connect timeout'));
|
|
138
|
-
}, NIP46_TIMEOUT);
|
|
139
|
-
|
|
140
128
|
this.sendRequest(pubkey!, 'connect', connectParams, 24133, (response: NDKRpcResponse) => {
|
|
141
|
-
clearTimeout(timeoutId);
|
|
142
129
|
if (response.result === 'ack') {
|
|
143
130
|
ok();
|
|
144
131
|
} else {
|
|
@@ -152,113 +139,24 @@ class NostrRpc extends NDKNostrRpc {
|
|
|
152
139
|
return Math.random().toString(36).substring(7);
|
|
153
140
|
}
|
|
154
141
|
|
|
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
142
|
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
|
-
this.processManager?.resetTimer();
|
|
222
|
-
} catch (e) {
|
|
223
|
-
console.error('Failed to ensure connection:', e);
|
|
224
|
-
if (cb) {
|
|
225
|
-
cb({
|
|
226
|
-
id: '',
|
|
227
|
-
result: '',
|
|
228
|
-
error: 'Failed to connect to relays: ' + (e as Error).message,
|
|
229
|
-
event: undefined as any,
|
|
230
|
-
});
|
|
231
|
-
}
|
|
232
|
-
throw e;
|
|
233
|
-
} finally {
|
|
234
|
-
this.processManager?.resume();
|
|
235
|
-
}
|
|
236
|
-
|
|
237
143
|
const id = this.getId();
|
|
238
144
|
|
|
145
|
+
// response handler will deduplicate auth urls and responses
|
|
239
146
|
this.setResponseHandler(id, cb);
|
|
240
147
|
|
|
148
|
+
// create and sign request
|
|
241
149
|
const event = await this.createRequestEvent(id, remotePubkey, method, params, kind);
|
|
242
|
-
console.log('sendRequest
|
|
150
|
+
console.log('sendRequest', { event, method, remotePubkey, params });
|
|
243
151
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
console.log('sendRequest event published successfully');
|
|
247
|
-
} catch (e) {
|
|
248
|
-
console.error('Failed to publish event:', e);
|
|
249
|
-
this.clearTimeout(id);
|
|
250
|
-
this.requests.delete(id);
|
|
251
|
-
if (cb) {
|
|
252
|
-
cb({
|
|
253
|
-
id,
|
|
254
|
-
result: '',
|
|
255
|
-
error: 'Failed to publish event: ' + (e as Error).message,
|
|
256
|
-
event: undefined as any,
|
|
257
|
-
});
|
|
258
|
-
}
|
|
259
|
-
throw e;
|
|
260
|
-
}
|
|
152
|
+
// send to relays
|
|
153
|
+
await event.publish();
|
|
261
154
|
|
|
155
|
+
// NOTE: ndk returns a promise that never resolves and
|
|
156
|
+
// in fact REQUIRES cb to be provided (otherwise no way
|
|
157
|
+
// to consume the result), we've already stepped on the bug
|
|
158
|
+
// of waiting for this unresolvable result, so now we return
|
|
159
|
+
// undefined to make sure waiters fail, not hang.
|
|
262
160
|
// @ts-ignore
|
|
263
161
|
return undefined as NDKRpcResponse;
|
|
264
162
|
}
|
|
@@ -266,26 +164,6 @@ class NostrRpc extends NDKNostrRpc {
|
|
|
266
164
|
protected setResponseHandler(id: string, cb?: (res: NDKRpcResponse) => void) {
|
|
267
165
|
let authUrlSent = false;
|
|
268
166
|
const now = Date.now();
|
|
269
|
-
|
|
270
|
-
const timeoutId = setTimeout(() => {
|
|
271
|
-
if (this.requests.has(id)) {
|
|
272
|
-
clearTimeout(timeoutId);
|
|
273
|
-
this.requests.delete(id);
|
|
274
|
-
this.requestTimeouts.delete(id);
|
|
275
|
-
console.log('NIP46 request timeout for', id);
|
|
276
|
-
if (cb) {
|
|
277
|
-
cb({
|
|
278
|
-
id,
|
|
279
|
-
result: '',
|
|
280
|
-
error: 'NIP46 request timeout',
|
|
281
|
-
event: undefined as any,
|
|
282
|
-
});
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
}, NIP46_TIMEOUT);
|
|
286
|
-
|
|
287
|
-
this.requestTimeouts.set(id, timeoutId);
|
|
288
|
-
|
|
289
167
|
return new Promise<NDKRpcResponse>(() => {
|
|
290
168
|
const responseHandler = (response: NDKRpcResponse) => {
|
|
291
169
|
if (response.result === 'auth_url') {
|
|
@@ -296,7 +174,6 @@ class NostrRpc extends NDKNostrRpc {
|
|
|
296
174
|
}
|
|
297
175
|
} else if (cb) {
|
|
298
176
|
if (this.requests.has(id)) {
|
|
299
|
-
this.clearTimeout(id);
|
|
300
177
|
this.requests.delete(id);
|
|
301
178
|
console.log('nostr-login processed nip46 request in', Date.now() - now, 'ms');
|
|
302
179
|
cb(response);
|
|
@@ -311,14 +188,6 @@ class NostrRpc extends NDKNostrRpc {
|
|
|
311
188
|
protected async createRequestEvent(id: string, remotePubkey: string, method: string, params: string[] = [], kind = 24133) {
|
|
312
189
|
this.requests.add(id);
|
|
313
190
|
const localUser = await this._signer.user();
|
|
314
|
-
|
|
315
|
-
if (!localUser.pubkey) {
|
|
316
|
-
throw new Error('CORRUPTION: Missing local pubkey. Signer state compromised.');
|
|
317
|
-
}
|
|
318
|
-
if (!remotePubkey) {
|
|
319
|
-
throw new Error('CORRUPTION: Missing remote pubkey. Signer state compromised.');
|
|
320
|
-
}
|
|
321
|
-
|
|
322
191
|
const remoteUser = this._ndk.getUser({ pubkey: remotePubkey });
|
|
323
192
|
const request = { id, method, params };
|
|
324
193
|
|
|
@@ -330,8 +199,8 @@ class NostrRpc extends NDKNostrRpc {
|
|
|
330
199
|
} as NostrEvent);
|
|
331
200
|
|
|
332
201
|
const useNip44 = this._useNip44 && method !== 'create_account';
|
|
333
|
-
|
|
334
|
-
event.content = await encrypt.call(this._signer, remoteUser, event.content);
|
|
202
|
+
event.content = useNip44 ? await this._signer.encrypt(remoteUser, event.content, 'nip44') : await this._signer.encrypt(remoteUser, event.content, 'nip04');
|
|
203
|
+
//event.content = await encrypt.call(this._signer, remoteUser, event.content);
|
|
335
204
|
await event.sign(this._signer);
|
|
336
205
|
|
|
337
206
|
return event;
|
|
@@ -343,7 +212,7 @@ export class IframeNostrRpc extends NostrRpc {
|
|
|
343
212
|
private iframePort?: MessagePort;
|
|
344
213
|
private iframeRequests = new Map<string, { id: string; pubkey: string }>();
|
|
345
214
|
|
|
346
|
-
public constructor(ndk: NDK, localSigner:
|
|
215
|
+
public constructor(ndk: NDK, localSigner: NDKPrivateKeySigner, iframePeerOrigin?: string) {
|
|
347
216
|
super(ndk, localSigner);
|
|
348
217
|
this._ndk = ndk;
|
|
349
218
|
this.peerOrigin = iframePeerOrigin;
|
|
@@ -355,6 +224,7 @@ export class IframeNostrRpc extends NostrRpc {
|
|
|
355
224
|
this._ndk,
|
|
356
225
|
{},
|
|
357
226
|
{
|
|
227
|
+
// don't send to relay
|
|
358
228
|
closeOnEose: true,
|
|
359
229
|
cacheUsage: NDKSubscriptionCacheUsage.ONLY_CACHE,
|
|
360
230
|
},
|
|
@@ -366,6 +236,7 @@ export class IframeNostrRpc extends NostrRpc {
|
|
|
366
236
|
|
|
367
237
|
this.iframePort = port;
|
|
368
238
|
|
|
239
|
+
// to make sure Chrome doesn't terminate the channel
|
|
369
240
|
setInterval(() => {
|
|
370
241
|
console.log('iframe-nip46 ping');
|
|
371
242
|
this.iframePort!.postMessage('ping');
|
|
@@ -380,6 +251,7 @@ export class IframeNostrRpc extends NostrRpc {
|
|
|
380
251
|
return;
|
|
381
252
|
}
|
|
382
253
|
|
|
254
|
+
// a copy-paste from rpc.subscribe
|
|
383
255
|
try {
|
|
384
256
|
const event = ev.data;
|
|
385
257
|
|
|
@@ -387,6 +259,7 @@ export class IframeNostrRpc extends NostrRpc {
|
|
|
387
259
|
if (!verifySignature(event)) throw new Error('Invalid event signature from iframe');
|
|
388
260
|
const nevent = new NDKEvent(this._ndk, event);
|
|
389
261
|
const parsedEvent = await this.parseEvent(nevent);
|
|
262
|
+
// we're only implementing client-side rpc
|
|
390
263
|
if (!(parsedEvent as NDKRpcRequest).method) {
|
|
391
264
|
console.log('parsed response', parsedEvent);
|
|
392
265
|
this.emit(`response-${parsedEvent.id}`, parsedEvent);
|
|
@@ -398,60 +271,31 @@ export class IframeNostrRpc extends NostrRpc {
|
|
|
398
271
|
}
|
|
399
272
|
|
|
400
273
|
public async sendRequest(remotePubkey: string, method: string, params: string[] = [], kind = 24133, cb?: (res: NDKRpcResponse) => void): Promise<NDKRpcResponse> {
|
|
401
|
-
console.log('IframeNostrRpc.sendRequest called:', method, 'iframePort:', !!this.iframePort);
|
|
402
|
-
|
|
403
|
-
if (!this.iframePort) {
|
|
404
|
-
try {
|
|
405
|
-
console.log(this.processManager);
|
|
406
|
-
this.processManager?.pause();
|
|
407
|
-
await this.ensureConnected();
|
|
408
|
-
} catch (e) {
|
|
409
|
-
console.error('Failed to ensure connection:', e);
|
|
410
|
-
if (cb) {
|
|
411
|
-
cb({
|
|
412
|
-
id: '',
|
|
413
|
-
result: '',
|
|
414
|
-
error: 'Failed to connect to relays: ' + (e as Error).message,
|
|
415
|
-
event: undefined as any,
|
|
416
|
-
});
|
|
417
|
-
}
|
|
418
|
-
throw e;
|
|
419
|
-
} finally {
|
|
420
|
-
this.processManager?.resume();
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
|
|
424
274
|
const id = this.getId();
|
|
425
275
|
|
|
276
|
+
// create and sign request event
|
|
426
277
|
const event = await this.createRequestEvent(id, remotePubkey, method, params, kind);
|
|
427
278
|
|
|
279
|
+
// set response handler, it will dedup auth urls,
|
|
280
|
+
// and also dedup response handlers - we're sending
|
|
281
|
+
// to relays and to iframe
|
|
428
282
|
this.setResponseHandler(id, cb);
|
|
429
283
|
|
|
430
284
|
if (this.iframePort) {
|
|
285
|
+
// map request event id to request id, if iframe
|
|
286
|
+
// has no key it will reply with error:event_id (it can't
|
|
287
|
+
// decrypt the request id without keys)
|
|
431
288
|
this.iframeRequests.set(event.id, { id, pubkey: remotePubkey });
|
|
432
289
|
|
|
290
|
+
// send to iframe
|
|
433
291
|
console.log('iframe-nip46 sending request to', this.peerOrigin, event.rawEvent());
|
|
434
292
|
this.iframePort.postMessage(event.rawEvent());
|
|
435
293
|
} else {
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
console.log('Request published to relays successfully');
|
|
439
|
-
} catch (e) {
|
|
440
|
-
console.error('Failed to publish event:', e);
|
|
441
|
-
this.clearTimeout(id);
|
|
442
|
-
this.requests.delete(id);
|
|
443
|
-
if (cb) {
|
|
444
|
-
cb({
|
|
445
|
-
id,
|
|
446
|
-
result: '',
|
|
447
|
-
error: 'Failed to publish event: ' + (e as Error).message,
|
|
448
|
-
event: undefined as any,
|
|
449
|
-
});
|
|
450
|
-
}
|
|
451
|
-
throw e;
|
|
452
|
-
}
|
|
294
|
+
// send to relays
|
|
295
|
+
await event.publish();
|
|
453
296
|
}
|
|
454
297
|
|
|
298
|
+
// see notes in 'super'
|
|
455
299
|
// @ts-ignore
|
|
456
300
|
return undefined as NDKRpcResponse;
|
|
457
301
|
}
|
|
@@ -468,11 +312,14 @@ export class ReadyListener {
|
|
|
468
312
|
this.promise = new Promise<any>(ok => {
|
|
469
313
|
console.log(new Date(), 'started listener for', this.messages);
|
|
470
314
|
|
|
315
|
+
// ready message handler
|
|
471
316
|
const onReady = async (e: MessageEvent) => {
|
|
472
317
|
const originHostname = new URL(origin!).hostname;
|
|
473
318
|
const messageHostname = new URL(e.origin).hostname;
|
|
319
|
+
// same host or subdomain
|
|
474
320
|
const validHost = messageHostname === originHostname || messageHostname.endsWith('.' + originHostname);
|
|
475
321
|
if (!validHost || !Array.isArray(e.data) || !e.data.length || !this.messages.includes(e.data[0])) {
|
|
322
|
+
// console.log(new Date(), 'got invalid ready message', e.origin, e.data);
|
|
476
323
|
return;
|
|
477
324
|
}
|
|
478
325
|
|
|
@@ -487,34 +334,50 @@ export class ReadyListener {
|
|
|
487
334
|
async wait(): Promise<any> {
|
|
488
335
|
console.log(new Date(), 'waiting for', this.messages);
|
|
489
336
|
const r = await this.promise;
|
|
337
|
+
// NOTE: timer here doesn't help bcs it must be activated when
|
|
338
|
+
// user "confirms", but that's happening on a different
|
|
339
|
+
// origin and we can't really know.
|
|
340
|
+
// await new Promise<any>((ok, err) => {
|
|
341
|
+
// // 10 sec should be more than enough
|
|
342
|
+
// setTimeout(() => err(new Date() + ' timeout for ' + this.message), 10000);
|
|
343
|
+
|
|
344
|
+
// // if promise already resolved or will resolve in the future
|
|
345
|
+
// this.promise.then(ok);
|
|
346
|
+
// });
|
|
347
|
+
|
|
490
348
|
console.log(new Date(), 'finished waiting for', this.messages, r);
|
|
491
349
|
return r;
|
|
492
350
|
}
|
|
493
351
|
}
|
|
494
352
|
|
|
495
353
|
export class Nip46Signer extends NDKNip46Signer {
|
|
496
|
-
private _userPubkey: string = '';
|
|
497
354
|
private _rpc: IframeNostrRpc;
|
|
355
|
+
private _remotePubkey: string = '';
|
|
498
356
|
|
|
499
|
-
constructor(ndk: NDK, localSigner:
|
|
357
|
+
constructor(ndk: NDK, localSigner: NDKPrivateKeySigner, signerPubkey: string, iframeOrigin?: string) {
|
|
500
358
|
super(ndk, signerPubkey, localSigner);
|
|
359
|
+
this._remotePubkey = signerPubkey;
|
|
501
360
|
|
|
502
361
|
this._rpc = new IframeNostrRpc(ndk, localSigner, iframeOrigin);
|
|
503
362
|
this._rpc.setUseNip44(true);
|
|
504
363
|
this._rpc.on('authUrl', (url: string) => {
|
|
505
364
|
this.emit('authUrl', url);
|
|
506
365
|
});
|
|
507
|
-
|
|
508
366
|
this.rpc = this._rpc;
|
|
509
367
|
}
|
|
510
368
|
|
|
511
|
-
get
|
|
512
|
-
return this.
|
|
369
|
+
get remotePubkey(): string {
|
|
370
|
+
return this._remotePubkey;
|
|
513
371
|
}
|
|
514
372
|
|
|
373
|
+
set remotePubkey(value: string) {
|
|
374
|
+
this._remotePubkey = value;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// userPubkeyのgetterを削除し、親クラスのプロパティを直接使用
|
|
378
|
+
|
|
515
379
|
private async setSignerPubkey(signerPubkey: string, sameAsUser: boolean = false) {
|
|
516
380
|
console.log('setSignerPubkey', signerPubkey);
|
|
517
|
-
|
|
518
381
|
this.remotePubkey = signerPubkey;
|
|
519
382
|
|
|
520
383
|
this._rpc.on(`iframeRestart-${signerPubkey}`, () => {
|
|
@@ -524,42 +387,20 @@ export class Nip46Signer extends NDKNip46Signer {
|
|
|
524
387
|
await this.initUserPubkey(sameAsUser ? signerPubkey : '');
|
|
525
388
|
}
|
|
526
389
|
|
|
527
|
-
public forceResetState() {
|
|
528
|
-
console.log('Nip46Signer state reset due to connection failure or timeout.');
|
|
529
|
-
|
|
530
|
-
// 1. ユーザー公開鍵をクリア
|
|
531
|
-
this._userPubkey = '';
|
|
532
|
-
|
|
533
|
-
// 2. リモート公開鍵をクリア
|
|
534
|
-
this.remotePubkey = ''; // 親クラスのプロパティをクリア
|
|
535
|
-
|
|
536
|
-
// 3. RPC側のタイマーとリクエストを、公開メソッド経由でクリア
|
|
537
|
-
(this._rpc as NostrRpc).cleanupTimersAndRequests();
|
|
538
|
-
}
|
|
539
390
|
public async initUserPubkey(hintPubkey?: string) {
|
|
540
|
-
|
|
391
|
+
// 親クラスのuserPubkeyプロパティを直接設定
|
|
392
|
+
if (this.userPubkey) throw new Error('Already called initUserPubkey');
|
|
541
393
|
|
|
542
394
|
if (hintPubkey) {
|
|
543
|
-
this.
|
|
395
|
+
this.userPubkey = hintPubkey;
|
|
544
396
|
return;
|
|
545
397
|
}
|
|
546
398
|
|
|
547
|
-
this.
|
|
399
|
+
this.userPubkey = await new Promise((ok, err) => {
|
|
548
400
|
if (!this.remotePubkey) throw new Error('Signer pubkey not set');
|
|
549
|
-
|
|
550
401
|
console.log('get_public_key', this.remotePubkey);
|
|
551
|
-
|
|
552
|
-
const timeoutId = setTimeout(() => {
|
|
553
|
-
err(new Error('NIP46 get_public_key timeout'));
|
|
554
|
-
}, NIP46_TIMEOUT);
|
|
555
|
-
|
|
556
402
|
this._rpc.sendRequest(this.remotePubkey, 'get_public_key', [], 24133, (response: NDKRpcResponse) => {
|
|
557
|
-
|
|
558
|
-
if (response.error) {
|
|
559
|
-
err(new Error(response.error));
|
|
560
|
-
} else {
|
|
561
|
-
ok(response.result);
|
|
562
|
-
}
|
|
403
|
+
ok(response.result);
|
|
563
404
|
});
|
|
564
405
|
});
|
|
565
406
|
}
|
|
@@ -583,26 +424,14 @@ export class Nip46Signer extends NDKNip46Signer {
|
|
|
583
424
|
public async createAccount2({ bunkerPubkey, name, domain, perms = '' }: { bunkerPubkey: string; name: string; domain: string; perms?: string }) {
|
|
584
425
|
const params = [name, domain, '', perms];
|
|
585
426
|
|
|
586
|
-
const r = await new Promise<NDKRpcResponse>(
|
|
587
|
-
|
|
588
|
-
err(new Error('NIP46 create_account timeout'));
|
|
589
|
-
}, NIP46_TIMEOUT);
|
|
590
|
-
|
|
591
|
-
this.rpc.sendRequest(bunkerPubkey, 'create_account', params, undefined, response => {
|
|
592
|
-
clearTimeout(timeoutId);
|
|
593
|
-
if (response.error) {
|
|
594
|
-
err(new Error(response.error));
|
|
595
|
-
} else {
|
|
596
|
-
ok(response);
|
|
597
|
-
}
|
|
598
|
-
});
|
|
427
|
+
const r = await new Promise<NDKRpcResponse>(ok => {
|
|
428
|
+
this.rpc.sendRequest(bunkerPubkey, 'create_account', params, undefined, ok);
|
|
599
429
|
});
|
|
600
430
|
|
|
601
431
|
console.log('create_account pubkey', r);
|
|
602
432
|
if (r.result === 'error') {
|
|
603
433
|
throw new Error(r.error);
|
|
604
434
|
}
|
|
605
|
-
|
|
606
435
|
return r.result;
|
|
607
436
|
}
|
|
608
437
|
}
|
package/src/modules/Nostr.ts
CHANGED