@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.
- 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/AmberDirectSigner.ts +106 -0
- package/src/modules/AuthNostrService.ts +143 -78
- package/src/modules/ModalManager.ts +3 -0
- package/src/modules/Nip46.ts +49 -64
- package/src/modules/Signer.ts +1 -2
- package/src/utils/index.ts +17 -15
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');
|