@konemono/nostr-login 1.7.49 → 1.7.50
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 +12 -42
- package/dist/index.esm.js.map +1 -1
- package/dist/modules/Nip46.d.ts +8 -8
- package/dist/modules/Signer.d.ts +9 -0
- package/dist/unpkg.js +12 -42
- package/dist/utils/nip44.d.ts +1 -1
- package/package.json +7 -7
- package/src/modules/AuthNostrService.ts +81 -77
- package/src/modules/Nip46.ts +49 -64
- package/src/modules/Signer.ts +1 -2
- package/src/utils/index.ts +17 -15
package/dist/utils/nip44.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ export declare function encryptNip44(plaintext: string, conversationKey: Uint8Ar
|
|
|
2
2
|
export declare function decryptNip44(payload: string, conversationKey: Uint8Array): string;
|
|
3
3
|
export declare class Nip44 {
|
|
4
4
|
private cache;
|
|
5
|
-
createKey(privkey: string, pubkey: string): Uint8Array
|
|
5
|
+
createKey(privkey: string, pubkey: string): Uint8Array;
|
|
6
6
|
private getKey;
|
|
7
7
|
encrypt(privkey: string, pubkey: string, text: string): string;
|
|
8
8
|
decrypt(privkey: string, pubkey: string, data: string): string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@konemono/nostr-login",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.50",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "./dist/index.esm.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -11,17 +11,17 @@
|
|
|
11
11
|
},
|
|
12
12
|
"author": "a-fralou",
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@nostr-dev-kit/ndk": "^2.
|
|
14
|
+
"@nostr-dev-kit/ndk": "^2.3.1",
|
|
15
15
|
"nostr-tools": "^1.17.0",
|
|
16
|
-
"tseep": "^1.
|
|
16
|
+
"tseep": "^1.2.1"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
|
-
"@rollup/plugin-commonjs": "^25.0.
|
|
20
|
-
"@rollup/plugin-node-resolve": "^15.3
|
|
19
|
+
"@rollup/plugin-commonjs": "^25.0.7",
|
|
20
|
+
"@rollup/plugin-node-resolve": "^15.2.3",
|
|
21
21
|
"@rollup/plugin-terser": "^0.4.4",
|
|
22
22
|
"nostr-login-components": "^1.0.3",
|
|
23
|
-
"prettier": "^3.
|
|
24
|
-
"rollup": "^4.
|
|
23
|
+
"prettier": "^3.2.2",
|
|
24
|
+
"rollup": "^4.9.6",
|
|
25
25
|
"rollup-plugin-typescript2": "^0.36.0"
|
|
26
26
|
},
|
|
27
27
|
"license": "MIT"
|
|
@@ -1,19 +1,18 @@
|
|
|
1
|
-
//AuthNostrService.ts
|
|
2
1
|
import { localStorageAddAccount, bunkerUrlToInfo, isBunkerUrl, fetchProfile, getBunkerUrl, localStorageRemoveCurrentAccount, createProfile, getIcon } from '../utils';
|
|
3
2
|
import { ConnectionString, Info } from 'nostr-login-components/dist/types/types';
|
|
4
3
|
import { generatePrivateKey, getEventHash, getPublicKey, nip19 } from 'nostr-tools';
|
|
5
4
|
import { NostrLoginAuthOptions, Response } from '../types';
|
|
6
|
-
import NDK, { NDKEvent, NDKNip46Signer,
|
|
5
|
+
import NDK, { NDKEvent, NDKNip46Signer, NDKRpcResponse, NDKUser, NostrEvent } from '@nostr-dev-kit/ndk';
|
|
7
6
|
import { NostrParams } from './';
|
|
8
7
|
import { EventEmitter } from 'tseep';
|
|
9
8
|
import { Signer } from './Nostr';
|
|
10
9
|
import { Nip44 } from '../utils/nip44';
|
|
11
10
|
import { IframeNostrRpc, Nip46Signer, ReadyListener } from './Nip46';
|
|
12
|
-
|
|
11
|
+
import { PrivateKeySigner } from './Signer';
|
|
13
12
|
|
|
14
13
|
const OUTBOX_RELAYS = ['wss://user.kindpag.es', 'wss://purplepag.es', 'wss://relay.nos.social'];
|
|
15
14
|
const DEFAULT_NOSTRCONNECT_RELAYS = ['wss://relay.nsec.app/', 'wss://ephemeral.snowflare.cc/'];
|
|
16
|
-
const CONNECT_TIMEOUT =
|
|
15
|
+
const CONNECT_TIMEOUT = 5000;
|
|
17
16
|
const NOSTRCONNECT_APPS: ConnectionString[] = [
|
|
18
17
|
{
|
|
19
18
|
name: 'Nsec.app',
|
|
@@ -41,7 +40,7 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
41
40
|
private ndk: NDK;
|
|
42
41
|
private profileNdk: NDK;
|
|
43
42
|
private signer: Nip46Signer | null = null;
|
|
44
|
-
private localSigner:
|
|
43
|
+
private localSigner: PrivateKeySigner | null = null;
|
|
45
44
|
private params: NostrParams;
|
|
46
45
|
private signerPromise?: Promise<void>;
|
|
47
46
|
private signerErrCallback?: (err: string) => void;
|
|
@@ -93,13 +92,13 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
93
92
|
if (this.signerPromise) {
|
|
94
93
|
try {
|
|
95
94
|
await this.signerPromise;
|
|
96
|
-
} catch {}
|
|
95
|
+
} catch { }
|
|
97
96
|
}
|
|
98
97
|
|
|
99
98
|
if (this.readyPromise) {
|
|
100
99
|
try {
|
|
101
100
|
await this.readyPromise;
|
|
102
|
-
} catch {}
|
|
101
|
+
} catch { }
|
|
103
102
|
}
|
|
104
103
|
}
|
|
105
104
|
|
|
@@ -124,6 +123,7 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
124
123
|
) {
|
|
125
124
|
relays = relays && relays.length > 0 ? relays : DEFAULT_NOSTRCONNECT_RELAYS;
|
|
126
125
|
|
|
126
|
+
|
|
127
127
|
const info: Info = {
|
|
128
128
|
authMethod: 'connect',
|
|
129
129
|
pubkey: '', // unknown yet!
|
|
@@ -154,6 +154,13 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
154
154
|
}
|
|
155
155
|
|
|
156
156
|
public async createNostrConnect(relays?: string[]) {
|
|
157
|
+
/*const relayList = relays
|
|
158
|
+
? relays
|
|
159
|
+
.split(",")
|
|
160
|
+
.map(r => r.trim().replace(/['"]/g, ""))
|
|
161
|
+
.filter(r => r.length > 0)
|
|
162
|
+
: [];*/
|
|
163
|
+
|
|
157
164
|
this.nostrConnectKey = generatePrivateKey();
|
|
158
165
|
this.nostrConnectSecret = Math.random().toString(36).substring(7);
|
|
159
166
|
|
|
@@ -165,16 +172,24 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
165
172
|
perms: encodeURIComponent(this.params.optionsModal.perms || ''),
|
|
166
173
|
};
|
|
167
174
|
|
|
168
|
-
|
|
169
|
-
const relayParams = (relays || []).length > 0 ? (relays || []).map(r => `&relay=${encodeURIComponent(r)}`).join('') : '';
|
|
170
|
-
|
|
171
|
-
return `nostrconnect://${pubkey}?image=${meta.icon}&url=${meta.url}&name=${meta.name}&perms=${meta.perms}&secret=${this.nostrConnectSecret}${relayParams}`;
|
|
175
|
+
return `nostrconnect://${pubkey}?image=${meta.icon}&url=${meta.url}&name=${meta.name}&perms=${meta.perms}&secret=${this.nostrConnectSecret}${(relays || []).length > 0 ? (relays || []).map((r, i) => `&relay=${r}`) : ""}`;
|
|
172
176
|
}
|
|
173
177
|
|
|
174
178
|
public async getNostrConnectServices(): Promise<[string, ConnectionString[]]> {
|
|
175
|
-
const nostrconnect = await this.createNostrConnect(
|
|
179
|
+
const nostrconnect = await this.createNostrConnect();
|
|
176
180
|
|
|
181
|
+
// copy defaults
|
|
177
182
|
const apps = NOSTRCONNECT_APPS.map(a => ({ ...a }));
|
|
183
|
+
// if (this.params.optionsModal.dev) {
|
|
184
|
+
// apps.push({
|
|
185
|
+
// name: 'Dev.Nsec.app',
|
|
186
|
+
// domain: 'new.nsec.app',
|
|
187
|
+
// canImport: true,
|
|
188
|
+
// img: 'https://new.nsec.app/assets/favicon.ico',
|
|
189
|
+
// link: 'https://dev.nsec.app/<nostrconnect>',
|
|
190
|
+
// relay: 'wss://relay.nsec.app/',
|
|
191
|
+
// });
|
|
192
|
+
// }
|
|
178
193
|
|
|
179
194
|
for (const a of apps) {
|
|
180
195
|
let relays: string[] = [...DEFAULT_NOSTRCONNECT_RELAYS];
|
|
@@ -196,12 +211,18 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
196
211
|
}
|
|
197
212
|
}
|
|
198
213
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
214
|
+
const relayParams = relays
|
|
215
|
+
.map(r => r.replace(/['"]/g, ''))
|
|
216
|
+
.map(r => `&relay=${encodeURIComponent(r)}`)
|
|
217
|
+
.join('');
|
|
203
218
|
|
|
204
|
-
|
|
219
|
+
const nc = nostrconnect + relayParams;
|
|
220
|
+
|
|
221
|
+
if (a.iframeUrl) {
|
|
222
|
+
a.link = nc;
|
|
223
|
+
} else {
|
|
224
|
+
a.link = a.link.replace('<nostrconnect>', nc);
|
|
225
|
+
}
|
|
205
226
|
}
|
|
206
227
|
|
|
207
228
|
return [nostrconnect, apps];
|
|
@@ -223,7 +244,7 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
223
244
|
|
|
224
245
|
public async setLocal(info: Info, signup?: boolean) {
|
|
225
246
|
this.releaseSigner();
|
|
226
|
-
this.localSigner = new
|
|
247
|
+
this.localSigner = new PrivateKeySigner(info.sk!);
|
|
227
248
|
|
|
228
249
|
if (signup) await createProfile(info, this.profileNdk, this.localSigner, this.params.optionsModal.signupRelays, this.params.optionsModal.outboxRelays);
|
|
229
250
|
|
|
@@ -297,7 +318,9 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
297
318
|
const userPubkey = await this.signer!.createAccount2({ bunkerPubkey: info.signerPubkey!, name, domain, perms: this.params.optionsModal.perms });
|
|
298
319
|
|
|
299
320
|
return {
|
|
300
|
-
bunkerUrl:
|
|
321
|
+
bunkerUrl:
|
|
322
|
+
`bunker://${userPubkey}?` +
|
|
323
|
+
(info.relays ?? []).map((r: string) => `relay=${encodeURIComponent(r)}`).join('&'),
|
|
301
324
|
sk: info.sk,
|
|
302
325
|
};
|
|
303
326
|
}
|
|
@@ -348,7 +371,7 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
348
371
|
if (info && this.params.userInfo && (info.pubkey !== this.params.userInfo.pubkey || info.authMethod !== this.params.userInfo.authMethod)) {
|
|
349
372
|
const event = new CustomEvent('nlAuth', { detail: { type: 'logout' } });
|
|
350
373
|
console.log('nostr-login auth', event.detail);
|
|
351
|
-
document.dispatchEvent(event)
|
|
374
|
+
document.dispatchEvent(event)
|
|
352
375
|
}
|
|
353
376
|
|
|
354
377
|
this.setUserInfo(info);
|
|
@@ -485,7 +508,7 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
485
508
|
}
|
|
486
509
|
|
|
487
510
|
public async startAuth() {
|
|
488
|
-
console.log(
|
|
511
|
+
console.log("startAuth");
|
|
489
512
|
if (this.readyCallback) throw new Error('Already started');
|
|
490
513
|
|
|
491
514
|
// start the new promise
|
|
@@ -529,100 +552,81 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
529
552
|
if (this.signerPromise) {
|
|
530
553
|
try {
|
|
531
554
|
await this.signerPromise;
|
|
532
|
-
} catch {}
|
|
555
|
+
} catch { }
|
|
533
556
|
}
|
|
534
557
|
|
|
558
|
+
// we remove support for iframe from nip05 and bunker-url methods,
|
|
559
|
+
// only nostrconnect flow will use it.
|
|
560
|
+
// info.iframeUrl = info.iframeUrl || (await this.getIframeUrl(info.domain));
|
|
535
561
|
console.log('initSigner info', info);
|
|
536
562
|
|
|
563
|
+
// start listening for the ready signal
|
|
537
564
|
const iframeOrigin = info.iframeUrl ? new URL(info.iframeUrl!).origin : undefined;
|
|
565
|
+
if (iframeOrigin) this.starterReady = new ReadyListener(['starterDone', 'starterError'], iframeOrigin);
|
|
538
566
|
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
}
|
|
542
|
-
|
|
567
|
+
// notify modals so they could show the starter iframe,
|
|
568
|
+
// FIXME shouldn't this come from nostrconnect service list?
|
|
543
569
|
this.emit('onIframeUrl', info.iframeUrl);
|
|
544
570
|
|
|
545
571
|
this.signerPromise = new Promise<void>(async (ok, err) => {
|
|
546
572
|
this.signerErrCallback = err;
|
|
547
|
-
|
|
548
573
|
try {
|
|
549
|
-
|
|
550
|
-
|
|
574
|
+
// pre-connect if we're creating the connection (listen|connect) or
|
|
575
|
+
// not iframe mode
|
|
551
576
|
if (info.relays && !info.iframeUrl) {
|
|
552
577
|
for (const r of info.relays) {
|
|
553
578
|
this.ndk.addExplicitRelay(r, undefined);
|
|
554
|
-
console.log('Added relay:', r);
|
|
555
579
|
}
|
|
556
580
|
}
|
|
557
581
|
|
|
558
|
-
|
|
582
|
+
// wait until we connect, otherwise
|
|
583
|
+
// signer won't start properly
|
|
584
|
+
await this.ndk.connect(CONNECT_TIMEOUT);
|
|
559
585
|
|
|
560
|
-
//
|
|
561
|
-
|
|
562
|
-
console.log(value);
|
|
563
|
-
});
|
|
564
|
-
|
|
565
|
-
// 少なくとも1つ接続されるのを待つ(致命扱いしない)
|
|
566
|
-
await new Promise<void>(resolve => {
|
|
567
|
-
const start = Date.now();
|
|
568
|
-
|
|
569
|
-
const timer = setInterval(() => {
|
|
570
|
-
const connected = this.ndk.pool.connectedRelays();
|
|
571
|
-
|
|
572
|
-
if (connected.length > 0) {
|
|
573
|
-
clearInterval(timer);
|
|
574
|
-
resolve();
|
|
575
|
-
return;
|
|
576
|
-
}
|
|
577
|
-
|
|
578
|
-
if (Date.now() - start > CONNECT_TIMEOUT) {
|
|
579
|
-
// タイムアウトしても続行
|
|
580
|
-
clearInterval(timer);
|
|
581
|
-
resolve();
|
|
582
|
-
}
|
|
583
|
-
}, 3000);
|
|
584
|
-
});
|
|
585
|
-
|
|
586
|
-
console.log(
|
|
587
|
-
'NDK connected relays:',
|
|
588
|
-
this.ndk.pool.connectedRelays().map(r => r.url),
|
|
589
|
-
);
|
|
590
|
-
|
|
591
|
-
const localSigner = new NDKPrivateKeySigner(info.sk!);
|
|
586
|
+
// create and prepare the signer
|
|
587
|
+
const localSigner = new PrivateKeySigner(info.sk!);
|
|
592
588
|
this.signer = new Nip46Signer(this.ndk, localSigner, info.signerPubkey!, iframeOrigin);
|
|
593
589
|
|
|
594
|
-
|
|
590
|
+
// we should notify the banner the same way as
|
|
591
|
+
// the onAuthUrl does
|
|
592
|
+
this.signer.on(`iframeRestart`, async () => {
|
|
595
593
|
const iframeUrl = info.iframeUrl + (info.iframeUrl!.includes('?') ? '&' : '?') + 'pubkey=' + info.pubkey + '&rebind=' + localSigner.pubkey;
|
|
596
|
-
|
|
597
|
-
this.emit('iframeRestart', {
|
|
598
|
-
pubkey: info.pubkey,
|
|
599
|
-
iframeUrl,
|
|
600
|
-
});
|
|
594
|
+
this.emit('iframeRestart', { pubkey: info.pubkey, iframeUrl });
|
|
601
595
|
});
|
|
602
596
|
|
|
597
|
+
// OAuth flow
|
|
598
|
+
// if (!listen) {
|
|
603
599
|
this.signer.on('authUrl', (url: string) => {
|
|
604
600
|
console.log('nostr login auth url', url);
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
eventToAddAccount,
|
|
609
|
-
});
|
|
601
|
+
|
|
602
|
+
// notify our UI
|
|
603
|
+
this.emit('onAuthUrl', { url, iframeUrl: info.iframeUrl, eventToAddAccount });
|
|
610
604
|
});
|
|
605
|
+
// }
|
|
611
606
|
|
|
612
607
|
if (listen) {
|
|
608
|
+
// nostrconnect: flow
|
|
609
|
+
// wait for the incoming message from signer
|
|
613
610
|
await this.listen(info);
|
|
614
611
|
} else if (connect) {
|
|
612
|
+
// bunker: flow
|
|
613
|
+
// send 'connect' message to signer
|
|
615
614
|
await this.connect(info, this.params.optionsModal.perms);
|
|
616
615
|
} else {
|
|
617
|
-
|
|
616
|
+
// provide saved pubkey as a hint
|
|
617
|
+
await this.signer!.initUserPubkey(info.pubkey);
|
|
618
618
|
}
|
|
619
619
|
|
|
620
|
-
|
|
621
|
-
info
|
|
620
|
+
// ensure, we're using it in callbacks above
|
|
621
|
+
// and expect info to be valid after this call
|
|
622
|
+
info.pubkey = this.signer!.userPubkey;
|
|
623
|
+
// learned after nostrconnect flow
|
|
624
|
+
info.signerPubkey = this.signer!.remotePubkey;
|
|
622
625
|
|
|
623
626
|
ok();
|
|
624
627
|
} catch (e) {
|
|
625
628
|
console.log('initSigner failure', e);
|
|
629
|
+
// make sure signer isn't set
|
|
626
630
|
this.signer = null;
|
|
627
631
|
err(e);
|
|
628
632
|
}
|
package/src/modules/Nip46.ts
CHANGED
|
@@ -1,27 +1,15 @@
|
|
|
1
|
-
|
|
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
|
-
|
|
3
|
+
import { PrivateKeySigner } from './Signer';
|
|
16
4
|
|
|
17
5
|
class NostrRpc extends NDKNostrRpc {
|
|
18
6
|
protected _ndk: NDK;
|
|
19
|
-
protected _signer:
|
|
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:
|
|
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
|
|
59
|
-
|
|
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
|
-
//
|
|
147
|
-
|
|
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
|
-
//
|
|
139
|
+
// send to relays
|
|
155
140
|
await event.publish();
|
|
156
141
|
|
|
157
|
-
//
|
|
158
|
-
|
|
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
|
-
|
|
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
|
-
|
|
210
|
-
|
|
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:
|
|
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:
|
|
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
|
-
|
|
377
|
-
return this._remotePubkey;
|
|
354
|
+
this.rpc = this._rpc;
|
|
378
355
|
}
|
|
379
356
|
|
|
380
|
-
|
|
381
|
-
this.
|
|
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(
|
|
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
|
-
|
|
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.
|
|
380
|
+
this._userPubkey = hintPubkey;
|
|
403
381
|
return;
|
|
404
382
|
}
|
|
405
383
|
|
|
406
|
-
this.
|
|
384
|
+
this._userPubkey = await new Promise<string>((ok, err) => {
|
|
407
385
|
if (!this.remotePubkey) throw new Error('Signer pubkey not set');
|
|
408
|
-
|
|
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 = [
|
|
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
|
}
|
package/src/modules/Signer.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
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
|
-
*/
|
package/src/utils/index.ts
CHANGED
|
@@ -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
|
|
118
|
-
|
|
119
|
-
const
|
|
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
|
-
|
|
123
|
-
const
|
|
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
|
-
|
|
126
|
-
|
|
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
|
-
|
|
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');
|