@konemono/nostr-login 1.15.8 → 1.16.1
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 +0 -1
- package/dist/index.esm.js +5 -5
- package/dist/index.esm.js.map +1 -1
- package/dist/modules/nip46/Nip46Signer.d.ts +25 -0
- package/dist/unpkg.js +5 -5
- package/dist/utils/index.d.ts +0 -1
- package/package.json +2 -2
- package/src/index.ts +1 -22
- package/src/modules/AuthNostrService.ts +33 -3
- package/src/modules/BannerManager.ts +0 -4
- package/src/modules/ModalManager.ts +0 -4
- package/src/modules/nip46/Nip46Signer.ts +87 -0
- package/src/utils/index.ts +0 -42
package/dist/utils/index.d.ts
CHANGED
|
@@ -19,7 +19,6 @@ export declare const checkNip05: (nip05: string) => Promise<{
|
|
|
19
19
|
}>;
|
|
20
20
|
export declare const localStorageAddAccount: (info: Info) => void;
|
|
21
21
|
export declare const localStorageRemoveCurrentAccount: () => void;
|
|
22
|
-
export declare const localStorageRemoveAccount: (user: Info) => void;
|
|
23
22
|
export declare const localStorageRemoveRecent: (user: RecentType) => void;
|
|
24
23
|
export declare const localStorageGetRecents: () => RecentType[];
|
|
25
24
|
export declare const localStorageGetAccounts: () => Info[];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@konemono/nostr-login",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.16.1",
|
|
4
4
|
"description": "Extended fork of nostr-login with multi-relay support, QR scanner, and improved stability",
|
|
5
5
|
"main": "./dist/index.esm.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"tseep": "^1.2.1"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
|
-
"@konemono/nostr-login-components": "^1.
|
|
30
|
+
"@konemono/nostr-login-components": "^1.5.0",
|
|
31
31
|
"@rollup/plugin-commonjs": "^25.0.7",
|
|
32
32
|
"@rollup/plugin-node-resolve": "^15.2.3",
|
|
33
33
|
"@rollup/plugin-terser": "^0.4.4",
|
package/src/index.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import '@konemono/nostr-login-components';
|
|
2
2
|
import { AuthNostrService, NostrExtensionService, Popup, NostrParams, Nostr, ProcessManager, BannerManager, ModalManager } from './modules';
|
|
3
3
|
import { NostrLoginAuthOptions, NostrLoginOptions, StartScreens } from './types';
|
|
4
|
-
import { localStorageGetAccounts, localStorageGetCurrent, localStorageGetRecents,
|
|
4
|
+
import { localStorageGetAccounts, localStorageGetCurrent, localStorageGetRecents, localStorageSetItem } from './utils';
|
|
5
5
|
import { Info } from '@konemono/nostr-login-components/dist/types/types';
|
|
6
6
|
import { NostrObjectParams } from './modules/Nostr';
|
|
7
7
|
|
|
@@ -105,10 +105,6 @@ export class NostrLoginInitializer {
|
|
|
105
105
|
this.switchAccount(info);
|
|
106
106
|
});
|
|
107
107
|
|
|
108
|
-
this.modalManager.on('onRemoveAccount', async (info: Info) => {
|
|
109
|
-
this.removeAccount(info);
|
|
110
|
-
});
|
|
111
|
-
|
|
112
108
|
this.modalManager.on('onLogoutBanner', async (info: Info) => {
|
|
113
109
|
logout();
|
|
114
110
|
});
|
|
@@ -133,10 +129,6 @@ export class NostrLoginInitializer {
|
|
|
133
129
|
this.switchAccount(info);
|
|
134
130
|
});
|
|
135
131
|
|
|
136
|
-
this.bannerManager.on('onRemoveAccount', async (info: Info) => {
|
|
137
|
-
this.removeAccount(info);
|
|
138
|
-
});
|
|
139
|
-
|
|
140
132
|
this.bannerManager.on('import', () => {
|
|
141
133
|
this.launch('import');
|
|
142
134
|
});
|
|
@@ -189,19 +181,6 @@ export class NostrLoginInitializer {
|
|
|
189
181
|
}
|
|
190
182
|
}
|
|
191
183
|
|
|
192
|
-
private async removeAccount(info: Info) {
|
|
193
|
-
const current = this.params.userInfo || localStorageGetCurrent();
|
|
194
|
-
const isCurrent = current?.pubkey === info.pubkey && current?.authMethod === info.authMethod;
|
|
195
|
-
|
|
196
|
-
if (isCurrent) {
|
|
197
|
-
await this.logout();
|
|
198
|
-
return;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
localStorageRemoveAccount(info);
|
|
202
|
-
this.updateAccounts();
|
|
203
|
-
}
|
|
204
|
-
|
|
205
184
|
private updateAccounts() {
|
|
206
185
|
const accounts = localStorageGetAccounts();
|
|
207
186
|
const recents = localStorageGetRecents();
|
|
@@ -456,6 +456,15 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
456
456
|
}
|
|
457
457
|
|
|
458
458
|
public async logout(keepSigner = false) {
|
|
459
|
+
// NIP-46 logout を送信(signer が session を削除)
|
|
460
|
+
if (this.signer && !keepSigner) {
|
|
461
|
+
try {
|
|
462
|
+
await this.signer.logout();
|
|
463
|
+
} catch (e) {
|
|
464
|
+
console.warn('NIP-46 logout RPC failed (non-fatal):', e);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
|
|
459
468
|
if (!keepSigner) this.releaseSigner();
|
|
460
469
|
|
|
461
470
|
localStorageRemoveCurrentAccount();
|
|
@@ -693,6 +702,27 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
693
702
|
await this.signer!.initUserPubkey(info.pubkey);
|
|
694
703
|
}
|
|
695
704
|
|
|
705
|
+
// NIP-46 Spec: 接続確立後に switch_relays を即時送信(should、非致命的)
|
|
706
|
+
try {
|
|
707
|
+
const newRelays = await this.signer!.switchRelays();
|
|
708
|
+
if (newRelays && newRelays.length > 0) {
|
|
709
|
+
// 一時的にリレーゼロにならないよう、先に追加してから削除
|
|
710
|
+
const oldRelays = this.pool.relayUrls;
|
|
711
|
+
for (const r of newRelays) {
|
|
712
|
+
this.pool.addRelay(r);
|
|
713
|
+
}
|
|
714
|
+
// 古いリレーを削除(新規に含まれないものを除外)
|
|
715
|
+
for (const r of oldRelays) {
|
|
716
|
+
if (!newRelays.includes(r)) {
|
|
717
|
+
this.pool.removeRelay(r);
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
this.signer!.rpc.resubscribe();
|
|
721
|
+
}
|
|
722
|
+
} catch (e) {
|
|
723
|
+
console.warn('NIP-46 switch_relays failed (non-fatal):', e);
|
|
724
|
+
}
|
|
725
|
+
|
|
696
726
|
info.pubkey = this.signer!.userPubkey as string;
|
|
697
727
|
info.signerPubkey = this.signer!.bunkerPubkey;
|
|
698
728
|
|
|
@@ -862,7 +892,7 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
862
892
|
return this.localSigner.decrypt({ pubkey }, ciphertext);
|
|
863
893
|
}
|
|
864
894
|
await this.ensureRelayConnection();
|
|
865
|
-
return this.
|
|
895
|
+
return this.signer!.decrypt(pubkey, ciphertext);
|
|
866
896
|
}
|
|
867
897
|
|
|
868
898
|
public async encrypt44(pubkey: string, plaintext: string) {
|
|
@@ -870,7 +900,7 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
870
900
|
return this.nip44Codec.encrypt(this.localSigner.privateKey!, pubkey, plaintext);
|
|
871
901
|
}
|
|
872
902
|
await this.ensureRelayConnection();
|
|
873
|
-
return this.
|
|
903
|
+
return this.signer!.nip44Encrypt(pubkey, plaintext);
|
|
874
904
|
}
|
|
875
905
|
|
|
876
906
|
public async decrypt44(pubkey: string, ciphertext: string) {
|
|
@@ -878,7 +908,7 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
878
908
|
return this.nip44Codec.decrypt(this.localSigner.privateKey!, pubkey, ciphertext);
|
|
879
909
|
}
|
|
880
910
|
await this.ensureRelayConnection();
|
|
881
|
-
return this.
|
|
911
|
+
return this.signer!.nip44Decrypt(pubkey, ciphertext);
|
|
882
912
|
}
|
|
883
913
|
}
|
|
884
914
|
|
|
@@ -130,10 +130,6 @@ class BannerManager extends EventEmitter {
|
|
|
130
130
|
this.emit('onSwitchAccount', event.detail);
|
|
131
131
|
});
|
|
132
132
|
|
|
133
|
-
this.banner.addEventListener('nlRemoveAccount', (event: any) => {
|
|
134
|
-
this.emit('onRemoveAccount', event.detail);
|
|
135
|
-
});
|
|
136
|
-
|
|
137
133
|
this.banner.addEventListener('nlOpenWelcomeModal', () => {
|
|
138
134
|
this.emit('launch');
|
|
139
135
|
|
|
@@ -492,10 +492,6 @@ class ModalManager extends EventEmitter {
|
|
|
492
492
|
this.emit('updateAccounts');
|
|
493
493
|
});
|
|
494
494
|
|
|
495
|
-
this.modal.addEventListener('nlRemoveAccount', (event: any) => {
|
|
496
|
-
this.emit('onRemoveAccount', event.detail as Info);
|
|
497
|
-
});
|
|
498
|
-
|
|
499
495
|
const nameToPubkey = async (nameNpub: string) => {
|
|
500
496
|
let pubkey = '';
|
|
501
497
|
if (nameNpub.includes('@')) {
|
|
@@ -151,7 +151,94 @@ export class Nip46Signer extends EventEmitter {
|
|
|
151
151
|
});
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
+
/**
|
|
155
|
+
* NIP-46 ping — signer の死活確認
|
|
156
|
+
*/
|
|
157
|
+
public async ping(): Promise<boolean> {
|
|
158
|
+
return new Promise<boolean>((resolve, reject) => {
|
|
159
|
+
this.rpc.sendRequest(this.bunkerPubkey, 'ping', [], 24133, (response: RpcResponse) => {
|
|
160
|
+
if (response.error) {
|
|
161
|
+
reject(new Nip46Error(response.error, 'SIGNER_REJECTED'));
|
|
162
|
+
} else {
|
|
163
|
+
resolve(response.result === 'pong');
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* NIP-46 switch_relays — リレーリストの更新
|
|
171
|
+
* Spec: 接続確立後に client が即時送信、signer が relay リストを返す
|
|
172
|
+
*/
|
|
173
|
+
public async switchRelays(): Promise<string[] | null> {
|
|
174
|
+
return new Promise<string[] | null>((resolve, reject) => {
|
|
175
|
+
this.rpc.sendRequest(this.bunkerPubkey, 'switch_relays', [], 24133, (response: RpcResponse) => {
|
|
176
|
+
if (response.error) {
|
|
177
|
+
reject(new Nip46Error(response.error, 'SIGNER_REJECTED'));
|
|
178
|
+
} else {
|
|
179
|
+
// result は JSON 文字列: ["wss://...", ...] または "null"
|
|
180
|
+
try {
|
|
181
|
+
const parsed = JSON.parse(response.result);
|
|
182
|
+
resolve(Array.isArray(parsed) ? parsed : null);
|
|
183
|
+
} catch {
|
|
184
|
+
resolve(null);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* NIP-46 logout — リモート signer にセッション終了を通知
|
|
193
|
+
*/
|
|
194
|
+
public async logout(): Promise<void> {
|
|
195
|
+
return new Promise<void>((resolve, reject) => {
|
|
196
|
+
this.rpc.sendRequest(this.bunkerPubkey, 'logout', [], 24133, (response: RpcResponse) => {
|
|
197
|
+
if (response.error) {
|
|
198
|
+
reject(new Nip46Error(response.error, 'SIGNER_REJECTED'));
|
|
199
|
+
} else {
|
|
200
|
+
resolve();
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* NIP-46 remote encrypt (NIP-44)
|
|
208
|
+
*/
|
|
209
|
+
public async nip44Encrypt(recipientPubkey: string, plaintext: string): Promise<string> {
|
|
210
|
+
return new Promise<string>((resolve, reject) => {
|
|
211
|
+
this.rpc.sendRequest(this.bunkerPubkey, 'nip44_encrypt', [recipientPubkey, plaintext], 24133, (response: RpcResponse) => {
|
|
212
|
+
if (response.error) {
|
|
213
|
+
reject(new Nip46Error(response.error, 'SIGNER_REJECTED'));
|
|
214
|
+
} else {
|
|
215
|
+
resolve(response.result);
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* NIP-46 remote decrypt (NIP-44)
|
|
223
|
+
*/
|
|
224
|
+
public async nip44Decrypt(senderPubkey: string, ciphertext: string): Promise<string> {
|
|
225
|
+
return new Promise<string>((resolve, reject) => {
|
|
226
|
+
this.rpc.sendRequest(this.bunkerPubkey, 'nip44_decrypt', [senderPubkey, ciphertext], 24133, (response: RpcResponse) => {
|
|
227
|
+
if (response.error) {
|
|
228
|
+
reject(new Nip46Error(response.error, 'SIGNER_REJECTED'));
|
|
229
|
+
} else {
|
|
230
|
+
resolve(response.result);
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* @deprecated NIP-46 spec から create_account は別 NIP へ移動済み。
|
|
238
|
+
* 将来的に削除されます。
|
|
239
|
+
*/
|
|
154
240
|
public async createAccount2({ bunkerPubkey, name, domain, perms = '' }: { bunkerPubkey: string; name: string; domain: string; perms?: string }) {
|
|
241
|
+
console.warn('[DEPRECATED] createAccount2 is deprecated per NIP-46 spec. Will be removed in a future version.');
|
|
155
242
|
const params = [name, domain, '', perms];
|
|
156
243
|
|
|
157
244
|
const r = await new Promise<RpcResponse>((ok, err) => {
|
package/src/utils/index.ts
CHANGED
|
@@ -303,48 +303,6 @@ export const localStorageRemoveCurrentAccount = () => {
|
|
|
303
303
|
localStorageRemoveItem(LOCAL_STORE_KEY);
|
|
304
304
|
};
|
|
305
305
|
|
|
306
|
-
export const localStorageRemoveAccount = (user: Info) => {
|
|
307
|
-
if (!user) return;
|
|
308
|
-
|
|
309
|
-
upgradeInfo(user);
|
|
310
|
-
|
|
311
|
-
const current: Info | null = localStorageGetItem(LOCAL_STORE_KEY);
|
|
312
|
-
if (current) upgradeInfo(current);
|
|
313
|
-
|
|
314
|
-
const recentUser: RecentType = { ...user };
|
|
315
|
-
delete (recentUser as Record<string, unknown>)['sk'];
|
|
316
|
-
delete (recentUser as Record<string, unknown>)['otpData'];
|
|
317
|
-
|
|
318
|
-
const loggedInAccounts: Info[] = localStorageGetItem(LOGGED_IN_ACCOUNTS) || [];
|
|
319
|
-
const recentsAccounts: RecentType[] = localStorageGetItem(RECENT_ACCOUNTS) || [];
|
|
320
|
-
|
|
321
|
-
loggedInAccounts.forEach(a => upgradeInfo(a));
|
|
322
|
-
recentsAccounts.forEach(a => upgradeInfo(a));
|
|
323
|
-
|
|
324
|
-
const accounts = loggedInAccounts.filter(el => el.pubkey !== user.pubkey || el.authMethod !== user.authMethod);
|
|
325
|
-
const recents: RecentType[] = recentsAccounts;
|
|
326
|
-
|
|
327
|
-
if (recentUser.authMethod === 'connect' && recentUser.bunkerUrl && recentUser.bunkerUrl.includes('secret=')) {
|
|
328
|
-
console.log('nostr login bunker conn with a secret not saved to recent');
|
|
329
|
-
} else if (recentUser.authMethod === 'local') {
|
|
330
|
-
console.log('nostr login temporary local keys not save to recent');
|
|
331
|
-
} else {
|
|
332
|
-
const index = recentsAccounts.findIndex((el: RecentType) => el.pubkey === recentUser.pubkey && el.authMethod === recentUser.authMethod);
|
|
333
|
-
if (index !== -1) {
|
|
334
|
-
recents[index] = recentUser;
|
|
335
|
-
} else {
|
|
336
|
-
recents.push(recentUser);
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
localStorageSetItem(RECENT_ACCOUNTS, JSON.stringify(recents));
|
|
341
|
-
localStorageSetItem(LOGGED_IN_ACCOUNTS, JSON.stringify(accounts));
|
|
342
|
-
|
|
343
|
-
if (current && current.pubkey === user.pubkey && current.authMethod === user.authMethod) {
|
|
344
|
-
localStorageRemoveItem(LOCAL_STORE_KEY);
|
|
345
|
-
}
|
|
346
|
-
};
|
|
347
|
-
|
|
348
306
|
export const localStorageRemoveRecent = (user: RecentType) => {
|
|
349
307
|
const recentsAccounts: RecentType[] = localStorageGetItem(RECENT_ACCOUNTS) || [];
|
|
350
308
|
recentsAccounts.forEach(a => upgradeInfo(a));
|