@konemono/nostr-login 1.15.3 → 1.15.5
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/package.json +2 -2
- package/src/modules/AuthNostrService.ts +72 -19
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@konemono/nostr-login",
|
|
3
|
-
"version": "1.15.
|
|
3
|
+
"version": "1.15.5",
|
|
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.4.
|
|
30
|
+
"@konemono/nostr-login-components": "^1.4.5",
|
|
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",
|
|
@@ -96,6 +96,7 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
96
96
|
public cancelNostrConnect() {
|
|
97
97
|
console.log('cancelNostrConnect called');
|
|
98
98
|
this.releaseSigner();
|
|
99
|
+
this.resetNostrConnectKeys();
|
|
99
100
|
|
|
100
101
|
// readyCallbackのみ解放
|
|
101
102
|
this.resetAuth();
|
|
@@ -144,7 +145,21 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
144
145
|
) {
|
|
145
146
|
console.log('[nostrConnect] Called', { relay, domain, link, iframeUrl, importConnect, customRelays });
|
|
146
147
|
|
|
147
|
-
|
|
148
|
+
// linkのnostrconnect URLからリレーヒントを抽出
|
|
149
|
+
let linkRelays: string[] = [];
|
|
150
|
+
if (link) {
|
|
151
|
+
try {
|
|
152
|
+
const ncMatch = link.match(/nostrconnect:\/\/[^?]*\?(.*)/);
|
|
153
|
+
if (ncMatch) {
|
|
154
|
+
const params = new URLSearchParams(ncMatch[1]);
|
|
155
|
+
linkRelays = params.getAll('relay');
|
|
156
|
+
}
|
|
157
|
+
} catch (e) {
|
|
158
|
+
console.warn('[nostrConnect] Failed to parse relay hints from link', e);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const relays = customRelays && customRelays.length > 0 ? customRelays : linkRelays.length > 0 ? linkRelays : relay ? [relay] : DEFAULT_NIP46_RELAYS;
|
|
148
163
|
|
|
149
164
|
const info: Info = {
|
|
150
165
|
authMethod: 'connect',
|
|
@@ -194,14 +209,35 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
194
209
|
this.onAuth('login', info);
|
|
195
210
|
}
|
|
196
211
|
|
|
212
|
+
// 接続成功後にkey/secretをリセット(次回のモーダル表示で新規生成される)
|
|
213
|
+
this.resetNostrConnectKeys();
|
|
214
|
+
|
|
197
215
|
console.log('[nostrConnect] Completed successfully');
|
|
198
216
|
return info;
|
|
199
217
|
}
|
|
200
218
|
|
|
201
|
-
public async createNostrConnect() {
|
|
202
|
-
this.
|
|
203
|
-
this.
|
|
219
|
+
public async createNostrConnect(relays: string[]) {
|
|
220
|
+
this.ensureNostrConnectKeys();
|
|
221
|
+
return this.buildNostrConnectUrl(relays);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* key/secret が未生成なら新規生成する。既存なら再利用。
|
|
226
|
+
* モーダル表示中にリレーが変更されても key/secret は維持される。
|
|
227
|
+
*/
|
|
228
|
+
private ensureNostrConnectKeys() {
|
|
229
|
+
if (!this.nostrConnectKey) {
|
|
230
|
+
this.nostrConnectKey = generatePrivateKey();
|
|
231
|
+
}
|
|
232
|
+
if (!this.nostrConnectSecret) {
|
|
233
|
+
this.nostrConnectSecret = Array.from(crypto.getRandomValues(new Uint8Array(16)), b => b.toString(16).padStart(2, '0')).join('');
|
|
234
|
+
}
|
|
235
|
+
}
|
|
204
236
|
|
|
237
|
+
/**
|
|
238
|
+
* 現在の key/secret を使って nostrconnect:// URL を構築する。
|
|
239
|
+
*/
|
|
240
|
+
private async buildNostrConnectUrl(relays: string[]): Promise<string> {
|
|
205
241
|
const pubkey = getPublicKey(hexToBytes(this.nostrConnectKey));
|
|
206
242
|
const meta = {
|
|
207
243
|
name: encodeURIComponent(document.location.host),
|
|
@@ -210,27 +246,34 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
210
246
|
perms: encodeURIComponent(this.params.optionsModal.perms || ''),
|
|
211
247
|
};
|
|
212
248
|
|
|
213
|
-
|
|
249
|
+
const relayParams = relays.map(r => `&relay=${encodeURIComponent(r)}`).join('');
|
|
250
|
+
return `nostrconnect://${pubkey}?image=${meta.icon}&url=${meta.url}&name=${meta.name}&perms=${meta.perms}&secret=${this.nostrConnectSecret}${relayParams}`;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* nostrconnect セッションをリセットし、key/secret を再生成可能にする。
|
|
255
|
+
*/
|
|
256
|
+
public resetNostrConnectKeys() {
|
|
257
|
+
this.nostrConnectKey = '';
|
|
258
|
+
this.nostrConnectSecret = '';
|
|
214
259
|
}
|
|
215
260
|
|
|
216
261
|
public async getNostrConnectServices(customRelays?: string[], onUpdate?: (apps: ConnectionString[]) => void): Promise<[string, ConnectionString[]]> {
|
|
217
|
-
const
|
|
262
|
+
const defaultRelays = customRelays && customRelays.length > 0 ? customRelays : DEFAULT_NIP46_RELAYS;
|
|
263
|
+
// ベースURLにリレーヒントを含める
|
|
264
|
+
const nostrconnect = await this.createNostrConnect(defaultRelays);
|
|
218
265
|
|
|
219
266
|
const apps: ConnectionString[] = NOSTRCONNECT_APPS.map(a => ({ ...a }));
|
|
220
|
-
const defaultRelays = customRelays && customRelays.length > 0 ? customRelays : DEFAULT_NIP46_RELAYS;
|
|
221
267
|
|
|
222
268
|
// Build initial list: https services are 'loading', others are immediately available
|
|
223
269
|
for (const a of apps) {
|
|
224
270
|
if (a.link.startsWith('https://')) {
|
|
225
271
|
a.available = 'loading';
|
|
226
|
-
//
|
|
227
|
-
|
|
228
|
-
a.link = nostrconnect + relayParams;
|
|
272
|
+
// nostrconnect URL にはすでにリレーヒントが含まれている
|
|
273
|
+
a.link = nostrconnect;
|
|
229
274
|
} else {
|
|
230
275
|
a.available = true;
|
|
231
|
-
|
|
232
|
-
const nc = nostrconnect + relayParams;
|
|
233
|
-
a.link = a.link.replace('<nostrconnect>', nc);
|
|
276
|
+
a.link = a.link.replace('<nostrconnect>', nostrconnect);
|
|
234
277
|
}
|
|
235
278
|
}
|
|
236
279
|
|
|
@@ -245,15 +288,15 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
245
288
|
try {
|
|
246
289
|
const info = await fetchNostrJson(domain);
|
|
247
290
|
const pubkey = info.names['_'];
|
|
248
|
-
let relays = defaultRelays;
|
|
249
291
|
const fetchedRelays = info.nip46[pubkey] as string[];
|
|
292
|
+
a.iframeUrl = info.nip46.iframe_url || '';
|
|
293
|
+
// サービス固有のリレーがあればURLを再構築
|
|
250
294
|
if (fetchedRelays && fetchedRelays.length && (!customRelays || customRelays.length === 0)) {
|
|
251
|
-
|
|
295
|
+
const serviceNostrconnect = this.replaceRelayHints(nostrconnect, fetchedRelays);
|
|
296
|
+
a.link = a.iframeUrl ? serviceNostrconnect : a.link;
|
|
297
|
+
} else {
|
|
298
|
+
a.link = a.iframeUrl ? nostrconnect : a.link;
|
|
252
299
|
}
|
|
253
|
-
a.iframeUrl = info.nip46.iframe_url || '';
|
|
254
|
-
const relayParams = relays.map(r => `&relay=${encodeURIComponent(r)}`).join('');
|
|
255
|
-
const nc = nostrconnect + relayParams;
|
|
256
|
-
a.link = a.iframeUrl ? nc : a.link;
|
|
257
300
|
a.available = true;
|
|
258
301
|
} catch (e) {
|
|
259
302
|
console.log('Service unavailable', domain, e);
|
|
@@ -267,6 +310,16 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
267
310
|
return [nostrconnect, apps];
|
|
268
311
|
}
|
|
269
312
|
|
|
313
|
+
private replaceRelayHints(nostrconnectUrl: string, newRelays: string[]): string {
|
|
314
|
+
// 既存のrelay=パラメータを除去して新しいリレーに置換
|
|
315
|
+
const url = new URL(nostrconnectUrl);
|
|
316
|
+
url.searchParams.delete('relay');
|
|
317
|
+
for (const r of newRelays) {
|
|
318
|
+
url.searchParams.append('relay', r);
|
|
319
|
+
}
|
|
320
|
+
return url.toString();
|
|
321
|
+
}
|
|
322
|
+
|
|
270
323
|
public async localSignup(name: string, sk?: string) {
|
|
271
324
|
const signup = !sk;
|
|
272
325
|
sk = sk || generatePrivateKey();
|