@konemono/nostr-login 1.11.0 → 1.11.3
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.esm.js +15 -20
- package/dist/index.esm.js.map +1 -1
- package/dist/modules/AuthNostrService.d.ts +4 -14
- package/dist/modules/Nip46.d.ts +26 -64
- package/dist/modules/Signer.d.ts +6 -12
- package/dist/unpkg.js +15 -20
- package/dist/utils/index.d.ts +3 -6
- package/dist/utils/nip44.d.ts +3 -3
- package/package.json +8 -8
- package/src/modules/AuthNostrService.ts +109 -210
- package/src/modules/ModalManager.ts +3 -3
- package/src/modules/Nip46.ts +185 -390
- package/src/modules/NostrExtensionService.ts +0 -2
- package/src/modules/Signer.ts +12 -35
- package/src/utils/index.ts +23 -73
- package/src/utils/nip44.ts +7 -12
- package/test-relay-management.html +0 -407
|
@@ -60,7 +60,6 @@ class NostrExtensionService extends EventEmitter {
|
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
private async setExtensionReadPubkey(expectedPubkey?: string) {
|
|
63
|
-
// @ts-ignore
|
|
64
63
|
window.nostr = this.nostrExtension;
|
|
65
64
|
// @ts-ignore
|
|
66
65
|
const pubkey = await window.nostr.getPublicKey();
|
|
@@ -82,7 +81,6 @@ class NostrExtensionService extends EventEmitter {
|
|
|
82
81
|
}
|
|
83
82
|
|
|
84
83
|
public unsetExtension(nostr: Nostr) {
|
|
85
|
-
// @ts-ignore
|
|
86
84
|
if (window.nostr === this.nostrExtension) {
|
|
87
85
|
// @ts-ignore
|
|
88
86
|
window.nostr = nostr;
|
package/src/modules/Signer.ts
CHANGED
|
@@ -1,48 +1,25 @@
|
|
|
1
|
+
import { NDKPrivateKeySigner, NDKUser } from '@nostr-dev-kit/ndk';
|
|
1
2
|
import { Nip44 } from '../utils/nip44';
|
|
2
|
-
import { getPublicKey
|
|
3
|
+
import { getPublicKey } from 'nostr-tools';
|
|
3
4
|
|
|
4
|
-
export class PrivateKeySigner {
|
|
5
|
-
public privateKey: Uint8Array;
|
|
5
|
+
export class PrivateKeySigner extends NDKPrivateKeySigner {
|
|
6
6
|
private nip44: Nip44 = new Nip44();
|
|
7
|
-
private
|
|
7
|
+
private _pubkey: string;
|
|
8
8
|
|
|
9
|
-
constructor(privateKey:
|
|
10
|
-
|
|
11
|
-
this.
|
|
9
|
+
constructor(privateKey: string) {
|
|
10
|
+
super(privateKey);
|
|
11
|
+
this._pubkey = getPublicKey(privateKey);
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
get pubkey() {
|
|
15
|
-
return this.
|
|
15
|
+
return this._pubkey;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
return
|
|
18
|
+
encryptNip44(recipient: NDKUser, value: string): Promise<string> {
|
|
19
|
+
return Promise.resolve(this.nip44.encrypt(this.privateKey!, recipient.pubkey, value));
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
...event,
|
|
25
|
-
created_at: event.created_at || Math.floor(Date.now() / 1000),
|
|
26
|
-
tags: event.tags || [],
|
|
27
|
-
content: event.content || '',
|
|
28
|
-
kind: event.kind
|
|
29
|
-
}, this.privateKey);
|
|
30
|
-
return signed.sig;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
async encrypt(recipientPubkey: string, value: string): Promise<string> {
|
|
34
|
-
return nip04.encrypt(this.privateKey, recipientPubkey, value);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
async decrypt(senderPubkey: string, value: string): Promise<string> {
|
|
38
|
-
return nip04.decrypt(this.privateKey, senderPubkey, value);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
async encryptNip44(recipientPubkey: string, value: string): Promise<string> {
|
|
42
|
-
return this.nip44.encrypt(this.privateKey, recipientPubkey, value);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
async decryptNip44(senderPubkey: string, value: string): Promise<string> {
|
|
46
|
-
return this.nip44.decrypt(this.privateKey, senderPubkey, value);
|
|
22
|
+
decryptNip44(sender: NDKUser, value: string): Promise<string> {
|
|
23
|
+
return Promise.resolve(this.nip44.decrypt(this.privateKey!, sender.pubkey, value));
|
|
47
24
|
}
|
|
48
25
|
}
|
package/src/utils/index.ts
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { Info, RecentType } from 'nostr-login-components/dist/types/types';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import NDK, { NDKEvent, NDKRelaySet, NDKSigner, NDKUser } from '@nostr-dev-kit/ndk';
|
|
3
|
+
import { generatePrivateKey } from 'nostr-tools';
|
|
4
4
|
import { NostrLoginOptions } from '../types';
|
|
5
|
-
import { PrivateKeySigner } from '../modules/Signer';
|
|
6
|
-
import { firstValueFrom } from 'rxjs'; // You might need to install rxjs if not present, but rx-nostr depends on it
|
|
7
5
|
|
|
8
6
|
const LOCAL_STORE_KEY = '__nostrlogin_nip46';
|
|
9
7
|
const LOGGED_IN_ACCOUNTS = '__nostrlogin_accounts';
|
|
@@ -11,19 +9,6 @@ const RECENT_ACCOUNTS = '__nostrlogin_recent';
|
|
|
11
9
|
const OUTBOX_RELAYS = ['wss://purplepag.es', 'wss://relay.nos.social', 'wss://user.kindpag.es', 'wss://relay.damus.io', 'wss://nos.lol'];
|
|
12
10
|
const DEFAULT_SIGNUP_RELAYS = ['wss://relay.damus.io/', 'wss://nos.lol/', 'wss://relay.primal.net/'];
|
|
13
11
|
|
|
14
|
-
export function bytesToHex(bytes: Uint8Array): string {
|
|
15
|
-
return Array.from(bytes).map(b => b.toString(16).padStart(2, '0')).join('');
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export function hexToBytes(hex: string): Uint8Array {
|
|
19
|
-
if (hex.length % 2 !== 0) throw new Error('Invalid hex string');
|
|
20
|
-
const bytes = new Uint8Array(hex.length / 2);
|
|
21
|
-
for (let i = 0; i < bytes.length; i++) {
|
|
22
|
-
bytes[i] = parseInt(hex.substr(i * 2, 2), 16);
|
|
23
|
-
}
|
|
24
|
-
return bytes;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
12
|
export const localStorageSetItem = (key: string, value: string) => {
|
|
28
13
|
localStorage.setItem(key, value);
|
|
29
14
|
};
|
|
@@ -34,7 +19,7 @@ export const localStorageGetItem = (key: string) => {
|
|
|
34
19
|
if (value) {
|
|
35
20
|
try {
|
|
36
21
|
return JSON.parse(value);
|
|
37
|
-
} catch {
|
|
22
|
+
} catch {}
|
|
38
23
|
}
|
|
39
24
|
|
|
40
25
|
return null;
|
|
@@ -44,30 +29,12 @@ export const localStorageRemoveItem = (key: string) => {
|
|
|
44
29
|
localStorage.removeItem(key);
|
|
45
30
|
};
|
|
46
31
|
|
|
47
|
-
export const fetchProfile = async (info: Info,
|
|
48
|
-
|
|
49
|
-
const req = createRxForwardReq();
|
|
50
|
-
const sub = rxNostr.use(req);
|
|
51
|
-
|
|
52
|
-
// We want the first event (replace specific logic handled by rx-nostr/relay usually, but here just take first)
|
|
53
|
-
// Actually we should wait for EOSE or timeout?
|
|
54
|
-
// For simplicity, let's try to get the latest kind 0.
|
|
32
|
+
export const fetchProfile = async (info: Info, profileNdk: NDK) => {
|
|
33
|
+
const user = new NDKUser({ pubkey: info.pubkey });
|
|
55
34
|
|
|
56
|
-
|
|
35
|
+
user.ndk = profileNdk;
|
|
57
36
|
|
|
58
|
-
|
|
59
|
-
const packet = await firstValueFrom(sub);
|
|
60
|
-
if (packet && packet.event) {
|
|
61
|
-
try {
|
|
62
|
-
return JSON.parse(packet.event.content);
|
|
63
|
-
} catch (e) {
|
|
64
|
-
console.error("Failed to parse profile content", e);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
} catch (e) {
|
|
68
|
-
console.log("Profile fetch timeout or error", e);
|
|
69
|
-
}
|
|
70
|
-
return null;
|
|
37
|
+
return await user.fetchProfile();
|
|
71
38
|
};
|
|
72
39
|
|
|
73
40
|
export const prepareSignupRelays = (signupRelays?: string) => {
|
|
@@ -79,70 +46,53 @@ export const prepareSignupRelays = (signupRelays?: string) => {
|
|
|
79
46
|
return relays;
|
|
80
47
|
};
|
|
81
48
|
|
|
82
|
-
export const createProfile = async (info: Info,
|
|
49
|
+
export const createProfile = async (info: Info, profileNdk: NDK, signer: NDKSigner, signupRelays?: string, outboxRelays?: string[]) => {
|
|
83
50
|
const meta = {
|
|
84
51
|
name: info.name,
|
|
85
52
|
};
|
|
86
53
|
|
|
87
|
-
const profileEvent
|
|
54
|
+
const profileEvent = new NDKEvent(profileNdk, {
|
|
88
55
|
kind: 0,
|
|
89
56
|
created_at: Math.floor(Date.now() / 1000),
|
|
90
57
|
pubkey: info.pubkey,
|
|
91
58
|
content: JSON.stringify(meta),
|
|
92
59
|
tags: [],
|
|
93
|
-
};
|
|
60
|
+
});
|
|
94
61
|
if (window.location.hostname) profileEvent.tags.push(['client', window.location.hostname]);
|
|
95
62
|
|
|
96
|
-
const relaysEvent
|
|
63
|
+
const relaysEvent = new NDKEvent(profileNdk, {
|
|
97
64
|
kind: 10002,
|
|
98
65
|
created_at: Math.floor(Date.now() / 1000),
|
|
99
66
|
pubkey: info.pubkey,
|
|
100
67
|
content: '',
|
|
101
68
|
tags: [],
|
|
102
|
-
};
|
|
69
|
+
});
|
|
103
70
|
|
|
104
71
|
const relays = prepareSignupRelays(signupRelays)
|
|
105
72
|
for (const r of relays) {
|
|
106
73
|
relaysEvent.tags.push(['r', r]);
|
|
107
74
|
}
|
|
108
75
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
// Let's assume it returns sig or modifies event.
|
|
114
|
-
// Ideally use nostr-tools finalizeEvent if we had the key directly, but we use the signer class.
|
|
115
|
-
|
|
116
|
-
// NOTE: PrivateKeySigner.sign(event) usually returns the signature string?
|
|
117
|
-
// And we need to calculate ID.
|
|
118
|
-
// Let's update the event object with ID and Sig as we go if the signer doesn't do it fully.
|
|
76
|
+
await profileEvent.sign(signer);
|
|
77
|
+
console.log('signed profile', profileEvent);
|
|
78
|
+
await relaysEvent.sign(signer);
|
|
79
|
+
console.log('signed relays', relaysEvent);
|
|
119
80
|
|
|
120
|
-
|
|
121
|
-
// event.id = getEventHash(event);
|
|
122
|
-
// event.sig = await signer.sign(event);
|
|
81
|
+
const outboxRelaysFinal = outboxRelays && outboxRelays.length ? outboxRelays : OUTBOX_RELAYS;
|
|
123
82
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
// Actually, let's just use the signer if it encapsulates it.
|
|
129
|
-
// The 'signer' passed here is `PrivateKeySigner`.
|
|
130
|
-
// `AuthNostrService` uses `this.localSigner.sign(event)`.
|
|
131
|
-
|
|
132
|
-
// I need to import getEventHash if I am to do it manually here.
|
|
133
|
-
// Or I can update PrivateKeySigner to do it.
|
|
134
|
-
// For now I will import getEventHash at top.
|
|
83
|
+
await profileEvent.publish(NDKRelaySet.fromRelayUrls(outboxRelaysFinal, profileNdk));
|
|
84
|
+
console.log('published profile', profileEvent);
|
|
85
|
+
await relaysEvent.publish(NDKRelaySet.fromRelayUrls(outboxRelaysFinal, profileNdk));
|
|
86
|
+
console.log('published relays', relaysEvent);
|
|
135
87
|
};
|
|
136
88
|
|
|
137
89
|
export const bunkerUrlToInfo = (bunkerUrl: string, sk = ''): Info => {
|
|
138
90
|
const url = new URL(bunkerUrl);
|
|
139
91
|
|
|
140
|
-
const skHex = sk || bytesToHex(generateSecretKey());
|
|
141
|
-
|
|
142
92
|
return {
|
|
143
93
|
pubkey: '',
|
|
144
94
|
signerPubkey: url.hostname || url.pathname.split('//')[1],
|
|
145
|
-
sk:
|
|
95
|
+
sk: sk || generatePrivateKey(),
|
|
146
96
|
relays: url.searchParams.getAll('relay'),
|
|
147
97
|
token: url.searchParams.get('secret') || '',
|
|
148
98
|
authMethod: 'connect',
|
|
@@ -215,7 +165,7 @@ export const checkNip05 = async (nip05: string) => {
|
|
|
215
165
|
pubkey = d.names[name];
|
|
216
166
|
return;
|
|
217
167
|
}
|
|
218
|
-
} catch {
|
|
168
|
+
} catch {}
|
|
219
169
|
|
|
220
170
|
available = true;
|
|
221
171
|
})();
|
package/src/utils/nip44.ts
CHANGED
|
@@ -10,7 +10,6 @@ import { sha256 } from "@noble/hashes/sha256"
|
|
|
10
10
|
import { hmac } from "@noble/hashes/hmac";
|
|
11
11
|
import { base64 } from "@scure/base";
|
|
12
12
|
import { getPublicKey } from 'nostr-tools'
|
|
13
|
-
import { hexToBytes, bytesToHex } from './index'
|
|
14
13
|
|
|
15
14
|
// from https://github.com/nbd-wtf/nostr-tools
|
|
16
15
|
|
|
@@ -160,30 +159,26 @@ export function decryptNip44(payload: string, conversationKey: Uint8Array): stri
|
|
|
160
159
|
export class Nip44 {
|
|
161
160
|
private cache = new Map<string, Uint8Array>()
|
|
162
161
|
|
|
163
|
-
public createKey(privkey: string
|
|
164
|
-
|
|
165
|
-
// but explicit cast might be needed if type defs are strict
|
|
166
|
-
return u.getConversationKey(privkey as any, pubkey)
|
|
162
|
+
public createKey(privkey: string, pubkey: string) {
|
|
163
|
+
return u.getConversationKey(privkey, pubkey)
|
|
167
164
|
}
|
|
168
165
|
|
|
169
|
-
private getKey(privkey: string
|
|
170
|
-
const
|
|
171
|
-
const privHex = typeof privkey === 'string' ? privkey : bytesToHex(privkey);
|
|
172
|
-
const id = getPublicKey(privBytes) + pubkey
|
|
166
|
+
private getKey(privkey: string, pubkey: string, extractable?: boolean) {
|
|
167
|
+
const id = getPublicKey(privkey) + pubkey
|
|
173
168
|
let cryptoKey = this.cache.get(id)
|
|
174
169
|
if (cryptoKey) return cryptoKey
|
|
175
170
|
|
|
176
|
-
const key = this.createKey(
|
|
171
|
+
const key = this.createKey(privkey, pubkey)
|
|
177
172
|
this.cache.set(id, key)
|
|
178
173
|
return key
|
|
179
174
|
}
|
|
180
175
|
|
|
181
|
-
public encrypt(privkey: string
|
|
176
|
+
public encrypt(privkey: string, pubkey: string, text: string): string {
|
|
182
177
|
const key = this.getKey(privkey, pubkey)
|
|
183
178
|
return encryptNip44(text, key)
|
|
184
179
|
}
|
|
185
180
|
|
|
186
|
-
public decrypt(privkey: string
|
|
181
|
+
public decrypt(privkey: string, pubkey: string, data: string): string {
|
|
187
182
|
const key = this.getKey(privkey, pubkey)
|
|
188
183
|
return decryptNip44(data, key)
|
|
189
184
|
}
|