@agnostack/verifyd 2.4.1-alpha.1 → 2.5.0-alpha.2

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.
@@ -0,0 +1,350 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { isString, objectEmpty, ensureString, ensureArray, } from './display';
11
+ import { CryptoError } from './errors';
12
+ export class WebCrypto {
13
+ constructor({ crypto: _crypto, util: _util } = {}) {
14
+ this._crypto = _crypto !== null && _crypto !== void 0 ? _crypto : {};
15
+ this._util = _util !== null && _util !== void 0 ? _util : {};
16
+ }
17
+ get subtle() {
18
+ var _a;
19
+ return (_a = this._crypto) === null || _a === void 0 ? void 0 : _a.subtle;
20
+ }
21
+ getWebCrypto() {
22
+ return __awaiter(this, void 0, void 0, function* () {
23
+ var _a, _b, _c, _d;
24
+ if (!((_a = this._crypto) === null || _a === void 0 ? void 0 : _a.subtle)) {
25
+ // 1. Try globalThis.crypto (available in all browsers and Node 18+)
26
+ if ((typeof globalThis !== 'undefined') && ((_b = globalThis.crypto) === null || _b === void 0 ? void 0 : _b.subtle)) {
27
+ this._crypto = globalThis.crypto;
28
+ }
29
+ }
30
+ // 2. If still no subtle, fall back to polyfills (Node.js < 18, unusual environments)
31
+ if (!((_c = this._crypto) === null || _c === void 0 ? void 0 : _c.subtle)) {
32
+ try {
33
+ this._crypto = (yield import('isomorphic-webcrypto')).default;
34
+ }
35
+ catch (_ignore) {
36
+ console.info('Failed to import isomorphic-webcrypto, retrying w/ node crypto');
37
+ try {
38
+ this._crypto = (yield import('crypto')).default;
39
+ }
40
+ catch (error) {
41
+ // eslint-disable-next-line max-len
42
+ console.error(`Failed to import node crypto, ensure 'isomorphic-webcrypto' (or node 'crypto') is installed and/or pass in implementation via 'new WebCrypto({ crypto })'`);
43
+ throw error;
44
+ }
45
+ }
46
+ }
47
+ if (!((_d = this._crypto) === null || _d === void 0 ? void 0 : _d.subtle)) {
48
+ throw new CryptoError('Invalid crypto, missing subtle');
49
+ }
50
+ return this._crypto;
51
+ });
52
+ }
53
+ getTextDecoder() {
54
+ return __awaiter(this, void 0, void 0, function* () {
55
+ var _a;
56
+ if ((_a = this._util) === null || _a === void 0 ? void 0 : _a.TextDecoder) {
57
+ return this._util.TextDecoder;
58
+ }
59
+ if ((typeof globalThis !== 'undefined') && (typeof globalThis.TextDecoder === 'function')) {
60
+ return globalThis.TextDecoder;
61
+ }
62
+ if ((typeof window !== 'undefined') && (typeof window.TextDecoder === 'function')) {
63
+ return window.TextDecoder;
64
+ }
65
+ try {
66
+ const TextDecoder = (yield import('util')).TextDecoder;
67
+ this._util.TextDecoder = TextDecoder;
68
+ return TextDecoder;
69
+ }
70
+ catch (error) {
71
+ console.error(`Failed to import 'utils.TextDecoder', ensure 'util' is available and/or pass in implementation via 'new WebCrypto({ util })'`);
72
+ throw error;
73
+ }
74
+ });
75
+ }
76
+ getTextEncoder() {
77
+ return __awaiter(this, void 0, void 0, function* () {
78
+ var _a;
79
+ if ((_a = this._util) === null || _a === void 0 ? void 0 : _a.TextEncoder) {
80
+ return this._util.TextEncoder;
81
+ }
82
+ if ((typeof globalThis !== 'undefined') && (typeof globalThis.TextEncoder === 'function')) {
83
+ return globalThis.TextEncoder;
84
+ }
85
+ if ((typeof window !== 'undefined') && (typeof window.TextEncoder === 'function')) {
86
+ return window.TextEncoder;
87
+ }
88
+ try {
89
+ const TextEncoder = (yield import('util')).TextEncoder;
90
+ this._util.TextEncoder = TextEncoder;
91
+ return TextEncoder;
92
+ }
93
+ catch (error) {
94
+ console.error(`Failed to import 'utils.TextEncoder', ensure 'util' is available and/or pass in implementation via 'new WebCrypto({ util })'`);
95
+ throw error;
96
+ }
97
+ });
98
+ }
99
+ timingSafeEqual(value1, value2) {
100
+ if ((value1 == undefined) ||
101
+ (value2 == undefined) ||
102
+ (value1.length !== value2.length)) {
103
+ return false;
104
+ }
105
+ let result = 0;
106
+ // eslint-disable-next-line no-plusplus
107
+ for (let i = 0; i < value1.length; i++) {
108
+ // eslint-disable-next-line no-bitwise
109
+ result |= value1[i] ^ value2[i];
110
+ }
111
+ return (result === 0);
112
+ }
113
+ stringToHex(stringValue) {
114
+ return (Array.from(ensureString(stringValue), (char) => (char.charCodeAt(0).toString(16).padStart(2, '0'))).join(''));
115
+ }
116
+ hexToString(hexValue) {
117
+ if (!isString(hexValue)) {
118
+ throw new CryptoError('hexValue must be a string');
119
+ }
120
+ if (!/^(?:[0-9a-f]{2})+$/.test(hexValue)) {
121
+ throw new CryptoError('hexValue must be a valid hex string');
122
+ }
123
+ return ensureArray(hexValue.match(/.{1,2}/g))
124
+ .map((byte) => String.fromCharCode(parseInt(byte, 16)))
125
+ .join('');
126
+ }
127
+ arrayBufferToString(arrayBuffer) {
128
+ return __awaiter(this, void 0, void 0, function* () {
129
+ const uint8Array = new Uint8Array(arrayBuffer);
130
+ const Decoder = yield this.getTextDecoder();
131
+ return new Decoder().decode(uint8Array);
132
+ });
133
+ }
134
+ arrayToArrayBuffer(array) {
135
+ return ((ArrayBuffer.from != undefined)
136
+ ? ArrayBuffer.from(array)
137
+ : new Uint8Array(array).buffer);
138
+ }
139
+ ensureArrayBuffer(arrayOrArrayBuffer) {
140
+ return ((arrayOrArrayBuffer instanceof ArrayBuffer)
141
+ ? arrayOrArrayBuffer
142
+ : this.arrayToArrayBuffer(arrayOrArrayBuffer));
143
+ }
144
+ getKeyOperations(keyType) {
145
+ switch (keyType) {
146
+ case 'paired':
147
+ case 'private':
148
+ case 'privateKey': {
149
+ return ['deriveKey'];
150
+ }
151
+ case 'secret':
152
+ case 'secretKey':
153
+ case 'sharedSecret': {
154
+ return ['encrypt', 'decrypt'];
155
+ }
156
+ default: {
157
+ return [];
158
+ }
159
+ }
160
+ }
161
+ getKeyAlgorythm(keyType) {
162
+ switch (keyType) {
163
+ case 'derivedKey':
164
+ case 'derived':
165
+ case 'secret':
166
+ case 'secretKey':
167
+ case 'sharedSecret': {
168
+ return {
169
+ name: 'AES-GCM',
170
+ };
171
+ }
172
+ default: {
173
+ return {
174
+ name: 'ECDH',
175
+ namedCurve: 'P-256',
176
+ };
177
+ }
178
+ }
179
+ }
180
+ generateKeyPair() {
181
+ return __awaiter(this, void 0, void 0, function* () {
182
+ const crypto = yield this.getWebCrypto();
183
+ const keyPair = yield crypto.subtle.generateKey(this.getKeyAlgorythm('paired'), true, this.getKeyOperations('paired'));
184
+ return keyPair;
185
+ });
186
+ }
187
+ generateSharedSecret() {
188
+ return __awaiter(this, void 0, void 0, function* () {
189
+ const crypto = yield this.getWebCrypto();
190
+ const keyPair = yield crypto.subtle.generateKey(this.getKeyAlgorythm('sharedSecret'), true, this.getKeyOperations('sharedSecret'));
191
+ return keyPair;
192
+ });
193
+ }
194
+ generateHMAC(message, derivedKey) {
195
+ return __awaiter(this, void 0, void 0, function* () {
196
+ if (!message || !derivedKey) {
197
+ return undefined;
198
+ }
199
+ const crypto = yield this.getWebCrypto();
200
+ const Encoder = yield this.getTextEncoder();
201
+ const signature = yield crypto.subtle.sign('HMAC', derivedKey, new Encoder().encode(message));
202
+ return this.stringToHex(this.arrayBufferToString(signature));
203
+ });
204
+ }
205
+ verifyHMAC(message, derivedKey, verifiableHMAC) {
206
+ return __awaiter(this, void 0, void 0, function* () {
207
+ const calculatedHMAC = yield this.generateHMAC(message, derivedKey);
208
+ return this.timingSafeEqual(calculatedHMAC, verifiableHMAC);
209
+ });
210
+ }
211
+ // NOTE: intentionally separated out as async to be able to .catch
212
+ getStorableKey(key) {
213
+ return __awaiter(this, void 0, void 0, function* () {
214
+ const crypto = yield this.getWebCrypto();
215
+ const exportedJWK = yield crypto.subtle.exportKey('jwk', key);
216
+ return this.stringToHex(JSON.stringify(exportedJWK));
217
+ });
218
+ }
219
+ // NOTE: intentionally separated out as async to be able to .catch
220
+ parseStorableHex(storableHex) {
221
+ return __awaiter(this, void 0, void 0, function* () {
222
+ return JSON.parse(this.hexToString(storableHex) || '{}');
223
+ });
224
+ }
225
+ restoreStorableKey(keyType, storableHex) {
226
+ return __awaiter(this, void 0, void 0, function* () {
227
+ // eslint-disable-next-line eqeqeq
228
+ if (storableHex == undefined) {
229
+ return undefined;
230
+ }
231
+ const crypto = yield this.getWebCrypto();
232
+ const exportedJWK = yield this.parseStorableHex(storableHex).catch((ignore) => {
233
+ console.error('Failed to parse storable hex value', ignore);
234
+ return undefined;
235
+ });
236
+ if (objectEmpty(exportedJWK)) {
237
+ return undefined;
238
+ }
239
+ return crypto.subtle.importKey('jwk', exportedJWK, this.getKeyAlgorythm(keyType), true, this.getKeyOperations(keyType));
240
+ });
241
+ }
242
+ getStorableKeyPair(keyPair) {
243
+ return __awaiter(this, void 0, void 0, function* () {
244
+ const storableKeys = {};
245
+ // eslint-disable-next-line no-restricted-syntax
246
+ for (const [keyType, key] of Object.entries(keyPair)) {
247
+ // eslint-disable-next-line no-await-in-loop
248
+ storableKeys[keyType] = yield this.getStorableKey(key);
249
+ }
250
+ return storableKeys;
251
+ });
252
+ }
253
+ restoreStorableKeyPair(keyPair) {
254
+ return __awaiter(this, void 0, void 0, function* () {
255
+ const restoredKeys = {};
256
+ // eslint-disable-next-line no-restricted-syntax
257
+ for (const [keyType, key] of Object.entries(keyPair)) {
258
+ // eslint-disable-next-line no-await-in-loop
259
+ restoredKeys[keyType] = yield this.restoreStorableKey(keyType, key);
260
+ }
261
+ return restoredKeys;
262
+ });
263
+ }
264
+ deriveSharedKey(_a) {
265
+ return __awaiter(this, arguments, void 0, function* ({ publicKey, privateKey }) {
266
+ if (!publicKey || !privateKey) {
267
+ return undefined;
268
+ }
269
+ const crypto = yield this.getWebCrypto();
270
+ const derivedKey = yield crypto.subtle.deriveKey({
271
+ name: 'ECDH',
272
+ public: publicKey,
273
+ }, privateKey, {
274
+ name: 'AES-GCM',
275
+ length: 256,
276
+ }, true, ['encrypt', 'decrypt']);
277
+ return derivedKey;
278
+ });
279
+ }
280
+ deriveHMACKey(_a) {
281
+ return __awaiter(this, arguments, void 0, function* ({ publicKey, privateKey }) {
282
+ if (!publicKey || !privateKey) {
283
+ return undefined;
284
+ }
285
+ const crypto = yield this.getWebCrypto();
286
+ const derivedKey = yield crypto.subtle.deriveKey({
287
+ name: 'ECDH',
288
+ public: publicKey,
289
+ }, privateKey, {
290
+ name: 'HMAC',
291
+ hash: { name: 'SHA-256' },
292
+ length: 256, // Adjusted key length, e.g., 128 bits
293
+ }, true, ['sign', 'verify']);
294
+ return derivedKey;
295
+ });
296
+ }
297
+ getVerificationKeys(_a) {
298
+ return __awaiter(this, arguments, void 0, function* ({ publicKey, privateKey }) {
299
+ if (!publicKey || !privateKey) {
300
+ return {};
301
+ }
302
+ const sharedKeyPair = yield this.restoreStorableKeyPair({ publicKey, privateKey });
303
+ const derivedHMACKey = yield this.deriveHMACKey(sharedKeyPair);
304
+ const derivedSecretKey = yield this.deriveSharedKey(sharedKeyPair);
305
+ return {
306
+ derivedSecretKey,
307
+ derivedHMACKey,
308
+ };
309
+ });
310
+ }
311
+ encryptMessage(decryptedMessage, derivedKey) {
312
+ return __awaiter(this, void 0, void 0, function* () {
313
+ if (!decryptedMessage || !derivedKey) {
314
+ return undefined;
315
+ }
316
+ const crypto = yield this.getWebCrypto();
317
+ const iv = crypto.getRandomValues(new Uint8Array(12));
318
+ const Encoder = yield this.getTextEncoder();
319
+ const encodedMessage = new Encoder().encode(decryptedMessage);
320
+ const ciphertext = yield crypto.subtle.encrypt({
321
+ name: 'AES-GCM',
322
+ iv,
323
+ }, derivedKey, encodedMessage);
324
+ const encryptedMessage = new Uint8Array([
325
+ ...iv,
326
+ ...new Uint8Array(ciphertext)
327
+ ]);
328
+ return Array.from(encryptedMessage);
329
+ });
330
+ }
331
+ decryptMessage(encryptedMessage, derivedKey) {
332
+ return __awaiter(this, void 0, void 0, function* () {
333
+ if (!encryptedMessage || !derivedKey) {
334
+ return undefined;
335
+ }
336
+ const crypto = yield this.getWebCrypto();
337
+ // NOTE: this presumed an array or arrayBuffer coming in as encryptedMessage (will fail w/ IV error if its a string)
338
+ const encryptedArrayBuffer = this.ensureArrayBuffer(encryptedMessage);
339
+ const iv = encryptedArrayBuffer.slice(0, 12);
340
+ const ciphertext = encryptedArrayBuffer.slice(12);
341
+ const decryptedArrayBuffer = yield crypto.subtle.decrypt({
342
+ name: 'AES-GCM',
343
+ iv,
344
+ }, derivedKey, ciphertext);
345
+ const Decoder = yield this.getTextDecoder();
346
+ const decryptedMessage = new Decoder().decode(decryptedArrayBuffer);
347
+ return decryptedMessage;
348
+ });
349
+ }
350
+ }
@@ -0,0 +1,26 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { stringEmpty } from './display';
11
+ import { WebCrypto } from './WebCrypto';
12
+ export const getAuthorizationHelpers = (sharedSecret_1, ...args_1) => __awaiter(void 0, [sharedSecret_1, ...args_1], void 0, function* (sharedSecret, { crypto: _crypto, util: _util } = {}) {
13
+ if (stringEmpty(sharedSecret)) {
14
+ return undefined;
15
+ }
16
+ const webCrypto = new WebCrypto({ crypto: _crypto, util: _util });
17
+ const sharedKey = yield webCrypto.restoreStorableKey('sharedSecret', sharedSecret);
18
+ return {
19
+ encrypt: (decryptedMessage) => __awaiter(void 0, void 0, void 0, function* () {
20
+ return (webCrypto.encryptMessage(decryptedMessage, sharedKey));
21
+ }),
22
+ decrypt: (encryptedMessage) => __awaiter(void 0, void 0, void 0, function* () {
23
+ return (webCrypto.decryptMessage(encryptedMessage, sharedKey));
24
+ }),
25
+ };
26
+ });