@konemono/nostr-login 1.7.49 → 1.7.51

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.
@@ -1,27 +1,15 @@
1
- //Nip46.ts
2
- import NDK, {
3
- NDKEvent,
4
- NDKFilter,
5
- NDKNip46Signer,
6
- NDKNostrRpc,
7
- NDKPrivateKeySigner,
8
- NDKRpcRequest,
9
- NDKRpcResponse,
10
- NDKSubscription,
11
- NDKSubscriptionCacheUsage,
12
- NostrEvent,
13
- } from '@nostr-dev-kit/ndk';
1
+ import NDK, { NDKEvent, NDKFilter, NDKNip46Signer, NDKNostrRpc, NDKRpcRequest, NDKRpcResponse, NDKSubscription, NDKSubscriptionCacheUsage, NostrEvent } from '@nostr-dev-kit/ndk';
14
2
  import { validateEvent, verifySignature } from 'nostr-tools';
15
- //import { PrivateKeySigner } from './Signer';
3
+ import { PrivateKeySigner } from './Signer';
16
4
 
17
5
  class NostrRpc extends NDKNostrRpc {
18
6
  protected _ndk: NDK;
19
- protected _signer: NDKPrivateKeySigner;
7
+ protected _signer: PrivateKeySigner;
20
8
  protected requests: Set<string> = new Set();
21
9
  private sub?: NDKSubscription;
22
10
  protected _useNip44: boolean = false;
23
11
 
24
- public constructor(ndk: NDK, signer: NDKPrivateKeySigner) {
12
+ public constructor(ndk: NDK, signer: PrivateKeySigner) {
25
13
  super(ndk, signer, ndk.debug.extend('nip46:signer:rpc'));
26
14
  this._ndk = ndk;
27
15
  this._signer = signer;
@@ -55,10 +43,8 @@ class NostrRpc extends NDKNostrRpc {
55
43
  public async parseEvent(event: NDKEvent): Promise<NDKRpcRequest | NDKRpcResponse> {
56
44
  const remoteUser = this._ndk.getUser({ pubkey: event.pubkey });
57
45
  remoteUser.ndk = this._ndk;
58
- const decryptedContent = this.isNip04(event.content)
59
- ? await this._signer.decrypt(remoteUser, event.content, 'nip04')
60
- : await this._signer.decrypt(remoteUser, event.content, 'nip44');
61
- //const decryptedContent = await decrypt.call(this._signer, remoteUser, event.content);
46
+ const decrypt = this.isNip04(event.content) ? this._signer.decrypt : this._signer.decryptNip44;
47
+ const decryptedContent = await decrypt.call(this._signer, remoteUser, event.content);
62
48
  const parsedContent = JSON.parse(decryptedContent);
63
49
  const { id, method, params, result, error } = parsedContent;
64
50
 
@@ -143,51 +129,45 @@ class NostrRpc extends NDKNostrRpc {
143
129
  public async sendRequest(remotePubkey: string, method: string, params: string[] = [], kind = 24133, cb?: (res: NDKRpcResponse) => void): Promise<NDKRpcResponse> {
144
130
  const id = this.getId();
145
131
 
146
- // 1. Promiseを変数に格納
147
- const responsePromise = this.setResponseHandler(id, cb);
148
-
149
- //ちょっと待つ
150
- await new Promise(r => setTimeout(r, 100));
132
+ // response handler will deduplicate auth urls and responses
133
+ this.setResponseHandler(id, cb);
151
134
 
135
+ // create and sign request
152
136
  const event = await this.createRequestEvent(id, remotePubkey, method, params, kind);
137
+ console.log("sendRequest", { event, method, remotePubkey, params });
153
138
 
154
- // 2. 送信
139
+ // send to relays
155
140
  await event.publish();
156
141
 
157
- // 3. undefined ではなく、レスポンスを待つ Promise を返す
158
- return responsePromise;
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.
147
+ // @ts-ignore
148
+ return undefined as NDKRpcResponse;
159
149
  }
160
150
 
161
151
  protected setResponseHandler(id: string, cb?: (res: NDKRpcResponse) => void) {
162
- const now = Date.now();
163
152
  let authUrlSent = false;
164
-
165
- // 1. 外部から解決できるように Promise を作成
166
- return new Promise<NDKRpcResponse>(resolve => {
153
+ const now = Date.now();
154
+ return new Promise<NDKRpcResponse>(() => {
167
155
  const responseHandler = (response: NDKRpcResponse) => {
168
- console.log(`[NIP46] Received response for ID: ${response.id}`, response);
169
-
170
156
  if (response.result === 'auth_url') {
171
157
  this.once(`response-${id}`, responseHandler);
172
158
  if (!authUrlSent) {
173
159
  authUrlSent = true;
174
160
  this.emit('authUrl', response.error);
175
161
  }
176
- } else {
177
- // IDが一致しているか、リクエストリストに存在するか確認
162
+ } else if (cb) {
178
163
  if (this.requests.has(id)) {
179
164
  this.requests.delete(id);
180
165
  console.log('nostr-login processed nip46 request in', Date.now() - now, 'ms');
181
-
182
- if (cb) cb(response); // 既存のコールバックを実行
183
- resolve(response); // ★Promise を解決する(これで await が終わる)
184
- } else {
185
- console.warn(`[NIP46] Received response for unknown ID: ${id}`);
166
+ cb(response);
186
167
  }
187
168
  }
188
169
  };
189
170
 
190
- // イベント登録
191
171
  this.once(`response-${id}`, responseHandler);
192
172
  });
193
173
  }
@@ -206,8 +186,8 @@ class NostrRpc extends NDKNostrRpc {
206
186
  } as NostrEvent);
207
187
 
208
188
  const useNip44 = this._useNip44 && method !== 'create_account';
209
- event.content = useNip44 ? await this._signer.encrypt(remoteUser, event.content, 'nip44') : await this._signer.encrypt(remoteUser, event.content, 'nip04');
210
- //event.content = await encrypt.call(this._signer, remoteUser, event.content);
189
+ const encrypt = useNip44 ? this._signer.encryptNip44 : this._signer.encrypt;
190
+ event.content = await encrypt.call(this._signer, remoteUser, event.content);
211
191
  await event.sign(this._signer);
212
192
 
213
193
  return event;
@@ -219,7 +199,7 @@ export class IframeNostrRpc extends NostrRpc {
219
199
  private iframePort?: MessagePort;
220
200
  private iframeRequests = new Map<string, { id: string; pubkey: string }>();
221
201
 
222
- public constructor(ndk: NDK, localSigner: NDKPrivateKeySigner, iframePeerOrigin?: string) {
202
+ public constructor(ndk: NDK, localSigner: PrivateKeySigner, iframePeerOrigin?: string) {
223
203
  super(ndk, localSigner);
224
204
  this._ndk = ndk;
225
205
  this.peerOrigin = iframePeerOrigin;
@@ -358,54 +338,53 @@ export class ReadyListener {
358
338
  }
359
339
 
360
340
  export class Nip46Signer extends NDKNip46Signer {
341
+ private _userPubkey: string = '';
361
342
  private _rpc: IframeNostrRpc;
362
- private _remotePubkey: string = '';
363
343
 
364
- constructor(ndk: NDK, localSigner: NDKPrivateKeySigner, signerPubkey: string, iframeOrigin?: string) {
344
+ constructor(ndk: NDK, localSigner: PrivateKeySigner, signerPubkey: string, iframeOrigin?: string) {
365
345
  super(ndk, signerPubkey, localSigner);
366
- this._remotePubkey = signerPubkey;
367
346
 
347
+ // override with our own rpc implementation
368
348
  this._rpc = new IframeNostrRpc(ndk, localSigner, iframeOrigin);
369
- this._rpc.setUseNip44(true);
349
+ this._rpc.setUseNip44(true); // !!this.params.optionsModal.dev);
370
350
  this._rpc.on('authUrl', (url: string) => {
371
351
  this.emit('authUrl', url);
372
352
  });
373
- this.rpc = this._rpc;
374
- }
375
353
 
376
- get remotePubkey(): string {
377
- return this._remotePubkey;
354
+ this.rpc = this._rpc;
378
355
  }
379
356
 
380
- set remotePubkey(value: string) {
381
- this._remotePubkey = value;
357
+ get userPubkey() {
358
+ return this._userPubkey;
382
359
  }
383
360
 
384
- // userPubkeyのgetterを削除し、親クラスのプロパティを直接使用
385
-
386
361
  private async setSignerPubkey(signerPubkey: string, sameAsUser: boolean = false) {
387
- console.log('setSignerPubkey', signerPubkey);
362
+ console.log("setSignerPubkey", signerPubkey);
363
+
364
+ // ensure it's set
388
365
  this.remotePubkey = signerPubkey;
389
366
 
367
+ // when we're sure it's known
390
368
  this._rpc.on(`iframeRestart-${signerPubkey}`, () => {
391
369
  this.emit('iframeRestart');
392
370
  });
393
371
 
372
+ // now call getPublicKey and swap remotePubkey w/ that
394
373
  await this.initUserPubkey(sameAsUser ? signerPubkey : '');
395
374
  }
396
375
 
397
376
  public async initUserPubkey(hintPubkey?: string) {
398
- // 親クラスのuserPubkeyプロパティを直接設定
399
- if (this.userPubkey) throw new Error('Already called initUserPubkey');
377
+ if (this._userPubkey) throw new Error('Already called initUserPubkey');
400
378
 
401
379
  if (hintPubkey) {
402
- this.userPubkey = hintPubkey;
380
+ this._userPubkey = hintPubkey;
403
381
  return;
404
382
  }
405
383
 
406
- this.userPubkey = await new Promise((ok, err) => {
384
+ this._userPubkey = await new Promise<string>((ok, err) => {
407
385
  if (!this.remotePubkey) throw new Error('Signer pubkey not set');
408
- console.log('get_public_key', this.remotePubkey);
386
+
387
+ console.log("get_public_key", this.remotePubkey);
409
388
  this._rpc.sendRequest(this.remotePubkey, 'get_public_key', [], 24133, (response: NDKRpcResponse) => {
410
389
  ok(response.result);
411
390
  });
@@ -429,7 +408,12 @@ export class Nip46Signer extends NDKNip46Signer {
429
408
  }
430
409
 
431
410
  public async createAccount2({ bunkerPubkey, name, domain, perms = '' }: { bunkerPubkey: string; name: string; domain: string; perms?: string }) {
432
- const params = [name, domain, '', perms];
411
+ const params = [
412
+ name,
413
+ domain,
414
+ '', // email
415
+ perms,
416
+ ];
433
417
 
434
418
  const r = await new Promise<NDKRpcResponse>(ok => {
435
419
  this.rpc.sendRequest(bunkerPubkey, 'create_account', params, undefined, ok);
@@ -439,6 +423,7 @@ export class Nip46Signer extends NDKNip46Signer {
439
423
  if (r.result === 'error') {
440
424
  throw new Error(r.error);
441
425
  }
426
+
442
427
  return r.result;
443
428
  }
444
429
  }
@@ -1,4 +1,4 @@
1
- /* import { NDKPrivateKeySigner, NDKUser } from '@nostr-dev-kit/ndk';
1
+ import { NDKPrivateKeySigner, NDKUser } from '@nostr-dev-kit/ndk';
2
2
  import { Nip44 } from '../utils/nip44';
3
3
  import { getPublicKey } from 'nostr-tools';
4
4
 
@@ -23,4 +23,3 @@ export class PrivateKeySigner extends NDKPrivateKeySigner {
23
23
  return Promise.resolve(this.nip44.decrypt(this.privateKey!, sender.pubkey, value));
24
24
  }
25
25
  }
26
- */
@@ -102,9 +102,7 @@ export const bunkerUrlToInfo = (bunkerUrl: string, sk = ''): Info => {
102
102
  export const isBunkerUrl = (value: string) => value.startsWith('bunker://');
103
103
 
104
104
  export const getBunkerUrl = async (value: string, optionsModal: NostrLoginOptions) => {
105
- if (!value) {
106
- return '';
107
- }
105
+ if (!value) return '';
108
106
 
109
107
  if (isBunkerUrl(value)) {
110
108
  return value;
@@ -113,24 +111,28 @@ export const getBunkerUrl = async (value: string, optionsModal: NostrLoginOption
113
111
  if (value.includes('@')) {
114
112
  const [name, domain] = value.toLocaleLowerCase().split('@');
115
113
  const origin = optionsModal.devOverrideBunkerOrigin || `https://${domain}`;
114
+
116
115
  const bunkerUrl = `${origin}/.well-known/nostr.json?name=_`;
117
- const userUrl = `${origin}/.well-known/nostr.json?name=${name}`;
118
- const bunker = await fetch(bunkerUrl);
119
- const bunkerData = await bunker.json();
116
+ const userUrl = `${origin}/.well-known/nostr.json?name=${name}`;
117
+
118
+ const bunkerRes = await fetch(bunkerUrl);
119
+ const bunkerData = await bunkerRes.json();
120
120
  const bunkerPubkey = bunkerData.names['_'];
121
- const bunkerRelays = bunkerData.nip46[bunkerPubkey];
122
- const user = await fetch(userUrl);
123
- const userData = await user.json();
121
+ const bunkerRelays: string[] = bunkerData.nip46[bunkerPubkey];
122
+
123
+ const userRes = await fetch(userUrl);
124
+ const userData = await userRes.json();
124
125
  const userPubkey = userData.names[name];
125
- // console.log({
126
- // bunkerData, userData, bunkerPubkey, bunkerRelays, userPubkey,
127
- // name, domain, origin
128
- // })
129
- if (!bunkerRelays.length) {
126
+
127
+ if (!bunkerRelays || bunkerRelays.length === 0) {
130
128
  throw new Error('Bunker relay not provided');
131
129
  }
132
130
 
133
- return `bunker://${userPubkey}?relay=${bunkerRelays[0]}`;
131
+ const relayParams = bunkerRelays
132
+ .map(r => `relay=${encodeURIComponent(r)}`)
133
+ .join('&');
134
+
135
+ return `bunker://${userPubkey}?${relayParams}`;
134
136
  }
135
137
 
136
138
  throw new Error('Invalid user name or bunker url');