@konemono/nostr-login 1.7.22 → 1.7.24

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,11 +1,13 @@
1
1
  import { NostrLoginOptions, StartScreens, TypeModal } from '../types';
2
- import { checkNip05, getBunkerUrl, getDarkMode, localStorageRemoveRecent, localStorageSetItem, prepareSignupRelays } from '../utils';
2
+ import { checkNip05, getBunkerUrl, getDarkMode, localStorageRemoveRecent, localStorageSetItem, prepareSignupRelays, localStorageGetItem } from '../utils';
3
3
  import { AuthNostrService, NostrExtensionService, NostrParams } from '.';
4
4
  import { EventEmitter } from 'tseep';
5
- import { ConnectionString, Info, RecentType } from 'nostr-login-components';
5
+ import { ConnectionString, Info, RecentType } from 'nostr-login-components/dist/types/types';
6
6
  import { nip19 } from 'nostr-tools';
7
7
  import { setDarkMode } from '..';
8
8
 
9
+ const RELAY_STORAGE_KEY = '__nostrlogin_user_relays';
10
+
9
11
  class ModalManager extends EventEmitter {
10
12
  private modal: TypeModal | null = null;
11
13
  private params: NostrParams;
@@ -23,6 +25,18 @@ class ModalManager extends EventEmitter {
23
25
  this.authNostrService = authNostrService;
24
26
  }
25
27
 
28
+ private getUserRelays(): string[] {
29
+ const stored = localStorageGetItem(RELAY_STORAGE_KEY);
30
+ if (stored && Array.isArray(stored)) {
31
+ return stored;
32
+ }
33
+ return [];
34
+ }
35
+
36
+ private saveUserRelays(relays: string[]) {
37
+ localStorageSetItem(RELAY_STORAGE_KEY, JSON.stringify(relays));
38
+ }
39
+
26
40
  public async waitReady() {
27
41
  if (this.launcherPromise) {
28
42
  try {
@@ -34,10 +48,8 @@ class ModalManager extends EventEmitter {
34
48
 
35
49
  public async launch(opt: NostrLoginOptions) {
36
50
  console.log('nostr-login launch', opt);
37
- // mutex
38
51
  if (this.launcherPromise) await this.waitReady();
39
52
 
40
- // hmm?!
41
53
  if (this.authNostrService.isAuthing()) this.authNostrService.resetAuth();
42
54
 
43
55
  this.opt = opt;
@@ -61,7 +73,6 @@ class ModalManager extends EventEmitter {
61
73
  this.modal.setAttribute('bunkers', opt.bunkers);
62
74
  } else {
63
75
  let bunkers = 'nsec.app,highlighter.com';
64
- // if (opt.dev) bunkers += ',new.nsec.app';
65
76
  this.modal.setAttribute('bunkers', bunkers);
66
77
  }
67
78
 
@@ -91,6 +102,11 @@ class ModalManager extends EventEmitter {
91
102
  this.modal.isLoadingExtension = false;
92
103
  this.modal.isLoading = false;
93
104
 
105
+ const userRelays = this.getUserRelays();
106
+ if (userRelays.length > 0) {
107
+ this.params.optionsModal.connectRelays = userRelays;
108
+ }
109
+
94
110
  [this.modal.connectionString, this.modal.connectionStringServices] = await this.authNostrService.getNostrConnectServices();
95
111
 
96
112
  dialog.appendChild(this.modal);
@@ -100,21 +116,11 @@ class ModalManager extends EventEmitter {
100
116
 
101
117
  this.launcherPromise = new Promise<void>((ok, err) => {
102
118
  dialog.addEventListener('close', () => {
103
- // noop if already resolved
104
119
  err(new Error('Closed'));
105
120
 
106
121
  this.authNostrService.resetAuth();
107
122
 
108
123
  if (this.modal) {
109
- // it's reset on modal creation
110
- // // reset state
111
- // this.modal.isLoading = false;
112
- // this.modal.authUrl = '';
113
- // this.modal.iframeUrl = '';
114
- // this.modal.error = '';
115
- // this.modal.isLoadingExtension = false;
116
-
117
- // drop it
118
124
  // @ts-ignore
119
125
  document.body.removeChild(this.modal.parentNode);
120
126
  this.modal = null;
@@ -157,20 +163,16 @@ class ModalManager extends EventEmitter {
157
163
 
158
164
  const login = async (name: string, domain?: string) => {
159
165
  await exec(async () => {
160
- // convert name to bunker url
161
166
  const bunkerUrl = await getBunkerUrl(name, this.params.optionsModal);
162
167
 
163
- // connect to bunker by url
164
168
  await this.authNostrService.authNip46('login', { name, bunkerUrl, domain });
165
169
  });
166
170
  };
167
171
 
168
172
  const signup = async (name: string) => {
169
173
  await exec(async () => {
170
- // create acc on service and get bunker url
171
174
  const { bunkerUrl, sk } = await this.authNostrService.createAccount(name);
172
175
 
173
- // connect to bunker by url
174
176
  await this.authNostrService.authNip46('signup', { name, bunkerUrl, sk });
175
177
  });
176
178
  };
@@ -190,7 +192,6 @@ class ModalManager extends EventEmitter {
190
192
  cs.link = this.authNostrService.prepareImportUrl(cs.link);
191
193
 
192
194
  if (this.modal && iframeUrl) {
193
- // we pass the link down to iframe so it could open it
194
195
  this.modal.authUrl = cs.link;
195
196
  this.modal.iframeUrl = iframeUrl;
196
197
  this.modal.isLoading = false;
@@ -208,7 +209,6 @@ class ModalManager extends EventEmitter {
208
209
 
209
210
  if (this.modal) {
210
211
  if (iframeUrl) {
211
- // we pass the link down to iframe so it could open it
212
212
  this.modal.authUrl = link;
213
213
  this.modal.iframeUrl = iframeUrl;
214
214
  this.modal.isLoading = false;
@@ -239,8 +239,6 @@ class ModalManager extends EventEmitter {
239
239
  .charAt(0)
240
240
  .toUpperCase() + self.hostname.slice(1);
241
241
  const relays = prepareSignupRelays(this.params.optionsModal.signupRelays);
242
- // const url = `https://start.njump.me/?an=${name}&at=popup&ac=${window.location.href}&s=${this.opt!.followNpubs || ''}&arr=${relays}&awr=${relays}`;
243
- // console.log('njump url', url);
244
242
 
245
243
  this.modal!.njumpIframe = `
246
244
  <html><body>
@@ -248,18 +246,15 @@ class ModalManager extends EventEmitter {
248
246
  <script>
249
247
  new NstartModal({
250
248
  baseUrl: 'https://start.njump.me',
251
- // Required parameters
252
249
  an: '${name}',
253
- // Optional parameters
254
250
  s: [${this.opt!.followNpubs ? `'${this.opt!.followNpubs}'` : ''}],
255
- afb: false, // forceBunker
256
- asb: false, // skipBunker
257
- aan: false, // avoidNsec
258
- aac: true, // avoidNcryptsec
259
- ahc: true, // hide close button
260
- arr: ${JSON.stringify(relays)}, //readRelays
261
- awr: ${JSON.stringify(relays)}, //writeRelays
262
- // Callbacks
251
+ afb: false,
252
+ asb: false,
253
+ aan: false,
254
+ aac: true,
255
+ ahc: true,
256
+ arr: ${JSON.stringify(relays)},
257
+ awr: ${JSON.stringify(relays)},
263
258
  onComplete: (result) => {
264
259
  console.log('Login token:', result.nostrLogin);
265
260
  window.parent.location.href='${window.location.href}#nostr-login='+result.nostrLogin;
@@ -270,11 +265,10 @@ class ModalManager extends EventEmitter {
270
265
  }).open();
271
266
  </script>
272
267
  </body></html>
273
- `.replaceAll('&', '&amp;'); // needed?
268
+ `.replaceAll('&', '&amp;');
274
269
 
275
270
  return new Promise((ok, err) => {
276
271
  const process = async (nsecOrBunker: string) => {
277
- // process the returned value
278
272
  console.log('nsecOrBunker', nsecOrBunker);
279
273
  if (nsecOrBunker.startsWith('nsec1')) {
280
274
  let decoded;
@@ -300,7 +294,6 @@ class ModalManager extends EventEmitter {
300
294
  if (window.location.hash.startsWith('#nostr-login=')) {
301
295
  const nsecOrBunker = window.location.hash.split('#nostr-login=')[1];
302
296
 
303
- // clear hash from history
304
297
  const url = new URL(window.location.toString());
305
298
  url.hash = '';
306
299
  window.history.replaceState({}, '', url.toString());
@@ -309,9 +302,6 @@ class ModalManager extends EventEmitter {
309
302
  }
310
303
  };
311
304
 
312
- // // use random 'target' to make sure window.opener is
313
- // // accessible to the popup
314
- // window.open(url, '' + Date.now(), 'popup=true,width=600,height=950');
315
305
  window.addEventListener('hashchange', onOpen);
316
306
  });
317
307
  });
@@ -359,7 +349,6 @@ class ModalManager extends EventEmitter {
359
349
  });
360
350
 
361
351
  this.modal.addEventListener('nlNostrConnectDefault', () => {
362
- // dedup the calls
363
352
  if (!this.authNostrService.isAuthing()) nostrConnect();
364
353
  });
365
354
 
@@ -368,18 +357,30 @@ class ModalManager extends EventEmitter {
368
357
  this.authNostrService.cancelNostrConnect();
369
358
  });
370
359
 
360
+ this.modal.addEventListener('nlSaveUserRelays', (event: any) => {
361
+ const relays = event.detail as string[];
362
+ console.log('nlSaveUserRelays', relays);
363
+ this.saveUserRelays(relays);
364
+ this.params.optionsModal.connectRelays = relays;
365
+ });
366
+
367
+ this.modal.addEventListener('nlGetUserRelays', () => {
368
+ const relays = this.getUserRelays();
369
+ console.log('nlGetUserRelays', relays);
370
+ if (this.modal) {
371
+ this.modal.dispatchEvent(
372
+ new CustomEvent('nlUserRelaysReply', {
373
+ detail: relays,
374
+ }),
375
+ );
376
+ }
377
+ });
378
+
371
379
  this.modal.addEventListener('nlSwitchAccount', (event: any) => {
372
380
  const eventInfo: Info = event.detail as Info;
373
381
 
374
382
  this.emit('onSwitchAccount', eventInfo);
375
383
 
376
- // wait a bit, if dialog closes before
377
- // switching finishes then launched promise rejects
378
-
379
- // FIXME this calls resetAuth which then prevents
380
- // endAuth from getting properly called. 300 is not
381
- // enough to init iframe, so there should be a
382
- // feedback from switchAccount here
383
384
  setTimeout(() => dialog.close(), 300);
384
385
  });
385
386
 
@@ -426,7 +427,7 @@ class ModalManager extends EventEmitter {
426
427
  else throw new Error('Bad npub');
427
428
  } else if (nameNpub.trim().length === 64) {
428
429
  pubkey = nameNpub.trim();
429
- nip19.npubEncode(pubkey); // check
430
+ nip19.npubEncode(pubkey);
430
431
  }
431
432
  return pubkey;
432
433
  };
@@ -466,13 +467,10 @@ class ModalManager extends EventEmitter {
466
467
  throw new Error('Failed to send DM');
467
468
  }
468
469
 
469
- // switch to 'enter code' mode
470
470
  this.modal.isOTP = true;
471
471
 
472
- // remember for code handler below
473
472
  otpPubkey = pubkey;
474
473
 
475
- // spinner off
476
474
  this.modal.isLoading = false;
477
475
  },
478
476
  { start: true },
@@ -529,8 +527,6 @@ class ModalManager extends EventEmitter {
529
527
  this.modal.isLoading = false;
530
528
  }
531
529
 
532
- // this.authNostrService.cancelListenNostrConnect();
533
-
534
530
  dialog.close();
535
531
  err(new Error('Cancelled'));
536
532
  };
@@ -555,9 +551,6 @@ class ModalManager extends EventEmitter {
555
551
  }
556
552
 
557
553
  public async showIframeUrl(url: string) {
558
- // make sure we consume the previous promise,
559
- // otherwise launch will start await-ing
560
- // before modal is created and setting iframeUrl will fail
561
554
  await this.waitReady();
562
555
 
563
556
  this.launch({