@konemono/nostr-login 1.15.8 → 1.16.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.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 +22 -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.0",
|
|
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,16 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
693
702
|
await this.signer!.initUserPubkey(info.pubkey);
|
|
694
703
|
}
|
|
695
704
|
|
|
705
|
+
// NIP-46 Spec: 接続確立後に switch_relays を即時送信
|
|
706
|
+
const newRelays = await this.signer!.switchRelays();
|
|
707
|
+
if (newRelays && newRelays.length > 0) {
|
|
708
|
+
this.pool.removeAllRelays();
|
|
709
|
+
for (const r of newRelays) {
|
|
710
|
+
this.pool.addRelay(r);
|
|
711
|
+
}
|
|
712
|
+
this.signer!.rpc.resubscribe();
|
|
713
|
+
}
|
|
714
|
+
|
|
696
715
|
info.pubkey = this.signer!.userPubkey as string;
|
|
697
716
|
info.signerPubkey = this.signer!.bunkerPubkey;
|
|
698
717
|
|
|
@@ -862,7 +881,7 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
862
881
|
return this.localSigner.decrypt({ pubkey }, ciphertext);
|
|
863
882
|
}
|
|
864
883
|
await this.ensureRelayConnection();
|
|
865
|
-
return this.
|
|
884
|
+
return this.signer!.decrypt(pubkey, ciphertext);
|
|
866
885
|
}
|
|
867
886
|
|
|
868
887
|
public async encrypt44(pubkey: string, plaintext: string) {
|
|
@@ -870,7 +889,7 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
870
889
|
return this.nip44Codec.encrypt(this.localSigner.privateKey!, pubkey, plaintext);
|
|
871
890
|
}
|
|
872
891
|
await this.ensureRelayConnection();
|
|
873
|
-
return this.
|
|
892
|
+
return this.signer!.nip44Encrypt(pubkey, plaintext);
|
|
874
893
|
}
|
|
875
894
|
|
|
876
895
|
public async decrypt44(pubkey: string, ciphertext: string) {
|
|
@@ -878,7 +897,7 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
878
897
|
return this.nip44Codec.decrypt(this.localSigner.privateKey!, pubkey, ciphertext);
|
|
879
898
|
}
|
|
880
899
|
await this.ensureRelayConnection();
|
|
881
|
-
return this.
|
|
900
|
+
return this.signer!.nip44Decrypt(pubkey, ciphertext);
|
|
882
901
|
}
|
|
883
902
|
}
|
|
884
903
|
|
|
@@ -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, 'TIMEOUT'));
|
|
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, 'TIMEOUT'));
|
|
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, 'TIMEOUT'));
|
|
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));
|