@workos-inc/node 7.49.0 → 7.50.1

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.
Files changed (39) hide show
  1. package/lib/actions/actions.js +2 -2
  2. package/lib/actions/actions.spec.js +3 -3
  3. package/lib/common/crypto/crypto-provider.d.ts +33 -0
  4. package/lib/common/crypto/{CryptoProvider.spec.js → crypto-provider.spec.js} +8 -8
  5. package/lib/common/crypto/node-crypto-provider.d.ts +7 -0
  6. package/lib/common/crypto/node-crypto-provider.js +38 -2
  7. package/lib/common/crypto/{SignatureProvider.d.ts → signature-provider.d.ts} +1 -1
  8. package/lib/common/crypto/{SignatureProvider.spec.js → signature-provider.spec.js} +4 -4
  9. package/lib/common/crypto/subtle-crypto-provider.d.ts +7 -0
  10. package/lib/common/crypto/subtle-crypto-provider.js +48 -0
  11. package/lib/common/utils/base64.d.ts +12 -0
  12. package/lib/common/utils/base64.js +52 -0
  13. package/lib/index.d.ts +2 -0
  14. package/lib/index.js +5 -9
  15. package/lib/index.worker.d.ts +2 -0
  16. package/lib/index.worker.js +3 -0
  17. package/lib/user-management/interfaces/update-user-options.interface.d.ts +2 -2
  18. package/lib/user-management/user-management.spec.js +10 -0
  19. package/lib/vault/vault-live-test.spec.js +15 -0
  20. package/lib/vault/vault.d.ts +7 -5
  21. package/lib/vault/vault.js +62 -8
  22. package/lib/vault/vault.spec.js +39 -0
  23. package/lib/webhooks/webhooks.js +2 -2
  24. package/lib/workos.d.ts +2 -0
  25. package/lib/workos.js +6 -3
  26. package/package.json +1 -1
  27. package/lib/common/crypto/CryptoProvider.d.ts +0 -32
  28. package/lib/common/crypto/CryptoProvider.js +0 -13
  29. package/lib/common/crypto/NodeCryptoProvider.d.ts +0 -12
  30. package/lib/common/crypto/NodeCryptoProvider.js +0 -73
  31. package/lib/common/crypto/SubtleCryptoProvider.d.ts +0 -15
  32. package/lib/common/crypto/SubtleCryptoProvider.js +0 -75
  33. package/lib/vault/cryptography/decrypt.d.ts +0 -9
  34. package/lib/vault/cryptography/decrypt.js +0 -37
  35. package/lib/vault/cryptography/encrypt.d.ts +0 -1
  36. package/lib/vault/cryptography/encrypt.js +0 -31
  37. /package/lib/common/crypto/{CryptoProvider.spec.d.ts → crypto-provider.spec.d.ts} +0 -0
  38. /package/lib/common/crypto/{SignatureProvider.js → signature-provider.js} +0 -0
  39. /package/lib/common/crypto/{SignatureProvider.spec.d.ts → signature-provider.spec.d.ts} +0 -0
@@ -10,12 +10,12 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.Actions = void 0;
13
- const SignatureProvider_1 = require("../common/crypto/SignatureProvider");
13
+ const signature_provider_1 = require("../common/crypto/signature-provider");
14
14
  const unreachable_1 = require("../common/utils/unreachable");
15
15
  const action_serializer_1 = require("./serializers/action.serializer");
