@konemono/nostr-login 1.7.50 → 1.7.52
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/'];
|
|
@@ -28,6 +30,12 @@ const NOSTRCONNECT_APPS: ConnectionString[] = [
|
|
|
28
30
|
link: '<nostrconnect>',
|
|
29
31
|
relays: DEFAULT_NOSTRCONNECT_RELAYS,
|
|
30
32
|
},
|
|
33
|
+
{
|
|
34
|
+
name: 'Amber (Direct)',
|
|
35
|
+
img: 'https://raw.githubusercontent.com/greenart7c3/Amber/refs/heads/master/assets/android-icon.svg',
|
|
36
|
+
link: 'amber',
|
|
37
|
+
relays: DEFAULT_NOSTRCONNECT_RELAYS,
|
|
38
|
+
},
|
|
31
39
|
{
|
|
32
40
|
name: 'Other key stores',
|
|
33
41
|
img: '',
|
|
@@ -40,6 +48,7 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
40
48
|
private ndk: NDK;
|
|
41
49
|
private profileNdk: NDK;
|
|
42
50
|
private signer: Nip46Signer | null = null;
|
|
51
|
+
private amberSigner: AmberDirectSigner | null = null;
|
|
43
52
|
private localSigner: PrivateKeySigner | null = null;
|
|
44
53
|
private params: NostrParams;
|
|
45
54
|
private signerPromise?: Promise<void>;
|
|
@@ -82,6 +91,31 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
82
91
|
encrypt: this.encrypt44.bind(this),
|
|
83
92
|
decrypt: this.decrypt44.bind(this),
|
|
84
93
|
};
|
|
94
|
+
|
|
95
|
+
this.checkAmberResponse();
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
private checkAmberResponse() {
|
|
99
|
+
const response = AmberDirectSigner.parseResponse();
|
|
100
|
+
if (response) {
|
|
101
|
+
if (response.type === 'get_public_key') {
|
|
102
|
+
const info: Info = {
|
|
103
|
+
pubkey: response.result,
|
|
104
|
+
authMethod: 'amber' as any,
|
|
105
|
+
};
|
|
106
|
+
this.onAuth('login', info);
|
|
107
|
+
} else {
|
|
108
|
+
// For other types, we might want to store the result in a way
|
|
109
|
+
// that the next call to the same method can return it immediately
|
|
110
|
+
// but for now, we just log it.
|
|
111
|
+
console.log('Amber response', response);
|
|
112
|
+
if (response.type === 'sign_event') {
|
|
113
|
+
// If it's a signed event, we could potentially use it if someone asks for it.
|
|
114
|
+
// But usually the app will re-request signing.
|
|
115
|
+
// A better way would be to have a session-based cache.
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
85
119
|
}
|
|
86
120
|
|
|
87
121
|
public isIframe() {
|
|
@@ -137,7 +171,13 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
137
171
|
console.log('nostrconnect info', info, link);
|
|
138
172
|
|
|
139
173
|
// non-iframe flow
|
|
140
|
-
if (link && !iframeUrl)
|
|
174
|
+
if (link && !iframeUrl) {
|
|
175
|
+
if (link === 'amber') {
|
|
176
|
+
const signer = new AmberDirectSigner();
|
|
177
|
+
return (signer as any).getPublicKey(); // will redirect
|
|
178
|
+
}
|
|
179
|
+
window.open(link, '_blank', 'width=400,height=700');
|
|
180
|
+
}
|
|
141
181
|
|
|
142
182
|
// init nip46 signer
|
|
143
183
|
await this.initSigner(info, { listen: true });
|
|
@@ -299,6 +339,12 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
299
339
|
await this.endAuth();
|
|
300
340
|
}
|
|
301
341
|
|
|
342
|
+
public async setAmber(info: Info) {
|
|
343
|
+
this.releaseSigner();
|
|
344
|
+
this.amberSigner = new AmberDirectSigner(info.pubkey);
|
|
345
|
+
this.onAuth('login', info);
|
|
346
|
+
}
|
|
347
|
+
|
|
302
348
|
public async createAccount(nip05: string) {
|
|
303
349
|
const [name, domain] = nip05.split('@');
|
|
304
350
|
|
|
@@ -329,6 +375,7 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
329
375
|
this.signer = null;
|
|
330
376
|
this.signerErrCallback?.('cancelled');
|
|
331
377
|
this.localSigner = null;
|
|
378
|
+
this.amberSigner = null;
|
|
332
379
|
|
|
333
380
|
// disconnect from signer relays
|
|
334
381
|
for (const r of this.ndk.pool.relays.keys()) {
|
|
@@ -678,6 +725,10 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
678
725
|
event.pubkey = getPublicKey(this.localSigner.privateKey!);
|
|
679
726
|
event.id = getEventHash(event);
|
|
680
727
|
event.sig = await this.localSigner.sign(event);
|
|
728
|
+
} else if (this.params.userInfo?.authMethod === ('amber' as any)) {
|
|
729
|
+
const userInfo = this.params.userInfo!;
|
|
730
|
+
if (!this.amberSigner) this.amberSigner = new AmberDirectSigner(userInfo.pubkey);
|
|
731
|
+
return this.amberSigner.signEvent(event);
|
|
681
732
|
} else {
|
|
682
733
|
event.pubkey = this.signer?.remotePubkey;
|
|
683
734
|
event.id = getEventHash(event);
|
|
@@ -710,6 +761,10 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
710
761
|
public async encrypt04(pubkey: string, plaintext: string) {
|
|
711
762
|
if (this.localSigner) {
|
|
712
763
|
return this.localSigner.encrypt(new NDKUser({ pubkey }), plaintext);
|
|
764
|
+
} else if (this.params.userInfo?.authMethod === ('amber' as any)) {
|
|
765
|
+
const userInfo = this.params.userInfo!;
|
|
766
|
+
if (!this.amberSigner) this.amberSigner = new AmberDirectSigner(userInfo.pubkey);
|
|
767
|
+
return this.amberSigner.encrypt04(pubkey, plaintext);
|
|
713
768
|
} else {
|
|
714
769
|
return this.signer!.encrypt(new NDKUser({ pubkey }), plaintext);
|
|
715
770
|
}
|
|
@@ -718,6 +773,10 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
718
773
|
public async decrypt04(pubkey: string, ciphertext: string) {
|
|
719
774
|
if (this.localSigner) {
|
|
720
775
|
return this.localSigner.decrypt(new NDKUser({ pubkey }), ciphertext);
|
|
776
|
+
} else if (this.params.userInfo?.authMethod === ('amber' as any)) {
|
|
777
|
+
const userInfo = this.params.userInfo!;
|
|
778
|
+
if (!this.amberSigner) this.amberSigner = new AmberDirectSigner(userInfo.pubkey);
|
|
779
|
+
return this.amberSigner.decrypt04(pubkey, ciphertext);
|
|
721
780
|
} else {
|
|
722
781
|
// decrypt is broken in ndk v2.3.1, and latest
|
|
723
782
|
// ndk v2.8.1 doesn't allow to override connect easily,
|
|
@@ -730,6 +789,10 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
730
789
|
public async encrypt44(pubkey: string, plaintext: string) {
|
|
731
790
|
if (this.localSigner) {
|
|
732
791
|
return this.nip44Codec.encrypt(this.localSigner.privateKey!, pubkey, plaintext);
|
|
792
|
+
} else if (this.params.userInfo?.authMethod === ('amber' as any)) {
|
|
793
|
+
const userInfo = this.params.userInfo!;
|
|
794
|
+
if (!this.amberSigner) this.amberSigner = new AmberDirectSigner(userInfo.pubkey);
|
|
795
|
+
return this.amberSigner.encrypt44(pubkey, plaintext);
|
|
733
796
|
} else {
|
|
734
797
|
// no support of nip44 in ndk yet
|
|
735
798
|
return this.codec_call('nip44_encrypt', pubkey, plaintext);
|
|
@@ -739,6 +802,10 @@ class AuthNostrService extends EventEmitter implements Signer {
|
|
|
739
802
|
public async decrypt44(pubkey: string, ciphertext: string) {
|
|
740
803
|
if (this.localSigner) {
|
|
741
804
|
return this.nip44Codec.decrypt(this.localSigner.privateKey!, pubkey, ciphertext);
|
|
805
|
+
} else if (this.params.userInfo?.authMethod === ('amber' as any)) {
|
|
806
|
+
const userInfo = this.params.userInfo!;
|
|
807
|
+
if (!this.amberSigner) this.amberSigner = new AmberDirectSigner(userInfo.pubkey);
|
|
808
|
+
return this.amberSigner.decrypt44(pubkey, ciphertext);
|
|
742
809
|
} else {
|
|
743
810
|
// no support of nip44 in ndk yet
|
|
744
811
|
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');
|