ns-auth-sdk 1.2.6 → 1.3.0
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/README.md +33 -16
- package/dist/index.cjs +1397 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.css +115 -16
- package/dist/index.css.map +1 -1
- package/dist/index.d.cts +289 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +232 -157
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +1342 -1206
- package/dist/index.mjs.map +1 -1
- package/dist/utils-BR2TqhEA.cjs +3 -0
- package/dist/utils-BVvtCpMQ.mjs +3 -0
- package/dist/utils-CV_lg5Ir.mjs +492 -0
- package/dist/utils-CV_lg5Ir.mjs.map +1 -0
- package/dist/utils-CxLeFzNn.cjs +528 -0
- package/dist/utils-CxLeFzNn.cjs.map +1 -0
- package/package.json +18 -17
- package/dist/index.d.ts +0 -214
- package/dist/index.js +0 -1234
- package/dist/index.js.map +0 -1
|
@@ -0,0 +1,528 @@
|
|
|
1
|
+
const require_index = require('./index.cjs');
|
|
2
|
+
let rx_nostr_crypto = require("rx-nostr-crypto");
|
|
3
|
+
|
|
4
|
+
//#region src/utils/utils.ts
|
|
5
|
+
/**
|
|
6
|
+
* @packageDocumentation
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* @param bytes
|
|
10
|
+
* @returns
|
|
11
|
+
*/
|
|
12
|
+
function bytesToHex(bytes) {
|
|
13
|
+
const key = "0123456789abcdef";
|
|
14
|
+
let hex = "";
|
|
15
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
16
|
+
const firstNibble = bytes[i] >> 4;
|
|
17
|
+
const secondNibble = bytes[i] & 15;
|
|
18
|
+
hex += key[firstNibble] + key[secondNibble];
|
|
19
|
+
}
|
|
20
|
+
return hex;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* @param hex
|
|
24
|
+
* @returns
|
|
25
|
+
*/
|
|
26
|
+
function hexToBytes(hex) {
|
|
27
|
+
const key = "0123456789abcdef";
|
|
28
|
+
const bytes = [];
|
|
29
|
+
let currentByte = 0;
|
|
30
|
+
let highNibble = true;
|
|
31
|
+
for (let i = 0; i < hex.length; i++) {
|
|
32
|
+
const charValue = key.indexOf(hex[i].toLowerCase());
|
|
33
|
+
if (charValue === -1) continue;
|
|
34
|
+
if (highNibble) {
|
|
35
|
+
currentByte = charValue << 4;
|
|
36
|
+
highNibble = false;
|
|
37
|
+
} else {
|
|
38
|
+
currentByte += charValue;
|
|
39
|
+
bytes.push(currentByte);
|
|
40
|
+
highNibble = true;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return new Uint8Array(bytes);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
//#endregion
|
|
47
|
+
//#region src/utils/key-cache.ts
|
|
48
|
+
/**
|
|
49
|
+
* Key cache manager for managing temporary secret keys
|
|
50
|
+
*/
|
|
51
|
+
var KeyCache = class {
|
|
52
|
+
#cachedEntry = null;
|
|
53
|
+
#expiryTimer = null;
|
|
54
|
+
#cacheOptions = {
|
|
55
|
+
enabled: false,
|
|
56
|
+
timeoutMs: 300 * 1e3
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* KeyCache
|
|
60
|
+
* @param options
|
|
61
|
+
*/
|
|
62
|
+
constructor(options) {
|
|
63
|
+
if (options) this.#cacheOptions = {
|
|
64
|
+
...this.#cacheOptions,
|
|
65
|
+
...options
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* @param options
|
|
70
|
+
*/
|
|
71
|
+
setCacheOptions(options) {
|
|
72
|
+
if (Object.keys(options).length > 0 && this.#cachedEntry !== null) this.clearAllCachedKeys();
|
|
73
|
+
this.#cacheOptions = {
|
|
74
|
+
...this.#cacheOptions,
|
|
75
|
+
...options
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
getCacheOptions() {
|
|
79
|
+
return { ...this.#cacheOptions };
|
|
80
|
+
}
|
|
81
|
+
isEnabled() {
|
|
82
|
+
return this.#cacheOptions.enabled;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* @param credentialId
|
|
86
|
+
* @param sk
|
|
87
|
+
*/
|
|
88
|
+
setKey(credentialId, sk) {
|
|
89
|
+
if (!this.#cacheOptions.enabled) return;
|
|
90
|
+
const id = typeof credentialId === "string" ? credentialId : bytesToHex(credentialId);
|
|
91
|
+
const timeout = this.#cacheOptions.timeoutMs !== void 0 ? this.#cacheOptions.timeoutMs : 300 * 1e3;
|
|
92
|
+
const expireAt = Date.now() + timeout;
|
|
93
|
+
this.#clearCachedEntry();
|
|
94
|
+
this.#cachedEntry = {
|
|
95
|
+
id,
|
|
96
|
+
sk: new Uint8Array(sk),
|
|
97
|
+
expireAt
|
|
98
|
+
};
|
|
99
|
+
try {
|
|
100
|
+
this.#scheduleExpiry();
|
|
101
|
+
} catch (error) {
|
|
102
|
+
this.#clearCachedEntry();
|
|
103
|
+
throw error;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* @param credentialId
|
|
108
|
+
* @returns undefined
|
|
109
|
+
*/
|
|
110
|
+
getKey(credentialId) {
|
|
111
|
+
if (!this.#cacheOptions.enabled) return void 0;
|
|
112
|
+
const id = typeof credentialId === "string" ? credentialId : bytesToHex(credentialId);
|
|
113
|
+
return this.#getCachedKeyIfValid(id);
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* @param credentialId
|
|
117
|
+
*/
|
|
118
|
+
clearCachedKey(credentialId) {
|
|
119
|
+
const id = typeof credentialId === "string" ? credentialId : bytesToHex(credentialId);
|
|
120
|
+
if (this.#cachedEntry && this.#cachedEntry.id === id) this.#clearCachedEntry();
|
|
121
|
+
}
|
|
122
|
+
clearAllCachedKeys() {
|
|
123
|
+
this.#clearCachedEntry();
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* @param credentialId
|
|
127
|
+
* @returns undefined
|
|
128
|
+
*/
|
|
129
|
+
#getCachedKeyIfValid(credentialId) {
|
|
130
|
+
if (!this.#cachedEntry || this.#cachedEntry.id !== credentialId) return;
|
|
131
|
+
if (Date.now() < this.#cachedEntry.expireAt) return this.#cachedEntry.sk;
|
|
132
|
+
this.#clearCachedEntry();
|
|
133
|
+
}
|
|
134
|
+
#clearCachedEntry() {
|
|
135
|
+
if (this.#cachedEntry) {
|
|
136
|
+
this.#clearKey(this.#cachedEntry.sk);
|
|
137
|
+
this.#cachedEntry = null;
|
|
138
|
+
}
|
|
139
|
+
if (this.#expiryTimer) {
|
|
140
|
+
clearTimeout(this.#expiryTimer);
|
|
141
|
+
this.#expiryTimer = null;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
#scheduleExpiry() {
|
|
145
|
+
if (!this.#cachedEntry) return;
|
|
146
|
+
const now = Date.now();
|
|
147
|
+
const timeToExpiry = this.#cachedEntry.expireAt - now;
|
|
148
|
+
if (timeToExpiry <= 0) {
|
|
149
|
+
this.#clearCachedEntry();
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
this.#expiryTimer = setTimeout(() => {
|
|
153
|
+
this.#clearCachedEntry();
|
|
154
|
+
}, timeToExpiry + 1);
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* @param key
|
|
158
|
+
*/
|
|
159
|
+
#clearKey(key) {
|
|
160
|
+
key?.fill?.(0);
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
//#endregion
|
|
165
|
+
//#region src/utils/prf-handler.ts
|
|
166
|
+
const PRF_EVAL_INPUT = new TextEncoder().encode("nostr-pwk");
|
|
167
|
+
/**
|
|
168
|
+
* @returns PRF
|
|
169
|
+
*/
|
|
170
|
+
async function isPrfSupported() {
|
|
171
|
+
try {
|
|
172
|
+
const response = await navigator.credentials.get({ publicKey: {
|
|
173
|
+
challenge: crypto.getRandomValues(new Uint8Array(32)),
|
|
174
|
+
allowCredentials: [],
|
|
175
|
+
userVerification: "required",
|
|
176
|
+
extensions: { prf: { eval: { first: PRF_EVAL_INPUT } } }
|
|
177
|
+
} });
|
|
178
|
+
if (!response) return false;
|
|
179
|
+
return !!response.getClientExtensionResults()?.prf?.results?.first;
|
|
180
|
+
} catch {
|
|
181
|
+
return false;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* @param options
|
|
186
|
+
* @returns Credential
|
|
187
|
+
*/
|
|
188
|
+
async function createPasskey(options = {}) {
|
|
189
|
+
const rpName = options.rp?.name || (typeof location !== "undefined" ? location.host : "Nosskey");
|
|
190
|
+
const rpId = options.rp?.id;
|
|
191
|
+
const userName = options.user?.name || "user@example.com";
|
|
192
|
+
const userDisplayName = options.user?.displayName || "Nosskey user";
|
|
193
|
+
const credentialCreationOptions = { publicKey: {
|
|
194
|
+
rp: {
|
|
195
|
+
name: rpName,
|
|
196
|
+
id: rpId
|
|
197
|
+
},
|
|
198
|
+
user: {
|
|
199
|
+
id: crypto.getRandomValues(new Uint8Array(16)),
|
|
200
|
+
name: userName,
|
|
201
|
+
displayName: userDisplayName
|
|
202
|
+
},
|
|
203
|
+
pubKeyCredParams: options.pubKeyCredParams || [{
|
|
204
|
+
type: "public-key",
|
|
205
|
+
alg: -7
|
|
206
|
+
}],
|
|
207
|
+
authenticatorSelection: options.authenticatorSelection || {
|
|
208
|
+
residentKey: "required",
|
|
209
|
+
userVerification: "required"
|
|
210
|
+
},
|
|
211
|
+
challenge: crypto.getRandomValues(new Uint8Array(32)),
|
|
212
|
+
extensions: options.extensions || { prf: {} }
|
|
213
|
+
} };
|
|
214
|
+
const cred = await navigator.credentials.create(credentialCreationOptions);
|
|
215
|
+
return new Uint8Array(cred.rawId);
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* ID
|
|
219
|
+
* @param credentialId
|
|
220
|
+
* @param options PRF(rpId、timeout、userVerification)
|
|
221
|
+
* @returns PRF credentialID
|
|
222
|
+
*/
|
|
223
|
+
async function getPrfSecret(credentialId, options) {
|
|
224
|
+
const allowCredentials = credentialId ? [{
|
|
225
|
+
type: "public-key",
|
|
226
|
+
id: credentialId
|
|
227
|
+
}] : [];
|
|
228
|
+
const requestOptions = {
|
|
229
|
+
challenge: crypto.getRandomValues(new Uint8Array(32)),
|
|
230
|
+
allowCredentials,
|
|
231
|
+
userVerification: options?.userVerification || "required",
|
|
232
|
+
extensions: { prf: { eval: { first: PRF_EVAL_INPUT } } }
|
|
233
|
+
};
|
|
234
|
+
if (options?.rpId) requestOptions.rpId = options.rpId;
|
|
235
|
+
if (options?.timeout) requestOptions.timeout = options.timeout;
|
|
236
|
+
const response = await navigator.credentials.get({ publicKey: requestOptions });
|
|
237
|
+
if (!response) throw new Error("Authentication failed");
|
|
238
|
+
const secret = response.getClientExtensionResults()?.prf?.results?.first;
|
|
239
|
+
if (!secret) throw new Error("PRF secret not available");
|
|
240
|
+
const responseId = new Uint8Array(response.rawId);
|
|
241
|
+
return {
|
|
242
|
+
secret: new Uint8Array(secret),
|
|
243
|
+
id: responseId
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
//#endregion
|
|
248
|
+
//#region src/utils/nosskey.ts
|
|
249
|
+
/**
|
|
250
|
+
* Nosskey class for Passkey-Derived Nostr Identity
|
|
251
|
+
* @packageDocumentation
|
|
252
|
+
*/
|
|
253
|
+
const STANDARD_SALT = "6e6f7374722d6b6579";
|
|
254
|
+
/**
|
|
255
|
+
* Nosskey - Passkey-Derived Nostr Keys
|
|
256
|
+
*/
|
|
257
|
+
var NosskeyManager = class {
|
|
258
|
+
#keyCache;
|
|
259
|
+
#currentKeyInfo = null;
|
|
260
|
+
#storageOptions = {
|
|
261
|
+
enabled: true,
|
|
262
|
+
storageKey: "nosskey_keyinfo"
|
|
263
|
+
};
|
|
264
|
+
#prfOptions = {};
|
|
265
|
+
/**
|
|
266
|
+
* NosskeyManager
|
|
267
|
+
* @param options
|
|
268
|
+
*/
|
|
269
|
+
constructor(options) {
|
|
270
|
+
this.#keyCache = new KeyCache(options?.cacheOptions);
|
|
271
|
+
if (options?.storageOptions) this.#storageOptions = {
|
|
272
|
+
...this.#storageOptions,
|
|
273
|
+
...options.storageOptions
|
|
274
|
+
};
|
|
275
|
+
const userVerification = options?.prfOptions?.userVerification ?? "required";
|
|
276
|
+
if (options?.prfOptions) this.#prfOptions = {
|
|
277
|
+
...options.prfOptions,
|
|
278
|
+
userVerification
|
|
279
|
+
};
|
|
280
|
+
else this.#prfOptions = { userVerification };
|
|
281
|
+
if (this.#storageOptions.enabled) {
|
|
282
|
+
const loadedKeyInfo = this.#loadKeyInfoFromStorage();
|
|
283
|
+
if (loadedKeyInfo) this.#currentKeyInfo = loadedKeyInfo;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* NostrKeyInfo
|
|
288
|
+
* @param options
|
|
289
|
+
*/
|
|
290
|
+
setStorageOptions(options) {
|
|
291
|
+
this.#storageOptions = {
|
|
292
|
+
...this.#storageOptions,
|
|
293
|
+
...options
|
|
294
|
+
};
|
|
295
|
+
if (options.enabled === false) this.clearStoredKeyInfo();
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* NostrKeyInfo
|
|
299
|
+
*/
|
|
300
|
+
getStorageOptions() {
|
|
301
|
+
return { ...this.#storageOptions };
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* NostrKeyInfo
|
|
305
|
+
* @param keyInfo NostrKeyInfo
|
|
306
|
+
*/
|
|
307
|
+
setCurrentKeyInfo(keyInfo) {
|
|
308
|
+
this.#currentKeyInfo = keyInfo;
|
|
309
|
+
if (this.#storageOptions.enabled) this.#saveKeyInfoToStorage(keyInfo);
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* NostrKeyInfo
|
|
313
|
+
*/
|
|
314
|
+
getCurrentKeyInfo() {
|
|
315
|
+
if (!this.#currentKeyInfo && this.#storageOptions.enabled) this.#currentKeyInfo = this.#loadKeyInfoFromStorage();
|
|
316
|
+
return this.#currentKeyInfo;
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* NostrKeyInfo
|
|
320
|
+
* @returns NostrKeyInfo
|
|
321
|
+
*/
|
|
322
|
+
hasKeyInfo() {
|
|
323
|
+
if (this.#currentKeyInfo) return true;
|
|
324
|
+
if (this.#storageOptions.enabled) {
|
|
325
|
+
const loadedKeyInfo = this.#loadKeyInfoFromStorage();
|
|
326
|
+
if (loadedKeyInfo) {
|
|
327
|
+
this.#currentKeyInfo = loadedKeyInfo;
|
|
328
|
+
return true;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
return false;
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* NostrKeyInfo
|
|
335
|
+
* @param keyInfo NostrKeyInfo
|
|
336
|
+
*/
|
|
337
|
+
async #saveKeyInfoToStorage(keyInfo) {
|
|
338
|
+
if (!this.#storageOptions.enabled) return;
|
|
339
|
+
const storage = this.#storageOptions.storage || (typeof localStorage !== "undefined" ? localStorage : null);
|
|
340
|
+
if (!storage) return;
|
|
341
|
+
const key = this.#storageOptions.storageKey || "nosskey_keyinfo";
|
|
342
|
+
storage.setItem(key, JSON.stringify(keyInfo));
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* NostrKeyInfo
|
|
346
|
+
*/
|
|
347
|
+
#loadKeyInfoFromStorage() {
|
|
348
|
+
if (!this.#storageOptions.enabled) return null;
|
|
349
|
+
const storage = this.#storageOptions.storage || (typeof localStorage !== "undefined" ? localStorage : null);
|
|
350
|
+
if (!storage) return null;
|
|
351
|
+
const key = this.#storageOptions.storageKey || "nosskey_keyinfo";
|
|
352
|
+
const data = storage.getItem(key);
|
|
353
|
+
if (!data) return null;
|
|
354
|
+
try {
|
|
355
|
+
return JSON.parse(data);
|
|
356
|
+
} catch (e) {
|
|
357
|
+
console.error("Failed to parse stored NostrKeyInfo", e);
|
|
358
|
+
return null;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* NostrKeyInfo
|
|
363
|
+
*/
|
|
364
|
+
clearStoredKeyInfo() {
|
|
365
|
+
const storage = this.#storageOptions.storage || (typeof localStorage !== "undefined" ? localStorage : null);
|
|
366
|
+
if (!storage) return;
|
|
367
|
+
const key = this.#storageOptions.storageKey || "nosskey_keyinfo";
|
|
368
|
+
storage.removeItem(key);
|
|
369
|
+
this.#currentKeyInfo = null;
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* NIP-07
|
|
373
|
+
* NostrKeyInfo
|
|
374
|
+
*/
|
|
375
|
+
async getPublicKey() {
|
|
376
|
+
const keyInfo = this.getCurrentKeyInfo();
|
|
377
|
+
if (!keyInfo) throw new Error("No current NostrKeyInfo set");
|
|
378
|
+
return keyInfo.pubkey;
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* NIP-07
|
|
382
|
+
* NostrKeyInfo
|
|
383
|
+
* @param event Nostr
|
|
384
|
+
*/
|
|
385
|
+
async signEvent(event) {
|
|
386
|
+
const keyInfo = this.getCurrentKeyInfo();
|
|
387
|
+
if (!keyInfo) throw new Error("No current NostrKeyInfo set");
|
|
388
|
+
return this.signEventWithKeyInfo(event, keyInfo);
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* @param options
|
|
392
|
+
*/
|
|
393
|
+
setCacheOptions(options) {
|
|
394
|
+
this.#keyCache.setCacheOptions(options);
|
|
395
|
+
}
|
|
396
|
+
getCacheOptions() {
|
|
397
|
+
return this.#keyCache.getCacheOptions();
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
* @param credentialId
|
|
401
|
+
*/
|
|
402
|
+
clearCachedKey(credentialId) {
|
|
403
|
+
this.#keyCache.clearCachedKey(credentialId);
|
|
404
|
+
}
|
|
405
|
+
clearAllCachedKeys() {
|
|
406
|
+
this.#keyCache.clearAllCachedKeys();
|
|
407
|
+
}
|
|
408
|
+
/**
|
|
409
|
+
* @param options
|
|
410
|
+
* @returns Credential
|
|
411
|
+
*/
|
|
412
|
+
async createPasskey(options = {}) {
|
|
413
|
+
return createPasskey({
|
|
414
|
+
rp: {
|
|
415
|
+
id: this.#prfOptions.rpId,
|
|
416
|
+
name: this.#prfOptions.rpId
|
|
417
|
+
},
|
|
418
|
+
authenticatorSelection: { userVerification: this.#prfOptions.userVerification },
|
|
419
|
+
...options
|
|
420
|
+
});
|
|
421
|
+
}
|
|
422
|
+
/**
|
|
423
|
+
* PRF NostrKeyInfo
|
|
424
|
+
* @param credentialId
|
|
425
|
+
* @param options
|
|
426
|
+
*/
|
|
427
|
+
async createNostrKey(credentialId, options = {}) {
|
|
428
|
+
const { secret: sk, id: responseId } = await getPrfSecret(credentialId, this.#prfOptions);
|
|
429
|
+
if (sk.every((byte) => byte === 0)) throw new Error("Invalid PRF output: all zeros");
|
|
430
|
+
const publicKey = await (0, rx_nostr_crypto.seckeySigner)(bytesToHex(sk)).getPublicKey();
|
|
431
|
+
return {
|
|
432
|
+
credentialId: bytesToHex(credentialId || responseId),
|
|
433
|
+
pubkey: publicKey,
|
|
434
|
+
salt: STANDARD_SALT,
|
|
435
|
+
...options.username && { username: options.username }
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
/**
|
|
439
|
+
* @param event Nostr
|
|
440
|
+
* @param keyInfo NostrKeyInfo
|
|
441
|
+
* @param options
|
|
442
|
+
*/
|
|
443
|
+
async signEventWithKeyInfo(event, keyInfo, options = {}) {
|
|
444
|
+
const { clearMemory = true, tags } = options;
|
|
445
|
+
const shouldUseCache = this.#keyCache.isEnabled();
|
|
446
|
+
let sk;
|
|
447
|
+
if (shouldUseCache) sk = this.#keyCache.getKey(keyInfo.credentialId);
|
|
448
|
+
if (!sk) {
|
|
449
|
+
const { secret: prfSecret } = await getPrfSecret(hexToBytes(keyInfo.credentialId), this.#prfOptions);
|
|
450
|
+
sk = prfSecret;
|
|
451
|
+
if (shouldUseCache) this.#keyCache.setKey(keyInfo.credentialId, sk);
|
|
452
|
+
}
|
|
453
|
+
const signedEvent = await (0, rx_nostr_crypto.seckeySigner)(bytesToHex(sk), { tags }).signEvent(event);
|
|
454
|
+
if (!shouldUseCache && clearMemory) this.#clearKey(sk);
|
|
455
|
+
return signedEvent;
|
|
456
|
+
}
|
|
457
|
+
/**
|
|
458
|
+
* @param keyInfo NostrKeyInfo
|
|
459
|
+
* @param credentialId NostrKeyInfoのcredentialId
|
|
460
|
+
* @param options
|
|
461
|
+
* @returns
|
|
462
|
+
*/
|
|
463
|
+
async exportNostrKey(keyInfo, credentialId) {
|
|
464
|
+
let usedCredentialId = credentialId;
|
|
465
|
+
if (!usedCredentialId && keyInfo.credentialId) usedCredentialId = hexToBytes(keyInfo.credentialId);
|
|
466
|
+
const { secret: sk } = await getPrfSecret(usedCredentialId, this.#prfOptions);
|
|
467
|
+
return bytesToHex(sk);
|
|
468
|
+
}
|
|
469
|
+
/**
|
|
470
|
+
* PRF
|
|
471
|
+
*/
|
|
472
|
+
async isPrfSupported() {
|
|
473
|
+
return isPrfSupported();
|
|
474
|
+
}
|
|
475
|
+
/**
|
|
476
|
+
* @param key
|
|
477
|
+
*/
|
|
478
|
+
#clearKey(key) {
|
|
479
|
+
key?.fill?.(0);
|
|
480
|
+
}
|
|
481
|
+
};
|
|
482
|
+
|
|
483
|
+
//#endregion
|
|
484
|
+
//#region src/utils/crypto-utils.ts
|
|
485
|
+
/**
|
|
486
|
+
* Cryptographic utilities for Nosskey
|
|
487
|
+
* @packageDocumentation
|
|
488
|
+
*/
|
|
489
|
+
const INFO_BYTES = new TextEncoder().encode("nostr-pwk");
|
|
490
|
+
|
|
491
|
+
//#endregion
|
|
492
|
+
Object.defineProperty(exports, 'NosskeyManager', {
|
|
493
|
+
enumerable: true,
|
|
494
|
+
get: function () {
|
|
495
|
+
return NosskeyManager;
|
|
496
|
+
}
|
|
497
|
+
});
|
|
498
|
+
Object.defineProperty(exports, 'bytesToHex', {
|
|
499
|
+
enumerable: true,
|
|
500
|
+
get: function () {
|
|
501
|
+
return bytesToHex;
|
|
502
|
+
}
|
|
503
|
+
});
|
|
504
|
+
Object.defineProperty(exports, 'createPasskey', {
|
|
505
|
+
enumerable: true,
|
|
506
|
+
get: function () {
|
|
507
|
+
return createPasskey;
|
|
508
|
+
}
|
|
509
|
+
});
|
|
510
|
+
Object.defineProperty(exports, 'getPrfSecret', {
|
|
511
|
+
enumerable: true,
|
|
512
|
+
get: function () {
|
|
513
|
+
return getPrfSecret;
|
|
514
|
+
}
|
|
515
|
+
});
|
|
516
|
+
Object.defineProperty(exports, 'hexToBytes', {
|
|
517
|
+
enumerable: true,
|
|
518
|
+
get: function () {
|
|
519
|
+
return hexToBytes;
|
|
520
|
+
}
|
|
521
|
+
});
|
|
522
|
+
Object.defineProperty(exports, 'isPrfSupported', {
|
|
523
|
+
enumerable: true,
|
|
524
|
+
get: function () {
|
|
525
|
+
return isPrfSupported;
|
|
526
|
+
}
|
|
527
|
+
});
|
|
528
|
+
//# sourceMappingURL=utils-CxLeFzNn.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils-CxLeFzNn.cjs","names":["#cacheOptions","#cachedEntry","#clearCachedEntry","#scheduleExpiry","#getCachedKeyIfValid","#clearKey","#expiryTimer","#keyCache","#storageOptions","#prfOptions","#loadKeyInfoFromStorage","#currentKeyInfo","#saveKeyInfoToStorage","#clearKey"],"sources":["../src/utils/utils.ts","../src/utils/key-cache.ts","../src/utils/prf-handler.ts","../src/utils/nosskey.ts","../src/utils/crypto-utils.ts"],"sourcesContent":["/**\n * @packageDocumentation\n */\n\n/**\n * @param bytes\n * @returns\n */\nexport function bytesToHex(bytes: Uint8Array): string {\n const key = '0123456789abcdef';\n let hex = '';\n for (let i = 0; i < bytes.length; i++) {\n const firstNibble = bytes[i] >> 4;\n const secondNibble = bytes[i] & 15;\n hex += key[firstNibble] + key[secondNibble];\n }\n return hex;\n}\n\n/**\n * @param hex\n * @returns\n */\nexport function hexToBytes(hex: string): Uint8Array {\n const key = '0123456789abcdef';\n const bytes = [];\n let currentByte = 0;\n let highNibble = true;\n\n for (let i = 0; i < hex.length; i++) {\n const charValue = key.indexOf(hex[i].toLowerCase());\n if (charValue === -1) continue;\n\n if (highNibble) {\n currentByte = charValue << 4;\n highNibble = false;\n } else {\n currentByte += charValue;\n bytes.push(currentByte);\n highNibble = true;\n }\n }\n\n return new Uint8Array(bytes);\n}\n","/**\n * Key cache management for Nosskey\n * @packageDocumentation\n */\n\nimport type { KeyCacheOptions } from './types.js';\nimport { bytesToHex } from './utils.js';\n\n/**\n * Key cache entry with expiration time\n */\ninterface CacheEntry {\n id: string;\n sk: Uint8Array;\n expireAt: number;\n}\n\n/**\n * Key cache manager for managing temporary secret keys\n */\nexport class KeyCache {\n #cachedEntry: CacheEntry | null = null;\n\n #expiryTimer: NodeJS.Timeout | null = null;\n\n #cacheOptions: KeyCacheOptions = {\n enabled: false,\n timeoutMs: 5 * 60 * 1000,\n };\n\n /**\n * KeyCache\n * @param options\n */\n constructor(options?: Partial<KeyCacheOptions>) {\n if (options) {\n this.#cacheOptions = { ...this.#cacheOptions, ...options };\n }\n }\n\n /**\n * @param options\n */\n setCacheOptions(options: Partial<KeyCacheOptions>): void {\n if (Object.keys(options).length > 0 && this.#cachedEntry !== null) {\n this.clearAllCachedKeys();\n }\n\n this.#cacheOptions = { ...this.#cacheOptions, ...options };\n }\n\n getCacheOptions(): KeyCacheOptions {\n return { ...this.#cacheOptions };\n }\n\n isEnabled(): boolean {\n return this.#cacheOptions.enabled;\n }\n\n /**\n * @param credentialId\n * @param sk\n */\n setKey(credentialId: Uint8Array | string, sk: Uint8Array): void {\n if (!this.#cacheOptions.enabled) return;\n\n const id = typeof credentialId === 'string' ? credentialId : bytesToHex(credentialId);\n const timeout =\n this.#cacheOptions.timeoutMs !== undefined ? this.#cacheOptions.timeoutMs : 5 * 60 * 1000;\n const expireAt = Date.now() + timeout;\n\n this.#clearCachedEntry();\n\n this.#cachedEntry = {\n id,\n sk: new Uint8Array(sk),\n expireAt,\n };\n\n try {\n this.#scheduleExpiry();\n } catch (error) {\n this.#clearCachedEntry();\n throw error;\n }\n }\n\n /**\n * @param credentialId\n * @returns undefined\n */\n getKey(credentialId: Uint8Array | string): Uint8Array | undefined {\n if (!this.#cacheOptions.enabled) return undefined;\n\n const id = typeof credentialId === 'string' ? credentialId : bytesToHex(credentialId);\n return this.#getCachedKeyIfValid(id);\n }\n\n /**\n * @param credentialId\n */\n clearCachedKey(credentialId: Uint8Array | string): void {\n const id = typeof credentialId === 'string' ? credentialId : bytesToHex(credentialId);\n\n if (this.#cachedEntry && this.#cachedEntry.id === id) {\n this.#clearCachedEntry();\n }\n }\n\n clearAllCachedKeys(): void {\n this.#clearCachedEntry();\n }\n\n /**\n * @param credentialId\n * @returns undefined\n */\n #getCachedKeyIfValid(credentialId: string): Uint8Array | undefined {\n if (!this.#cachedEntry || this.#cachedEntry.id !== credentialId) {\n return undefined;\n }\n\n if (Date.now() < this.#cachedEntry.expireAt) {\n return this.#cachedEntry.sk;\n }\n\n this.#clearCachedEntry();\n return undefined;\n }\n\n #clearCachedEntry(): void {\n if (this.#cachedEntry) {\n this.#clearKey(this.#cachedEntry.sk);\n this.#cachedEntry = null;\n }\n\n if (this.#expiryTimer) {\n clearTimeout(this.#expiryTimer);\n this.#expiryTimer = null;\n }\n }\n\n #scheduleExpiry(): void {\n if (!this.#cachedEntry) return;\n\n const now = Date.now();\n const timeToExpiry = this.#cachedEntry.expireAt - now;\n\n if (timeToExpiry <= 0) {\n this.#clearCachedEntry();\n return;\n }\n\n this.#expiryTimer = setTimeout(() => {\n this.#clearCachedEntry();\n }, timeToExpiry + 1);\n }\n\n /**\n * @param key\n */\n #clearKey(key: Uint8Array): void {\n key?.fill?.(0);\n }\n}\n","/**\n * PRF (Pseudo-Random Function) handler for WebAuthn\n * @packageDocumentation\n */\n\nimport type { GetPrfSecretOptions, PasskeyCreationOptions } from './types.js';\n\nconst PRF_EVAL_INPUT = new TextEncoder().encode('nostr-pwk');\n\n/**\n * @returns PRF\n */\nexport async function isPrfSupported(): Promise<boolean> {\n try {\n const response = await navigator.credentials.get({\n publicKey: {\n challenge: crypto.getRandomValues(new Uint8Array(32)),\n allowCredentials: [],\n userVerification: 'required',\n extensions: { prf: { eval: { first: PRF_EVAL_INPUT } } },\n } as PublicKeyCredentialRequestOptions,\n });\n\n if (!response) return false;\n\n const assertion = response as unknown as {\n getClientExtensionResults: () => {\n prf?: {\n results?: {\n first?: ArrayBuffer;\n };\n };\n };\n };\n\n const res = assertion.getClientExtensionResults()?.prf?.results?.first;\n return !!res;\n } catch {\n return false;\n }\n}\n\n/**\n * @param options\n * @returns Credential\n */\nexport async function createPasskey(options: PasskeyCreationOptions = {}): Promise<Uint8Array> {\n // Node\n const rpName = options.rp?.name || (typeof location !== 'undefined' ? location.host : 'Nosskey');\n const rpId = options.rp?.id;\n const userName = options.user?.name || 'user@example.com';\n const userDisplayName = options.user?.displayName || 'Nosskey user';\n\n const credentialCreationOptions: CredentialCreationOptions = {\n publicKey: {\n rp: {\n name: rpName,\n id: rpId,\n },\n user: {\n id: crypto.getRandomValues(new Uint8Array(16)),\n name: userName,\n displayName: userDisplayName,\n },\n pubKeyCredParams: options.pubKeyCredParams || [{ type: 'public-key', alg: -7 }], // ES256\n authenticatorSelection: options.authenticatorSelection || {\n residentKey: 'required',\n userVerification: 'required',\n },\n challenge: crypto.getRandomValues(new Uint8Array(32)),\n extensions: options.extensions || { prf: {} }, // PRF拡張を要求\n } as PublicKeyCredentialCreationOptions,\n };\n const cred = (await navigator.credentials.create(\n credentialCreationOptions\n )) as PublicKeyCredential;\n\n return new Uint8Array(cred.rawId);\n}\n\n/**\n * ID\n * @param credentialId \n * @param options PRF(rpId、timeout、userVerification)\n * @returns PRF credentialID\n */\nexport async function getPrfSecret(\n credentialId?: Uint8Array,\n options?: GetPrfSecretOptions\n): Promise<{ secret: Uint8Array; id: Uint8Array }> {\n const allowCredentials = credentialId ? [{ type: 'public-key' as const, id: credentialId }] : [];\n\n const requestOptions: PublicKeyCredentialRequestOptions = {\n challenge: crypto.getRandomValues(new Uint8Array(32)),\n allowCredentials,\n userVerification: options?.userVerification || 'required',\n extensions: {\n prf: { eval: { first: PRF_EVAL_INPUT } },\n } as AuthenticationExtensionsClientInputs,\n };\n\n if (options?.rpId) {\n requestOptions.rpId = options.rpId;\n }\n if (options?.timeout) {\n requestOptions.timeout = options.timeout;\n }\n\n const response = await navigator.credentials.get({\n publicKey: requestOptions,\n });\n\n if (!response) {\n throw new Error('Authentication failed');\n }\n\n const assertion = response as unknown as {\n getClientExtensionResults: () => {\n prf?: {\n results?: {\n first?: ArrayBuffer;\n };\n };\n };\n };\n\n const secret = assertion.getClientExtensionResults()?.prf?.results?.first;\n if (!secret) {\n throw new Error('PRF secret not available');\n }\n\n // response credentialId\n const responseId = new Uint8Array((response as PublicKeyCredential).rawId);\n\n return {\n secret: new Uint8Array(secret),\n id: responseId,\n };\n}\n","import { seckeySigner } from 'rx-nostr-crypto';\nimport { KeyCache } from './key-cache.js';\nimport { createPasskey, getPrfSecret, isPrfSupported } from './prf-handler.js';\nimport type {\n GetPrfSecretOptions,\n KeyCacheOptions,\n KeyOptions,\n NosskeyManagerLike,\n NosskeyManagerOptions,\n NostrEvent,\n NostrKeyInfo,\n NostrKeyStorageOptions,\n PasskeyCreationOptions,\n SignOptions,\n} from './types.js';\n/**\n * Nosskey class for Passkey-Derived Nostr Identity\n * @packageDocumentation\n */\nimport { bytesToHex, hexToBytes } from './utils.js';\n\n// salt(\"nostr-key\" UTF-8)\nconst STANDARD_SALT = '6e6f7374722d6b6579';\n\n/**\n * Nosskey - Passkey-Derived Nostr Keys\n */\nexport class NosskeyManager implements NosskeyManagerLike {\n #keyCache: KeyCache;\n\n // NostrKeyInfo\n #currentKeyInfo: NostrKeyInfo | null = null;\n\n // NostrKeyInfo\n #storageOptions: NostrKeyStorageOptions = {\n enabled: true,\n storageKey: 'nosskey_keyinfo',\n };\n\n // PRF\n #prfOptions: GetPrfSecretOptions = {};\n\n /**\n * NosskeyManager\n * @param options\n */\n constructor(options?: NosskeyManagerOptions) {\n // KeyCache\n this.#keyCache = new KeyCache(options?.cacheOptions);\n\n if (options?.storageOptions) {\n this.#storageOptions = { ...this.#storageOptions, ...options.storageOptions };\n }\n\n // option\n const userVerification = options?.prfOptions?.userVerification ?? 'required';\n if (options?.prfOptions) {\n this.#prfOptions = { ...options.prfOptions, userVerification };\n } else {\n this.#prfOptions = { userVerification };\n }\n\n // NostrKeyInfo\n if (this.#storageOptions.enabled) {\n const loadedKeyInfo = this.#loadKeyInfoFromStorage();\n if (loadedKeyInfo) {\n this.#currentKeyInfo = loadedKeyInfo;\n }\n }\n }\n\n /**\n * NostrKeyInfo\n * @param options\n */\n setStorageOptions(options: Partial<NostrKeyStorageOptions>): void {\n this.#storageOptions = { ...this.#storageOptions, ...options };\n\n if (options.enabled === false) {\n this.clearStoredKeyInfo();\n }\n }\n\n /**\n * NostrKeyInfo\n */\n getStorageOptions(): NostrKeyStorageOptions {\n return { ...this.#storageOptions };\n }\n\n /**\n * NostrKeyInfo\n * @param keyInfo NostrKeyInfo\n */\n setCurrentKeyInfo(keyInfo: NostrKeyInfo): void {\n this.#currentKeyInfo = keyInfo;\n\n if (this.#storageOptions.enabled) {\n void this.#saveKeyInfoToStorage(keyInfo);\n }\n }\n\n /**\n * NostrKeyInfo\n */\n getCurrentKeyInfo(): NostrKeyInfo | null {\n // NostrKeyInfo\n if (!this.#currentKeyInfo && this.#storageOptions.enabled) {\n this.#currentKeyInfo = this.#loadKeyInfoFromStorage();\n }\n return this.#currentKeyInfo;\n }\n\n /**\n * NostrKeyInfo\n * @returns NostrKeyInfo\n */\n hasKeyInfo(): boolean {\n if (this.#currentKeyInfo) {\n return true;\n }\n\n if (this.#storageOptions.enabled) {\n const loadedKeyInfo = this.#loadKeyInfoFromStorage();\n if (loadedKeyInfo) {\n this.#currentKeyInfo = loadedKeyInfo;\n return true;\n }\n }\n\n return false;\n }\n\n /**\n * NostrKeyInfo\n * @param keyInfo NostrKeyInfo\n */\n async #saveKeyInfoToStorage(keyInfo: NostrKeyInfo): Promise<void> {\n if (!this.#storageOptions.enabled) return;\n\n const storage =\n this.#storageOptions.storage || (typeof localStorage !== 'undefined' ? localStorage : null);\n\n if (!storage) return;\n\n const key = this.#storageOptions.storageKey || 'nosskey_keyinfo';\n storage.setItem(key, JSON.stringify(keyInfo));\n }\n\n /**\n * NostrKeyInfo\n */\n #loadKeyInfoFromStorage(): NostrKeyInfo | null {\n if (!this.#storageOptions.enabled) return null;\n\n const storage =\n this.#storageOptions.storage || (typeof localStorage !== 'undefined' ? localStorage : null);\n\n if (!storage) return null;\n\n const key = this.#storageOptions.storageKey || 'nosskey_keyinfo';\n const data = storage.getItem(key);\n\n if (!data) return null;\n\n try {\n return JSON.parse(data) as NostrKeyInfo;\n } catch (e) {\n console.error('Failed to parse stored NostrKeyInfo', e);\n return null;\n }\n }\n\n /**\n * NostrKeyInfo\n */\n clearStoredKeyInfo(): void {\n const storage =\n this.#storageOptions.storage || (typeof localStorage !== 'undefined' ? localStorage : null);\n\n if (!storage) return;\n\n const key = this.#storageOptions.storageKey || 'nosskey_keyinfo';\n storage.removeItem(key);\n\n // NostrKeyInfo\n this.#currentKeyInfo = null;\n }\n\n /**\n * NIP-07\n * NostrKeyInfo\n */\n async getPublicKey(): Promise<string> {\n const keyInfo = this.getCurrentKeyInfo();\n if (!keyInfo) {\n throw new Error('No current NostrKeyInfo set');\n }\n return keyInfo.pubkey;\n }\n\n /**\n * NIP-07\n * NostrKeyInfo\n * @param event Nostr\n */\n async signEvent(event: NostrEvent): Promise<NostrEvent> {\n const keyInfo = this.getCurrentKeyInfo();\n if (!keyInfo) {\n throw new Error('No current NostrKeyInfo set');\n }\n return this.signEventWithKeyInfo(event, keyInfo);\n }\n\n /**\n * @param options\n */\n setCacheOptions(options: Partial<KeyCacheOptions>): void {\n this.#keyCache.setCacheOptions(options);\n }\n\n getCacheOptions(): KeyCacheOptions {\n return this.#keyCache.getCacheOptions();\n }\n\n /**\n * @param credentialId\n */\n clearCachedKey(credentialId: Uint8Array | string): void {\n this.#keyCache.clearCachedKey(credentialId);\n }\n\n clearAllCachedKeys(): void {\n this.#keyCache.clearAllCachedKeys();\n }\n\n /**\n * @param options\n * @returns Credential\n */\n async createPasskey(options: PasskeyCreationOptions = {}): Promise<Uint8Array> {\n return createPasskey({\n rp: {\n id: this.#prfOptions.rpId,\n name: this.#prfOptions.rpId,\n },\n authenticatorSelection: {\n userVerification: this.#prfOptions.userVerification,\n },\n ...options,\n });\n }\n\n /**\n * PRF NostrKeyInfo\n * @param credentialId\n * @param options\n */\n async createNostrKey(credentialId?: Uint8Array, options: KeyOptions = {}): Promise<NostrKeyInfo> {\n const { secret: sk, id: responseId } = await getPrfSecret(credentialId, this.#prfOptions);\n\n // secp256k1\n if (sk.every((byte) => byte === 0)) {\n throw new Error('Invalid PRF output: all zeros');\n }\n\n // HEX\n const skHex = bytesToHex(sk);\n\n // rx-nostr-crypto\n const signer = seckeySigner(skHex);\n const publicKey = await signer.getPublicKey();\n\n // NostrKeyInfo\n const keyInfo: NostrKeyInfo = {\n credentialId: bytesToHex(credentialId || responseId),\n pubkey: publicKey,\n salt: STANDARD_SALT, // salt\n ...(options.username && { username: options.username }), // username\n };\n\n return keyInfo;\n }\n\n /**\n * @param event Nostr\n * @param keyInfo NostrKeyInfo\n * @param options\n */\n async signEventWithKeyInfo(\n event: NostrEvent,\n keyInfo: NostrKeyInfo,\n options: SignOptions = {}\n ): Promise<NostrEvent> {\n const { clearMemory = true, tags } = options;\n\n const shouldUseCache = this.#keyCache.isEnabled();\n\n let sk: Uint8Array | undefined;\n\n if (shouldUseCache) {\n sk = this.#keyCache.getKey(keyInfo.credentialId);\n }\n\n if (!sk) {\n const { secret: prfSecret } = await getPrfSecret(\n hexToBytes(keyInfo.credentialId),\n this.#prfOptions\n );\n sk = prfSecret;\n\n if (shouldUseCache) {\n this.#keyCache.setKey(keyInfo.credentialId, sk);\n }\n }\n\n const skHex = bytesToHex(sk);\n\n // rx-nostr-crypto seckeySigner\n const signer = seckeySigner(skHex, { tags });\n const signedEvent = await signer.signEvent(event);\n\n // clearMemory=true\n if (!shouldUseCache && clearMemory) {\n this.#clearKey(sk);\n }\n\n return signedEvent;\n }\n\n /**\n * @param keyInfo NostrKeyInfo\n * @param credentialId NostrKeyInfoのcredentialId\n * @param options\n * @returns \n */\n async exportNostrKey(keyInfo: NostrKeyInfo, credentialId?: Uint8Array): Promise<string> {\n // NostrKeyInfo credentialId\n let usedCredentialId = credentialId;\n\n // credentialId NostrKeyInfo\n if (!usedCredentialId && keyInfo.credentialId) {\n usedCredentialId = hexToBytes(keyInfo.credentialId);\n }\n\n // PRF\n const { secret: sk } = await getPrfSecret(usedCredentialId, this.#prfOptions);\n\n // HEX\n const skHex = bytesToHex(sk);\n\n return skHex;\n }\n\n /**\n * PRF\n */\n async isPrfSupported(): Promise<boolean> {\n return isPrfSupported();\n }\n\n /**\n * @param key\n */\n #clearKey(key: Uint8Array): void {\n key?.fill?.(0);\n }\n}\n","/**\n * Cryptographic utilities for Nosskey\n * @packageDocumentation\n */\n\nconst INFO_BYTES = new TextEncoder().encode('nostr-pwk');\nconst AES_LENGTH = 256; // bits\n\n/**\n * PRF AES-GCM\n * @param secret PRF\n * @param salt\n * @returns AES-GCM\n */\nexport async function deriveAesGcmKey(secret: Uint8Array, salt: Uint8Array): Promise<CryptoKey> {\n const keyMaterial = await crypto.subtle.importKey('raw', secret, 'HKDF', false, ['deriveKey']);\n\n return crypto.subtle.deriveKey(\n { name: 'HKDF', hash: 'SHA-256', salt, info: INFO_BYTES },\n keyMaterial,\n { name: 'AES-GCM', length: AES_LENGTH },\n false,\n ['encrypt', 'decrypt']\n );\n}\n\n/**\n * AES-GCM\n * @param key\n * @param iv\n * @param plaintext\n * @returns\n */\nexport async function aesGcmEncrypt(key: CryptoKey, iv: Uint8Array, plaintext: Uint8Array) {\n const buf = await crypto.subtle.encrypt({ name: 'AES-GCM', iv }, key, plaintext);\n\n const bytes = new Uint8Array(buf);\n return {\n ciphertext: bytes.slice(0, -16),\n tag: bytes.slice(-16),\n };\n}\n\n/**\n * AES-GCM\n * @param key\n * @param iv\n * @param ct\n * @param tag\n * @returns\n */\nexport async function aesGcmDecrypt(\n key: CryptoKey,\n iv: Uint8Array,\n ct: Uint8Array,\n tag: Uint8Array\n): Promise<Uint8Array> {\n const buf = await crypto.subtle.decrypt(\n { name: 'AES-GCM', iv },\n key,\n new Uint8Array([...ct, ...tag])\n );\n return new Uint8Array(buf);\n}\n"],"mappings":";;;;;;;;;;;AAQA,SAAgB,WAAW,OAA2B;CACpD,MAAM,MAAM;CACZ,IAAI,MAAM;AACV,MAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;EACrC,MAAM,cAAc,MAAM,MAAM;EAChC,MAAM,eAAe,MAAM,KAAK;AAChC,SAAO,IAAI,eAAe,IAAI;;AAEhC,QAAO;;;;;;AAOT,SAAgB,WAAW,KAAyB;CAClD,MAAM,MAAM;CACZ,MAAM,QAAQ,EAAE;CAChB,IAAI,cAAc;CAClB,IAAI,aAAa;AAEjB,MAAK,IAAI,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;EACnC,MAAM,YAAY,IAAI,QAAQ,IAAI,GAAG,aAAa,CAAC;AACnD,MAAI,cAAc,GAAI;AAEtB,MAAI,YAAY;AACd,iBAAc,aAAa;AAC3B,gBAAa;SACR;AACL,kBAAe;AACf,SAAM,KAAK,YAAY;AACvB,gBAAa;;;AAIjB,QAAO,IAAI,WAAW,MAAM;;;;;;;;ACvB9B,IAAa,WAAb,MAAsB;CACpB,eAAkC;CAElC,eAAsC;CAEtC,gBAAiC;EAC/B,SAAS;EACT,WAAW,MAAS;EACrB;;;;;CAMD,YAAY,SAAoC;AAC9C,MAAI,QACF,OAAKA,eAAgB;GAAE,GAAG,MAAKA;GAAe,GAAG;GAAS;;;;;CAO9D,gBAAgB,SAAyC;AACvD,MAAI,OAAO,KAAK,QAAQ,CAAC,SAAS,KAAK,MAAKC,gBAAiB,KAC3D,MAAK,oBAAoB;AAG3B,QAAKD,eAAgB;GAAE,GAAG,MAAKA;GAAe,GAAG;GAAS;;CAG5D,kBAAmC;AACjC,SAAO,EAAE,GAAG,MAAKA,cAAe;;CAGlC,YAAqB;AACnB,SAAO,MAAKA,aAAc;;;;;;CAO5B,OAAO,cAAmC,IAAsB;AAC9D,MAAI,CAAC,MAAKA,aAAc,QAAS;EAEjC,MAAM,KAAK,OAAO,iBAAiB,WAAW,eAAe,WAAW,aAAa;EACrF,MAAM,UACJ,MAAKA,aAAc,cAAc,SAAY,MAAKA,aAAc,YAAY,MAAS;EACvF,MAAM,WAAW,KAAK,KAAK,GAAG;AAE9B,QAAKE,kBAAmB;AAExB,QAAKD,cAAe;GAClB;GACA,IAAI,IAAI,WAAW,GAAG;GACtB;GACD;AAED,MAAI;AACF,SAAKE,gBAAiB;WACf,OAAO;AACd,SAAKD,kBAAmB;AACxB,SAAM;;;;;;;CAQV,OAAO,cAA2D;AAChE,MAAI,CAAC,MAAKF,aAAc,QAAS,QAAO;EAExC,MAAM,KAAK,OAAO,iBAAiB,WAAW,eAAe,WAAW,aAAa;AACrF,SAAO,MAAKI,oBAAqB,GAAG;;;;;CAMtC,eAAe,cAAyC;EACtD,MAAM,KAAK,OAAO,iBAAiB,WAAW,eAAe,WAAW,aAAa;AAErF,MAAI,MAAKH,eAAgB,MAAKA,YAAa,OAAO,GAChD,OAAKC,kBAAmB;;CAI5B,qBAA2B;AACzB,QAAKA,kBAAmB;;;;;;CAO1B,qBAAqB,cAA8C;AACjE,MAAI,CAAC,MAAKD,eAAgB,MAAKA,YAAa,OAAO,aACjD;AAGF,MAAI,KAAK,KAAK,GAAG,MAAKA,YAAa,SACjC,QAAO,MAAKA,YAAa;AAG3B,QAAKC,kBAAmB;;CAI1B,oBAA0B;AACxB,MAAI,MAAKD,aAAc;AACrB,SAAKI,SAAU,MAAKJ,YAAa,GAAG;AACpC,SAAKA,cAAe;;AAGtB,MAAI,MAAKK,aAAc;AACrB,gBAAa,MAAKA,YAAa;AAC/B,SAAKA,cAAe;;;CAIxB,kBAAwB;AACtB,MAAI,CAAC,MAAKL,YAAc;EAExB,MAAM,MAAM,KAAK,KAAK;EACtB,MAAM,eAAe,MAAKA,YAAa,WAAW;AAElD,MAAI,gBAAgB,GAAG;AACrB,SAAKC,kBAAmB;AACxB;;AAGF,QAAKI,cAAe,iBAAiB;AACnC,SAAKJ,kBAAmB;KACvB,eAAe,EAAE;;;;;CAMtB,UAAU,KAAuB;AAC/B,OAAK,OAAO,EAAE;;;;;;AC3JlB,MAAM,iBAAiB,IAAI,aAAa,CAAC,OAAO,YAAY;;;;AAK5D,eAAsB,iBAAmC;AACvD,KAAI;EACF,MAAM,WAAW,MAAM,UAAU,YAAY,IAAI,EAC/C,WAAW;GACT,WAAW,OAAO,gBAAgB,IAAI,WAAW,GAAG,CAAC;GACrD,kBAAkB,EAAE;GACpB,kBAAkB;GAClB,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,gBAAgB,EAAE,EAAE;GACzD,EACF,CAAC;AAEF,MAAI,CAAC,SAAU,QAAO;AAatB,SAAO,CAAC,CAXU,SAUI,2BAA2B,EAAE,KAAK,SAAS;SAE3D;AACN,SAAO;;;;;;;AAQX,eAAsB,cAAc,UAAkC,EAAE,EAAuB;CAE7F,MAAM,SAAS,QAAQ,IAAI,SAAS,OAAO,aAAa,cAAc,SAAS,OAAO;CACtF,MAAM,OAAO,QAAQ,IAAI;CACzB,MAAM,WAAW,QAAQ,MAAM,QAAQ;CACvC,MAAM,kBAAkB,QAAQ,MAAM,eAAe;CAErD,MAAM,4BAAuD,EAC3D,WAAW;EACT,IAAI;GACF,MAAM;GACN,IAAI;GACL;EACD,MAAM;GACJ,IAAI,OAAO,gBAAgB,IAAI,WAAW,GAAG,CAAC;GAC9C,MAAM;GACN,aAAa;GACd;EACD,kBAAkB,QAAQ,oBAAoB,CAAC;GAAE,MAAM;GAAc,KAAK;GAAI,CAAC;EAC/E,wBAAwB,QAAQ,0BAA0B;GACxD,aAAa;GACb,kBAAkB;GACnB;EACD,WAAW,OAAO,gBAAgB,IAAI,WAAW,GAAG,CAAC;EACrD,YAAY,QAAQ,cAAc,EAAE,KAAK,EAAE,EAAE;EAC9C,EACF;CACD,MAAM,OAAQ,MAAM,UAAU,YAAY,OACxC,0BACD;AAED,QAAO,IAAI,WAAW,KAAK,MAAM;;;;;;;;AASnC,eAAsB,aACpB,cACA,SACiD;CACjD,MAAM,mBAAmB,eAAe,CAAC;EAAE,MAAM;EAAuB,IAAI;EAAc,CAAC,GAAG,EAAE;CAEhG,MAAM,iBAAoD;EACxD,WAAW,OAAO,gBAAgB,IAAI,WAAW,GAAG,CAAC;EACrD;EACA,kBAAkB,SAAS,oBAAoB;EAC/C,YAAY,EACV,KAAK,EAAE,MAAM,EAAE,OAAO,gBAAgB,EAAE,EACzC;EACF;AAED,KAAI,SAAS,KACX,gBAAe,OAAO,QAAQ;AAEhC,KAAI,SAAS,QACX,gBAAe,UAAU,QAAQ;CAGnC,MAAM,WAAW,MAAM,UAAU,YAAY,IAAI,EAC/C,WAAW,gBACZ,CAAC;AAEF,KAAI,CAAC,SACH,OAAM,IAAI,MAAM,wBAAwB;CAa1C,MAAM,SAVY,SAUO,2BAA2B,EAAE,KAAK,SAAS;AACpE,KAAI,CAAC,OACH,OAAM,IAAI,MAAM,2BAA2B;CAI7C,MAAM,aAAa,IAAI,WAAY,SAAiC,MAAM;AAE1E,QAAO;EACL,QAAQ,IAAI,WAAW,OAAO;EAC9B,IAAI;EACL;;;;;;;;;ACnHH,MAAM,gBAAgB;;;;AAKtB,IAAa,iBAAb,MAA0D;CACxD;CAGA,kBAAuC;CAGvC,kBAA0C;EACxC,SAAS;EACT,YAAY;EACb;CAGD,cAAmC,EAAE;;;;;CAMrC,YAAY,SAAiC;AAE3C,QAAKK,WAAY,IAAI,SAAS,SAAS,aAAa;AAEpD,MAAI,SAAS,eACX,OAAKC,iBAAkB;GAAE,GAAG,MAAKA;GAAiB,GAAG,QAAQ;GAAgB;EAI/E,MAAM,mBAAmB,SAAS,YAAY,oBAAoB;AAClE,MAAI,SAAS,WACX,OAAKC,aAAc;GAAE,GAAG,QAAQ;GAAY;GAAkB;MAE9D,OAAKA,aAAc,EAAE,kBAAkB;AAIzC,MAAI,MAAKD,eAAgB,SAAS;GAChC,MAAM,gBAAgB,MAAKE,wBAAyB;AACpD,OAAI,cACF,OAAKC,iBAAkB;;;;;;;CAS7B,kBAAkB,SAAgD;AAChE,QAAKH,iBAAkB;GAAE,GAAG,MAAKA;GAAiB,GAAG;GAAS;AAE9D,MAAI,QAAQ,YAAY,MACtB,MAAK,oBAAoB;;;;;CAO7B,oBAA4C;AAC1C,SAAO,EAAE,GAAG,MAAKA,gBAAiB;;;;;;CAOpC,kBAAkB,SAA6B;AAC7C,QAAKG,iBAAkB;AAEvB,MAAI,MAAKH,eAAgB,QACvB,CAAK,MAAKI,qBAAsB,QAAQ;;;;;CAO5C,oBAAyC;AAEvC,MAAI,CAAC,MAAKD,kBAAmB,MAAKH,eAAgB,QAChD,OAAKG,iBAAkB,MAAKD,wBAAyB;AAEvD,SAAO,MAAKC;;;;;;CAOd,aAAsB;AACpB,MAAI,MAAKA,eACP,QAAO;AAGT,MAAI,MAAKH,eAAgB,SAAS;GAChC,MAAM,gBAAgB,MAAKE,wBAAyB;AACpD,OAAI,eAAe;AACjB,UAAKC,iBAAkB;AACvB,WAAO;;;AAIX,SAAO;;;;;;CAOT,OAAMC,qBAAsB,SAAsC;AAChE,MAAI,CAAC,MAAKJ,eAAgB,QAAS;EAEnC,MAAM,UACJ,MAAKA,eAAgB,YAAY,OAAO,iBAAiB,cAAc,eAAe;AAExF,MAAI,CAAC,QAAS;EAEd,MAAM,MAAM,MAAKA,eAAgB,cAAc;AAC/C,UAAQ,QAAQ,KAAK,KAAK,UAAU,QAAQ,CAAC;;;;;CAM/C,0BAA+C;AAC7C,MAAI,CAAC,MAAKA,eAAgB,QAAS,QAAO;EAE1C,MAAM,UACJ,MAAKA,eAAgB,YAAY,OAAO,iBAAiB,cAAc,eAAe;AAExF,MAAI,CAAC,QAAS,QAAO;EAErB,MAAM,MAAM,MAAKA,eAAgB,cAAc;EAC/C,MAAM,OAAO,QAAQ,QAAQ,IAAI;AAEjC,MAAI,CAAC,KAAM,QAAO;AAElB,MAAI;AACF,UAAO,KAAK,MAAM,KAAK;WAChB,GAAG;AACV,WAAQ,MAAM,uCAAuC,EAAE;AACvD,UAAO;;;;;;CAOX,qBAA2B;EACzB,MAAM,UACJ,MAAKA,eAAgB,YAAY,OAAO,iBAAiB,cAAc,eAAe;AAExF,MAAI,CAAC,QAAS;EAEd,MAAM,MAAM,MAAKA,eAAgB,cAAc;AAC/C,UAAQ,WAAW,IAAI;AAGvB,QAAKG,iBAAkB;;;;;;CAOzB,MAAM,eAAgC;EACpC,MAAM,UAAU,KAAK,mBAAmB;AACxC,MAAI,CAAC,QACH,OAAM,IAAI,MAAM,8BAA8B;AAEhD,SAAO,QAAQ;;;;;;;CAQjB,MAAM,UAAU,OAAwC;EACtD,MAAM,UAAU,KAAK,mBAAmB;AACxC,MAAI,CAAC,QACH,OAAM,IAAI,MAAM,8BAA8B;AAEhD,SAAO,KAAK,qBAAqB,OAAO,QAAQ;;;;;CAMlD,gBAAgB,SAAyC;AACvD,QAAKJ,SAAU,gBAAgB,QAAQ;;CAGzC,kBAAmC;AACjC,SAAO,MAAKA,SAAU,iBAAiB;;;;;CAMzC,eAAe,cAAyC;AACtD,QAAKA,SAAU,eAAe,aAAa;;CAG7C,qBAA2B;AACzB,QAAKA,SAAU,oBAAoB;;;;;;CAOrC,MAAM,cAAc,UAAkC,EAAE,EAAuB;AAC7E,SAAO,cAAc;GACnB,IAAI;IACF,IAAI,MAAKE,WAAY;IACrB,MAAM,MAAKA,WAAY;IACxB;GACD,wBAAwB,EACtB,kBAAkB,MAAKA,WAAY,kBACpC;GACD,GAAG;GACJ,CAAC;;;;;;;CAQJ,MAAM,eAAe,cAA2B,UAAsB,EAAE,EAAyB;EAC/F,MAAM,EAAE,QAAQ,IAAI,IAAI,eAAe,MAAM,aAAa,cAAc,MAAKA,WAAY;AAGzF,MAAI,GAAG,OAAO,SAAS,SAAS,EAAE,CAChC,OAAM,IAAI,MAAM,gCAAgC;EAQlD,MAAM,YAAY,wCAJJ,WAAW,GAAG,CAGM,CACH,cAAc;AAU7C,SAP8B;GAC5B,cAAc,WAAW,gBAAgB,WAAW;GACpD,QAAQ;GACR,MAAM;GACN,GAAI,QAAQ,YAAY,EAAE,UAAU,QAAQ,UAAU;GACvD;;;;;;;CAUH,MAAM,qBACJ,OACA,SACA,UAAuB,EAAE,EACJ;EACrB,MAAM,EAAE,cAAc,MAAM,SAAS;EAErC,MAAM,iBAAiB,MAAKF,SAAU,WAAW;EAEjD,IAAI;AAEJ,MAAI,eACF,MAAK,MAAKA,SAAU,OAAO,QAAQ,aAAa;AAGlD,MAAI,CAAC,IAAI;GACP,MAAM,EAAE,QAAQ,cAAc,MAAM,aAClC,WAAW,QAAQ,aAAa,EAChC,MAAKE,WACN;AACD,QAAK;AAEL,OAAI,eACF,OAAKF,SAAU,OAAO,QAAQ,cAAc,GAAG;;EAQnD,MAAM,cAAc,wCAJN,WAAW,GAAG,EAGO,EAAE,MAAM,CAAC,CACX,UAAU,MAAM;AAGjD,MAAI,CAAC,kBAAkB,YACrB,OAAKM,SAAU,GAAG;AAGpB,SAAO;;;;;;;;CAST,MAAM,eAAe,SAAuB,cAA4C;EAEtF,IAAI,mBAAmB;AAGvB,MAAI,CAAC,oBAAoB,QAAQ,aAC/B,oBAAmB,WAAW,QAAQ,aAAa;EAIrD,MAAM,EAAE,QAAQ,OAAO,MAAM,aAAa,kBAAkB,MAAKJ,WAAY;AAK7E,SAFc,WAAW,GAAG;;;;;CAQ9B,MAAM,iBAAmC;AACvC,SAAO,gBAAgB;;;;;CAMzB,UAAU,KAAuB;AAC/B,OAAK,OAAO,EAAE;;;;;;;;;;ACxWlB,MAAM,aAAa,IAAI,aAAa,CAAC,OAAO,YAAY"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ns-auth-sdk",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "SSO library
|
|
3
|
+
"version": "1.3.0",
|
|
4
|
+
"description": "Decentralized SSO library - Authentication, membership, and profile management",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
@@ -17,8 +17,8 @@
|
|
|
17
17
|
"dist"
|
|
18
18
|
],
|
|
19
19
|
"scripts": {
|
|
20
|
-
"build": "
|
|
21
|
-
"dev": "
|
|
20
|
+
"build": "tsdown",
|
|
21
|
+
"dev": "tsdown --watch",
|
|
22
22
|
"type-check": "tsc --noEmit",
|
|
23
23
|
"semantic-release": "semantic-release"
|
|
24
24
|
},
|
|
@@ -26,39 +26,40 @@
|
|
|
26
26
|
"nostr",
|
|
27
27
|
"sso",
|
|
28
28
|
"authentication",
|
|
29
|
-
"membership"
|
|
30
|
-
"applesauce"
|
|
29
|
+
"membership"
|
|
31
30
|
],
|
|
32
31
|
"author": "",
|
|
33
32
|
"license": "Apache-2.0",
|
|
34
33
|
"repository": {
|
|
35
34
|
"type": "git",
|
|
36
|
-
"url": "https://github.com/
|
|
35
|
+
"url": "https://github.com/stoic-one/ns-auth-sdk.git"
|
|
37
36
|
},
|
|
38
37
|
"publishConfig": {
|
|
39
38
|
"registry": "https://registry.npmjs.org/",
|
|
40
39
|
"access": "public"
|
|
41
40
|
},
|
|
42
41
|
"peerDependencies": {
|
|
42
|
+
"applesauce-core": "^5.0.0",
|
|
43
43
|
"react": "^18.0.0",
|
|
44
44
|
"react-dom": "^18.0.0",
|
|
45
|
-
"
|
|
46
|
-
"
|
|
45
|
+
"rx-nostr": "^3.6.1",
|
|
46
|
+
"rx-nostr-crypto": "^3.1.3"
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"
|
|
49
|
+
"isomorphic-dompurify": "^2.35.0",
|
|
50
50
|
"qrcode.react": "^4.2.0",
|
|
51
|
-
"react-zxing": "^2.1.0"
|
|
51
|
+
"react-zxing": "^2.1.0",
|
|
52
|
+
"zustand": "^4.5.7"
|
|
52
53
|
},
|
|
53
54
|
"devDependencies": {
|
|
54
55
|
"@semantic-release/changelog": "^6.0.3",
|
|
55
56
|
"@semantic-release/git": "^10.0.1",
|
|
56
57
|
"@semantic-release/github": "^9.2.6",
|
|
57
|
-
"@semantic-release/npm": "^11.0.
|
|
58
|
-
"@types/react": "^18.3.
|
|
59
|
-
"@types/react-dom": "^18.3.
|
|
60
|
-
"semantic-release": "^23.
|
|
61
|
-
"
|
|
62
|
-
"typescript": "^5.
|
|
58
|
+
"@semantic-release/npm": "^11.0.3",
|
|
59
|
+
"@types/react": "^18.3.27",
|
|
60
|
+
"@types/react-dom": "^18.3.7",
|
|
61
|
+
"semantic-release": "^23.1.1",
|
|
62
|
+
"tsdown": "^0.19.0",
|
|
63
|
+
"typescript": "^5.9.3"
|
|
63
64
|
}
|
|
64
65
|
}
|