@workos-inc/node 7.5.0-beta.node-compatibility → 7.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -4
- package/lib/common/interfaces/event.interface.d.ts +19 -3
- package/lib/common/interfaces/index.d.ts +0 -1
- package/lib/common/interfaces/index.js +0 -1
- package/lib/common/interfaces/workos-options.interface.d.ts +0 -1
- package/lib/common/serializers/event.serializer.js +4 -0
- package/lib/common/utils/fetch-client.d.ts +31 -0
- package/lib/common/utils/fetch-client.js +108 -0
- package/lib/user-management/fixtures/email_verification.json +10 -0
- package/lib/user-management/fixtures/invitation.json +1 -1
- package/lib/user-management/fixtures/list-invitations.json +1 -1
- package/lib/user-management/fixtures/password_reset.json +10 -0
- package/lib/user-management/interfaces/create-password-reset-options.interface.d.ts +6 -0
- package/lib/user-management/interfaces/email-verification.interface.d.ts +38 -0
- package/lib/user-management/interfaces/email-verification.interface.js +2 -0
- package/lib/user-management/interfaces/index.d.ts +3 -0
- package/lib/user-management/interfaces/index.js +3 -0
- package/lib/user-management/interfaces/password-reset.interface.d.ts +36 -0
- package/lib/user-management/interfaces/password-reset.interface.js +2 -0
- package/lib/user-management/serializers/create-password-reset-options.serializer.d.ts +2 -0
- package/lib/user-management/serializers/create-password-reset-options.serializer.js +7 -0
- package/lib/user-management/serializers/email-verification.serializer.d.ts +3 -0
- package/lib/user-management/serializers/email-verification.serializer.js +24 -0
- package/lib/user-management/serializers/index.d.ts +3 -0
- package/lib/user-management/serializers/index.js +3 -0
- package/lib/user-management/serializers/password-reset.serializer.d.ts +3 -0
- package/lib/user-management/serializers/password-reset.serializer.js +23 -0
- package/lib/user-management/user-management.d.ts +7 -1
- package/lib/user-management/user-management.js +21 -0
- package/lib/user-management/user-management.spec.js +57 -0
- package/lib/webhooks/webhooks.d.ts +2 -2
- package/lib/webhooks/webhooks.js +37 -11
- package/lib/webhooks/webhooks.spec.js +0 -29
- package/lib/workos.d.ts +1 -1
- package/lib/workos.js +12 -18
- package/lib/workos.spec.js +3 -56
- package/package.json +4 -3
- package/lib/common/crypto/CryptoProvider.d.ts +0 -32
- package/lib/common/crypto/CryptoProvider.js +0 -13
- package/lib/common/crypto/NodeCryptoProvider.d.ts +0 -12
- package/lib/common/crypto/NodeCryptoProvider.js +0 -73
- package/lib/common/crypto/SubtleCryptoProvider.d.ts +0 -15
- package/lib/common/crypto/SubtleCryptoProvider.js +0 -75
- package/lib/common/crypto/index.d.ts +0 -3
- package/lib/common/crypto/index.js +0 -19
- package/lib/common/interfaces/http-client.interface.d.ts +0 -20
- package/lib/common/net/fetch-client.d.ts +0 -22
- package/lib/common/net/fetch-client.js +0 -112
- package/lib/common/net/http-client.d.ts +0 -39
- package/lib/common/net/http-client.js +0 -76
- package/lib/common/net/index.d.ts +0 -5
- package/lib/common/net/index.js +0 -31
- package/lib/common/net/node-client.d.ts +0 -23
- package/lib/common/net/node-client.js +0 -155
- /package/lib/{common/interfaces/http-client.interface.js → user-management/interfaces/create-password-reset-options.interface.js} +0 -0
|
@@ -16,6 +16,7 @@ const jest_fetch_mock_1 = __importDefault(require("jest-fetch-mock"));
|
|
|
16
16
|
const test_utils_1 = require("../common/utils/test-utils");
|
|
17
17
|
const workos_1 = require("../workos");
|
|
18
18
|
const deactivate_organization_membership_json_1 = __importDefault(require("./fixtures/deactivate-organization-membership.json"));
|
|
19
|
+
const email_verification_json_1 = __importDefault(require("./fixtures/email_verification.json"));
|
|
19
20
|
const invitation_json_1 = __importDefault(require("./fixtures/invitation.json"));
|
|
20
21
|
const list_factors_json_1 = __importDefault(require("./fixtures/list-factors.json"));
|
|
21
22
|
const list_invitations_json_1 = __importDefault(require("./fixtures/list-invitations.json"));
|
|
@@ -23,12 +24,15 @@ const list_organization_memberships_json_1 = __importDefault(require("./fixtures
|
|
|
23
24
|
const list_users_json_1 = __importDefault(require("./fixtures/list-users.json"));
|
|
24
25
|
const magic_auth_json_1 = __importDefault(require("./fixtures/magic_auth.json"));
|
|
25
26
|
const organization_membership_json_1 = __importDefault(require("./fixtures/organization-membership.json"));
|
|
27
|
+
const password_reset_json_1 = __importDefault(require("./fixtures/password_reset.json"));
|
|
26
28
|
const user_json_1 = __importDefault(require("./fixtures/user.json"));
|
|
27
29
|
const workos = new workos_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU');
|
|
28
30
|
const userId = 'user_01H5JQDV7R7ATEYZDEG0W5PRYS';
|
|
29
31
|
const organizationMembershipId = 'om_01H5JQDV7R7ATEYZDEG0W5PRYS';
|
|
32
|
+
const emailVerificationId = 'email_verification_01H5JQDV7R7ATEYZDEG0W5PRYS';
|
|
30
33
|
const invitationId = 'invitation_01H5JQDV7R7ATEYZDEG0W5PRYS';
|
|
31
34
|
const magicAuthId = 'magic_auth_01H5JQDV7R7ATEYZDEG0W5PRYS';
|
|
35
|
+
const passwordResetId = 'password_reset_01H5JQDV7R7ATEYZDEG0W5PRYS';
|
|
32
36
|
describe('UserManagement', () => {
|
|
33
37
|
beforeEach(() => jest_fetch_mock_1.default.resetMocks());
|
|
34
38
|
describe('getUser', () => {
|
|
@@ -293,6 +297,22 @@ describe('UserManagement', () => {
|
|
|
293
297
|
});
|
|
294
298
|
}));
|
|
295
299
|
});
|
|
300
|
+
describe('getEmailVerification', () => {
|
|
301
|
+
it('sends a Get EmailVerification request', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
302
|
+
(0, test_utils_1.fetchOnce)(email_verification_json_1.default);
|
|
303
|
+
const emailVerification = yield workos.userManagement.getEmailVerification(emailVerificationId);
|
|
304
|
+
expect((0, test_utils_1.fetchURL)()).toContain(`/user_management/email_verification/${emailVerificationId}`);
|
|
305
|
+
expect(emailVerification).toMatchObject({
|
|
306
|
+
id: 'email_verification_01H5JQDV7R7ATEYZDEG0W5PRYS',
|
|
307
|
+
userId: 'user_01H5JQDV7R7ATEYZDEG0W5PRYS',
|
|
308
|
+
email: 'dane@workos.com',
|
|
309
|
+
expiresAt: '2023-07-18T02:07:19.911Z',
|
|
310
|
+
code: '123456',
|
|
311
|
+
createdAt: '2023-07-18T02:07:19.911Z',
|
|
312
|
+
updatedAt: '2023-07-18T02:07:19.911Z',
|
|
313
|
+
});
|
|
314
|
+
}));
|
|
315
|
+
});
|
|
296
316
|
describe('sendVerificationEmail', () => {
|
|
297
317
|
it('sends a Create Email Verification Challenge request', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
298
318
|
(0, test_utils_1.fetchOnce)({ user: user_json_1.default });
|
|
@@ -377,6 +397,43 @@ describe('UserManagement', () => {
|
|
|
377
397
|
expect(response).toBeUndefined();
|
|
378
398
|
}));
|
|
379
399
|
});
|
|
400
|
+
describe('getPasswordReset', () => {
|
|
401
|
+
it('sends a Get PaswordReset request', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
402
|
+
(0, test_utils_1.fetchOnce)(password_reset_json_1.default);
|
|
403
|
+
const passwordReset = yield workos.userManagement.getPasswordReset(passwordResetId);
|
|
404
|
+
expect((0, test_utils_1.fetchURL)()).toContain(`/user_management/password_reset/${passwordResetId}`);
|
|
405
|
+
expect(passwordReset).toMatchObject({
|
|
406
|
+
id: 'password_reset_01H5JQDV7R7ATEYZDEG0W5PRYS',
|
|
407
|
+
userId: 'user_01H5JQDV7R7ATEYZDEG0W5PRYS',
|
|
408
|
+
email: 'dane@workos.com',
|
|
409
|
+
passwordResetToken: 'Z1uX3RbwcIl5fIGJJJCXXisdI',
|
|
410
|
+
passwordResetUrl: 'https://your-app.com/reset-password?token=Z1uX3RbwcIl5fIGJJJCXXisdI',
|
|
411
|
+
expiresAt: '2023-07-18T02:07:19.911Z',
|
|
412
|
+
createdAt: '2023-07-18T02:07:19.911Z',
|
|
413
|
+
});
|
|
414
|
+
}));
|
|
415
|
+
});
|
|
416
|
+
describe('createMagicAuth', () => {
|
|
417
|
+
it('sends a Create Magic Auth request', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
418
|
+
(0, test_utils_1.fetchOnce)(password_reset_json_1.default);
|
|
419
|
+
const response = yield workos.userManagement.createPasswordReset({
|
|
420
|
+
email: 'dane@workos.com',
|
|
421
|
+
});
|
|
422
|
+
expect((0, test_utils_1.fetchURL)()).toContain('/user_management/password_reset');
|
|
423
|
+
expect((0, test_utils_1.fetchBody)()).toEqual({
|
|
424
|
+
email: 'dane@workos.com',
|
|
425
|
+
});
|
|
426
|
+
expect(response).toMatchObject({
|
|
427
|
+
id: 'password_reset_01H5JQDV7R7ATEYZDEG0W5PRYS',
|
|
428
|
+
userId: 'user_01H5JQDV7R7ATEYZDEG0W5PRYS',
|
|
429
|
+
email: 'dane@workos.com',
|
|
430
|
+
passwordResetToken: 'Z1uX3RbwcIl5fIGJJJCXXisdI',
|
|
431
|
+
passwordResetUrl: 'https://your-app.com/reset-password?token=Z1uX3RbwcIl5fIGJJJCXXisdI',
|
|
432
|
+
expiresAt: '2023-07-18T02:07:19.911Z',
|
|
433
|
+
createdAt: '2023-07-18T02:07:19.911Z',
|
|
434
|
+
});
|
|
435
|
+
}));
|
|
436
|
+
});
|
|
380
437
|
describe('sendPasswordResetEmail', () => {
|
|
381
438
|
it('sends a Send Password Reset Email request', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
382
439
|
(0, test_utils_1.fetchOnce)();
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { Event } from '../common/interfaces';
|
|
2
2
|
export declare class Webhooks {
|
|
3
|
-
private
|
|
4
|
-
constructor(subtleCrypto?: typeof crypto.subtle);
|
|
3
|
+
private encoder;
|
|
5
4
|
constructEvent({ payload, sigHeader, secret, tolerance, }: {
|
|
6
5
|
payload: unknown;
|
|
7
6
|
sigHeader: string;
|
|
@@ -16,4 +15,5 @@ export declare class Webhooks {
|
|
|
16
15
|
}): Promise<boolean>;
|
|
17
16
|
getTimestampAndSignatureHash(sigHeader: string): [string, string];
|
|
18
17
|
computeSignature(timestamp: any, payload: any, secret: string): Promise<string>;
|
|
18
|
+
secureCompare(stringA: string, stringB: string): Promise<boolean>;
|
|
19
19
|
}
|
package/lib/webhooks/webhooks.js
CHANGED
|
@@ -12,15 +12,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
12
12
|
exports.Webhooks = void 0;
|
|
13
13
|
const exceptions_1 = require("../common/exceptions");
|
|
14
14
|
const serializers_1 = require("../common/serializers");
|
|
15
|
-
const crypto_1 = require("../common/crypto");
|
|
16
15
|
class Webhooks {
|
|
17
|
-
constructor(
|
|
18
|
-
|
|
19
|
-
this.cryptoProvider = new crypto_1.SubtleCryptoProvider(subtleCrypto);
|
|
20
|
-
}
|
|
21
|
-
else {
|
|
22
|
-
this.cryptoProvider = new crypto_1.NodeCryptoProvider();
|
|
23
|
-
}
|
|
16
|
+
constructor() {
|
|
17
|
+
this.encoder = new TextEncoder();
|
|
24
18
|
}
|
|
25
19
|
constructEvent({ payload, sigHeader, secret, tolerance = 180000, }) {
|
|
26
20
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -40,8 +34,7 @@ class Webhooks {
|
|
|
40
34
|
throw new exceptions_1.SignatureVerificationException('Timestamp outside the tolerance zone');
|
|
41
35
|
}
|
|
42
36
|
const expectedSig = yield this.computeSignature(timestamp, payload, secret);
|
|
43
|
-
if ((yield this.
|
|
44
|
-
false) {
|
|
37
|
+
if ((yield this.secureCompare(expectedSig, signatureHash)) === false) {
|
|
45
38
|
throw new exceptions_1.SignatureVerificationException('Signature hash does not match the expected signature hash for payload');
|
|
46
39
|
}
|
|
47
40
|
return true;
|
|
@@ -61,8 +54,41 @@ class Webhooks {
|
|
|
61
54
|
return __awaiter(this, void 0, void 0, function* () {
|
|
62
55
|
payload = JSON.stringify(payload);
|
|
63
56
|
const signedPayload = `${timestamp}.${payload}`;
|
|
64
|
-
|
|
57
|
+
const key = yield crypto.subtle.importKey('raw', this.encoder.encode(secret), { name: 'HMAC', hash: 'SHA-256' }, false, ['sign']);
|
|
58
|
+
const signatureBuffer = yield crypto.subtle.sign('HMAC', key, this.encoder.encode(signedPayload));
|
|
59
|
+
// crypto.subtle returns the signature in base64 format. This must be
|
|
60
|
+
// encoded in hex to match the CryptoProvider contract. We map each byte in
|
|
61
|
+
// the buffer to its corresponding hex octet and then combine into a string.
|
|
62
|
+
const signatureBytes = new Uint8Array(signatureBuffer);
|
|
63
|
+
const signatureHexCodes = new Array(signatureBytes.length);
|
|
64
|
+
for (let i = 0; i < signatureBytes.length; i++) {
|
|
65
|
+
signatureHexCodes[i] = byteHexMapping[signatureBytes[i]];
|
|
66
|
+
}
|
|
67
|
+
return signatureHexCodes.join('');
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
secureCompare(stringA, stringB) {
|
|
71
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
72
|
+
const bufferA = this.encoder.encode(stringA);
|
|
73
|
+
const bufferB = this.encoder.encode(stringB);
|
|
74
|
+
if (bufferA.length !== bufferB.length) {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
const algorithm = { name: 'HMAC', hash: 'SHA-256' };
|
|
78
|
+
const key = (yield crypto.subtle.generateKey(algorithm, false, [
|
|
79
|
+
'sign',
|
|
80
|
+
'verify',
|
|
81
|
+
]));
|
|
82
|
+
const hmac = yield crypto.subtle.sign(algorithm, key, bufferA);
|
|
83
|
+
const equal = yield crypto.subtle.verify(algorithm, key, hmac, bufferB);
|
|
84
|
+
return equal;
|
|
65
85
|
});
|
|
66
86
|
}
|
|
67
87
|
}
|
|
68
88
|
exports.Webhooks = Webhooks;
|
|
89
|
+
// Cached mapping of byte to hex representation. We do this once to avoid re-
|
|
90
|
+
// computing every time we need to convert the result of a signature to hex.
|
|
91
|
+
const byteHexMapping = new Array(256);
|
|
92
|
+
for (let i = 0; i < byteHexMapping.length; i++) {
|
|
93
|
+
byteHexMapping[i] = i.toString(16).padStart(2, '0');
|
|
94
|
+
}
|
|
@@ -17,7 +17,6 @@ const workos_1 = require("../workos");
|
|
|
17
17
|
const webhook_json_1 = __importDefault(require("./fixtures/webhook.json"));
|
|
18
18
|
const workos = new workos_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU');
|
|
19
19
|
const exceptions_1 = require("../common/exceptions");
|
|
20
|
-
const crypto_2 = require("../common/crypto");
|
|
21
20
|
describe('Webhooks', () => {
|
|
22
21
|
let payload;
|
|
23
22
|
let secret;
|
|
@@ -188,32 +187,4 @@ describe('Webhooks', () => {
|
|
|
188
187
|
expect(signature).toEqual(signatureHash);
|
|
189
188
|
}));
|
|
190
189
|
});
|
|
191
|
-
describe('when in an environment that supports SubtleCrypto', () => {
|
|
192
|
-
it('automatically uses the subtle crypto library', () => {
|
|
193
|
-
// tslint:disable-next-line
|
|
194
|
-
expect(workos.webhooks['cryptoProvider']).toBeInstanceOf(crypto_2.SubtleCryptoProvider);
|
|
195
|
-
});
|
|
196
|
-
});
|
|
197
|
-
describe('CryptoProvider', () => {
|
|
198
|
-
describe('when computing HMAC signature', () => {
|
|
199
|
-
it('returns the same for the Node crypto and Web Crypto versions', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
200
|
-
const nodeCryptoProvider = new crypto_2.NodeCryptoProvider();
|
|
201
|
-
const subtleCryptoProvider = new crypto_2.SubtleCryptoProvider();
|
|
202
|
-
const stringifiedPayload = JSON.stringify(payload);
|
|
203
|
-
const payloadHMAC = `${timestamp}.${stringifiedPayload}`;
|
|
204
|
-
const nodeCompare = yield nodeCryptoProvider.computeHMACSignatureAsync(payloadHMAC, secret);
|
|
205
|
-
const subtleCompare = yield subtleCryptoProvider.computeHMACSignatureAsync(payloadHMAC, secret);
|
|
206
|
-
expect(nodeCompare).toEqual(subtleCompare);
|
|
207
|
-
}));
|
|
208
|
-
});
|
|
209
|
-
describe('when securely comparing', () => {
|
|
210
|
-
it('returns the same for the Node crypto and Web Crypto versions', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
211
|
-
const nodeCryptoProvider = new crypto_2.NodeCryptoProvider();
|
|
212
|
-
const subtleCryptoProvider = new crypto_2.SubtleCryptoProvider();
|
|
213
|
-
const signature = yield workos.webhooks.computeSignature(timestamp, payload, secret);
|
|
214
|
-
expect(nodeCryptoProvider.secureCompare(signature, signatureHash)).toEqual(subtleCryptoProvider.secureCompare(signature, signatureHash));
|
|
215
|
-
expect(nodeCryptoProvider.secureCompare(signature, 'foo')).toEqual(subtleCryptoProvider.secureCompare(signature, 'foo'));
|
|
216
|
-
}));
|
|
217
|
-
});
|
|
218
|
-
});
|
|
219
190
|
});
|
package/lib/workos.d.ts
CHANGED
package/lib/workos.js
CHANGED
|
@@ -23,8 +23,8 @@ const mfa_1 = require("./mfa/mfa");
|
|
|
23
23
|
const audit_logs_1 = require("./audit-logs/audit-logs");
|
|
24
24
|
const user_management_1 = require("./user-management/user-management");
|
|
25
25
|
const bad_request_exception_1 = require("./common/exceptions/bad-request.exception");
|
|
26
|
-
const
|
|
27
|
-
const VERSION = '7.
|
|
26
|
+
const fetch_client_1 = require("./common/utils/fetch-client");
|
|
27
|
+
const VERSION = '7.6.0';
|
|
28
28
|
const DEFAULT_HOSTNAME = 'api.workos.com';
|
|
29
29
|
class WorkOS {
|
|
30
30
|
constructor(key, options = {}) {
|
|
@@ -64,7 +64,7 @@ class WorkOS {
|
|
|
64
64
|
const { name, version } = options.appInfo;
|
|
65
65
|
userAgent += ` ${name}: ${version}`;
|
|
66
66
|
}
|
|
67
|
-
this.client =
|
|
67
|
+
this.client = new fetch_client_1.FetchClient(this.baseURL, Object.assign(Object.assign({}, options.config), { headers: Object.assign(Object.assign({}, (_a = options.config) === null || _a === void 0 ? void 0 : _a.headers), { Authorization: `Bearer ${this.key}`, 'User-Agent': userAgent }) }));
|
|
68
68
|
}
|
|
69
69
|
get version() {
|
|
70
70
|
return VERSION;
|
|
@@ -76,14 +76,13 @@ class WorkOS {
|
|
|
76
76
|
requestHeaders['Idempotency-Key'] = options.idempotencyKey;
|
|
77
77
|
}
|
|
78
78
|
try {
|
|
79
|
-
|
|
79
|
+
return yield this.client.post(path, entity, {
|
|
80
80
|
params: options.query,
|
|
81
81
|
headers: requestHeaders,
|
|
82
82
|
});
|
|
83
|
-
return { data: yield res.toJSON() };
|
|
84
83
|
}
|
|
85
84
|
catch (error) {
|
|
86
|
-
this.
|
|
85
|
+
this.handleFetchError({ path, error });
|
|
87
86
|
throw error;
|
|
88
87
|
}
|
|
89
88
|
});
|
|
@@ -92,16 +91,15 @@ class WorkOS {
|
|
|
92
91
|
return __awaiter(this, void 0, void 0, function* () {
|
|
93
92
|
try {
|
|
94
93
|
const { accessToken } = options;
|
|
95
|
-
|
|
94
|
+
return yield this.client.get(path, {
|
|
96
95
|
params: options.query,
|
|
97
96
|
headers: accessToken
|
|
98
97
|
? { Authorization: `Bearer ${accessToken}` }
|
|
99
98
|
: undefined,
|
|
100
99
|
});
|
|
101
|
-
return { data: yield res.toJSON() };
|
|
102
100
|
}
|
|
103
101
|
catch (error) {
|
|
104
|
-
this.
|
|
102
|
+
this.handleFetchError({ path, error });
|
|
105
103
|
throw error;
|
|
106
104
|
}
|
|
107
105
|
});
|
|
@@ -113,14 +111,13 @@ class WorkOS {
|
|
|
113
111
|
requestHeaders['Idempotency-Key'] = options.idempotencyKey;
|
|
114
112
|
}
|
|
115
113
|
try {
|
|
116
|
-
|
|
114
|
+
return yield this.client.put(path, entity, {
|
|
117
115
|
params: options.query,
|
|
118
116
|
headers: requestHeaders,
|
|
119
117
|
});
|
|
120
|
-
return { data: yield res.toJSON() };
|
|
121
118
|
}
|
|
122
119
|
catch (error) {
|
|
123
|
-
this.
|
|
120
|
+
this.handleFetchError({ path, error });
|
|
124
121
|
throw error;
|
|
125
122
|
}
|
|
126
123
|
});
|
|
@@ -133,7 +130,7 @@ class WorkOS {
|
|
|
133
130
|
});
|
|
134
131
|
}
|
|
135
132
|
catch (error) {
|
|
136
|
-
this.
|
|
133
|
+
this.handleFetchError({ path, error });
|
|
137
134
|
throw error;
|
|
138
135
|
}
|
|
139
136
|
});
|
|
@@ -146,15 +143,12 @@ class WorkOS {
|
|
|
146
143
|
}
|
|
147
144
|
return process.emitWarning(warning, 'WorkOS');
|
|
148
145
|
}
|
|
149
|
-
|
|
146
|
+
handleFetchError({ path, error }) {
|
|
150
147
|
var _a;
|
|
151
|
-
if (!(error instanceof net_1.HttpClientError)) {
|
|
152
|
-
throw new Error(`Unexpected error: ${error}`);
|
|
153
|
-
}
|
|
154
148
|
const { response } = error;
|
|
155
149
|
if (response) {
|
|
156
150
|
const { status, data, headers } = response;
|
|
157
|
-
const requestID = (_a = headers
|
|
151
|
+
const requestID = (_a = headers.get('X-Request-ID')) !== null && _a !== void 0 ? _a : '';
|
|
158
152
|
const { code, error_description: errorDescription, error, errors, message, } = data;
|
|
159
153
|
switch (status) {
|
|
160
154
|
case 401: {
|
package/lib/workos.spec.js
CHANGED
|
@@ -18,7 +18,6 @@ const promises_1 = __importDefault(require("fs/promises"));
|
|
|
18
18
|
const exceptions_1 = require("./common/exceptions");
|
|
19
19
|
const workos_1 = require("./workos");
|
|
20
20
|
const rate_limit_exceeded_exception_1 = require("./common/exceptions/rate-limit-exceeded.exception");
|
|
21
|
-
const net_1 = require("./common/net");
|
|
22
21
|
describe('WorkOS', () => {
|
|
23
22
|
beforeEach(() => jest_fetch_mock_1.default.resetMocks());
|
|
24
23
|
describe('constructor', () => {
|
|
@@ -96,40 +95,10 @@ describe('WorkOS', () => {
|
|
|
96
95
|
});
|
|
97
96
|
yield workos.post('/somewhere', {});
|
|
98
97
|
expect((0, test_utils_1.fetchHeaders)()).toMatchObject({
|
|
99
|
-
'User-Agent': `workos-node/${packageJson.version}
|
|
98
|
+
'User-Agent': `workos-node/${packageJson.version} fooApp: 1.0.0`,
|
|
100
99
|
});
|
|
101
100
|
}));
|
|
102
101
|
});
|
|
103
|
-
describe('when no `appInfo` option is provided', () => {
|
|
104
|
-
it('adds the HTTP client name to the user-agent', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
105
|
-
(0, test_utils_1.fetchOnce)('{}');
|
|
106
|
-
const packageJson = JSON.parse(yield promises_1.default.readFile('package.json', 'utf8'));
|
|
107
|
-
const workos = new workos_1.WorkOS('sk_test');
|
|
108
|
-
yield workos.post('/somewhere', {});
|
|
109
|
-
expect((0, test_utils_1.fetchHeaders)()).toMatchObject({
|
|
110
|
-
'User-Agent': `workos-node/${packageJson.version}/fetch`,
|
|
111
|
-
});
|
|
112
|
-
}));
|
|
113
|
-
});
|
|
114
|
-
describe('when no `appInfo` option is provided', () => {
|
|
115
|
-
it('adds the HTTP client name to the user-agent', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
116
|
-
(0, test_utils_1.fetchOnce)('{}');
|
|
117
|
-
const packageJson = JSON.parse(yield promises_1.default.readFile('package.json', 'utf8'));
|
|
118
|
-
const workos = new workos_1.WorkOS('sk_test');
|
|
119
|
-
yield workos.post('/somewhere', {});
|
|
120
|
-
expect((0, test_utils_1.fetchHeaders)()).toMatchObject({
|
|
121
|
-
'User-Agent': `workos-node/${packageJson.version}/fetch`,
|
|
122
|
-
});
|
|
123
|
-
}));
|
|
124
|
-
});
|
|
125
|
-
describe('when using an environment that supports fetch', () => {
|
|
126
|
-
it('automatically uses the fetch HTTP client', () => {
|
|
127
|
-
const workos = new workos_1.WorkOS('sk_test');
|
|
128
|
-
// Bracket notation gets past private visibility
|
|
129
|
-
// tslint:disable-next-line
|
|
130
|
-
expect(workos['client']).toBeInstanceOf(net_1.FetchHttpClient);
|
|
131
|
-
});
|
|
132
|
-
});
|
|
133
102
|
});
|
|
134
103
|
describe('version', () => {
|
|
135
104
|
it('matches the version in `package.json`', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
@@ -208,34 +177,12 @@ describe('WorkOS', () => {
|
|
|
208
177
|
}));
|
|
209
178
|
});
|
|
210
179
|
describe('when the entity is null', () => {
|
|
211
|
-
it('sends
|
|
180
|
+
it('sends a null body', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
212
181
|
(0, test_utils_1.fetchOnce)();
|
|
213
182
|
const workos = new workos_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU');
|
|
214
183
|
yield workos.post('/somewhere', null);
|
|
215
|
-
expect((0, test_utils_1.fetchBody)({ raw: true })).
|
|
184
|
+
expect((0, test_utils_1.fetchBody)({ raw: true })).toBeNull();
|
|
216
185
|
}));
|
|
217
186
|
});
|
|
218
187
|
});
|
|
219
|
-
describe('when in an environment that does not support fetch', () => {
|
|
220
|
-
const fetchFn = globalThis.fetch;
|
|
221
|
-
beforeEach(() => {
|
|
222
|
-
// @ts-ignore
|
|
223
|
-
delete globalThis.fetch;
|
|
224
|
-
});
|
|
225
|
-
afterEach(() => {
|
|
226
|
-
globalThis.fetch = fetchFn;
|
|
227
|
-
});
|
|
228
|
-
it('automatically uses the node HTTP client', () => {
|
|
229
|
-
const workos = new workos_1.WorkOS('sk_test_key');
|
|
230
|
-
// tslint:disable-next-line
|
|
231
|
-
expect(workos['client']).toBeInstanceOf(net_1.NodeHttpClient);
|
|
232
|
-
});
|
|
233
|
-
it('uses a fetch function if provided', () => {
|
|
234
|
-
const workos = new workos_1.WorkOS('sk_test_key', {
|
|
235
|
-
fetchFn,
|
|
236
|
-
});
|
|
237
|
-
// tslint:disable-next-line
|
|
238
|
-
expect(workos['client']).toBeInstanceOf(net_1.FetchHttpClient);
|
|
239
|
-
});
|
|
240
|
-
});
|
|
241
188
|
});
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "7.
|
|
2
|
+
"version": "7.6.0",
|
|
3
3
|
"name": "@workos-inc/node",
|
|
4
4
|
"author": "WorkOS",
|
|
5
5
|
"description": "A Node wrapper for the WorkOS API",
|
|
@@ -13,8 +13,9 @@
|
|
|
13
13
|
"yarn": "1.22.19"
|
|
14
14
|
},
|
|
15
15
|
"engines": {
|
|
16
|
-
"node": ">=
|
|
16
|
+
"node": ">=19"
|
|
17
17
|
},
|
|
18
|
+
"engineStrict": true,
|
|
18
19
|
"main": "lib/index.js",
|
|
19
20
|
"typings": "lib/index.d.ts",
|
|
20
21
|
"files": [
|
|
@@ -48,7 +49,7 @@
|
|
|
48
49
|
"jest-fetch-mock": "^3.0.3",
|
|
49
50
|
"prettier": "2.8.8",
|
|
50
51
|
"supertest": "6.3.3",
|
|
51
|
-
"ts-jest": "29.1.
|
|
52
|
+
"ts-jest": "29.1.3",
|
|
52
53
|
"tslint": "6.1.3",
|
|
53
54
|
"typescript": "5.1.6"
|
|
54
55
|
}
|
|
@@ -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
|
-
}
|