@konemono/nostr-login 1.7.50 → 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/package.json
CHANGED
|
@@ -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
|
+
}
|
|
@@ -9,6 +9,8 @@ import { Signer } from './Nostr';
|
|
|
9
9
|
import { Nip44 } from '../utils/nip44';
|
|
10
10
|
import { IframeNostrRpc, Nip46Signer, ReadyListener } from './Nip46';
|
|
11
11
|
import { PrivateKeySigner } from './Signer';
|
|
12
|
+
import { AmberDirectSigner } from './AmberDirectSigner';
|
|
13
|
+
|
|
12
14
|
|
|
13
15
|
const OUTBOX_RELAYS = ['wss://user.kindpag.es', 'wss://purplepag.es', 'wss://relay.nos.social'];
|
|
14
16
|
const DEFAULT_NOSTRCONNECT_RELAYS = ['wss://relay.nsec.app/', 'wss://ephemeral.snowflare.cc/'];
|
|
@@ -40,6 +42,7 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
40
42
|
private ndk: NDK;
|
|
41
43
|
private profileNdk: NDK;
|
|
42
44
|
private signer: Nip46Signer | null = null;
|
|
45
|
+
private amberSigner: AmberDirectSigner | null = null;
|
|
43
46
|
private localSigner: PrivateKeySigner | null = null;
|
|
44
47
|
private params: NostrParams;
|
|
45
48
|
private signerPromise?: Promise<void>;
|
|
@@ -82,6 +85,31 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
82
85
|
encrypt: this.encrypt44.bind(this),
|
|
83
86
|
decrypt: this.decrypt44.bind(this),
|
|
84
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
|
+
}
|
|
85
113
|
}
|
|
86
114
|
|
|
87
115
|
public isIframe() {
|
|
@@ -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 });
|
|
@@ -299,6 +333,12 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
299
333
|
await this.endAuth();
|
|
300
334
|
}
|
|
301
335
|
|
|
336
|
+
public async setAmber(info: Info) {
|
|
337
|
+
this.releaseSigner();
|
|
338
|
+
this.amberSigner = new AmberDirectSigner(info.pubkey);
|
|
339
|
+
this.onAuth('login', info);
|
|
340
|
+
}
|
|
341
|
+
|
|
302
342
|
public async createAccount(nip05: string) {
|
|
303
343
|
const [name, domain] = nip05.split('@');
|
|
304
344
|
|
|
@@ -329,6 +369,7 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
329
369
|
this.signer = null;
|
|
330
370
|
this.signerErrCallback?.('cancelled');
|
|
331
371
|
this.localSigner = null;
|
|
372
|
+
this.amberSigner = null;
|
|
332
373
|
|
|
333
374
|
// disconnect from signer relays
|
|
334
375
|
for (const r of this.ndk.pool.relays.keys()) {
|
|
@@ -678,6 +719,10 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
678
719
|
event.pubkey = getPublicKey(this.localSigner.privateKey!);
|
|
679
720
|
event.id = getEventHash(event);
|
|
680
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);
|
|
681
726
|
} else {
|
|
682
727
|
event.pubkey = this.signer?.remotePubkey;
|
|
683
728
|
event.id = getEventHash(event);
|
|
@@ -710,6 +755,10 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
710
755
|
public async encrypt04(pubkey: string, plaintext: string) {
|
|
711
756
|
if (this.localSigner) {
|
|
712
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);
|
|
713
762
|
} else {
|
|
714
763
|
return this.signer!.encrypt(new NDKUser({ pubkey }), plaintext);
|
|
715
764
|
}
|
|
@@ -718,6 +767,10 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
718
767
|
public async decrypt04(pubkey: string, ciphertext: string) {
|
|
719
768
|
if (this.localSigner) {
|
|
720
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);
|
|
721
774
|
} else {
|
|
722
775
|
// decrypt is broken in ndk v2.3.1, and latest
|
|
723
776
|
// ndk v2.8.1 doesn't allow to override connect easily,
|
|
@@ -730,6 +783,10 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
730
783
|
public async encrypt44(pubkey: string, plaintext: string) {
|
|
731
784
|
if (this.localSigner) {
|
|
732
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);
|
|
733
790
|
} else {
|
|
734
791
|
// no support of nip44 in ndk yet
|
|
735
792
|
return this.codec_call('nip44_encrypt', pubkey, plaintext);
|
|
@@ -739,6 +796,10 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
739
796
|
public async decrypt44(pubkey: string, ciphertext: string) {
|
|
740
797
|
if (this.localSigner) {
|
|
741
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);
|
|
742
803
|
} else {
|
|
743
804
|
// no support of nip44 in ndk yet
|
|
744
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');
|