@konemono/nostr-login 1.7.49 → 1.7.51
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 +2 -2
- package/dist/index.esm.js +12 -42
- package/dist/index.esm.js.map +1 -1
- package/dist/modules/Nip46.d.ts +8 -8
- package/dist/modules/Signer.d.ts +9 -0
- package/dist/unpkg.js +12 -42
- package/dist/utils/nip44.d.ts +1 -1
- package/package.json +7 -7
- package/src/modules/AmberDirectSigner.ts +106 -0
- package/src/modules/AuthNostrService.ts +143 -78
- package/src/modules/ModalManager.ts +3 -0
- package/src/modules/Nip46.ts +49 -64
- package/src/modules/Signer.ts +1 -2
- package/src/utils/index.ts +17 -15
package/dist/utils/nip44.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ 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, pubkey: string): Uint8Array;
|
|
6
6
|
private getKey;
|
|
7
7
|
encrypt(privkey: string, pubkey: string, text: string): string;
|
|
8
8
|
decrypt(privkey: string, pubkey: string, data: string): string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@konemono/nostr-login",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.51",
|
|
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-dev-kit/ndk": "^2.
|
|
14
|
+
"@nostr-dev-kit/ndk": "^2.3.1",
|
|
15
15
|
"nostr-tools": "^1.17.0",
|
|
16
|
-
"tseep": "^1.
|
|
16
|
+
"tseep": "^1.2.1"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
|
-
"@rollup/plugin-commonjs": "^25.0.
|
|
20
|
-
"@rollup/plugin-node-resolve": "^15.3
|
|
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"
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { NDKUser } from '@nostr-dev-kit/ndk';
|
|
2
|
+
import { Signer } from './Nostr';
|
|
3
|
+
|
|
4
|
+
export class AmberDirectSigner implements Signer {
|
|
5
|
+
private _pubkey: string = '';
|
|
6
|
+
|
|
7
|
+
constructor(pubkey?: string) {
|
|
8
|
+
this._pubkey = pubkey || '';
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
get pubkey() {
|
|
12
|
+
return this._pubkey;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
public set pubkey(v: string) {
|
|
16
|
+
this._pubkey = v;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
nip04 = {
|
|
20
|
+
encrypt: (pubkey: string, plaintext: string) => this.encrypt04(pubkey, plaintext),
|
|
21
|
+
decrypt: (pubkey: string, ciphertext: string) => this.decrypt04(pubkey, ciphertext),
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
nip44 = {
|
|
25
|
+
encrypt: (pubkey: string, plaintext: string) => this.encrypt44(pubkey, plaintext),
|
|
26
|
+
decrypt: (pubkey: string, ciphertext: string) => this.decrypt44(pubkey, ciphertext),
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
async signEvent(event: any): Promise<any> {
|
|
30
|
+
const id = Math.random().toString(36).substring(7);
|
|
31
|
+
const url = this.generateUrl(JSON.stringify(event), 'sign_event', id);
|
|
32
|
+
window.location.href = url;
|
|
33
|
+
// This will never resolve because of page reload
|
|
34
|
+
return new Promise(() => {});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async encrypt04(pubkey: string, plaintext: string): Promise<string> {
|
|
38
|
+
const id = Math.random().toString(36).substring(7);
|
|
39
|
+
const url = this.generateUrl(plaintext, 'nip04_encrypt', id, pubkey);
|
|
40
|
+
window.location.href = url;
|
|
41
|
+
return new Promise(() => {});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async decrypt04(pubkey: string, ciphertext: string): Promise<string> {
|
|
45
|
+
const id = Math.random().toString(36).substring(7);
|
|
46
|
+
const url = this.generateUrl(ciphertext, 'nip04_decrypt', id, pubkey);
|
|
47
|
+
window.location.href = url;
|
|
48
|
+
return new Promise(() => {});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async encrypt44(pubkey: string, plaintext: string): Promise<string> {
|
|
52
|
+
const id = Math.random().toString(36).substring(7);
|
|
53
|
+
const url = this.generateUrl(plaintext, 'nip44_encrypt', id, pubkey);
|
|
54
|
+
window.location.href = url;
|
|
55
|
+
return new Promise(() => {});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async decrypt44(pubkey: string, ciphertext: string): Promise<string> {
|
|
59
|
+
const id = Math.random().toString(36).substring(7);
|
|
60
|
+
const url = this.generateUrl(ciphertext, 'nip44_decrypt', id, pubkey);
|
|
61
|
+
window.location.href = url;
|
|
62
|
+
return new Promise(() => {});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
public async getPublicKey(): Promise<string> {
|
|
66
|
+
const id = Math.random().toString(36).substring(7);
|
|
67
|
+
const url = this.generateUrl('', 'get_public_key', id);
|
|
68
|
+
window.location.href = url;
|
|
69
|
+
return new Promise(() => {});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
private generateUrl(content: string, type: string, id: string, recipient?: string): string {
|
|
73
|
+
const callbackUrl = new URL(window.location.href);
|
|
74
|
+
callbackUrl.searchParams.set('amberType', type);
|
|
75
|
+
callbackUrl.searchParams.set('amberId', id);
|
|
76
|
+
|
|
77
|
+
const params = new URLSearchParams();
|
|
78
|
+
params.set('type', type);
|
|
79
|
+
params.set('id', id);
|
|
80
|
+
params.set('callbackUrl', callbackUrl.toString());
|
|
81
|
+
if (this._pubkey) params.set('pubkey', this._pubkey);
|
|
82
|
+
if (recipient) params.set('pubkey', recipient); // Amber uses pubkey param for recipient in encrypt/decrypt
|
|
83
|
+
|
|
84
|
+
return `nostrsigner:${encodeURIComponent(content)}?${params.toString()}`;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
public static parseResponse(): { type: string; id: string; result: string } | null {
|
|
88
|
+
const params = new URLSearchParams(window.location.search);
|
|
89
|
+
const type = params.get('amberType');
|
|
90
|
+
const id = params.get('amberId');
|
|
91
|
+
const result = params.get('signature') || params.get('result'); // Amber uses signature for events, result for others?
|
|
92
|
+
|
|
93
|
+
if (type && id && result) {
|
|
94
|
+
// Clean up URL
|
|
95
|
+
const newUrl = new URL(window.location.href);
|
|
96
|
+
newUrl.searchParams.delete('amberType');
|
|
97
|
+
newUrl.searchParams.delete('amberId');
|
|
98
|
+
newUrl.searchParams.delete('signature');
|
|
99
|
+
newUrl.searchParams.delete('result');
|
|
100
|
+
window.history.replaceState({}, '', newUrl.toString());
|
|
101
|
+
|
|
102
|
+
return { type, id, result };
|
|
103
|
+
}
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -1,19 +1,20 @@
|
|
|
1
|
-
//AuthNostrService.ts
|
|
2
1
|
import { localStorageAddAccount, bunkerUrlToInfo, isBunkerUrl, fetchProfile, getBunkerUrl, localStorageRemoveCurrentAccount, createProfile, getIcon } from '../utils';
|
|
3
2
|
import { ConnectionString, Info } from 'nostr-login-components/dist/types/types';
|
|
4
3
|
import { generatePrivateKey, getEventHash, getPublicKey, nip19 } from 'nostr-tools';
|
|
5
4
|
import { NostrLoginAuthOptions, Response } from '../types';
|
|
6
|
-
import NDK, { NDKEvent, NDKNip46Signer,
|
|
5
|
+
import NDK, { NDKEvent, NDKNip46Signer, NDKRpcResponse, NDKUser, NostrEvent } from '@nostr-dev-kit/ndk';
|
|
7
6
|
import { NostrParams } from './';
|
|
8
7
|
import { EventEmitter } from 'tseep';
|
|
9
8
|
import { Signer } from './Nostr';
|
|
10
9
|
import { Nip44 } from '../utils/nip44';
|
|
11
10
|
import { IframeNostrRpc, Nip46Signer, ReadyListener } from './Nip46';
|
|
12
|
-
|
|
11
|
+
import { PrivateKeySigner } from './Signer';
|
|
12
|
+
import { AmberDirectSigner } from './AmberDirectSigner';
|
|
13
|
+
|
|
13
14
|
|
|
14
15
|
const OUTBOX_RELAYS = ['wss://user.kindpag.es', 'wss://purplepag.es', 'wss://relay.nos.social'];
|
|
15
16
|
const DEFAULT_NOSTRCONNECT_RELAYS = ['wss://relay.nsec.app/', 'wss://ephemeral.snowflare.cc/'];
|
|
16
|
-
const CONNECT_TIMEOUT =
|
|
17
|
+
const CONNECT_TIMEOUT = 5000;
|
|
17
18
|
const NOSTRCONNECT_APPS: ConnectionString[] = [
|
|
18
19
|
{
|
|
19
20
|
name: 'Nsec.app',
|
|
@@ -41,7 +42,8 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
41
42
|
private ndk: NDK;
|
|
42
43
|
private profileNdk: NDK;
|
|
43
44
|
private signer: Nip46Signer | null = null;
|
|
44
|
-
private
|
|
45
|
+
private amberSigner: AmberDirectSigner | null = null;
|
|
46
|
+
private localSigner: PrivateKeySigner | null = null;
|
|
45
47
|
private params: NostrParams;
|
|
46
48
|
private signerPromise?: Promise<void>;
|
|
47
49
|
private signerErrCallback?: (err: string) => void;
|
|
@@ -83,6 +85,31 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
83
85
|
encrypt: this.encrypt44.bind(this),
|
|
84
86
|
decrypt: this.decrypt44.bind(this),
|
|
85
87
|
};
|
|
88
|
+
|
|
89
|
+
this.checkAmberResponse();
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
private checkAmberResponse() {
|
|
93
|
+
const response = AmberDirectSigner.parseResponse();
|
|
94
|
+
if (response) {
|
|
95
|
+
if (response.type === 'get_public_key') {
|
|
96
|
+
const info: Info = {
|
|
97
|
+
pubkey: response.result,
|
|
98
|
+
authMethod: 'amber' as any,
|
|
99
|
+
};
|
|
100
|
+
this.onAuth('login', info);
|
|
101
|
+
} else {
|
|
102
|
+
// For other types, we might want to store the result in a way
|
|
103
|
+
// that the next call to the same method can return it immediately
|
|
104
|
+
// but for now, we just log it.
|
|
105
|
+
console.log('Amber response', response);
|
|
106
|
+
if (response.type === 'sign_event') {
|
|
107
|
+
// If it's a signed event, we could potentially use it if someone asks for it.
|
|
108
|
+
// But usually the app will re-request signing.
|
|
109
|
+
// A better way would be to have a session-based cache.
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
86
113
|
}
|
|
87
114
|
|
|
88
115
|
public isIframe() {
|
|
@@ -93,13 +120,13 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
93
120
|
if (this.signerPromise) {
|
|
94
121
|
try {
|
|
95
122
|
await this.signerPromise;
|
|
96
|
-
} catch {}
|
|
123
|
+
} catch { }
|
|
97
124
|
}
|
|
98
125
|
|
|
99
126
|
if (this.readyPromise) {
|
|
100
127
|
try {
|
|
101
128
|
await this.readyPromise;
|
|
102
|
-
} catch {}
|
|
129
|
+
} catch { }
|
|
103
130
|
}
|
|
104
131
|
}
|
|
105
132
|
|
|
@@ -124,6 +151,7 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
124
151
|
) {
|
|
125
152
|
relays = relays && relays.length > 0 ? relays : DEFAULT_NOSTRCONNECT_RELAYS;
|
|
126
153
|
|
|
154
|
+
|
|
127
155
|
const info: Info = {
|
|
128
156
|
authMethod: 'connect',
|
|
129
157
|
pubkey: '', // unknown yet!
|
|
@@ -137,7 +165,13 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
137
165
|
console.log('nostrconnect info', info, link);
|
|
138
166
|
|
|
139
167
|
// non-iframe flow
|
|
140
|
-
if (link && !iframeUrl)
|
|
168
|
+
if (link && !iframeUrl) {
|
|
169
|
+
if (link === 'amber') {
|
|
170
|
+
const signer = new AmberDirectSigner();
|
|
171
|
+
return (signer as any).getPublicKey(); // will redirect
|
|
172
|
+
}
|
|
173
|
+
window.open(link, '_blank', 'width=400,height=700');
|
|
174
|
+
}
|
|
141
175
|
|
|
142
176
|
// init nip46 signer
|
|
143
177
|
await this.initSigner(info, { listen: true });
|
|
@@ -154,6 +188,13 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
154
188
|
}
|
|
155
189
|
|
|
156
190
|
public async createNostrConnect(relays?: string[]) {
|
|
191
|
+
/*const relayList = relays
|
|
192
|
+
? relays
|
|
193
|
+
.split(",")
|
|
194
|
+
.map(r => r.trim().replace(/['"]/g, ""))
|
|
195
|
+
.filter(r => r.length > 0)
|
|
196
|
+
: [];*/
|
|
197
|
+
|
|
157
198
|
this.nostrConnectKey = generatePrivateKey();
|
|
158
199
|
this.nostrConnectSecret = Math.random().toString(36).substring(7);
|
|
159
200
|
|
|
@@ -165,16 +206,24 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
165
206
|
perms: encodeURIComponent(this.params.optionsModal.perms || ''),
|
|
166
207
|
};
|
|
167
208
|
|
|
168
|
-
|
|
169
|
-
const relayParams = (relays || []).length > 0 ? (relays || []).map(r => `&relay=${encodeURIComponent(r)}`).join('') : '';
|
|
170
|
-
|
|
171
|
-
return `nostrconnect://${pubkey}?image=${meta.icon}&url=${meta.url}&name=${meta.name}&perms=${meta.perms}&secret=${this.nostrConnectSecret}${relayParams}`;
|
|
209
|
+
return `nostrconnect://${pubkey}?image=${meta.icon}&url=${meta.url}&name=${meta.name}&perms=${meta.perms}&secret=${this.nostrConnectSecret}${(relays || []).length > 0 ? (relays || []).map((r, i) => `&relay=${r}`) : ""}`;
|
|
172
210
|
}
|
|
173
211
|
|
|
174
212
|
public async getNostrConnectServices(): Promise<[string, ConnectionString[]]> {
|
|
175
|
-
const nostrconnect = await this.createNostrConnect(
|
|
213
|
+
const nostrconnect = await this.createNostrConnect();
|
|
176
214
|
|
|
215
|
+
// copy defaults
|
|
177
216
|
const apps = NOSTRCONNECT_APPS.map(a => ({ ...a }));
|
|
217
|
+
// if (this.params.optionsModal.dev) {
|
|
218
|
+
// apps.push({
|
|
219
|
+
// name: 'Dev.Nsec.app',
|
|
220
|
+
// domain: 'new.nsec.app',
|
|
221
|
+
// canImport: true,
|
|
222
|
+
// img: 'https://new.nsec.app/assets/favicon.ico',
|
|
223
|
+
// link: 'https://dev.nsec.app/<nostrconnect>',
|
|
224
|
+
// relay: 'wss://relay.nsec.app/',
|
|
225
|
+
// });
|
|
226
|
+
// }
|
|
178
227
|
|
|
179
228
|
for (const a of apps) {
|
|
180
229
|
let relays: string[] = [...DEFAULT_NOSTRCONNECT_RELAYS];
|
|
@@ -196,12 +245,18 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
196
245
|
}
|
|
197
246
|
}
|
|
198
247
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
248
|
+
const relayParams = relays
|
|
249
|
+
.map(r => r.replace(/['"]/g, ''))
|
|
250
|
+
.map(r => `&relay=${encodeURIComponent(r)}`)
|
|
251
|
+
.join('');
|
|
252
|
+
|
|
253
|
+
const nc = nostrconnect + relayParams;
|
|
203
254
|
|
|
204
|
-
|
|
255
|
+
if (a.iframeUrl) {
|
|
256
|
+
a.link = nc;
|
|
257
|
+
} else {
|
|
258
|
+
a.link = a.link.replace('<nostrconnect>', nc);
|
|
259
|
+
}
|
|
205
260
|
}
|
|
206
261
|
|
|
207
262
|
return [nostrconnect, apps];
|
|
@@ -223,7 +278,7 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
223
278
|
|
|
224
279
|
public async setLocal(info: Info, signup?: boolean) {
|
|
225
280
|
this.releaseSigner();
|
|
226
|
-
this.localSigner = new
|
|
281
|
+
this.localSigner = new PrivateKeySigner(info.sk!);
|
|
227
282
|
|
|
228
283
|
if (signup) await createProfile(info, this.profileNdk, this.localSigner, this.params.optionsModal.signupRelays, this.params.optionsModal.outboxRelays);
|
|
229
284
|
|
|
@@ -278,6 +333,12 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
278
333
|
await this.endAuth();
|
|
279
334
|
}
|
|
280
335
|
|
|
336
|
+
public async setAmber(info: Info) {
|
|
337
|
+
this.releaseSigner();
|
|
338
|
+
this.amberSigner = new AmberDirectSigner(info.pubkey);
|
|
339
|
+
this.onAuth('login', info);
|
|
340
|
+
}
|
|
341
|
+
|
|
281
342
|
public async createAccount(nip05: string) {
|
|
282
343
|
const [name, domain] = nip05.split('@');
|
|
283
344
|
|
|
@@ -297,7 +358,9 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
297
358
|
const userPubkey = await this.signer!.createAccount2({ bunkerPubkey: info.signerPubkey!, name, domain, perms: this.params.optionsModal.perms });
|
|
298
359
|
|
|
299
360
|
return {
|
|
300
|
-
bunkerUrl:
|
|
361
|
+
bunkerUrl:
|
|
362
|
+
`bunker://${userPubkey}?` +
|
|
363
|
+
(info.relays ?? []).map((r: string) => `relay=${encodeURIComponent(r)}`).join('&'),
|
|
301
364
|
sk: info.sk,
|
|
302
365
|
};
|
|
303
366
|
}
|
|
@@ -306,6 +369,7 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
306
369
|
this.signer = null;
|
|
307
370
|
this.signerErrCallback?.('cancelled');
|
|
308
371
|
this.localSigner = null;
|
|
372
|
+
this.amberSigner = null;
|
|
309
373
|
|
|
310
374
|
// disconnect from signer relays
|
|
311
375
|
for (const r of this.ndk.pool.relays.keys()) {
|
|
@@ -348,7 +412,7 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
348
412
|
if (info && this.params.userInfo && (info.pubkey !== this.params.userInfo.pubkey || info.authMethod !== this.params.userInfo.authMethod)) {
|
|
349
413
|
const event = new CustomEvent('nlAuth', { detail: { type: 'logout' } });
|
|
350
414
|
console.log('nostr-login auth', event.detail);
|
|
351
|
-
document.dispatchEvent(event)
|
|
415
|
+
document.dispatchEvent(event)
|
|
352
416
|
}
|
|
353
417
|
|
|
354
418
|
this.setUserInfo(info);
|
|
@@ -485,7 +549,7 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
485
549
|
}
|
|
486
550
|
|
|
487
551
|
public async startAuth() {
|
|
488
|
-
console.log(
|
|
552
|
+
console.log("startAuth");
|
|
489
553
|
if (this.readyCallback) throw new Error('Already started');
|
|
490
554
|
|
|
491
555
|
// start the new promise
|
|
@@ -529,100 +593,81 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
529
593
|
if (this.signerPromise) {
|
|
530
594
|
try {
|
|
531
595
|
await this.signerPromise;
|
|
532
|
-
} catch {}
|
|
596
|
+
} catch { }
|
|
533
597
|
}
|
|
534
598
|
|
|
599
|
+
// we remove support for iframe from nip05 and bunker-url methods,
|
|
600
|
+
// only nostrconnect flow will use it.
|
|
601
|
+
// info.iframeUrl = info.iframeUrl || (await this.getIframeUrl(info.domain));
|
|
535
602
|
console.log('initSigner info', info);
|
|
536
603
|
|
|
604
|
+
// start listening for the ready signal
|
|
537
605
|
const iframeOrigin = info.iframeUrl ? new URL(info.iframeUrl!).origin : undefined;
|
|
606
|
+
if (iframeOrigin) this.starterReady = new ReadyListener(['starterDone', 'starterError'], iframeOrigin);
|
|
538
607
|
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
}
|
|
542
|
-
|
|
608
|
+
// notify modals so they could show the starter iframe,
|
|
609
|
+
// FIXME shouldn't this come from nostrconnect service list?
|
|
543
610
|
this.emit('onIframeUrl', info.iframeUrl);
|
|
544
611
|
|
|
545
612
|
this.signerPromise = new Promise<void>(async (ok, err) => {
|
|
546
613
|
this.signerErrCallback = err;
|
|
547
|
-
|
|
548
614
|
try {
|
|
549
|
-
|
|
550
|
-
|
|
615
|
+
// pre-connect if we're creating the connection (listen|connect) or
|
|
616
|
+
// not iframe mode
|
|
551
617
|
if (info.relays && !info.iframeUrl) {
|
|
552
618
|
for (const r of info.relays) {
|
|
553
619
|
this.ndk.addExplicitRelay(r, undefined);
|
|
554
|
-
console.log('Added relay:', r);
|
|
555
620
|
}
|
|
556
621
|
}
|
|
557
622
|
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
this.ndk.connect(CONNECT_TIMEOUT).then(value => {
|
|
562
|
-
console.log(value);
|
|
563
|
-
});
|
|
564
|
-
|
|
565
|
-
// 少なくとも1つ接続されるのを待つ(致命扱いしない)
|
|
566
|
-
await new Promise<void>(resolve => {
|
|
567
|
-
const start = Date.now();
|
|
568
|
-
|
|
569
|
-
const timer = setInterval(() => {
|
|
570
|
-
const connected = this.ndk.pool.connectedRelays();
|
|
571
|
-
|
|
572
|
-
if (connected.length > 0) {
|
|
573
|
-
clearInterval(timer);
|
|
574
|
-
resolve();
|
|
575
|
-
return;
|
|
576
|
-
}
|
|
577
|
-
|
|
578
|
-
if (Date.now() - start > CONNECT_TIMEOUT) {
|
|
579
|
-
// タイムアウトしても続行
|
|
580
|
-
clearInterval(timer);
|
|
581
|
-
resolve();
|
|
582
|
-
}
|
|
583
|
-
}, 3000);
|
|
584
|
-
});
|
|
585
|
-
|
|
586
|
-
console.log(
|
|
587
|
-
'NDK connected relays:',
|
|
588
|
-
this.ndk.pool.connectedRelays().map(r => r.url),
|
|
589
|
-
);
|
|
623
|
+
// wait until we connect, otherwise
|
|
624
|
+
// signer won't start properly
|
|
625
|
+
await this.ndk.connect(CONNECT_TIMEOUT);
|
|
590
626
|
|
|
591
|
-
|
|
627
|
+
// create and prepare the signer
|
|
628
|
+
const localSigner = new PrivateKeySigner(info.sk!);
|
|
592
629
|
this.signer = new Nip46Signer(this.ndk, localSigner, info.signerPubkey!, iframeOrigin);
|
|
593
630
|
|
|
594
|
-
|
|
631
|
+
// we should notify the banner the same way as
|
|
632
|
+
// the onAuthUrl does
|
|
633
|
+
this.signer.on(`iframeRestart`, async () => {
|
|
595
634
|
const iframeUrl = info.iframeUrl + (info.iframeUrl!.includes('?') ? '&' : '?') + 'pubkey=' + info.pubkey + '&rebind=' + localSigner.pubkey;
|
|
596
|
-
|
|
597
|
-
this.emit('iframeRestart', {
|
|
598
|
-
pubkey: info.pubkey,
|
|
599
|
-
iframeUrl,
|
|
600
|
-
});
|
|
635
|
+
this.emit('iframeRestart', { pubkey: info.pubkey, iframeUrl });
|
|
601
636
|
});
|
|
602
637
|
|
|
638
|
+
// OAuth flow
|
|
639
|
+
// if (!listen) {
|
|
603
640
|
this.signer.on('authUrl', (url: string) => {
|
|
604
641
|
console.log('nostr login auth url', url);
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
eventToAddAccount,
|
|
609
|
-
});
|
|
642
|
+
|
|
643
|
+
// notify our UI
|
|
644
|
+
this.emit('onAuthUrl', { url, iframeUrl: info.iframeUrl, eventToAddAccount });
|
|
610
645
|
});
|
|
646
|
+
// }
|
|
611
647
|
|
|
612
648
|
if (listen) {
|
|
649
|
+
// nostrconnect: flow
|
|
650
|
+
// wait for the incoming message from signer
|
|
613
651
|
await this.listen(info);
|
|
614
652
|
} else if (connect) {
|
|
653
|
+
// bunker: flow
|
|
654
|
+
// send 'connect' message to signer
|
|
615
655
|
await this.connect(info, this.params.optionsModal.perms);
|
|
616
656
|
} else {
|
|
617
|
-
|
|
657
|
+
// provide saved pubkey as a hint
|
|
658
|
+
await this.signer!.initUserPubkey(info.pubkey);
|
|
618
659
|
}
|
|
619
660
|
|
|
620
|
-
|
|
621
|
-
info
|
|
661
|
+
// ensure, we're using it in callbacks above
|
|
662
|
+
// and expect info to be valid after this call
|
|
663
|
+
info.pubkey = this.signer!.userPubkey;
|
|
664
|
+
// learned after nostrconnect flow
|
|
665
|
+
info.signerPubkey = this.signer!.remotePubkey;
|
|
622
666
|
|
|
623
667
|
ok();
|
|
624
668
|
} catch (e) {
|
|
625
669
|
console.log('initSigner failure', e);
|
|
670
|
+
// make sure signer isn't set
|
|
626
671
|
this.signer = null;
|
|
627
672
|
err(e);
|
|
628
673
|
}
|
|
@@ -674,6 +719,10 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
674
719
|
event.pubkey = getPublicKey(this.localSigner.privateKey!);
|
|
675
720
|
event.id = getEventHash(event);
|
|
676
721
|
event.sig = await this.localSigner.sign(event);
|
|
722
|
+
} else if (this.params.userInfo?.authMethod === ('amber' as any)) {
|
|
723
|
+
const userInfo = this.params.userInfo!;
|
|
724
|
+
if (!this.amberSigner) this.amberSigner = new AmberDirectSigner(userInfo.pubkey);
|
|
725
|
+
return this.amberSigner.signEvent(event);
|
|
677
726
|
} else {
|
|
678
727
|
event.pubkey = this.signer?.remotePubkey;
|
|
679
728
|
event.id = getEventHash(event);
|
|
@@ -706,6 +755,10 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
706
755
|
public async encrypt04(pubkey: string, plaintext: string) {
|
|
707
756
|
if (this.localSigner) {
|
|
708
757
|
return this.localSigner.encrypt(new NDKUser({ pubkey }), plaintext);
|
|
758
|
+
} else if (this.params.userInfo?.authMethod === ('amber' as any)) {
|
|
759
|
+
const userInfo = this.params.userInfo!;
|
|
760
|
+
if (!this.amberSigner) this.amberSigner = new AmberDirectSigner(userInfo.pubkey);
|
|
761
|
+
return this.amberSigner.encrypt04(pubkey, plaintext);
|
|
709
762
|
} else {
|
|
710
763
|
return this.signer!.encrypt(new NDKUser({ pubkey }), plaintext);
|
|
711
764
|
}
|
|
@@ -714,6 +767,10 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
714
767
|
public async decrypt04(pubkey: string, ciphertext: string) {
|
|
715
768
|
if (this.localSigner) {
|
|
716
769
|
return this.localSigner.decrypt(new NDKUser({ pubkey }), ciphertext);
|
|
770
|
+
} else if (this.params.userInfo?.authMethod === ('amber' as any)) {
|
|
771
|
+
const userInfo = this.params.userInfo!;
|
|
772
|
+
if (!this.amberSigner) this.amberSigner = new AmberDirectSigner(userInfo.pubkey);
|
|
773
|
+
return this.amberSigner.decrypt04(pubkey, ciphertext);
|
|
717
774
|
} else {
|
|
718
775
|
// decrypt is broken in ndk v2.3.1, and latest
|
|
719
776
|
// ndk v2.8.1 doesn't allow to override connect easily,
|
|
@@ -726,6 +783,10 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
726
783
|
public async encrypt44(pubkey: string, plaintext: string) {
|
|
727
784
|
if (this.localSigner) {
|
|
728
785
|
return this.nip44Codec.encrypt(this.localSigner.privateKey!, pubkey, plaintext);
|
|
786
|
+
} else if (this.params.userInfo?.authMethod === ('amber' as any)) {
|
|
787
|
+
const userInfo = this.params.userInfo!;
|
|
788
|
+
if (!this.amberSigner) this.amberSigner = new AmberDirectSigner(userInfo.pubkey);
|
|
789
|
+
return this.amberSigner.encrypt44(pubkey, plaintext);
|
|
729
790
|
} else {
|
|
730
791
|
// no support of nip44 in ndk yet
|
|
731
792
|
return this.codec_call('nip44_encrypt', pubkey, plaintext);
|
|
@@ -735,6 +796,10 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
735
796
|
public async decrypt44(pubkey: string, ciphertext: string) {
|
|
736
797
|
if (this.localSigner) {
|
|
737
798
|
return this.nip44Codec.decrypt(this.localSigner.privateKey!, pubkey, ciphertext);
|
|
799
|
+
} else if (this.params.userInfo?.authMethod === ('amber' as any)) {
|
|
800
|
+
const userInfo = this.params.userInfo!;
|
|
801
|
+
if (!this.amberSigner) this.amberSigner = new AmberDirectSigner(userInfo.pubkey);
|
|
802
|
+
return this.amberSigner.decrypt44(pubkey, ciphertext);
|
|
738
803
|
} else {
|
|
739
804
|
// no support of nip44 in ndk yet
|
|
740
805
|
return this.codec_call('nip44_decrypt', pubkey, ciphertext);
|
|
@@ -402,6 +402,9 @@ class ModalManager extends EventEmitter {
|
|
|
402
402
|
} else if (userInfo.authMethod === 'extension') {
|
|
403
403
|
await this.extensionService.trySetExtensionForPubkey(userInfo.pubkey);
|
|
404
404
|
dialog.close();
|
|
405
|
+
} else if (userInfo.authMethod === ('amber' as any)) {
|
|
406
|
+
this.authNostrService.setAmber(userInfo);
|
|
407
|
+
dialog.close();
|
|
405
408
|
} else {
|
|
406
409
|
const input = userInfo.bunkerUrl || userInfo.nip05;
|
|
407
410
|
if (!input) throw new Error('Bad connect info');
|