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