@konemono/nostr-login 1.11.0 → 1.11.3
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.esm.js +15 -20
- package/dist/index.esm.js.map +1 -1
- package/dist/modules/AuthNostrService.d.ts +4 -14
- package/dist/modules/Nip46.d.ts +26 -64
- package/dist/modules/Signer.d.ts +6 -12
- package/dist/unpkg.js +15 -20
- package/dist/utils/index.d.ts +3 -6
- package/dist/utils/nip44.d.ts +3 -3
- package/package.json +8 -8
- package/src/modules/AuthNostrService.ts +109 -210
- package/src/modules/ModalManager.ts +3 -3
- package/src/modules/Nip46.ts +185 -390
- package/src/modules/NostrExtensionService.ts +0 -2
- package/src/modules/Signer.ts +12 -35
- package/src/utils/index.ts +23 -73
- package/src/utils/nip44.ts +7 -12
- package/test-relay-management.html +0 -407
package/dist/utils/index.d.ts
CHANGED
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
import { Info, RecentType } from 'nostr-login-components/dist/types/types';
|
|
2
|
-
import {
|
|
2
|
+
import NDK, { NDKSigner } from '@nostr-dev-kit/ndk';
|
|
3
3
|
import { NostrLoginOptions } from '../types';
|
|
4
|
-
import { PrivateKeySigner } from '../modules/Signer';
|
|
5
|
-
export declare function bytesToHex(bytes: Uint8Array): string;
|
|
6
|
-
export declare function hexToBytes(hex: string): Uint8Array;
|
|
7
4
|
export declare const localStorageSetItem: (key: string, value: string) => void;
|
|
8
5
|
export declare const localStorageGetItem: (key: string) => any;
|
|
9
6
|
export declare const localStorageRemoveItem: (key: string) => void;
|
|
10
|
-
export declare const fetchProfile: (info: Info,
|
|
7
|
+
export declare const fetchProfile: (info: Info, profileNdk: NDK) => Promise<import("@nostr-dev-kit/ndk").NDKUserProfile | null>;
|
|
11
8
|
export declare const prepareSignupRelays: (signupRelays?: string) => string[];
|
|
12
|
-
export declare const createProfile: (info: Info,
|
|
9
|
+
export declare const createProfile: (info: Info, profileNdk: NDK, signer: NDKSigner, signupRelays?: string, outboxRelays?: string[]) => Promise<void>;
|
|
13
10
|
export declare const bunkerUrlToInfo: (bunkerUrl: string, sk?: string) => Info;
|
|
14
11
|
export declare const isBunkerUrl: (value: string) => boolean;
|
|
15
12
|
export declare const getBunkerUrl: (value: string, optionsModal: NostrLoginOptions) => Promise<string>;
|
package/dist/utils/nip44.d.ts
CHANGED
|
@@ -2,8 +2,8 @@ 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
|
|
5
|
+
createKey(privkey: string, pubkey: string): Uint8Array;
|
|
6
6
|
private getKey;
|
|
7
|
-
encrypt(privkey: string
|
|
8
|
-
decrypt(privkey: string
|
|
7
|
+
encrypt(privkey: string, pubkey: string, text: string): string;
|
|
8
|
+
decrypt(privkey: string, pubkey: string, data: string): string;
|
|
9
9
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@konemono/nostr-login",
|
|
3
|
-
"version": "1.11.
|
|
3
|
+
"version": "1.11.3",
|
|
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-
|
|
15
|
-
"
|
|
16
|
-
"tseep": "^1.
|
|
14
|
+
"@nostr-dev-kit/ndk": "^2.3.1",
|
|
15
|
+
"nostr-tools": "^1.17.0",
|
|
16
|
+
"tseep": "^1.2.1"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
|
-
"@rollup/plugin-commonjs": "^
|
|
20
|
-
"@rollup/plugin-node-resolve": "^
|
|
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,14 +1,8 @@
|
|
|
1
|
-
import { localStorageAddAccount, bunkerUrlToInfo, isBunkerUrl, fetchProfile, getBunkerUrl, localStorageRemoveCurrentAccount, createProfile, getIcon
|
|
1
|
+
import { localStorageAddAccount, bunkerUrlToInfo, isBunkerUrl, fetchProfile, getBunkerUrl, localStorageRemoveCurrentAccount, createProfile, getIcon } from '../utils';
|
|
2
2
|
import { ConnectionString, Info } from 'nostr-login-components/dist/types/types';
|
|
3
|
-
import {
|
|
4
|
-
import { generateSecretKey, getEventHash, getPublicKey, nip19 } from 'nostr-tools';
|
|
3
|
+
import { generatePrivateKey, getEventHash, getPublicKey, nip19 } from 'nostr-tools';
|
|
5
4
|
import { NostrLoginAuthOptions, Response } from '../types';
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
// Placeholder types for SimplePool transition
|
|
10
|
-
// private pool: SimplePool;
|
|
11
|
-
// private outboxPool: SimplePool;
|
|
5
|
+
import NDK, { NDKEvent, NDKNip46Signer, NDKRpcResponse, NDKUser, NostrEvent } from '@nostr-dev-kit/ndk';
|
|
12
6
|
import { NostrParams } from './';
|
|
13
7
|
import { EventEmitter } from 'tseep';
|
|
14
8
|
import { Signer } from './Nostr';
|
|
@@ -39,7 +33,8 @@ const NOSTRCONNECT_APPS: ConnectionString[] = [
|
|
|
39
33
|
];
|
|
40
34
|
|
|
41
35
|
class AuthNostrService extends EventEmitter implements Signer {
|
|
42
|
-
private
|
|
36
|
+
private ndk: NDK;
|
|
37
|
+
private profileNdk: NDK;
|
|
43
38
|
private signer: Nip46Signer | null = null;
|
|
44
39
|
private localSigner: PrivateKeySigner | null = null;
|
|
45
40
|
private params: NostrParams;
|
|
@@ -66,11 +61,15 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
66
61
|
constructor(params: NostrParams) {
|
|
67
62
|
super();
|
|
68
63
|
this.params = params;
|
|
64
|
+
this.ndk = new NDK({
|
|
65
|
+
enableOutboxModel: false,
|
|
66
|
+
});
|
|
69
67
|
|
|
70
|
-
this.
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
68
|
+
this.profileNdk = new NDK({
|
|
69
|
+
enableOutboxModel: true,
|
|
70
|
+
explicitRelayUrls: OUTBOX_RELAYS,
|
|
71
|
+
});
|
|
72
|
+
this.profileNdk.connect();
|
|
74
73
|
|
|
75
74
|
this.nip04 = {
|
|
76
75
|
encrypt: this.encrypt04.bind(this),
|
|
@@ -82,30 +81,30 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
82
81
|
};
|
|
83
82
|
}
|
|
84
83
|
|
|
85
|
-
public isIframe()
|
|
84
|
+
public isIframe() {
|
|
86
85
|
return !!this.iframe;
|
|
87
86
|
}
|
|
88
87
|
|
|
89
|
-
public async waitReady()
|
|
88
|
+
public async waitReady() {
|
|
90
89
|
if (this.signerPromise) {
|
|
91
90
|
try {
|
|
92
91
|
await this.signerPromise;
|
|
93
|
-
} catch {
|
|
92
|
+
} catch {}
|
|
94
93
|
}
|
|
95
94
|
|
|
96
95
|
if (this.readyPromise) {
|
|
97
96
|
try {
|
|
98
97
|
await this.readyPromise;
|
|
99
|
-
} catch {
|
|
98
|
+
} catch {}
|
|
100
99
|
}
|
|
101
100
|
}
|
|
102
101
|
|
|
103
|
-
public cancelNostrConnect()
|
|
102
|
+
public cancelNostrConnect() {
|
|
104
103
|
this.releaseSigner();
|
|
105
104
|
this.resetAuth();
|
|
106
105
|
}
|
|
107
106
|
|
|
108
|
-
public cancelSignerInit()
|
|
107
|
+
public cancelSignerInit() {
|
|
109
108
|
if (this.signerAbortController) {
|
|
110
109
|
this.signerAbortController.abort();
|
|
111
110
|
this.signerAbortController = undefined;
|
|
@@ -134,7 +133,7 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
134
133
|
iframeUrl?: string;
|
|
135
134
|
customRelays?: string[];
|
|
136
135
|
} = {},
|
|
137
|
-
)
|
|
136
|
+
) {
|
|
138
137
|
// カスタムリレーが指定されていれば使用、そうでなければ単一リレーまたはデフォルト
|
|
139
138
|
const relays = customRelays && customRelays.length > 0 ? customRelays : relay ? [relay] : DEFAULT_NIP46_RELAYS;
|
|
140
139
|
|
|
@@ -169,13 +168,11 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
169
168
|
return info;
|
|
170
169
|
}
|
|
171
170
|
|
|
172
|
-
public async createNostrConnect()
|
|
173
|
-
|
|
174
|
-
// @ts-ignore
|
|
175
|
-
this.nostrConnectKey = bytesToHex(skBytes);
|
|
171
|
+
public async createNostrConnect() {
|
|
172
|
+
this.nostrConnectKey = generatePrivateKey();
|
|
176
173
|
this.nostrConnectSecret = Math.random().toString(36).substring(7);
|
|
177
174
|
|
|
178
|
-
const pubkey = getPublicKey(
|
|
175
|
+
const pubkey = getPublicKey(this.nostrConnectKey);
|
|
179
176
|
const meta = {
|
|
180
177
|
name: encodeURIComponent(document.location.host),
|
|
181
178
|
url: encodeURIComponent(document.location.origin),
|
|
@@ -232,14 +229,10 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
232
229
|
return [nostrconnect, apps];
|
|
233
230
|
}
|
|
234
231
|
|
|
235
|
-
public async localSignup(name: string, sk?: string)
|
|
232
|
+
public async localSignup(name: string, sk?: string) {
|
|
236
233
|
const signup = !sk;
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
sk = bytesToHex(skBytes);
|
|
240
|
-
}
|
|
241
|
-
// @ts-ignore
|
|
242
|
-
const pubkey = getPublicKey(hexToBytes(sk!));
|
|
234
|
+
sk = sk || generatePrivateKey();
|
|
235
|
+
const pubkey = getPublicKey(sk);
|
|
243
236
|
const info: Info = {
|
|
244
237
|
pubkey,
|
|
245
238
|
sk,
|
|
@@ -250,118 +243,25 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
250
243
|
await this.setLocal(info, signup);
|
|
251
244
|
}
|
|
252
245
|
|
|
253
|
-
public async setLocal(info: Info, signup?: boolean)
|
|
246
|
+
public async setLocal(info: Info, signup?: boolean) {
|
|
254
247
|
this.releaseSigner();
|
|
255
|
-
this.localSigner = new PrivateKeySigner(
|
|
248
|
+
this.localSigner = new PrivateKeySigner(info.sk!);
|
|
256
249
|
|
|
257
|
-
|
|
258
|
-
if (signup) {
|
|
259
|
-
await createProfile(info, this.rxNostr, this.localSigner, this.params.optionsModal.signupRelays, this.params.optionsModal.outboxRelays);
|
|
260
|
-
}
|
|
250
|
+
if (signup) await createProfile(info, this.profileNdk, this.localSigner, this.params.optionsModal.signupRelays, this.params.optionsModal.outboxRelays);
|
|
261
251
|
|
|
262
252
|
this.onAuth(signup ? 'signup' : 'login', info);
|
|
263
253
|
}
|
|
264
254
|
|
|
265
|
-
public prepareImportUrl(url: string)
|
|
255
|
+
public prepareImportUrl(url: string) {
|
|
266
256
|
// for OTP we choose interactive import
|
|
267
257
|
if (this.params.userInfo?.authMethod === 'otp') return url + '&import=true';
|
|
268
258
|
|
|
269
259
|
// for local we export our existing key
|
|
270
260
|
if (!this.localSigner || this.params.userInfo?.authMethod !== 'local') throw new Error('Most be local keys');
|
|
271
|
-
|
|
272
|
-
const skBytes = this.localSigner.privateKey!;
|
|
273
|
-
return url + '#import=' + nip19.nsecEncode(skBytes);
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
// リレー管理メソッド
|
|
277
|
-
public getRelayStatus(): Record<string, string> {
|
|
278
|
-
const status = this.rxNostr.getAllRelayStatus();
|
|
279
|
-
const result: Record<string, string> = {};
|
|
280
|
-
for (const [url, state] of Object.entries(status)) {
|
|
281
|
-
result[url] = String(state);
|
|
282
|
-
}
|
|
283
|
-
return result;
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
public getRelayStats(): {
|
|
287
|
-
total: number;
|
|
288
|
-
connected: number;
|
|
289
|
-
connecting: number;
|
|
290
|
-
disconnected: number;
|
|
291
|
-
error: number;
|
|
292
|
-
} {
|
|
293
|
-
const status = this.rxNostr.getAllRelayStatus();
|
|
294
|
-
const stats = {
|
|
295
|
-
total: 0,
|
|
296
|
-
connected: 0,
|
|
297
|
-
connecting: 0,
|
|
298
|
-
disconnected: 0,
|
|
299
|
-
error: 0,
|
|
300
|
-
};
|
|
301
|
-
|
|
302
|
-
for (const state of Object.values(status)) {
|
|
303
|
-
stats.total++;
|
|
304
|
-
const stateStr = String(state).toLowerCase();
|
|
305
|
-
if (stateStr === 'connected') stats.connected++;
|
|
306
|
-
else if (stateStr === 'connecting') stats.connecting++;
|
|
307
|
-
else if (stateStr === 'error') stats.error++;
|
|
308
|
-
else stats.disconnected++;
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
return stats;
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
public async connectToRelay(relayUrl: string): Promise<void> {
|
|
315
|
-
try {
|
|
316
|
-
this.rxNostr.reconnect(relayUrl);
|
|
317
|
-
console.log(`Connecting to relay: ${relayUrl}`);
|
|
318
|
-
} catch (error) {
|
|
319
|
-
console.error(`Failed to connect to relay ${relayUrl}:`, error);
|
|
320
|
-
throw error;
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
public async disconnectFromRelay(relayUrl: string): Promise<void> {
|
|
325
|
-
try {
|
|
326
|
-
// rx-nostrにはdisconnect APIがないため、リレーリストから除外する方法を使用
|
|
327
|
-
const currentRelays = Object.keys(this.rxNostr.getAllRelayStatus());
|
|
328
|
-
const newRelays = currentRelays.filter(url => url !== relayUrl);
|
|
329
|
-
if (newRelays.length > 0) {
|
|
330
|
-
// @ts-ignore
|
|
331
|
-
this.rxNostr.switchRelays(newRelays);
|
|
332
|
-
}
|
|
333
|
-
console.log(`Disconnected from relay: ${relayUrl}`);
|
|
334
|
-
} catch (error) {
|
|
335
|
-
console.error(`Failed to disconnect from relay ${relayUrl}:`, error);
|
|
336
|
-
throw error;
|
|
337
|
-
}
|
|
261
|
+
return url + '#import=' + nip19.nsecEncode(this.localSigner.privateKey!);
|
|
338
262
|
}
|
|
339
263
|
|
|
340
|
-
public async
|
|
341
|
-
try {
|
|
342
|
-
const relays = Object.keys(this.rxNostr.getAllRelayStatus());
|
|
343
|
-
console.log(`Reconnecting to ${relays.length} relays...`);
|
|
344
|
-
|
|
345
|
-
for (const relay of relays) {
|
|
346
|
-
try {
|
|
347
|
-
this.rxNostr.reconnect(relay);
|
|
348
|
-
} catch (error) {
|
|
349
|
-
console.warn(`Failed to reconnect to ${relay}:`, error);
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
} catch (error) {
|
|
353
|
-
console.error('Failed to reconnect all relays:', error);
|
|
354
|
-
throw error;
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
public async checkRelayHealth(): Promise<boolean> {
|
|
359
|
-
const stats = this.getRelayStats();
|
|
360
|
-
// 少なくとも1つのリレーが接続されていればOK
|
|
361
|
-
return stats.connected > 0;
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
public async importAndConnect(cs: ConnectionString): Promise<void> {
|
|
264
|
+
public async importAndConnect(cs: ConnectionString) {
|
|
365
265
|
const { relay, domain, link, iframeUrl } = cs;
|
|
366
266
|
if (!domain) throw new Error('Domain required');
|
|
367
267
|
|
|
@@ -378,22 +278,22 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
378
278
|
this.onAuth('login', info);
|
|
379
279
|
}
|
|
380
280
|
|
|
381
|
-
public setReadOnly(pubkey: string)
|
|
281
|
+
public setReadOnly(pubkey: string) {
|
|
382
282
|
const info: Info = { pubkey, authMethod: 'readOnly' };
|
|
383
283
|
this.onAuth('login', info);
|
|
384
284
|
}
|
|
385
285
|
|
|
386
|
-
public setExtension(pubkey: string)
|
|
286
|
+
public setExtension(pubkey: string) {
|
|
387
287
|
const info: Info = { pubkey, authMethod: 'extension' };
|
|
388
288
|
this.onAuth('login', info);
|
|
389
289
|
}
|
|
390
290
|
|
|
391
|
-
public setOTP(pubkey: string, data: string)
|
|
291
|
+
public setOTP(pubkey: string, data: string) {
|
|
392
292
|
const info: Info = { pubkey, authMethod: 'otp', otpData: data };
|
|
393
293
|
this.onAuth('login', info);
|
|
394
294
|
}
|
|
395
295
|
|
|
396
|
-
public async setConnect(info: Info)
|
|
296
|
+
public async setConnect(info: Info) {
|
|
397
297
|
this.releaseSigner();
|
|
398
298
|
await this.startAuth();
|
|
399
299
|
await this.initSigner(info);
|
|
@@ -401,7 +301,7 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
401
301
|
await this.endAuth();
|
|
402
302
|
}
|
|
403
303
|
|
|
404
|
-
public async createAccount(nip05: string)
|
|
304
|
+
public async createAccount(nip05: string) {
|
|
405
305
|
const [name, domain] = nip05.split('@');
|
|
406
306
|
|
|
407
307
|
// bunker's own url
|
|
@@ -425,19 +325,18 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
425
325
|
};
|
|
426
326
|
}
|
|
427
327
|
|
|
428
|
-
private releaseSigner()
|
|
328
|
+
private releaseSigner() {
|
|
429
329
|
this.signer = null;
|
|
430
330
|
this.signerErrCallback?.('cancelled');
|
|
431
331
|
this.localSigner = null;
|
|
432
332
|
|
|
433
333
|
// disconnect from signer relays
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
// this.rxNostr.switchRelays([]); // Should we disconnect? Maybe better to keep connection for next signer?
|
|
334
|
+
for (const r of this.ndk.pool.relays.keys()) {
|
|
335
|
+
this.ndk.pool.removeRelay(r);
|
|
336
|
+
}
|
|
438
337
|
}
|
|
439
338
|
|
|
440
|
-
public async logout(keepSigner = false)
|
|
339
|
+
public async logout(keepSigner = false) {
|
|
441
340
|
if (!keepSigner) this.releaseSigner();
|
|
442
341
|
|
|
443
342
|
// move current to recent
|
|
@@ -449,7 +348,7 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
449
348
|
this.emit('updateAccounts');
|
|
450
349
|
}
|
|
451
350
|
|
|
452
|
-
private setUserInfo(userInfo: Info | null)
|
|
351
|
+
private setUserInfo(userInfo: Info | null) {
|
|
453
352
|
this.params.userInfo = userInfo;
|
|
454
353
|
this.emit('onUserInfo', userInfo);
|
|
455
354
|
|
|
@@ -459,14 +358,13 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
459
358
|
}
|
|
460
359
|
}
|
|
461
360
|
|
|
462
|
-
public exportKeys()
|
|
361
|
+
public exportKeys() {
|
|
463
362
|
if (!this.params.userInfo) return '';
|
|
464
363
|
if (this.params.userInfo.authMethod !== 'local') return '';
|
|
465
|
-
|
|
466
|
-
return nip19.nsecEncode(skBytes);
|
|
364
|
+
return nip19.nsecEncode(this.params.userInfo.sk!);
|
|
467
365
|
}
|
|
468
366
|
|
|
469
|
-
private onAuth(type: 'login' | 'signup' | 'logout', info: Info | null = null)
|
|
367
|
+
private onAuth(type: 'login' | 'signup' | 'logout', info: Info | null = null) {
|
|
470
368
|
if (type !== 'logout' && !info) throw new Error('No user info in onAuth');
|
|
471
369
|
|
|
472
370
|
// make sure we emulate logout first
|
|
@@ -480,8 +378,7 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
480
378
|
|
|
481
379
|
if (info) {
|
|
482
380
|
// async profile fetch
|
|
483
|
-
|
|
484
|
-
fetchProfile(info, this.rxNostr as any).then(p => {
|
|
381
|
+
fetchProfile(info, this.profileNdk).then(p => {
|
|
485
382
|
if (this.params.userInfo !== info) return;
|
|
486
383
|
|
|
487
384
|
const userInfo = {
|
|
@@ -514,7 +411,7 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
514
411
|
options.name = info!.name;
|
|
515
412
|
|
|
516
413
|
if (info!.sk) {
|
|
517
|
-
options.localNsec = nip19.nsecEncode(
|
|
414
|
+
options.localNsec = nip19.nsecEncode(info!.sk);
|
|
518
415
|
}
|
|
519
416
|
|
|
520
417
|
if (info!.relays) {
|
|
@@ -540,7 +437,7 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
540
437
|
}
|
|
541
438
|
}
|
|
542
439
|
|
|
543
|
-
private async createIframe(iframeUrl?: string)
|
|
440
|
+
private async createIframe(iframeUrl?: string) {
|
|
544
441
|
if (!iframeUrl) return undefined;
|
|
545
442
|
|
|
546
443
|
// ensure iframe
|
|
@@ -599,18 +496,18 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
599
496
|
// }
|
|
600
497
|
// }
|
|
601
498
|
|
|
602
|
-
public async sendNeedAuth()
|
|
499
|
+
public async sendNeedAuth() {
|
|
603
500
|
const [nostrconnect] = await this.getNostrConnectServices();
|
|
604
501
|
const event = new CustomEvent('nlNeedAuth', { detail: { nostrconnect } });
|
|
605
502
|
console.log('nostr-login need auth', nostrconnect);
|
|
606
503
|
document.dispatchEvent(event);
|
|
607
504
|
}
|
|
608
505
|
|
|
609
|
-
public isAuthing()
|
|
506
|
+
public isAuthing() {
|
|
610
507
|
return !!this.readyCallback;
|
|
611
508
|
}
|
|
612
509
|
|
|
613
|
-
public async startAuth()
|
|
510
|
+
public async startAuth() {
|
|
614
511
|
console.log('startAuth');
|
|
615
512
|
if (this.readyCallback) throw new Error('Already started');
|
|
616
513
|
|
|
@@ -618,7 +515,7 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
618
515
|
this.readyPromise = new Promise<void>(ok => (this.readyCallback = ok));
|
|
619
516
|
}
|
|
620
517
|
|
|
621
|
-
public async endAuth()
|
|
518
|
+
public async endAuth() {
|
|
622
519
|
console.log('endAuth', this.params.userInfo);
|
|
623
520
|
if (this.params.userInfo && this.params.userInfo.iframeUrl) {
|
|
624
521
|
// create iframe
|
|
@@ -634,28 +531,28 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
634
531
|
this.readyCallback = undefined;
|
|
635
532
|
}
|
|
636
533
|
|
|
637
|
-
public resetAuth()
|
|
534
|
+
public resetAuth() {
|
|
638
535
|
if (this.readyCallback) this.readyCallback();
|
|
639
536
|
this.readyCallback = undefined;
|
|
640
537
|
}
|
|
641
538
|
|
|
642
|
-
private async listen(info: Info)
|
|
539
|
+
private async listen(info: Info) {
|
|
643
540
|
if (!info.iframeUrl) return this.signer!.listen(this.nostrConnectSecret);
|
|
644
541
|
const r = await this.starterReady!.wait();
|
|
645
542
|
if (r[0] === 'starterError') throw new Error(r[1]);
|
|
646
543
|
return this.signer!.setListenReply(r[1], this.nostrConnectSecret);
|
|
647
544
|
}
|
|
648
545
|
|
|
649
|
-
public async connect(info: Info, perms?: string)
|
|
546
|
+
public async connect(info: Info, perms?: string) {
|
|
650
547
|
return this.signer!.connect(info.token, perms);
|
|
651
548
|
}
|
|
652
549
|
|
|
653
|
-
public async initSigner(info: Info, { listen = false, connect = false, eventToAddAccount = false } = {})
|
|
550
|
+
public async initSigner(info: Info, { listen = false, connect = false, eventToAddAccount = false } = {}) {
|
|
654
551
|
// mutex
|
|
655
552
|
if (this.signerPromise) {
|
|
656
553
|
try {
|
|
657
554
|
await this.signerPromise;
|
|
658
|
-
} catch {
|
|
555
|
+
} catch {}
|
|
659
556
|
}
|
|
660
557
|
|
|
661
558
|
// we remove support for iframe from nip05 and bunker-url methods,
|
|
@@ -696,28 +593,22 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
696
593
|
return this.signerPromise;
|
|
697
594
|
}
|
|
698
595
|
|
|
699
|
-
private async initSignerInternal(info: Info, listen: boolean, connect: boolean, eventToAddAccount: boolean, resolve: () => void)
|
|
596
|
+
private async initSignerInternal(info: Info, listen: boolean, connect: boolean, eventToAddAccount: boolean, resolve: () => void) {
|
|
700
597
|
// pre-connect if we're creating the connection (listen|connect) or
|
|
701
598
|
// not iframe mode
|
|
702
599
|
if (info.relays && !info.iframeUrl) {
|
|
703
|
-
|
|
704
|
-
|
|
600
|
+
for (const r of info.relays) {
|
|
601
|
+
this.ndk.addExplicitRelay(r, undefined);
|
|
602
|
+
}
|
|
705
603
|
}
|
|
706
604
|
|
|
707
|
-
//
|
|
605
|
+
// wait until we connect, otherwise
|
|
606
|
+
// signer won't start properly
|
|
607
|
+
await this.ndk.connect();
|
|
708
608
|
|
|
709
609
|
// create and prepare the signer
|
|
710
|
-
const localSigner = new PrivateKeySigner(
|
|
711
|
-
|
|
712
|
-
// TODO: 元のNDKロジック:
|
|
713
|
-
// This initialized the Nip46Signer with NDK instance.
|
|
714
|
-
//
|
|
715
|
-
// New Implementation Plan:
|
|
716
|
-
// 1. Pass the SimplePool instance or relay list to Nip46Signer.
|
|
717
|
-
// 2. Nip46Signer should manage its own connection or use the shared pool to publish/subscribe.
|
|
718
|
-
|
|
719
|
-
// TODO: ndk引数を削除する
|
|
720
|
-
this.signer = new Nip46Signer(this.rxNostr, localSigner, info.signerPubkey!, info.iframeUrl ? new URL(info.iframeUrl!).origin : undefined);
|
|
610
|
+
const localSigner = new PrivateKeySigner(info.sk!);
|
|
611
|
+
this.signer = new Nip46Signer(this.ndk, localSigner, info.signerPubkey!, info.iframeUrl ? new URL(info.iframeUrl!).origin : undefined);
|
|
721
612
|
|
|
722
613
|
// we should notify the banner the same way as
|
|
723
614
|
// the onAuthUrl does
|
|
@@ -769,7 +660,7 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
769
660
|
iframeUrl = '',
|
|
770
661
|
customRelays,
|
|
771
662
|
}: { name: string; bunkerUrl: string; sk?: string; domain?: string; iframeUrl?: string; customRelays?: string[] },
|
|
772
|
-
)
|
|
663
|
+
) {
|
|
773
664
|
try {
|
|
774
665
|
const info = bunkerUrlToInfo(bunkerUrl, sk);
|
|
775
666
|
if (isBunkerUrl(name)) info.bunkerUrl = name;
|
|
@@ -806,9 +697,8 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
806
697
|
}
|
|
807
698
|
}
|
|
808
699
|
|
|
809
|
-
public async signEvent(event: any)
|
|
700
|
+
public async signEvent(event: any) {
|
|
810
701
|
if (this.localSigner) {
|
|
811
|
-
// this.localSigner.privateKey is Uint8Array
|
|
812
702
|
event.pubkey = getPublicKey(this.localSigner.privateKey!);
|
|
813
703
|
event.id = getEventHash(event);
|
|
814
704
|
event.sig = await this.localSigner.sign(event);
|
|
@@ -823,7 +713,7 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
823
713
|
return event;
|
|
824
714
|
}
|
|
825
715
|
|
|
826
|
-
private async ensureSigner()
|
|
716
|
+
private async ensureSigner() {
|
|
827
717
|
// signerがキャンセル等で破棄されている場合は再初期化
|
|
828
718
|
if (!this.signer && this.params.userInfo) {
|
|
829
719
|
console.log('Signer was destroyed, reinitializing...');
|
|
@@ -836,23 +726,11 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
836
726
|
}
|
|
837
727
|
|
|
838
728
|
// リレー接続を確認・再接続
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
// 2. If no relays are connected, modify code to reconnect.
|
|
845
|
-
|
|
846
|
-
// TODO: rx-nostrの統計を確認する
|
|
847
|
-
// const stats = this.pool.listConnectionStatus();
|
|
848
|
-
// const stats = this.pool.listConnectionStatus();
|
|
849
|
-
// const stats = this.ndk.pool.stats();
|
|
850
|
-
// console.log('NDK pool stats:', stats);
|
|
851
|
-
const relayStates = this.rxNostr.getAllRelayStatus();
|
|
852
|
-
const connectedCount = Object.values(relayStates).filter(s => String(s) === 'connected').length;
|
|
853
|
-
|
|
854
|
-
if (connectedCount === 0) {
|
|
855
|
-
console.log('RxNostr relays disconnected, reinitializing signer...');
|
|
729
|
+
const stats = this.ndk.pool.stats();
|
|
730
|
+
console.log('NDK pool stats:', stats);
|
|
731
|
+
|
|
732
|
+
if (stats.connected === 0) {
|
|
733
|
+
console.log('NDK relays disconnected, reinitializing signer...');
|
|
856
734
|
|
|
857
735
|
// リレーが完全に切断されている場合、signerも再初期化する必要がある
|
|
858
736
|
// (RPCサブスクリプションも切断されているため)
|
|
@@ -860,8 +738,14 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
860
738
|
// 古いsignerを破棄
|
|
861
739
|
this.signer = null;
|
|
862
740
|
|
|
863
|
-
// 既存のリレーを一度切断
|
|
864
|
-
this.
|
|
741
|
+
// 既存のリレーを一度切断
|
|
742
|
+
for (const relay of this.ndk.pool.relays.values()) {
|
|
743
|
+
try {
|
|
744
|
+
relay.disconnect();
|
|
745
|
+
} catch (e) {
|
|
746
|
+
console.log('Error disconnecting relay:', e);
|
|
747
|
+
}
|
|
748
|
+
}
|
|
865
749
|
|
|
866
750
|
// signerを再初期化(リレー接続も含む)
|
|
867
751
|
await this.initSigner(this.params.userInfo);
|
|
@@ -871,41 +755,56 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
871
755
|
}
|
|
872
756
|
}
|
|
873
757
|
|
|
758
|
+
private async codec_call(method: string, pubkey: string, param: string) {
|
|
759
|
+
return new Promise<string>((resolve, reject) => {
|
|
760
|
+
this.signer!.rpc.sendRequest(this.signer!.remotePubkey!, method, [pubkey, param], 24133, (response: NDKRpcResponse) => {
|
|
761
|
+
if (!response.error) {
|
|
762
|
+
resolve(response.result);
|
|
763
|
+
} else {
|
|
764
|
+
reject(response.error);
|
|
765
|
+
}
|
|
766
|
+
});
|
|
767
|
+
});
|
|
768
|
+
}
|
|
874
769
|
|
|
875
|
-
|
|
876
|
-
public async encrypt04(pubkey: string, plaintext: string): Promise<string> {
|
|
770
|
+
public async encrypt04(pubkey: string, plaintext: string) {
|
|
877
771
|
if (this.localSigner) {
|
|
878
|
-
return this.localSigner.encrypt(pubkey
|
|
772
|
+
return this.localSigner.encrypt(new NDKUser({ pubkey }), plaintext);
|
|
879
773
|
} else {
|
|
880
774
|
await this.ensureSigner();
|
|
881
|
-
return this.signer!.encrypt(pubkey, plaintext);
|
|
775
|
+
return this.signer!.encrypt(new NDKUser({ pubkey }), plaintext);
|
|
882
776
|
}
|
|
883
777
|
}
|
|
884
778
|
|
|
885
|
-
public async decrypt04(pubkey: string, ciphertext: string)
|
|
779
|
+
public async decrypt04(pubkey: string, ciphertext: string) {
|
|
886
780
|
if (this.localSigner) {
|
|
887
|
-
return this.localSigner.decrypt(pubkey
|
|
781
|
+
return this.localSigner.decrypt(new NDKUser({ pubkey }), ciphertext);
|
|
888
782
|
} else {
|
|
783
|
+
// decrypt is broken in ndk v2.3.1, and latest
|
|
784
|
+
// ndk v2.8.1 doesn't allow to override connect easily,
|
|
785
|
+
// so we reimplement and fix decrypt here as a temporary fix
|
|
889
786
|
await this.ensureSigner();
|
|
890
|
-
return this.
|
|
787
|
+
return this.codec_call('nip04_decrypt', pubkey, ciphertext);
|
|
891
788
|
}
|
|
892
789
|
}
|
|
893
790
|
|
|
894
|
-
public async encrypt44(pubkey: string, plaintext: string)
|
|
791
|
+
public async encrypt44(pubkey: string, plaintext: string) {
|
|
895
792
|
if (this.localSigner) {
|
|
896
793
|
return this.nip44Codec.encrypt(this.localSigner.privateKey!, pubkey, plaintext);
|
|
897
794
|
} else {
|
|
795
|
+
// no support of nip44 in ndk yet
|
|
898
796
|
await this.ensureSigner();
|
|
899
|
-
return this.
|
|
797
|
+
return this.codec_call('nip44_encrypt', pubkey, plaintext);
|
|
900
798
|
}
|
|
901
799
|
}
|
|
902
800
|
|
|
903
|
-
public async decrypt44(pubkey: string, ciphertext: string)
|
|
801
|
+
public async decrypt44(pubkey: string, ciphertext: string) {
|
|
904
802
|
if (this.localSigner) {
|
|
905
803
|
return this.nip44Codec.decrypt(this.localSigner.privateKey!, pubkey, ciphertext);
|
|
906
804
|
} else {
|
|
805
|
+
// no support of nip44 in ndk yet
|
|
907
806
|
await this.ensureSigner();
|
|
908
|
-
return this.
|
|
807
|
+
return this.codec_call('nip44_decrypt', pubkey, ciphertext);
|
|
909
808
|
}
|
|
910
809
|
}
|
|
911
810
|
}
|