16
16
  class Actions {
17
17
  constructor(cryptoProvider) {
18
- this.signatureProvider = new SignatureProvider_1.SignatureProvider(cryptoProvider);
18
+ this.signatureProvider = new signature_provider_1.SignatureProvider(cryptoProvider);
19
19
  }
20
20
  get computeSignature() {
21
21
  return this.signatureProvider.computeSignature.bind(this.signatureProvider);
@@ -16,8 +16,8 @@ const crypto_1 = __importDefault(require("crypto"));
16
16
  const workos_1 = require("../workos");
17
17
  const authentication_action_context_json_1 = __importDefault(require("./fixtures/authentication-action-context.json"));
18
18
  const user_registration_action_context_json_1 = __importDefault(require("./fixtures/user-registration-action-context.json"));
19
+ const node_crypto_provider_1 = require("../common/crypto/node-crypto-provider");
19
20
  const workos = new workos_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU');
20
- const NodeCryptoProvider_1 = require("../common/crypto/NodeCryptoProvider");
21
21
  describe('Actions', () => {
22
22
  let secret;
23
23
  beforeEach(() => {
@@ -36,7 +36,7 @@ describe('Actions', () => {
36
36
  describe('signResponse', () => {
37
37
  describe('type: authentication', () => {
38
38
  it('returns a signed response', () => __awaiter(void 0, void 0, void 0, function* () {
39
- const nodeCryptoProvider = new NodeCryptoProvider_1.NodeCryptoProvider();
39
+ const nodeCryptoProvider = new node_crypto_provider_1.NodeCryptoProvider();
40
40
  const response = yield workos.actions.signResponse({
41
41
  type: 'authentication',
42
42
  verdict: 'Allow',
@@ -51,7 +51,7 @@ describe('Actions', () => {
51
51
  });
52
52
  describe('type: user_registration', () => {
53
53
  it('returns a signed response', () => __awaiter(void 0, void 0, void 0, function* () {
54
- const nodeCryptoProvider = new NodeCryptoProvider_1.NodeCryptoProvider();
54
+ const nodeCryptoProvider = new node_crypto_provider_1.NodeCryptoProvider();
55
55
  const response = yield workos.actions.signResponse({
56
56
  type: 'user_registration',
57
57
  verdict: 'Deny',
@@ -29,4 +29,37 @@ export declare abstract class CryptoProvider {
29
29
  * Cryptographically determine whether two signatures are equal
30
30
  */
31
31
  abstract secureCompare(stringA: string, stringB: string): Promise<boolean>;
32
+ /**
33
+ * Encrypts data using AES-256-GCM algorithm.
34
+ *
35
+ * @param plaintext The data to encrypt
36
+ * @param key The encryption key (should be 32 bytes for AES-256)
37
+ * @param iv Optional initialization vector (if not provided, a random one will be generated)
38
+ * @param aad Optional additional authenticated data
39
+ * @returns Object containing the encrypted ciphertext, the IV used, and the authentication tag
40
+ */
41
+ abstract encrypt(plaintext: Uint8Array, key: Uint8Array, iv?: Uint8Array, aad?: Uint8Array): Promise<{
42
+ ciphertext: Uint8Array;
43
+ iv: Uint8Array;
44
+ tag: Uint8Array;
45
+ }>;
46
+ /**
47
+ * Decrypts data that was encrypted using AES-256-GCM algorithm.
48
+ *
49
+ * @param ciphertext The encrypted data
50
+ * @param key The decryption key (must be the same key used for encryption)
51
+ * @param iv The initialization vector used during encryption
52
+ * @param tag The authentication tag produced during encryption
53
+ * @param aad Optional additional authenticated data (must match what was used during encryption)
54
+ * @returns The decrypted data
55
+ * @throws Will throw an error if authentication fails or the data has been tampered with
56
+ */
57
+ abstract decrypt(ciphertext: Uint8Array, key: Uint8Array, iv: Uint8Array, tag: Uint8Array, aad?: Uint8Array): Promise<Uint8Array>;
58
+ /**
59
+ * Generates cryptographically secure random bytes.
60
+ *
61
+ * @param length The number of random bytes to generate
62
+ * @returns A Uint8Array containing the random bytes
63
+ */
64
+ abstract randomBytes(length: number): Uint8Array;
32
65
  }
@@ -13,10 +13,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
13
13
  };
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  const crypto_1 = __importDefault(require("crypto"));
16
- const NodeCryptoProvider_1 = require("./NodeCryptoProvider");
17
- const SubtleCryptoProvider_1 = require("./SubtleCryptoProvider");
16
+ const node_crypto_provider_1 = require("./node-crypto-provider");
17
+ const subtle_crypto_provider_1 = require("./subtle-crypto-provider");
18
18
  const webhook_json_1 = __importDefault(require("../../webhooks/fixtures/webhook.json"));
19
- const SignatureProvider_1 = require("./SignatureProvider");
19
+ const signature_provider_1 = require("./signature-provider");
20
20
  describe('CryptoProvider', () => {
21
21
  let payload;
22
22
  let secret;
@@ -35,8 +35,8 @@ describe('CryptoProvider', () => {
35
35
  });
36
36
  describe('when computing HMAC signature', () => {
37
37
  it('returns the same for the Node crypto and Web Crypto versions', () => __awaiter(void 0, void 0, void 0, function* () {
38
- const nodeCryptoProvider = new NodeCryptoProvider_1.NodeCryptoProvider();
39
- const subtleCryptoProvider = new SubtleCryptoProvider_1.SubtleCryptoProvider();
38
+ const nodeCryptoProvider = new node_crypto_provider_1.NodeCryptoProvider();
39
+ const subtleCryptoProvider = new subtle_crypto_provider_1.SubtleCryptoProvider();
40
40
  const stringifiedPayload = JSON.stringify(payload);
41
41
  const payloadHMAC = `${timestamp}.${stringifiedPayload}`;
42
42
  const nodeCompare = yield nodeCryptoProvider.computeHMACSignatureAsync(payloadHMAC, secret);
@@ -46,9 +46,9 @@ describe('CryptoProvider', () => {
46
46
  });
47
47
  describe('when securely comparing', () => {
48
48
  it('returns the same for the Node crypto and Web Crypto versions', () => __awaiter(void 0, void 0, void 0, function* () {
49
- const nodeCryptoProvider = new NodeCryptoProvider_1.NodeCryptoProvider();
50
- const subtleCryptoProvider = new SubtleCryptoProvider_1.SubtleCryptoProvider();
51
- const signatureProvider = new SignatureProvider_1.SignatureProvider(subtleCryptoProvider);
49
+ const nodeCryptoProvider = new node_crypto_provider_1.NodeCryptoProvider();
50
+ const subtleCryptoProvider = new subtle_crypto_provider_1.SubtleCryptoProvider();
51
+ const signatureProvider = new signature_provider_1.SignatureProvider(subtleCryptoProvider);
52
52
  const signature = yield signatureProvider.computeSignature(timestamp, payload, secret);
53
53
  expect(nodeCryptoProvider.secureCompare(signature, signatureHash)).toEqual(subtleCryptoProvider.secureCompare(signature, signatureHash));
54
54
  expect(nodeCryptoProvider.secureCompare(signature, 'foo')).toEqual(subtleCryptoProvider.secureCompare(signature, 'foo'));
@@ -9,4 +9,11 @@ export declare class NodeCryptoProvider extends CryptoProvider {
9
9
  computeHMACSignatureAsync(payload: string, secret: string): Promise<string>;
10
10
  /** @override */
11
11
  secureCompare(stringA: string, stringB: string): Promise<boolean>;
12
+ encrypt(plaintext: Uint8Array, key: Uint8Array, iv?: Uint8Array, aad?: Uint8Array): Promise<{
13
+ ciphertext: Uint8Array;
14
+ iv: Uint8Array;
15
+ tag: Uint8Array;
16
+ }>;
17
+ decrypt(ciphertext: Uint8Array, key: Uint8Array, iv: Uint8Array, tag: Uint8Array, aad?: Uint8Array): Promise<Uint8Array>;
18
+ randomBytes(length: number): Uint8Array;
12
19
  }
@@ -33,7 +33,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
33
33
  };
34
34
  Object.defineProperty(exports, "__esModule", { value: true });
35
35
  exports.NodeCryptoProvider = void 0;
36
- const crypto = __importStar(require("node:crypto"));
36
+ const crypto = __importStar(require("crypto"));
37
37
  const crypto_provider_1 = require("./crypto-provider");
38
38
  /**
39
39
  * `CryptoProvider which uses the Node `crypto` package for its computations.
@@ -49,7 +49,7 @@ class NodeCryptoProvider extends crypto_provider_1.CryptoProvider {
49
49
  /** @override */
50
50
  computeHMACSignatureAsync(payload, secret) {
51
51
  return __awaiter(this, void 0, void 0, function* () {
52
- const signature = yield this.computeHMACSignature(payload, secret);
52
+ const signature = this.computeHMACSignature(payload, secret);
53
53
  return signature;
54
54
  });
55
55
  }
@@ -69,5 +69,41 @@ class NodeCryptoProvider extends crypto_provider_1.CryptoProvider {
69
69
  return crypto.timingSafeEqual(hmacA, hmacB);
70
70
  });
71
71
  }
72
+ encrypt(plaintext, key, iv, aad) {
73
+ return __awaiter(this, void 0, void 0, function* () {
74
+ const actualIv = iv || crypto.randomBytes(32);
75
+ const cipher = crypto.createCipheriv('aes-256-gcm', key, actualIv);
76
+ if (aad) {
77
+ cipher.setAAD(Buffer.from(aad));
78
+ }
79
+ const ciphertext = Buffer.concat([
80
+ cipher.update(Buffer.from(plaintext)),
81
+ cipher.final(),
82
+ ]);
83
+ const tag = cipher.getAuthTag();
84
+ return {
85
+ ciphertext: new Uint8Array(ciphertext),
86
+ iv: new Uint8Array(actualIv),
87
+ tag: new Uint8Array(tag),
88
+ };
89
+ });
90
+ }
91
+ decrypt(ciphertext, key, iv, tag, aad) {
92
+ return __awaiter(this, void 0, void 0, function* () {
93
+ const decipher = crypto.createDecipheriv('aes-256-gcm', key, iv);
94
+ decipher.setAuthTag(Buffer.from(tag));
95
+ if (aad) {
96
+ decipher.setAAD(Buffer.from(aad));
97
+ }
98
+ const decrypted = Buffer.concat([
99
+ decipher.update(Buffer.from(ciphertext)),
100
+ decipher.final(),
101
+ ]);
102
+ return new Uint8Array(decrypted);
103
+ });
104
+ }
105
+ randomBytes(length) {
106
+ return new Uint8Array(crypto.randomBytes(length));
107
+ }
72
108
  }
73
109
  exports.NodeCryptoProvider = NodeCryptoProvider;
@@ -1,4 +1,4 @@
1
- import { CryptoProvider } from './CryptoProvider';
1
+ import { CryptoProvider } from './crypto-provider';
2
2
  export declare class SignatureProvider {
3
3
  private cryptoProvider;
4
4
  constructor(cryptoProvider: CryptoProvider);
@@ -13,15 +13,15 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
13
13
  };
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  const crypto_1 = __importDefault(require("crypto"));
16
- const SubtleCryptoProvider_1 = require("./SubtleCryptoProvider");
16
+ const subtle_crypto_provider_1 = require("./subtle-crypto-provider");
17
17
  const webhook_json_1 = __importDefault(require("../../webhooks/fixtures/webhook.json"));
18
- const SignatureProvider_1 = require("./SignatureProvider");
18
+ const signature_provider_1 = require("./signature-provider");
19
19
  describe('SignatureProvider', () => {
20
20
  let payload;
21
21
  let secret;
22
22
  let timestamp;
23
23
  let signatureHash;
24
- const signatureProvider = new SignatureProvider_1.SignatureProvider(new SubtleCryptoProvider_1.SubtleCryptoProvider());
24
+ const signatureProvider = new signature_provider_1.SignatureProvider(new subtle_crypto_provider_1.SubtleCryptoProvider());
25
25
  beforeEach(() => {
26
26
  payload = webhook_json_1.default;
27
27
  secret = 'secret';
@@ -60,7 +60,7 @@ describe('SignatureProvider', () => {
60
60
  describe('when in an environment that supports SubtleCrypto', () => {
61
61
  it('automatically uses the subtle crypto library', () => {
62
62
  // tslint:disable-next-line
63
- expect(signatureProvider['cryptoProvider']).toBeInstanceOf(SubtleCryptoProvider_1.SubtleCryptoProvider);
63
+ expect(signatureProvider['cryptoProvider']).toBeInstanceOf(subtle_crypto_provider_1.SubtleCryptoProvider);
64
64
  });
65
65
  });
66
66
  });
@@ -12,4 +12,11 @@ export declare class SubtleCryptoProvider extends CryptoProvider {
12
12
  computeHMACSignatureAsync(payload: string, secret: string): Promise<string>;
13
13
  /** @override */
14
14
  secureCompare(stringA: string, stringB: string): Promise<boolean>;
15
+ encrypt(plaintext: Uint8Array, key: Uint8Array, iv?: Uint8Array, aad?: Uint8Array): Promise<{
16
+ ciphertext: Uint8Array;
17
+ iv: Uint8Array;
18
+ tag: Uint8Array;
19
+ }>;
20
+ decrypt(ciphertext: Uint8Array, key: Uint8Array, iv: Uint8Array, tag: Uint8Array, aad?: Uint8Array): Promise<Uint8Array>;
21
+ randomBytes(length: number): Uint8Array;
15
22
  }
@@ -65,6 +65,54 @@ class SubtleCryptoProvider extends crypto_provider_1.CryptoProvider {
65
65
  return equal;
66
66
  });
67
67
  }
68
+ encrypt(plaintext, key, iv, aad) {
69
+ return __awaiter(this, void 0, void 0, function* () {
70
+ const actualIv = iv || crypto.getRandomValues(new Uint8Array(32));
71
+ const cryptoKey = yield this.subtleCrypto.importKey('raw', key, { name: 'AES-GCM' }, false, ['encrypt']);
72
+ const encryptParams = {
73
+ name: 'AES-GCM',
74
+ iv: actualIv,
75
+ };
76
+ if (aad) {
77
+ encryptParams.additionalData = aad;
78
+ }
79
+ const encryptedData = yield this.subtleCrypto.encrypt(encryptParams, cryptoKey, plaintext);
80
+ const encryptedBytes = new Uint8Array(encryptedData);
81
+ // Extract tag (last 16 bytes)
82
+ const tagSize = 16;
83
+ const tagStart = encryptedBytes.length - tagSize;
84
+ const tag = encryptedBytes.slice(tagStart);
85
+ const ciphertext = encryptedBytes.slice(0, tagStart);
86
+ return {
87
+ ciphertext,
88
+ iv: actualIv,
89
+ tag,
90
+ };
91
+ });
92
+ }
93
+ decrypt(ciphertext, key, iv, tag, aad) {
94
+ return __awaiter(this, void 0, void 0, function* () {
95
+ // SubtleCrypto expects tag to be appended to ciphertext for AES-GCM
96
+ const combinedData = new Uint8Array(ciphertext.length + tag.length);
97
+ combinedData.set(ciphertext, 0);
98
+ combinedData.set(tag, ciphertext.length);
99
+ const cryptoKey = yield this.subtleCrypto.importKey('raw', key, { name: 'AES-GCM' }, false, ['decrypt']);
100
+ const decryptParams = {
101
+ name: 'AES-GCM',
102
+ iv,
103
+ };
104
+ if (aad) {
105
+ decryptParams.additionalData = aad;
106
+ }
107
+ const decryptedData = yield this.subtleCrypto.decrypt(decryptParams, cryptoKey, combinedData);
108
+ return new Uint8Array(decryptedData);
109
+ });
110
+ }
111
+ randomBytes(length) {
112
+ const bytes = new Uint8Array(length);
113
+ crypto.getRandomValues(bytes);
114
+ return bytes;
115
+ }
68
116
  }
69
117
  exports.SubtleCryptoProvider = SubtleCryptoProvider;
70
118
  // Cached mapping of byte to hex representation. We do this once to avoid re-
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Cross-runtime compatible base64 encoding/decoding utilities
3
+ * that work in both Node.js and browser environments
4
+ */
5
+ /**
6
+ * Converts a base64 string to a Uint8Array
7
+ */
8
+ export declare function base64ToUint8Array(base64: string): Uint8Array;
9
+ /**
10
+ * Converts a Uint8Array to a base64 string
11
+ */
12
+ export declare function uint8ArrayToBase64(bytes: Uint8Array): string;
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ /**
3
+ * Cross-runtime compatible base64 encoding/decoding utilities
4
+ * that work in both Node.js and browser environments
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.uint8ArrayToBase64 = exports.base64ToUint8Array = void 0;
8
+ /**
9
+ * Converts a base64 string to a Uint8Array
10
+ */
11
+ function base64ToUint8Array(base64) {
12
+ // In browsers and modern Node.js
13
+ if (typeof atob === 'function') {
14
+ const binary = atob(base64);
15
+ const bytes = new Uint8Array(binary.length);
16
+ for (let i = 0; i < binary.length; i++) {
17
+ bytes[i] = binary.charCodeAt(i);
18
+ }
19
+ return bytes;
20
+ }
21
+ // Node.js fallback using Buffer
22
+ else if (typeof Buffer !== 'undefined') {
23
+ return new Uint8Array(Buffer.from(base64, 'base64'));
24
+ }
25
+ // Fallback implementation if neither is available
26
+ else {
27
+ throw new Error('No base64 decoding implementation available');
28
+ }
29
+ }
30
+ exports.base64ToUint8Array = base64ToUint8Array;
31
+ /**
32
+ * Converts a Uint8Array to a base64 string
33
+ */
34
+ function uint8ArrayToBase64(bytes) {
35
+ // In browsers and modern Node.js
36
+ if (typeof btoa === 'function') {
37
+ let binary = '';
38
+ for (let i = 0; i < bytes.byteLength; i++) {
39
+ binary += String.fromCharCode(bytes[i]);
40
+ }
41
+ return btoa(binary);
42
+ }
43
+ // Node.js fallback using Buffer
44
+ else if (typeof Buffer !== 'undefined') {
45
+ return Buffer.from(bytes).toString('base64');
46
+ }
47
+ // Fallback implementation if neither is available
48
+ else {
49
+ throw new Error('No base64 encoding implementation available');
50
+ }
51
+ }
52
+ exports.uint8ArrayToBase64 = uint8ArrayToBase64;
package/lib/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { CryptoProvider } from './common/crypto/crypto-provider';
1
2
  import { HttpClient } from './common/net/http-client';
2
3
  import { Actions } from './actions/actions';
3
4
  import { Webhooks } from './webhooks/webhooks';
@@ -25,6 +26,7 @@ declare class WorkOSNode extends WorkOS {
25
26
  createHttpClient(options: WorkOSOptions, userAgent: string): HttpClient;
26
27
  /** @override */
27
28
  createWebhookClient(): Webhooks;
29
+ getCryptoProvider(): CryptoProvider;
28
30
  /** @override */
29
31
  createActionsClient(): Actions;
30
32
  /** @override */
package/lib/index.js CHANGED
@@ -54,6 +54,9 @@ class WorkOSNode extends workos_1.WorkOS {
54
54
  }
55
55
  /** @override */
56
56
  createWebhookClient() {
57
+ return new webhooks_1.Webhooks(this.getCryptoProvider());
58
+ }
59
+ getCryptoProvider() {
57
60
  let cryptoProvider;
58
61
  if (typeof crypto !== 'undefined' && typeof crypto.subtle !== 'undefined') {
59
62
  cryptoProvider = new subtle_crypto_provider_1.SubtleCryptoProvider();
@@ -61,18 +64,11 @@ class WorkOSNode extends workos_1.WorkOS {
61
64
  else {
62
65
  cryptoProvider = new node_crypto_provider_1.NodeCryptoProvider();
63
66
  }
64
- return new webhooks_1.Webhooks(cryptoProvider);
67
+ return cryptoProvider;
65
68
  }
66
69
  /** @override */
67
70
  createActionsClient() {
68
- let cryptoProvider;
69
- if (typeof crypto !== 'undefined' && typeof crypto.subtle !== 'undefined') {
70
- cryptoProvider = new subtle_crypto_provider_1.SubtleCryptoProvider();
71
- }
72
- else {
73
- cryptoProvider = new node_crypto_provider_1.NodeCryptoProvider();
74
- }
75
- return new actions_1.Actions(cryptoProvider);
71
+ return new actions_1.Actions(this.getCryptoProvider());
76
72
  }
77
73
  /** @override */
78
74
  createIronSessionProvider() {
@@ -1,4 +1,5 @@
1
1
  import { Actions } from './actions/actions';
2
+ import { CryptoProvider } from './common/crypto/crypto-provider';
2
3
  import { IronSessionProvider } from './common/iron-session/iron-session-provider';
3
4
  import { HttpClient } from './common/net/http-client';
4
5
  import { WorkOSOptions } from './index.worker';
@@ -25,6 +26,7 @@ declare class WorkOSWorker extends WorkOS {
25
26
  createHttpClient(options: WorkOSOptions, userAgent: string): HttpClient;
26
27
  /** @override */
27
28
  createWebhookClient(): Webhooks;
29
+ getCryptoProvider(): CryptoProvider;
28
30
  /** @override */
29
31
  createActionsClient(): Actions;
30
32
  /** @override */
@@ -48,6 +48,9 @@ class WorkOSWorker extends workos_1.WorkOS {
48
48
  const cryptoProvider = new subtle_crypto_provider_1.SubtleCryptoProvider();
49
49
  return new webhooks_1.Webhooks(cryptoProvider);
50
50
  }
51
+ getCryptoProvider() {
52
+ return new subtle_crypto_provider_1.SubtleCryptoProvider();
53
+ }
51
54
  /** @override */
52
55
  createActionsClient() {
53
56
  const cryptoProvider = new subtle_crypto_provider_1.SubtleCryptoProvider();
@@ -8,7 +8,7 @@ export interface UpdateUserOptions {
8
8
  passwordHash?: string;
9
9
  passwordHashType?: PasswordHashType;
10
10
  externalId?: string;
11
- metadata?: Record<string, string>;
11
+ metadata?: Record<string, string | null>;
12
12
  }
13
13
  export interface SerializedUpdateUserOptions {
14
14
  first_name?: string;
@@ -18,5 +18,5 @@ export interface SerializedUpdateUserOptions {
18
18
  password_hash?: string;
19
19
  password_hash_type?: PasswordHashType;
20
20
  external_id?: string;
21
- metadata?: Record<string, string>;
21
+ metadata?: Record<string, string | null>;
22
22
  }
@@ -1112,6 +1112,16 @@ describe('UserManagement', () => {
1112
1112
  metadata: { key: 'value' },
1113
1113
  });
1114
1114
  }));
1115
+ it('removes metadata from the request', () => __awaiter(void 0, void 0, void 0, function* () {
1116
+ (0, test_utils_1.fetchOnce)(user_json_1.default);
1117
+ yield workos.userManagement.updateUser({
1118
+ userId,
1119
+ metadata: { key: null },
1120
+ });
1121
+ expect((0, test_utils_1.fetchBody)()).toMatchObject({
1122
+ metadata: {},
1123
+ });
1124
+ }));
1115
1125
  });
1116
1126
  describe('enrollAuthFactor', () => {
1117
1127
  it('sends an enrollAuthFactor request', () => __awaiter(void 0, void 0, void 0, function* () {
@@ -241,5 +241,20 @@ describe.skip('Vault Live Test', () => {
241
241
  const decrypted = yield workos.vault.decrypt(encrypted);
242
242
  expect(decrypted).toBe(superObject);
243
243
  }));
244
+ it('authenticates additional data', () => __awaiter(void 0, void 0, void 0, function* () {
245
+ const data = 'hot water freezes faster than cold water';
246
+ const keyContext = { everything: 'everywhere' };
247
+ const aad = 'seq1';
248
+ const encrypted = yield workos.vault.encrypt(data, keyContext, aad);
249
+ const decrypted = yield workos.vault.decrypt(encrypted, aad);
250
+ expect(decrypted).toBe(data);
251
+ }));
252
+ it('fails with invalid AD', () => __awaiter(void 0, void 0, void 0, function* () {
253
+ const data = 'hot water freezes faster than cold water';
254
+ const keyContext = { everything: 'everywhere' };
255
+ const aad = 'seq1';
256
+ const encrypted = yield workos.vault.encrypt(data, keyContext, aad);
257
+ yield expect(() => workos.vault.decrypt(encrypted)).rejects.toThrow('unable to authenticate data');
258
+ }));
244
259
  });
245
260
  });
@@ -1,10 +1,12 @@
1
- import { PaginationOptions } from '../index.worker';
2
- import { WorkOS } from '../workos';
3
- import { CreateDataKeyOptions, CreateObjectOptions, DataKey, DataKeyPair, DecryptDataKeyOptions, DeleteObjectOptions, ReadObjectOptions, KeyContext, ObjectDigest, ObjectMetadata, ObjectVersion, UpdateObjectOptions, VaultObject } from './interfaces';
4
1
  import { List } from '../common/interfaces';
2
+ import { PaginationOptions } from '../index.worker';
3
+ import type { WorkOS } from '../workos';
4
+ import { CreateDataKeyOptions, CreateObjectOptions, DataKey, DataKeyPair, DecryptDataKeyOptions, DeleteObjectOptions, KeyContext, ObjectDigest, ObjectMetadata, ObjectVersion, ReadObjectOptions, UpdateObjectOptions, VaultObject } from './interfaces';
5
5
  export declare class Vault {
6
6
  private readonly workos;
7
+ private cryptoProvider;
7
8
  constructor(workos: WorkOS);
9
+ private decode;
8
10
  createObject(options: CreateObjectOptions): Promise<ObjectMetadata>;
9
11
  listObjects(options?: PaginationOptions | undefined): Promise<List<ObjectDigest>>;
10
12
  listObjectVersions(options: ReadObjectOptions): Promise<ObjectVersion[]>;
@@ -14,8 +16,8 @@ export declare class Vault {
14
16
  deleteObject(options: DeleteObjectOptions): Promise<void>;
15
17
  createDataKey(options: CreateDataKeyOptions): Promise<DataKeyPair>;
16
18
  decryptDataKey(options: DecryptDataKeyOptions): Promise<DataKey>;
17
- encrypt(data: string, context: KeyContext): Promise<string>;
18
- decrypt(encryptedData: string): Promise<string>;
19
+ encrypt(data: string, context: KeyContext, associatedData?: string): Promise<string>;
20
+ decrypt(encryptedData: string, associatedData?: string): Promise<string>;
19
21
  createSecret: (options: CreateObjectOptions) => Promise<ObjectMetadata>;
20
22
  listSecrets: (options?: PaginationOptions | undefined) => Promise<List<ObjectDigest>>;
21
23
  listSecretVersions: (options: ReadObjectOptions) => Promise<ObjectVersion[]>;
@@ -10,8 +10,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.Vault = void 0;
13
- const decrypt_1 = require("./cryptography/decrypt");
14
- const encrypt_1 = require("./cryptography/encrypt");
13
+ const leb_1 = require("leb");
14
+ const base64_1 = require("../common/utils/base64");
15
15
  const vault_key_serializer_1 = require("./serializers/vault-key.serializer");
16
16
  const vault_object_serializer_1 = require("./serializers/vault-object.serializer");
17
17
  class Vault {
@@ -45,6 +45,24 @@ class Vault {
45
45
  * @deprecated Use `deleteObject` instead.
46
46
  */
47
47
  this.deleteSecret = this.deleteObject;
48
+ this.cryptoProvider = workos.getCryptoProvider();
49
+ }
50
+ decode(payload) {
51
+ const inputData = (0, base64_1.base64ToUint8Array)(payload);
52
+ // Use 12 bytes for IV (standard for AES-GCM)
53
+ const iv = new Uint8Array(inputData.subarray(0, 12));
54
+ const tag = new Uint8Array(inputData.subarray(12, 28));
55
+ const { value: keyLen, nextIndex } = (0, leb_1.decodeUInt32)(inputData, 28);
56
+ // Use subarray instead of slice and convert directly to base64
57
+ const keysBuffer = inputData.subarray(nextIndex, nextIndex + keyLen);
58
+ const keys = (0, base64_1.uint8ArrayToBase64)(keysBuffer);
59
+ const ciphertext = new Uint8Array(inputData.subarray(nextIndex + keyLen));
60
+ return {
61
+ iv,
62
+ tag,
63
+ keys,
64
+ ciphertext,
65
+ };
48
66
  }
49
67
  createObject(options) {
50
68
  return __awaiter(this, void 0, void 0, function* () {
@@ -106,19 +124,55 @@ class Vault {
106
124
  return (0, vault_key_serializer_1.deserializeDecryptDataKeyResponse)(data);
107
125
  });
108
126
  }
109
- encrypt(data, context) {
127
+ encrypt(data, context, associatedData) {
110
128
  return __awaiter(this, void 0, void 0, function* () {
111
- const { dataKey, encryptedKeys } = yield this.createDataKey({
129
+ const keyPair = yield this.createDataKey({
112
130
  context,
113
131
  });
114
- return (0, encrypt_1.encrypt)(data, dataKey.key, encryptedKeys);
132
+ // Convert base64 key to Uint8Array
133
+ const encoder = new TextEncoder();
134
+ // Use our cross-runtime base64 utility
135
+ const key = (0, base64_1.base64ToUint8Array)(keyPair.dataKey.key);
136
+ const keyBlob = (0, base64_1.base64ToUint8Array)(keyPair.encryptedKeys);
137
+ const prefixLenBuffer = (0, leb_1.encodeUInt32)(keyBlob.length);
138
+ const aadBuffer = associatedData
139
+ ? encoder.encode(associatedData)
140
+ : undefined;
141
+ // Use a 12-byte IV for AES-GCM (industry standard)
142
+ const iv = this.cryptoProvider.randomBytes(12);
143
+ const { ciphertext, iv: resultIv, tag, } = yield this.cryptoProvider.encrypt(encoder.encode(data), key, iv, aadBuffer);
144
+ // Concatenate all parts into a single array
145
+ const resultArray = new Uint8Array(resultIv.length +
146
+ tag.length +
147
+ prefixLenBuffer.length +
148
+ keyBlob.length +
149
+ ciphertext.length);
150
+ let offset = 0;
151
+ resultArray.set(resultIv, offset);
152
+ offset += resultIv.length;
153
+ resultArray.set(tag, offset);
154
+ offset += tag.length;
155
+ resultArray.set(new Uint8Array(prefixLenBuffer), offset);
156
+ offset += prefixLenBuffer.length;
157
+ resultArray.set(keyBlob, offset);
158
+ offset += keyBlob.length;
159
+ resultArray.set(ciphertext, offset);
160
+ // Convert to base64 using our cross-runtime utility
161
+ return (0, base64_1.uint8ArrayToBase64)(resultArray);
115
162
  });
116
163
  }
117
- decrypt(encryptedData) {
164
+ decrypt(encryptedData, associatedData) {
118
165
  return __awaiter(this, void 0, void 0, function* () {
119
- const decoded = (0, decrypt_1.decode)(encryptedData);
166
+ const decoded = this.decode(encryptedData);
120
167
  const dataKey = yield this.decryptDataKey({ keys: decoded.keys });
121
- return (0, decrypt_1.decrypt)(decoded, dataKey.key);
168
+ // Convert base64 key to Uint8Array using our cross-runtime utility
169
+ const key = (0, base64_1.base64ToUint8Array)(dataKey.key);
170
+ const encoder = new TextEncoder();
171
+ const aadBuffer = associatedData
172
+ ? encoder.encode(associatedData)
173
+ : undefined;
174
+ const decrypted = yield this.cryptoProvider.decrypt(decoded.ciphertext, key, decoded.iv, decoded.tag, aadBuffer);
175
+ return new TextDecoder().decode(decrypted);
122
176
  });
123
177
  }
124
178
  }
@@ -244,4 +244,43 @@ describe('Vault', () => {
244
244
  expect((0, test_utils_1.fetchMethod)()).toBe('PUT');
245
245
  }));
246
246
  });
247
+ describe('encrypt and decrypt', () => {
248
+ it('correctly encrypts and decrypts data', () => __awaiter(void 0, void 0, void 0, function* () {
249
+ // Generate a valid 32-byte (256-bit) key for AES-256-GCM
250
+ const validKey = Buffer.alloc(32).fill('A').toString('base64');
251
+ // Mock createDataKey to return a valid key for testing
252
+ (0, test_utils_1.fetchOnce)({
253
+ data_key: validKey,
254
+ encrypted_keys: 'ZW5jcnlwdGVkX2tleXM=',
255
+ id: 'key123',
256
+ context: { type: 'test' },
257
+ });
258
+ // Mock decryptDataKey to return same key
259
+ (0, test_utils_1.fetchOnce)({
260
+ data_key: validKey,
261
+ id: 'key123',
262
+ });
263
+ const originalText = 'This is a secret message';
264
+ const context = { type: 'test' };
265
+ const associatedData = 'additional-auth-data';
266
+ // Encrypt the data
267
+ const encrypted = yield workos.vault.encrypt(originalText, context, associatedData);
268
+ // Verify encrypt API call
269
+ expect((0, test_utils_1.fetchURL)()).toContain('/vault/v1/keys/data-key');
270
+ expect((0, test_utils_1.fetchMethod)()).toBe('POST');
271
+ // Reset fetch for the decrypt call
272
+ jest_fetch_mock_1.default.resetMocks();
273
+ (0, test_utils_1.fetchOnce)({
274
+ data_key: validKey,
275
+ id: 'key123',
276
+ });
277
+ // Decrypt the data
278
+ const decrypted = yield workos.vault.decrypt(encrypted, associatedData);
279
+ // Verify decrypt API call
280
+ expect((0, test_utils_1.fetchURL)()).toContain('/vault/v1/keys/decrypt');
281
+ expect((0, test_utils_1.fetchMethod)()).toBe('POST');
282
+ // Verify the decrypted text matches the original
283
+ expect(decrypted).toBe(originalText);
284
+ }));
285
+ });
247
286
  });
@@ -11,10 +11,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.Webhooks = void 0;
13
13
  const serializers_1 = require("../common/serializers");
14
- const SignatureProvider_1 = require("../common/crypto/SignatureProvider");
14
+ const signature_provider_1 = require("../common/crypto/signature-provider");
15
15
  class Webhooks {
16
16
  constructor(cryptoProvider) {
17
- this.signatureProvider = new SignatureProvider_1.SignatureProvider(cryptoProvider);
17
+ this.signatureProvider = new signature_provider_1.SignatureProvider(cryptoProvider);
18
18
  }
19
19
  get verifyHeader() {
20
20
  return this.signatureProvider.verifyHeader.bind(this.signatureProvider);
package/lib/workos.d.ts CHANGED
@@ -16,6 +16,7 @@ import { IronSessionProvider } from './common/iron-session/iron-session-provider
16
16
  import { Widgets } from './widgets/widgets';
17
17
  import { Actions } from './actions/actions';
18
18
  import { Vault } from './vault/vault';
19
+ import { CryptoProvider } from './common/crypto/crypto-provider';
19
20
  export declare class WorkOS {
20
21
  readonly key?: string | undefined;
21
22
  readonly options: WorkOSOptions;
@@ -40,6 +41,7 @@ export declare class WorkOS {
40
41
  constructor(key?: string | undefined, options?: WorkOSOptions);
41
42
  createWebhookClient(): Webhooks;
42
43
  createActionsClient(): Actions;
44
+ getCryptoProvider(): CryptoProvider;
43
45
  createHttpClient(options: WorkOSOptions, userAgent: string): HttpClient;
44
46
  createIronSessionProvider(): IronSessionProvider;
45
47
  get version(): string;
package/lib/workos.js CHANGED
@@ -31,7 +31,7 @@ const widgets_1 = require("./widgets/widgets");
31
31
  const actions_1 = require("./actions/actions");
32
32
  const vault_1 = require("./vault/vault");
33
33
  const conflict_exception_1 = require("./common/exceptions/conflict.exception");
34
- const VERSION = '7.49.0';
34
+ const VERSION = '7.50.1';
35
35
  const DEFAULT_HOSTNAME = 'api.workos.com';
36
36
  const HEADER_AUTHORIZATION = 'Authorization';
37
37
  const HEADER_IDEMPOTENCY_KEY = 'Idempotency-Key';
@@ -88,10 +88,13 @@ class WorkOS {
88
88
  this.client = this.createHttpClient(options, userAgent);
89
89
  }
90
90
  createWebhookClient() {
91
- return new webhooks_1.Webhooks(new subtle_crypto_provider_1.SubtleCryptoProvider());
91
+ return new webhooks_1.Webhooks(this.getCryptoProvider());
92
92
  }
93
93
  createActionsClient() {
94
- return new actions_1.Actions(new subtle_crypto_provider_1.SubtleCryptoProvider());
94
+ return new actions_1.Actions(this.getCryptoProvider());
95
+ }
96
+ getCryptoProvider() {
97
+ return new subtle_crypto_provider_1.SubtleCryptoProvider();
95
98
  }
96
99
  createHttpClient(options, userAgent) {
97
100
  var _a;
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "7.49.0",
2
+ "version": "7.50.1",
3
3
  "name": "@workos-inc/node",
4
4
  "author": "WorkOS",
5
5
  "description": "A Node wrapper for the WorkOS API",
@@ -1,32 +0,0 @@
1
- /**
2
- * Interface encapsulating the various crypto computations used by the library,
3
- * allowing pluggable underlying crypto implementations.
4
- */
5
- export declare abstract class CryptoProvider {
6
- encoder: TextEncoder;
7
- /**
8
- * Computes a SHA-256 HMAC given a secret and a payload (encoded in UTF-8).
9
- * The output HMAC should be encoded in hexadecimal.
10
- *
11
- * Sample values for implementations:
12
- * - computeHMACSignature('', 'test_secret') => 'f7f9bd47fb987337b5796fdc1fdb9ba221d0d5396814bfcaf9521f43fd8927fd'
13
- * - computeHMACSignature('\ud83d\ude00', 'test_secret') => '837da296d05c4fe31f61d5d7ead035099d9585a5bcde87de952012a78f0b0c43
14
- */
15
- abstract computeHMACSignature(payload: string, secret: string): string;
16
- /**
17
- * Asynchronous version of `computeHMACSignature`. Some implementations may
18
- * only allow support async signature computation.
19
- *
20
- * Computes a SHA-256 HMAC given a secret and a payload (encoded in UTF-8).
21
- * The output HMAC should be encoded in hexadecimal.
22
- *
23
- * Sample values for implementations:
24
- * - computeHMACSignature('', 'test_secret') => 'f7f9bd47fb987337b5796fdc1fdb9ba221d0d5396814bfcaf9521f43fd8927fd'
25
- * - computeHMACSignature('\ud83d\ude00', 'test_secret') => '837da296d05c4fe31f61d5d7ead035099d9585a5bcde87de952012a78f0b0c43
26
- */
27
- abstract computeHMACSignatureAsync(payload: string, secret: string): Promise<string>;
28
- /**
29
- * Cryptographically determine whether two signatures are equal
30
- */
31
- abstract secureCompare(stringA: string, stringB: string): Promise<boolean>;
32
- }
@@ -1,13 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.CryptoProvider = void 0;
4
- /**
5
- * Interface encapsulating the various crypto computations used by the library,
6
- * allowing pluggable underlying crypto implementations.
7
- */
8
- class CryptoProvider {
9
- constructor() {
10
- this.encoder = new TextEncoder();
11
- }
12
- }
13
- exports.CryptoProvider = CryptoProvider;
@@ -1,12 +0,0 @@
1
- import { CryptoProvider } from './CryptoProvider';
2
- /**
3
- * `CryptoProvider which uses the Node `crypto` package for its computations.
4
- */
5
- export declare class NodeCryptoProvider extends CryptoProvider {
6
- /** @override */
7
- computeHMACSignature(payload: string, secret: string): string;
8
- /** @override */
9
- computeHMACSignatureAsync(payload: string, secret: string): Promise<string>;
10
- /** @override */
11
- secureCompare(stringA: string, stringB: string): Promise<boolean>;
12
- }
@@ -1,73 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
25
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
26
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
27
- return new (P || (P = Promise))(function (resolve, reject) {
28
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
29
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
30
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
31
- step((generator = generator.apply(thisArg, _arguments || [])).next());
32
- });
33
- };
34
- Object.defineProperty(exports, "__esModule", { value: true });
35
- exports.NodeCryptoProvider = void 0;
36
- const crypto = __importStar(require("crypto"));
37
- const CryptoProvider_1 = require("./CryptoProvider");
38
- /**
39
- * `CryptoProvider which uses the Node `crypto` package for its computations.
40
- */
41
- class NodeCryptoProvider extends CryptoProvider_1.CryptoProvider {
42
- /** @override */
43
- computeHMACSignature(payload, secret) {
44
- return crypto
45
- .createHmac('sha256', secret)
46
- .update(payload, 'utf8')
47
- .digest('hex');
48
- }
49
- /** @override */
50
- computeHMACSignatureAsync(payload, secret) {
51
- return __awaiter(this, void 0, void 0, function* () {
52
- const signature = yield this.computeHMACSignature(payload, secret);
53
- return signature;
54
- });
55
- }
56
- /** @override */
57
- secureCompare(stringA, stringB) {
58
- return __awaiter(this, void 0, void 0, function* () {
59
- const bufferA = this.encoder.encode(stringA);
60
- const bufferB = this.encoder.encode(stringB);
61
- if (bufferA.length !== bufferB.length) {
62
- return false;
63
- }
64
- // Generate a random key for HMAC
65
- const key = crypto.randomBytes(32); // Generates a 256-bit key
66
- const hmacA = crypto.createHmac('sha256', key).update(bufferA).digest();
67
- const hmacB = crypto.createHmac('sha256', key).update(bufferB).digest();
68
- // Perform a constant time comparison
69
- return crypto.timingSafeEqual(hmacA, hmacB);
70
- });
71
- }
72
- }
73
- exports.NodeCryptoProvider = NodeCryptoProvider;
@@ -1,15 +0,0 @@
1
- import { CryptoProvider } from './CryptoProvider';
2
- /**
3
- * `CryptoProvider which uses the SubtleCrypto interface of the Web Crypto API.
4
- *
5
- * This only supports asynchronous operations.
6
- */
7
- export declare class SubtleCryptoProvider extends CryptoProvider {
8
- subtleCrypto: SubtleCrypto;
9
- constructor(subtleCrypto?: SubtleCrypto);
10
- computeHMACSignature(_payload: string, _secret: string): string;
11
- /** @override */
12
- computeHMACSignatureAsync(payload: string, secret: string): Promise<string>;
13
- /** @override */
14
- secureCompare(stringA: string, stringB: string): Promise<boolean>;
15
- }
@@ -1,75 +0,0 @@
1
- "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
- Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.SubtleCryptoProvider = void 0;
13
- const CryptoProvider_1 = require("./CryptoProvider");
14
- /**
15
- * `CryptoProvider which uses the SubtleCrypto interface of the Web Crypto API.
16
- *
17
- * This only supports asynchronous operations.
18
- */
19
- class SubtleCryptoProvider extends CryptoProvider_1.CryptoProvider {
20
- constructor(subtleCrypto) {
21
- super();
22
- // If no subtle crypto is interface, default to the global namespace. This
23
- // is to allow custom interfaces (eg. using the Node webcrypto interface in
24
- // tests).
25
- this.subtleCrypto = subtleCrypto || crypto.subtle;
26
- }
27
- computeHMACSignature(_payload, _secret) {
28
- throw new Error('SubleCryptoProvider cannot be used in a synchronous context.');
29
- }
30
- /** @override */
31
- computeHMACSignatureAsync(payload, secret) {
32
- return __awaiter(this, void 0, void 0, function* () {
33
- const encoder = new TextEncoder();
34
- const key = yield this.subtleCrypto.importKey('raw', encoder.encode(secret), {
35
- name: 'HMAC',
36
- hash: { name: 'SHA-256' },
37
- }, false, ['sign']);
38
- const signatureBuffer = yield this.subtleCrypto.sign('hmac', key, encoder.encode(payload));
39
- // crypto.subtle returns the signature in base64 format. This must be
40
- // encoded in hex to match the CryptoProvider contract. We map each byte in
41
- // the buffer to its corresponding hex octet and then combine into a string.
42
- const signatureBytes = new Uint8Array(signatureBuffer);
43
- const signatureHexCodes = new Array(signatureBytes.length);
44
- for (let i = 0; i < signatureBytes.length; i++) {
45
- signatureHexCodes[i] = byteHexMapping[signatureBytes[i]];
46
- }
47
- return signatureHexCodes.join('');
48
- });
49
- }
50
- /** @override */
51
- secureCompare(stringA, stringB) {
52
- return __awaiter(this, void 0, void 0, function* () {
53
- const bufferA = this.encoder.encode(stringA);
54
- const bufferB = this.encoder.encode(stringB);
55
- if (bufferA.length !== bufferB.length) {
56
- return false;
57
- }
58
- const algorithm = { name: 'HMAC', hash: 'SHA-256' };
59
- const key = (yield crypto.subtle.generateKey(algorithm, false, [
60
- 'sign',
61
- 'verify',
62
- ]));
63
- const hmac = yield crypto.subtle.sign(algorithm, key, bufferA);
64
- const equal = yield crypto.subtle.verify(algorithm, key, hmac, bufferB);
65
- return equal;
66
- });
67
- }
68
- }
69
- exports.SubtleCryptoProvider = SubtleCryptoProvider;
70
- // Cached mapping of byte to hex representation. We do this once to avoid re-
71
- // computing every time we need to convert the result of a signature to hex.
72
- const byteHexMapping = new Array(256);
73
- for (let i = 0; i < byteHexMapping.length; i++) {
74
- byteHexMapping[i] = i.toString(16).padStart(2, '0');
75
- }
@@ -1,9 +0,0 @@
1
- /// <reference types="node" />
2
- export interface Decoded {
3
- iv: Buffer;
4
- tag: Buffer;
5
- keys: string;
6
- ciphertext: Buffer;
7
- }
8
- export declare const decrypt: (payload: string | Decoded, dataKey: string) => string;
9
- export declare const decode: (payload: string) => Decoded;
@@ -1,37 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.decode = exports.decrypt = void 0;
7
- const crypto_1 = __importDefault(require("crypto"));
8
- const leb_1 = require("leb");
9
- const decrypt = (payload, dataKey) => {
10
- if (typeof payload === 'string') {
11
- payload = (0, exports.decode)(payload);
12
- }
13
- const { iv, tag, ciphertext } = payload;
14
- const key = Buffer.from(dataKey, 'base64');
15
- const decipher = crypto_1.default.createDecipheriv('aes-256-gcm', key, iv);
16
- decipher.setAuthTag(tag);
17
- const decrypted = decipher.update(ciphertext, undefined, 'utf-8') + decipher.final('utf-8');
18
- return decrypted;
19
- };
20
- exports.decrypt = decrypt;
21
- const decode = (payload) => {
22
- const inputData = Buffer.from(payload, 'base64');
23
- const iv = inputData.slice(0, 32);
24
- const tag = inputData.slice(32, 48);
25
- const { value: keyLen, nextIndex } = (0, leb_1.decodeUInt32)(inputData, 48);
26
- const keys = inputData
27
- .slice(nextIndex, nextIndex + keyLen)
28
- .toString('base64');
29
- const ciphertext = inputData.slice(nextIndex + keyLen);
30
- return {
31
- iv,
32
- tag,
33
- keys,
34
- ciphertext,
35
- };
36
- };
37
- exports.decode = decode;
@@ -1 +0,0 @@
1
- export declare const encrypt: (data: string, dataKey: string, encryptedKeys: string) => string;
@@ -1,31 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.encrypt = void 0;
7
- const crypto_1 = __importDefault(require("crypto"));
8
- const leb_1 = require("leb");
9
- const encrypt = (data, dataKey, encryptedKeys) => {
10
- // encrypt using the returned data key
11
- const key = Buffer.from(dataKey, 'base64');
12
- const keyBlob = Buffer.from(encryptedKeys, 'base64');
13
- const prefixLen = (0, leb_1.encodeUInt32)(keyBlob.length);
14
- const iv = crypto_1.default.randomBytes(32);
15
- const cipher = crypto_1.default.createCipheriv('aes-256-gcm', key, iv);
16
- const ciphertext = Buffer.concat([
17
- cipher.update(data, 'utf8'),
18
- cipher.final(),
19
- ]);
20
- const tag = cipher.getAuthTag();
21
- // store the encrypted keys with the ciphertext
22
- const payload = Buffer.concat([
23
- iv,
24
- tag,
25
- prefixLen,
26
- keyBlob,
27
- ciphertext,
28
- ]).toString('base64');
29
- return payload;
30
- };
31
- exports.encrypt = encrypt;