@bananalink-sdk/protocol 1.2.7 → 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/dist/{chunk-32OWUOZ3.js → chunk-KJ7QIHAY.js} +11 -7
- package/dist/chunk-KJ7QIHAY.js.map +1 -0
- package/dist/{chunk-VXLUSU5B.cjs → chunk-MUYKP6UQ.cjs} +63 -8
- package/dist/chunk-MUYKP6UQ.cjs.map +1 -0
- package/dist/{chunk-MCZG7QEM.cjs → chunk-NGPP7HUR.cjs} +11 -7
- package/dist/chunk-NGPP7HUR.cjs.map +1 -0
- package/dist/{chunk-LELPCIE7.js → chunk-OBJR2TL4.js} +54 -4
- package/dist/chunk-OBJR2TL4.js.map +1 -0
- package/dist/crypto/providers/noble-provider.cjs +2 -3
- package/dist/crypto/providers/noble-provider.d.cts +0 -7
- package/dist/crypto/providers/noble-provider.d.ts +0 -7
- package/dist/crypto/providers/noble-provider.js +1 -2
- package/dist/crypto/providers/node-provider.cjs +7 -29
- package/dist/crypto/providers/node-provider.cjs.map +1 -1
- package/dist/crypto/providers/node-provider.d.cts +0 -7
- package/dist/crypto/providers/node-provider.d.ts +0 -7
- package/dist/crypto/providers/node-provider.js +7 -29
- package/dist/crypto/providers/node-provider.js.map +1 -1
- package/dist/crypto/providers/quickcrypto-provider.cjs +8 -46
- package/dist/crypto/providers/quickcrypto-provider.cjs.map +1 -1
- package/dist/crypto/providers/quickcrypto-provider.d.cts +0 -9
- package/dist/crypto/providers/quickcrypto-provider.d.ts +0 -9
- package/dist/crypto/providers/quickcrypto-provider.js +7 -45
- package/dist/crypto/providers/quickcrypto-provider.js.map +1 -1
- package/dist/crypto/providers/webcrypto-provider.cjs +0 -2
- package/dist/crypto/providers/webcrypto-provider.cjs.map +1 -1
- package/dist/crypto/providers/webcrypto-provider.d.cts +0 -7
- package/dist/crypto/providers/webcrypto-provider.d.ts +0 -7
- package/dist/crypto/providers/webcrypto-provider.js +0 -2
- package/dist/crypto/providers/webcrypto-provider.js.map +1 -1
- package/dist/crypto-export.cjs +50 -51
- package/dist/crypto-export.cjs.map +1 -1
- package/dist/crypto-export.js +2 -4
- package/dist/crypto-export.js.map +1 -1
- package/dist/index.cjs +3 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2 -3
- package/dist/index.js.map +1 -1
- package/package.json +17 -18
- package/src/crypto/providers/noble-provider.ts +44 -49
- package/src/crypto/providers/node-provider.ts +18 -59
- package/src/crypto/providers/quickcrypto-provider.ts +25 -84
- package/src/crypto/providers/registry.ts +14 -9
- package/src/crypto/providers/webcrypto-provider.ts +28 -43
- package/dist/chunk-32OWUOZ3.js.map +0 -1
- package/dist/chunk-A6FLEJ7R.cjs +0 -62
- package/dist/chunk-A6FLEJ7R.cjs.map +0 -1
- package/dist/chunk-LELPCIE7.js.map +0 -1
- package/dist/chunk-MCZG7QEM.cjs.map +0 -1
- package/dist/chunk-TCVKC227.js +0 -56
- package/dist/chunk-TCVKC227.js.map +0 -1
- package/dist/chunk-VXLUSU5B.cjs.map +0 -1
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { Logger } from '@bananalink-sdk/logger';
|
|
2
2
|
import type { CryptoProvider, CryptoKeyLike, ProviderKeyPair } from '../../types/crypto-provider';
|
|
3
|
-
import { registerCryptoProvider } from './registry';
|
|
4
3
|
|
|
5
4
|
/**
|
|
6
5
|
* Type definition for Node.js crypto module (loaded dynamically to prevent Metro bundling)
|
|
@@ -14,7 +13,7 @@ type NodeCrypto = typeof import('crypto');
|
|
|
14
13
|
class NodeCryptoKeyWrapper implements CryptoKeyLike {
|
|
15
14
|
constructor(
|
|
16
15
|
private readonly keyObject: unknown, // crypto.KeyObject | Buffer at runtime
|
|
17
|
-
private readonly keyType: 'public' | 'private' | 'secret'
|
|
16
|
+
private readonly keyType: 'public' | 'private' | 'secret',
|
|
18
17
|
) {}
|
|
19
18
|
|
|
20
19
|
get type(): 'public' | 'private' | 'secret' {
|
|
@@ -101,10 +100,7 @@ export class NodeCryptoProvider implements CryptoProvider {
|
|
|
101
100
|
// Dynamic import prevents static analysis by bundlers
|
|
102
101
|
this.cryptoModule = await import('crypto');
|
|
103
102
|
} catch {
|
|
104
|
-
throw new Error(
|
|
105
|
-
'Failed to load Node.js crypto module. ' +
|
|
106
|
-
'This provider requires a Node.js environment.'
|
|
107
|
-
);
|
|
103
|
+
throw new Error('Failed to load Node.js crypto module. ' + 'This provider requires a Node.js environment.');
|
|
108
104
|
}
|
|
109
105
|
}
|
|
110
106
|
return this.cryptoModule;
|
|
@@ -138,7 +134,7 @@ export class NodeCryptoProvider implements CryptoProvider {
|
|
|
138
134
|
publicKey: new NodeCryptoKeyWrapper(publicKey, 'public'),
|
|
139
135
|
privateKey: new NodeCryptoKeyWrapper(privateKey, 'private'),
|
|
140
136
|
});
|
|
141
|
-
}
|
|
137
|
+
},
|
|
142
138
|
);
|
|
143
139
|
});
|
|
144
140
|
}
|
|
@@ -152,9 +148,10 @@ export class NodeCryptoProvider implements CryptoProvider {
|
|
|
152
148
|
const keyObject = unwrapKeyObject(publicKey);
|
|
153
149
|
|
|
154
150
|
// If it's a Buffer (DER format from generateKeyPair), convert to KeyObject first
|
|
155
|
-
const keyObj =
|
|
156
|
-
|
|
157
|
-
|
|
151
|
+
const keyObj =
|
|
152
|
+
keyObject instanceof Buffer
|
|
153
|
+
? cryptoModule.createPublicKey({ key: keyObject, format: 'der', type: 'spki' })
|
|
154
|
+
: keyObject;
|
|
158
155
|
|
|
159
156
|
// Export as JWK to get X/Y coordinates
|
|
160
157
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any
|
|
@@ -168,10 +165,7 @@ export class NodeCryptoProvider implements CryptoProvider {
|
|
|
168
165
|
const uncompressed = Buffer.concat([Buffer.from([0x04]), x, y]);
|
|
169
166
|
|
|
170
167
|
return await Promise.resolve(
|
|
171
|
-
uncompressed.buffer.slice(
|
|
172
|
-
uncompressed.byteOffset,
|
|
173
|
-
uncompressed.byteOffset + uncompressed.byteLength
|
|
174
|
-
)
|
|
168
|
+
uncompressed.buffer.slice(uncompressed.byteOffset, uncompressed.byteOffset + uncompressed.byteLength),
|
|
175
169
|
);
|
|
176
170
|
}
|
|
177
171
|
|
|
@@ -195,9 +189,7 @@ export class NodeCryptoProvider implements CryptoProvider {
|
|
|
195
189
|
const jwk = keyObj.export({ format: 'jwk' });
|
|
196
190
|
const dValue = Buffer.from(jwk.d as string, 'base64url');
|
|
197
191
|
|
|
198
|
-
return await Promise.resolve(
|
|
199
|
-
dValue.buffer.slice(dValue.byteOffset, dValue.byteOffset + dValue.byteLength)
|
|
200
|
-
);
|
|
192
|
+
return await Promise.resolve(dValue.buffer.slice(dValue.byteOffset, dValue.byteOffset + dValue.byteLength));
|
|
201
193
|
}
|
|
202
194
|
|
|
203
195
|
/**
|
|
@@ -279,11 +271,7 @@ export class NodeCryptoProvider implements CryptoProvider {
|
|
|
279
271
|
/**
|
|
280
272
|
* Derive AES-GCM encryption key using HKDF-SHA256
|
|
281
273
|
*/
|
|
282
|
-
async deriveEncryptionKey(
|
|
283
|
-
sharedSecret: CryptoKeyLike,
|
|
284
|
-
salt: ArrayBuffer,
|
|
285
|
-
info: ArrayBuffer
|
|
286
|
-
): Promise<CryptoKeyLike> {
|
|
274
|
+
async deriveEncryptionKey(sharedSecret: CryptoKeyLike, salt: ArrayBuffer, info: ArrayBuffer): Promise<CryptoKeyLike> {
|
|
287
275
|
this.logger?.debug('Deriving AES-GCM encryption key');
|
|
288
276
|
const cryptoModule = await this.getCrypto();
|
|
289
277
|
|
|
@@ -298,7 +286,7 @@ export class NodeCryptoProvider implements CryptoProvider {
|
|
|
298
286
|
Buffer.isBuffer(sharedSecretRaw) ? sharedSecretRaw : Buffer.from(sharedSecretRaw),
|
|
299
287
|
Buffer.from(salt),
|
|
300
288
|
Buffer.from(info),
|
|
301
|
-
32 // 256 bits
|
|
289
|
+
32, // 256 bits
|
|
302
290
|
) as Buffer;
|
|
303
291
|
|
|
304
292
|
// Create secret key object
|
|
@@ -318,20 +306,13 @@ export class NodeCryptoProvider implements CryptoProvider {
|
|
|
318
306
|
'aes-256-gcm',
|
|
319
307
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any
|
|
320
308
|
(keyObject as any).export(),
|
|
321
|
-
Buffer.from(iv)
|
|
309
|
+
Buffer.from(iv),
|
|
322
310
|
);
|
|
323
311
|
|
|
324
|
-
const encrypted = Buffer.concat([
|
|
325
|
-
cipher.update(Buffer.from(data)),
|
|
326
|
-
cipher.final(),
|
|
327
|
-
cipher.getAuthTag(),
|
|
328
|
-
]);
|
|
312
|
+
const encrypted = Buffer.concat([cipher.update(Buffer.from(data)), cipher.final(), cipher.getAuthTag()]);
|
|
329
313
|
|
|
330
314
|
return await Promise.resolve(
|
|
331
|
-
encrypted.buffer.slice(
|
|
332
|
-
encrypted.byteOffset,
|
|
333
|
-
encrypted.byteOffset + encrypted.byteLength
|
|
334
|
-
)
|
|
315
|
+
encrypted.buffer.slice(encrypted.byteOffset, encrypted.byteOffset + encrypted.byteLength),
|
|
335
316
|
);
|
|
336
317
|
}
|
|
337
318
|
|
|
@@ -352,17 +333,14 @@ export class NodeCryptoProvider implements CryptoProvider {
|
|
|
352
333
|
'aes-256-gcm',
|
|
353
334
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any
|
|
354
335
|
(keyObject as any).export(),
|
|
355
|
-
Buffer.from(iv)
|
|
336
|
+
Buffer.from(iv),
|
|
356
337
|
);
|
|
357
338
|
decipher.setAuthTag(authTag);
|
|
358
339
|
|
|
359
340
|
const decrypted = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
|
|
360
341
|
|
|
361
342
|
return await Promise.resolve(
|
|
362
|
-
decrypted.buffer.slice(
|
|
363
|
-
decrypted.byteOffset,
|
|
364
|
-
decrypted.byteOffset + decrypted.byteLength
|
|
365
|
-
)
|
|
343
|
+
decrypted.buffer.slice(decrypted.byteOffset, decrypted.byteOffset + decrypted.byteLength),
|
|
366
344
|
);
|
|
367
345
|
}
|
|
368
346
|
|
|
@@ -397,10 +375,7 @@ export class NodeCryptoProvider implements CryptoProvider {
|
|
|
397
375
|
}
|
|
398
376
|
|
|
399
377
|
// Constant-time comparison
|
|
400
|
-
return cryptoModule.timingSafeEqual(
|
|
401
|
-
Buffer.from(expected),
|
|
402
|
-
Buffer.from(actual)
|
|
403
|
-
);
|
|
378
|
+
return cryptoModule.timingSafeEqual(Buffer.from(expected), Buffer.from(actual));
|
|
404
379
|
}
|
|
405
380
|
|
|
406
381
|
/**
|
|
@@ -410,24 +385,8 @@ export class NodeCryptoProvider implements CryptoProvider {
|
|
|
410
385
|
randomBytes(length: number): ArrayBuffer {
|
|
411
386
|
// Use cached module if available, otherwise use synchronous require
|
|
412
387
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
413
|
-
const cryptoModule = this.cryptoModule ?? require('crypto') as NodeCrypto;
|
|
388
|
+
const cryptoModule = this.cryptoModule ?? (require('crypto') as NodeCrypto);
|
|
414
389
|
const buffer = cryptoModule.randomBytes(length);
|
|
415
390
|
return buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
|
|
416
391
|
}
|
|
417
392
|
}
|
|
418
|
-
|
|
419
|
-
/**
|
|
420
|
-
* Self-register Node provider on import
|
|
421
|
-
* This allows the provider to be available when explicitly imported
|
|
422
|
-
*/
|
|
423
|
-
registerCryptoProvider('node', (logger) => new NodeCryptoProvider(logger));
|
|
424
|
-
|
|
425
|
-
// TypeScript module augmentation to track this provider is available
|
|
426
|
-
declare global {
|
|
427
|
-
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
428
|
-
namespace BananaLink {
|
|
429
|
-
interface RegisteredCryptoProviders {
|
|
430
|
-
node: true;
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { Logger } from '@bananalink-sdk/logger';
|
|
2
2
|
import type { CryptoProvider, CryptoKeyLike, ProviderKeyPair } from '../../types/crypto-provider';
|
|
3
3
|
import { NobleCryptoProvider } from './noble-provider';
|
|
4
|
-
import { registerCryptoProvider } from './registry';
|
|
5
4
|
|
|
6
5
|
// Global require function type for React Native environments
|
|
7
6
|
type RequireFunction = (id: string) => unknown;
|
|
@@ -51,7 +50,7 @@ class QuickCryptoKey implements CryptoKeyLike {
|
|
|
51
50
|
public readonly type: 'public' | 'private' | 'secret',
|
|
52
51
|
public readonly algorithm: string,
|
|
53
52
|
public readonly extractable: boolean = true,
|
|
54
|
-
public readonly usages: readonly string[] = []
|
|
53
|
+
public readonly usages: readonly string[] = [],
|
|
55
54
|
) {}
|
|
56
55
|
}
|
|
57
56
|
|
|
@@ -110,8 +109,8 @@ export class QuickCryptoProvider implements CryptoProvider {
|
|
|
110
109
|
this.logger?.error('Failed to initialize QuickCrypto', {
|
|
111
110
|
error: {
|
|
112
111
|
message: error instanceof Error ? error.message : String(error),
|
|
113
|
-
stack: error instanceof Error ? error.stack : undefined
|
|
114
|
-
}
|
|
112
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
113
|
+
},
|
|
115
114
|
});
|
|
116
115
|
// Mark as unavailable if we can't actually use it
|
|
117
116
|
(this as { isAvailable: boolean }).isAvailable = false;
|
|
@@ -137,20 +136,8 @@ export class QuickCryptoProvider implements CryptoProvider {
|
|
|
137
136
|
}
|
|
138
137
|
|
|
139
138
|
return {
|
|
140
|
-
privateKey: new QuickCryptoKey(
|
|
141
|
-
|
|
142
|
-
'private',
|
|
143
|
-
'ECDH-P256',
|
|
144
|
-
true,
|
|
145
|
-
['deriveKey']
|
|
146
|
-
),
|
|
147
|
-
publicKey: new QuickCryptoKey(
|
|
148
|
-
nobleKeyPair.publicKey.data,
|
|
149
|
-
'public',
|
|
150
|
-
'ECDH-P256',
|
|
151
|
-
true,
|
|
152
|
-
[]
|
|
153
|
-
)
|
|
139
|
+
privateKey: new QuickCryptoKey(nobleKeyPair.privateKey.data, 'private', 'ECDH-P256', true, ['deriveKey']),
|
|
140
|
+
publicKey: new QuickCryptoKey(nobleKeyPair.publicKey.data, 'public', 'ECDH-P256', true, []),
|
|
154
141
|
};
|
|
155
142
|
}
|
|
156
143
|
|
|
@@ -179,13 +166,7 @@ export class QuickCryptoProvider implements CryptoProvider {
|
|
|
179
166
|
}
|
|
180
167
|
|
|
181
168
|
// Wrap in QuickCryptoKey for consistency
|
|
182
|
-
return new QuickCryptoKey(
|
|
183
|
-
nobleKey.data,
|
|
184
|
-
'public',
|
|
185
|
-
'ECDH-P256',
|
|
186
|
-
true,
|
|
187
|
-
[]
|
|
188
|
-
);
|
|
169
|
+
return new QuickCryptoKey(nobleKey.data, 'public', 'ECDH-P256', true, []);
|
|
189
170
|
}
|
|
190
171
|
|
|
191
172
|
/**
|
|
@@ -199,13 +180,7 @@ export class QuickCryptoProvider implements CryptoProvider {
|
|
|
199
180
|
}
|
|
200
181
|
|
|
201
182
|
// Wrap in QuickCryptoKey for consistency
|
|
202
|
-
return new QuickCryptoKey(
|
|
203
|
-
nobleKey.data,
|
|
204
|
-
'private',
|
|
205
|
-
'ECDH-P256',
|
|
206
|
-
true,
|
|
207
|
-
['deriveKey']
|
|
208
|
-
);
|
|
183
|
+
return new QuickCryptoKey(nobleKey.data, 'private', 'ECDH-P256', true, ['deriveKey']);
|
|
209
184
|
}
|
|
210
185
|
|
|
211
186
|
/**
|
|
@@ -221,13 +196,7 @@ export class QuickCryptoProvider implements CryptoProvider {
|
|
|
221
196
|
}
|
|
222
197
|
|
|
223
198
|
// Wrap in QuickCryptoKey for consistency
|
|
224
|
-
return new QuickCryptoKey(
|
|
225
|
-
sharedSecret.data,
|
|
226
|
-
'secret',
|
|
227
|
-
'AES-GCM',
|
|
228
|
-
true,
|
|
229
|
-
['encrypt', 'decrypt']
|
|
230
|
-
);
|
|
199
|
+
return new QuickCryptoKey(sharedSecret.data, 'secret', 'AES-GCM', true, ['encrypt', 'decrypt']);
|
|
231
200
|
}
|
|
232
201
|
|
|
233
202
|
/**
|
|
@@ -241,13 +210,7 @@ export class QuickCryptoProvider implements CryptoProvider {
|
|
|
241
210
|
}
|
|
242
211
|
|
|
243
212
|
// Wrap in QuickCryptoKey for consistency
|
|
244
|
-
return new QuickCryptoKey(
|
|
245
|
-
encryptionKey.data,
|
|
246
|
-
'secret',
|
|
247
|
-
'AES-GCM',
|
|
248
|
-
true,
|
|
249
|
-
['encrypt', 'decrypt']
|
|
250
|
-
);
|
|
213
|
+
return new QuickCryptoKey(encryptionKey.data, 'secret', 'AES-GCM', true, ['encrypt', 'decrypt']);
|
|
251
214
|
}
|
|
252
215
|
|
|
253
216
|
/**
|
|
@@ -265,8 +228,8 @@ export class QuickCryptoProvider implements CryptoProvider {
|
|
|
265
228
|
} catch (error) {
|
|
266
229
|
this.logger?.error('QuickCrypto randomBytes failed, falling back to Noble', {
|
|
267
230
|
error: {
|
|
268
|
-
message: error instanceof Error ? error.message : String(error)
|
|
269
|
-
}
|
|
231
|
+
message: error instanceof Error ? error.message : String(error),
|
|
232
|
+
},
|
|
270
233
|
});
|
|
271
234
|
return this.nobleProvider.randomBytes(length);
|
|
272
235
|
}
|
|
@@ -283,7 +246,7 @@ export class QuickCryptoProvider implements CryptoProvider {
|
|
|
283
246
|
|
|
284
247
|
this.logger?.debug('Encrypting data with AES-GCM using QuickCrypto', {
|
|
285
248
|
dataSize: data.byteLength,
|
|
286
|
-
ivSize: iv.byteLength
|
|
249
|
+
ivSize: iv.byteLength,
|
|
287
250
|
});
|
|
288
251
|
|
|
289
252
|
const secretKey = key as QuickCryptoKey;
|
|
@@ -291,7 +254,7 @@ export class QuickCryptoProvider implements CryptoProvider {
|
|
|
291
254
|
if (secretKey.type !== 'secret') {
|
|
292
255
|
const error = new Error('Expected secret key');
|
|
293
256
|
this.logger?.error('Encryption failed - invalid key type', {
|
|
294
|
-
actualType: secretKey.type
|
|
257
|
+
actualType: secretKey.type,
|
|
295
258
|
});
|
|
296
259
|
throw error;
|
|
297
260
|
}
|
|
@@ -313,7 +276,7 @@ export class QuickCryptoProvider implements CryptoProvider {
|
|
|
313
276
|
result.set(authTag, encrypted.length + final.length);
|
|
314
277
|
|
|
315
278
|
this.logger?.debug('Encryption completed using QuickCrypto', {
|
|
316
|
-
ciphertextSize: result.byteLength
|
|
279
|
+
ciphertextSize: result.byteLength,
|
|
317
280
|
});
|
|
318
281
|
|
|
319
282
|
return result.buffer.slice(result.byteOffset, result.byteOffset + result.byteLength);
|
|
@@ -321,8 +284,8 @@ export class QuickCryptoProvider implements CryptoProvider {
|
|
|
321
284
|
this.logger?.error('QuickCrypto encryption failed, falling back to Noble', {
|
|
322
285
|
error: {
|
|
323
286
|
message: error instanceof Error ? error.message : String(error),
|
|
324
|
-
stack: error instanceof Error ? error.stack : undefined
|
|
325
|
-
}
|
|
287
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
288
|
+
},
|
|
326
289
|
});
|
|
327
290
|
return this.nobleProvider.encrypt(key, data, iv);
|
|
328
291
|
}
|
|
@@ -339,7 +302,7 @@ export class QuickCryptoProvider implements CryptoProvider {
|
|
|
339
302
|
|
|
340
303
|
this.logger?.debug('Decrypting data with AES-GCM using QuickCrypto', {
|
|
341
304
|
dataSize: data.byteLength,
|
|
342
|
-
ivSize: iv.byteLength
|
|
305
|
+
ivSize: iv.byteLength,
|
|
343
306
|
});
|
|
344
307
|
|
|
345
308
|
const secretKey = key as QuickCryptoKey;
|
|
@@ -347,7 +310,7 @@ export class QuickCryptoProvider implements CryptoProvider {
|
|
|
347
310
|
if (secretKey.type !== 'secret') {
|
|
348
311
|
const error = new Error('Expected secret key');
|
|
349
312
|
this.logger?.error('Decryption failed - invalid key type', {
|
|
350
|
-
actualType: secretKey.type
|
|
313
|
+
actualType: secretKey.type,
|
|
351
314
|
});
|
|
352
315
|
throw error;
|
|
353
316
|
}
|
|
@@ -378,7 +341,7 @@ export class QuickCryptoProvider implements CryptoProvider {
|
|
|
378
341
|
result.set(final, decrypted.length);
|
|
379
342
|
|
|
380
343
|
this.logger?.debug('Decryption completed using QuickCrypto', {
|
|
381
|
-
plaintextSize: result.byteLength
|
|
344
|
+
plaintextSize: result.byteLength,
|
|
382
345
|
});
|
|
383
346
|
|
|
384
347
|
return result.buffer.slice(result.byteOffset, result.byteOffset + result.byteLength);
|
|
@@ -386,8 +349,8 @@ export class QuickCryptoProvider implements CryptoProvider {
|
|
|
386
349
|
this.logger?.error('QuickCrypto decryption failed, falling back to Noble', {
|
|
387
350
|
error: {
|
|
388
351
|
message: error instanceof Error ? error.message : String(error),
|
|
389
|
-
stack: error instanceof Error ? error.stack : undefined
|
|
390
|
-
}
|
|
352
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
353
|
+
},
|
|
391
354
|
});
|
|
392
355
|
return this.nobleProvider.decrypt(key, data, iv);
|
|
393
356
|
}
|
|
@@ -417,8 +380,8 @@ export class QuickCryptoProvider implements CryptoProvider {
|
|
|
417
380
|
} catch (error) {
|
|
418
381
|
this.logger?.error('QuickCrypto HMAC failed, falling back to Noble', {
|
|
419
382
|
error: {
|
|
420
|
-
message: error instanceof Error ? error.message : String(error)
|
|
421
|
-
}
|
|
383
|
+
message: error instanceof Error ? error.message : String(error),
|
|
384
|
+
},
|
|
422
385
|
});
|
|
423
386
|
return this.nobleProvider.generateHMAC(key, data);
|
|
424
387
|
}
|
|
@@ -452,32 +415,10 @@ export class QuickCryptoProvider implements CryptoProvider {
|
|
|
452
415
|
} catch (error) {
|
|
453
416
|
this.logger?.error('QuickCrypto HMAC verification failed, falling back to Noble', {
|
|
454
417
|
error: {
|
|
455
|
-
message: error instanceof Error ? error.message : String(error)
|
|
456
|
-
}
|
|
418
|
+
message: error instanceof Error ? error.message : String(error),
|
|
419
|
+
},
|
|
457
420
|
});
|
|
458
421
|
return this.nobleProvider.verifyHMAC(key, data, mac);
|
|
459
422
|
}
|
|
460
423
|
}
|
|
461
424
|
}
|
|
462
|
-
|
|
463
|
-
/**
|
|
464
|
-
* Self-register QuickCrypto provider on import
|
|
465
|
-
* This allows the provider to be available when explicitly imported
|
|
466
|
-
*
|
|
467
|
-
* Note: QuickCrypto depends on Noble for ECDH operations, so we auto-register
|
|
468
|
-
* Noble as well to ensure all required functionality is available.
|
|
469
|
-
*/
|
|
470
|
-
// Auto-register noble as a dependency (QuickCrypto delegates ECDH to Noble)
|
|
471
|
-
import './noble-provider';
|
|
472
|
-
|
|
473
|
-
registerCryptoProvider('quickcrypto', (logger) => new QuickCryptoProvider(logger));
|
|
474
|
-
|
|
475
|
-
// TypeScript module augmentation to track this provider is available
|
|
476
|
-
declare global {
|
|
477
|
-
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
478
|
-
namespace BananaLink {
|
|
479
|
-
interface RegisteredCryptoProviders {
|
|
480
|
-
quickcrypto: true;
|
|
481
|
-
}
|
|
482
|
-
}
|
|
483
|
-
}
|
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Global registry for crypto providers
|
|
3
3
|
*
|
|
4
|
-
* This
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* @deprecated This module is deprecated. Use crypto factory functions instead:
|
|
5
|
+
* ```typescript
|
|
6
|
+
* import { BananaLink, webSocketTransport, nobleCrypto } from '@bananalink-sdk/client'
|
|
7
|
+
*
|
|
8
|
+
* const client = new BananaLink({
|
|
9
|
+
* transport: webSocketTransport(),
|
|
10
|
+
* crypto: nobleCrypto(),
|
|
11
|
+
* })
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* The registry is kept for backward compatibility but will be removed in a future version.
|
|
7
15
|
*/
|
|
8
16
|
|
|
9
17
|
import type { CryptoProvider, CryptoProviderType } from '../../types/crypto-provider';
|
|
@@ -35,10 +43,7 @@ const cryptoProviders = new Map<CryptoProviderType, CryptoProviderFactory>();
|
|
|
35
43
|
* registerCryptoProvider('noble', (logger) => new NobleCryptoProvider(logger));
|
|
36
44
|
* ```
|
|
37
45
|
*/
|
|
38
|
-
export function registerCryptoProvider(
|
|
39
|
-
type: CryptoProviderType,
|
|
40
|
-
factory: CryptoProviderFactory
|
|
41
|
-
): void {
|
|
46
|
+
export function registerCryptoProvider(type: CryptoProviderType, factory: CryptoProviderFactory): void {
|
|
42
47
|
// Skip if already registered (idempotent)
|
|
43
48
|
if (cryptoProviders.has(type)) {
|
|
44
49
|
return;
|
|
@@ -62,8 +67,8 @@ export function getCryptoProviderFactory(type: CryptoProviderType): CryptoProvid
|
|
|
62
67
|
|
|
63
68
|
throw new Error(
|
|
64
69
|
`Crypto provider '${type}' is not registered. ${importHint}\n` +
|
|
65
|
-
|
|
66
|
-
|
|
70
|
+
`Available providers: ${availableProviders || 'none'}\n` +
|
|
71
|
+
`Make sure to import the provider before using it.`,
|
|
67
72
|
);
|
|
68
73
|
}
|
|
69
74
|
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { Logger } from '@bananalink-sdk/logger';
|
|
2
2
|
import type { CryptoProvider, CryptoKeyLike, ProviderKeyPair } from '../../types/crypto-provider';
|
|
3
|
-
import { registerCryptoProvider } from './registry';
|
|
4
3
|
|
|
5
4
|
/**
|
|
6
5
|
* WebCrypto CryptoKey wrapper to implement CryptoKeyLike interface
|
|
@@ -74,7 +73,7 @@ export class WebCryptoProvider implements CryptoProvider {
|
|
|
74
73
|
namedCurve: 'P-256',
|
|
75
74
|
},
|
|
76
75
|
true, // extractable
|
|
77
|
-
['deriveKey']
|
|
76
|
+
['deriveKey'],
|
|
78
77
|
);
|
|
79
78
|
|
|
80
79
|
this.logger?.debug('Key pair generation completed');
|
|
@@ -110,7 +109,9 @@ export class WebCryptoProvider implements CryptoProvider {
|
|
|
110
109
|
|
|
111
110
|
this.logger?.debug('importPublicKey called', {
|
|
112
111
|
keyLength: keyBytes.length,
|
|
113
|
-
keyBytesFirst20: Array.from(keyBytes.slice(0, 20))
|
|
112
|
+
keyBytesFirst20: Array.from(keyBytes.slice(0, 20))
|
|
113
|
+
.map((b) => b.toString(16).padStart(2, '0'))
|
|
114
|
+
.join(' '),
|
|
114
115
|
});
|
|
115
116
|
|
|
116
117
|
try {
|
|
@@ -122,7 +123,7 @@ export class WebCryptoProvider implements CryptoProvider {
|
|
|
122
123
|
namedCurve: 'P-256',
|
|
123
124
|
},
|
|
124
125
|
true,
|
|
125
|
-
[]
|
|
126
|
+
[],
|
|
126
127
|
);
|
|
127
128
|
|
|
128
129
|
this.logger?.debug('Public key import successful');
|
|
@@ -131,8 +132,8 @@ export class WebCryptoProvider implements CryptoProvider {
|
|
|
131
132
|
this.logger?.error('Public key import failed', {
|
|
132
133
|
error: {
|
|
133
134
|
message: error instanceof Error ? error.message : String(error),
|
|
134
|
-
stack: error instanceof Error ? error.stack : undefined
|
|
135
|
-
}
|
|
135
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
136
|
+
},
|
|
136
137
|
});
|
|
137
138
|
throw new Error(`Invalid P-256 public key: ${String(error)}`);
|
|
138
139
|
}
|
|
@@ -143,7 +144,7 @@ export class WebCryptoProvider implements CryptoProvider {
|
|
|
143
144
|
*/
|
|
144
145
|
async importPrivateKey(keyData: ArrayBuffer): Promise<CryptoKeyLike> {
|
|
145
146
|
this.logger?.debug('Importing private key', {
|
|
146
|
-
keyLength: keyData.byteLength
|
|
147
|
+
keyLength: keyData.byteLength,
|
|
147
148
|
});
|
|
148
149
|
|
|
149
150
|
try {
|
|
@@ -155,7 +156,7 @@ export class WebCryptoProvider implements CryptoProvider {
|
|
|
155
156
|
namedCurve: 'P-256',
|
|
156
157
|
},
|
|
157
158
|
true,
|
|
158
|
-
['deriveKey']
|
|
159
|
+
['deriveKey'],
|
|
159
160
|
);
|
|
160
161
|
|
|
161
162
|
this.logger?.debug('Private key import successful');
|
|
@@ -164,8 +165,8 @@ export class WebCryptoProvider implements CryptoProvider {
|
|
|
164
165
|
this.logger?.error('Private key import failed', {
|
|
165
166
|
error: {
|
|
166
167
|
message: error instanceof Error ? error.message : String(error),
|
|
167
|
-
stack: error instanceof Error ? error.stack : undefined
|
|
168
|
-
}
|
|
168
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
169
|
+
},
|
|
169
170
|
});
|
|
170
171
|
throw new Error(`Invalid P-256 private key: ${String(error)}`);
|
|
171
172
|
}
|
|
@@ -189,7 +190,7 @@ export class WebCryptoProvider implements CryptoProvider {
|
|
|
189
190
|
length: 256,
|
|
190
191
|
},
|
|
191
192
|
true,
|
|
192
|
-
['encrypt', 'decrypt']
|
|
193
|
+
['encrypt', 'decrypt'],
|
|
193
194
|
);
|
|
194
195
|
|
|
195
196
|
this.logger?.debug('Shared secret derivation completed');
|
|
@@ -198,8 +199,8 @@ export class WebCryptoProvider implements CryptoProvider {
|
|
|
198
199
|
this.logger?.error('Shared secret derivation failed', {
|
|
199
200
|
error: {
|
|
200
201
|
message: error instanceof Error ? error.message : String(error),
|
|
201
|
-
stack: error instanceof Error ? error.stack : undefined
|
|
202
|
-
}
|
|
202
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
203
|
+
},
|
|
203
204
|
});
|
|
204
205
|
throw error;
|
|
205
206
|
}
|
|
@@ -215,7 +216,7 @@ export class WebCryptoProvider implements CryptoProvider {
|
|
|
215
216
|
await crypto.subtle.exportKey('raw', unwrapCryptoKey(sharedSecret)),
|
|
216
217
|
{ name: 'HKDF' },
|
|
217
218
|
false,
|
|
218
|
-
['deriveKey']
|
|
219
|
+
['deriveKey'],
|
|
219
220
|
);
|
|
220
221
|
|
|
221
222
|
// Derive encryption key using HKDF
|
|
@@ -229,7 +230,7 @@ export class WebCryptoProvider implements CryptoProvider {
|
|
|
229
230
|
baseKey,
|
|
230
231
|
{ name: 'AES-GCM', length: 256 },
|
|
231
232
|
true,
|
|
232
|
-
['encrypt', 'decrypt']
|
|
233
|
+
['encrypt', 'decrypt'],
|
|
233
234
|
);
|
|
234
235
|
return new WebCryptoKeyWrapper(derivedKey);
|
|
235
236
|
}
|
|
@@ -250,7 +251,7 @@ export class WebCryptoProvider implements CryptoProvider {
|
|
|
250
251
|
async encrypt(key: CryptoKeyLike, data: ArrayBuffer, iv: ArrayBuffer): Promise<ArrayBuffer> {
|
|
251
252
|
this.logger?.debug('Encrypting data with AES-GCM', {
|
|
252
253
|
dataSize: data.byteLength,
|
|
253
|
-
ivSize: iv.byteLength
|
|
254
|
+
ivSize: iv.byteLength,
|
|
254
255
|
});
|
|
255
256
|
|
|
256
257
|
try {
|
|
@@ -261,19 +262,19 @@ export class WebCryptoProvider implements CryptoProvider {
|
|
|
261
262
|
tagLength: 128, // 128-bit tag
|
|
262
263
|
},
|
|
263
264
|
unwrapCryptoKey(key),
|
|
264
|
-
data
|
|
265
|
+
data,
|
|
265
266
|
);
|
|
266
267
|
|
|
267
268
|
this.logger?.debug('Encryption completed', {
|
|
268
|
-
ciphertextSize: ciphertext.byteLength
|
|
269
|
+
ciphertextSize: ciphertext.byteLength,
|
|
269
270
|
});
|
|
270
271
|
return ciphertext;
|
|
271
272
|
} catch (error) {
|
|
272
273
|
this.logger?.error('Encryption failed', {
|
|
273
274
|
error: {
|
|
274
275
|
message: error instanceof Error ? error.message : String(error),
|
|
275
|
-
stack: error instanceof Error ? error.stack : undefined
|
|
276
|
-
}
|
|
276
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
277
|
+
},
|
|
277
278
|
});
|
|
278
279
|
throw error;
|
|
279
280
|
}
|
|
@@ -285,7 +286,7 @@ export class WebCryptoProvider implements CryptoProvider {
|
|
|
285
286
|
async decrypt(key: CryptoKeyLike, data: ArrayBuffer, iv: ArrayBuffer): Promise<ArrayBuffer> {
|
|
286
287
|
this.logger?.debug('Decrypting data with AES-GCM', {
|
|
287
288
|
dataSize: data.byteLength,
|
|
288
|
-
ivSize: iv.byteLength
|
|
289
|
+
ivSize: iv.byteLength,
|
|
289
290
|
});
|
|
290
291
|
|
|
291
292
|
try {
|
|
@@ -296,19 +297,19 @@ export class WebCryptoProvider implements CryptoProvider {
|
|
|
296
297
|
tagLength: 128, // 128-bit tag
|
|
297
298
|
},
|
|
298
299
|
unwrapCryptoKey(key),
|
|
299
|
-
data
|
|
300
|
+
data,
|
|
300
301
|
);
|
|
301
302
|
|
|
302
303
|
this.logger?.debug('Decryption completed', {
|
|
303
|
-
plaintextSize: plaintext.byteLength
|
|
304
|
+
plaintextSize: plaintext.byteLength,
|
|
304
305
|
});
|
|
305
306
|
return plaintext;
|
|
306
307
|
} catch (error) {
|
|
307
308
|
this.logger?.error('Decryption failed', {
|
|
308
309
|
error: {
|
|
309
310
|
message: error instanceof Error ? error.message : String(error),
|
|
310
|
-
stack: error instanceof Error ? error.stack : undefined
|
|
311
|
-
}
|
|
311
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
312
|
+
},
|
|
312
313
|
});
|
|
313
314
|
throw error;
|
|
314
315
|
}
|
|
@@ -324,7 +325,7 @@ export class WebCryptoProvider implements CryptoProvider {
|
|
|
324
325
|
await crypto.subtle.exportKey('raw', unwrapCryptoKey(key)),
|
|
325
326
|
{ name: 'HMAC', hash: 'SHA-256' },
|
|
326
327
|
false,
|
|
327
|
-
['sign']
|
|
328
|
+
['sign'],
|
|
328
329
|
);
|
|
329
330
|
|
|
330
331
|
return crypto.subtle.sign('HMAC', hmacKey, data);
|
|
@@ -340,25 +341,9 @@ export class WebCryptoProvider implements CryptoProvider {
|
|
|
340
341
|
await crypto.subtle.exportKey('raw', unwrapCryptoKey(key)),
|
|
341
342
|
{ name: 'HMAC', hash: 'SHA-256' },
|
|
342
343
|
false,
|
|
343
|
-
['verify']
|
|
344
|
+
['verify'],
|
|
344
345
|
);
|
|
345
346
|
|
|
346
347
|
return crypto.subtle.verify('HMAC', hmacKey, mac, data);
|
|
347
348
|
}
|
|
348
349
|
}
|
|
349
|
-
|
|
350
|
-
/**
|
|
351
|
-
* Self-register WebCrypto provider on import
|
|
352
|
-
* This allows the provider to be available when explicitly imported
|
|
353
|
-
*/
|
|
354
|
-
registerCryptoProvider('webcrypto', () => new WebCryptoProvider());
|
|
355
|
-
|
|
356
|
-
// TypeScript module augmentation to track this provider is available
|
|
357
|
-
declare global {
|
|
358
|
-
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
359
|
-
namespace BananaLink {
|
|
360
|
-
interface RegisteredCryptoProviders {
|
|
361
|
-
webcrypto: true;
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
}
|