@openstax/ts-utils 1.44.4 → 1.46.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/cjs/index.d.ts +0 -1
- package/dist/cjs/index.js +0 -1
- package/dist/cjs/services/accountsGateway/index.d.ts +8 -4
- package/dist/cjs/services/accountsGateway/index.js +10 -2
- package/dist/cjs/services/authProvider/index.d.ts +6 -1
- package/dist/cjs/services/httpMessage/index.d.ts +2 -0
- package/dist/cjs/services/httpMessage/index.js +7 -0
- package/dist/cjs/services/httpMessage/signer.d.ts +15 -0
- package/dist/cjs/services/httpMessage/signer.js +42 -0
- package/dist/cjs/services/keyStore/index.d.ts +20 -0
- package/dist/cjs/services/keyStore/index.js +27 -0
- package/dist/cjs/services/launchParams/signer.d.ts +4 -6
- package/dist/cjs/services/launchParams/signer.js +6 -12
- package/dist/cjs/tsconfig.without-specs.cjs.tsbuildinfo +1 -1
- package/dist/esm/index.d.ts +0 -1
- package/dist/esm/index.js +0 -1
- package/dist/esm/services/accountsGateway/index.d.ts +8 -4
- package/dist/esm/services/accountsGateway/index.js +8 -1
- package/dist/esm/services/authProvider/index.d.ts +6 -1
- package/dist/esm/services/httpMessage/index.d.ts +2 -0
- package/dist/esm/services/httpMessage/index.js +2 -0
- package/dist/esm/services/httpMessage/signer.d.ts +15 -0
- package/dist/esm/services/httpMessage/signer.js +38 -0
- package/dist/esm/services/keyStore/index.d.ts +20 -0
- package/dist/esm/services/keyStore/index.js +23 -0
- package/dist/esm/services/launchParams/signer.d.ts +4 -6
- package/dist/esm/services/launchParams/signer.js +6 -12
- package/dist/esm/tsconfig.without-specs.esm.tsbuildinfo +1 -1
- package/package.json +10 -5
- /package/dist/cjs/services/{httpMessageVerifier/index.d.ts → httpMessage/verifier.d.ts} +0 -0
- /package/dist/cjs/services/{httpMessageVerifier/index.js → httpMessage/verifier.js} +0 -0
- /package/dist/esm/services/{httpMessageVerifier/index.d.ts → httpMessage/verifier.d.ts} +0 -0
- /package/dist/esm/services/{httpMessageVerifier/index.js → httpMessage/verifier.js} +0 -0
package/dist/cjs/index.d.ts
CHANGED
package/dist/cjs/index.js
CHANGED
|
@@ -18,4 +18,3 @@ __exportStar(require("./misc/hashValue.js"), exports);
|
|
|
18
18
|
__exportStar(require("./misc/helpers.js"), exports);
|
|
19
19
|
__exportStar(require("./misc/merge.js"), exports);
|
|
20
20
|
__exportStar(require("./misc/partitionSequence.js"), exports);
|
|
21
|
-
__exportStar(require("./misc/timingSafeCompareStrings.js"), exports);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ConfigProviderForConfig } from '../../config/index.js';
|
|
2
2
|
import { GenericFetch } from '../../fetch/index.js';
|
|
3
3
|
import { JsonCompatibleStruct } from '../../routing/index.js';
|
|
4
|
-
import { ApiUser } from '../authProvider/index.js';
|
|
4
|
+
import { ApiUser, ExternalId } from '../authProvider/index.js';
|
|
5
5
|
import { Logger } from '../logger/index.js';
|
|
6
6
|
export type Config = {
|
|
7
7
|
accountsBase: string;
|
|
@@ -36,12 +36,12 @@ export type FindOrCreateUserPayload = {
|
|
|
36
36
|
export type FindOrCreateUserResponse = {
|
|
37
37
|
id: number;
|
|
38
38
|
uuid: string;
|
|
39
|
-
external_ids:
|
|
39
|
+
external_ids: ExternalId[];
|
|
40
40
|
is_test: boolean;
|
|
41
41
|
sso: string;
|
|
42
42
|
};
|
|
43
43
|
export type FindUserResponse = (FindOrCreateUserResponse & {
|
|
44
|
-
external_ids:
|
|
44
|
+
external_ids: ExternalId[];
|
|
45
45
|
}) | undefined;
|
|
46
46
|
export type LinkUserPayload = {
|
|
47
47
|
userId: number;
|
|
@@ -59,7 +59,7 @@ export type SearchUsersPayload = {
|
|
|
59
59
|
};
|
|
60
60
|
export type SearchUsersResponse = {
|
|
61
61
|
items: Array<ApiUser & {
|
|
62
|
-
external_ids:
|
|
62
|
+
external_ids: ExternalId[];
|
|
63
63
|
} & JsonCompatibleStruct>;
|
|
64
64
|
total_count: number;
|
|
65
65
|
};
|
|
@@ -72,6 +72,10 @@ export type MappedUserInfo<T> = {
|
|
|
72
72
|
platformUserId?: string;
|
|
73
73
|
uuid: string;
|
|
74
74
|
};
|
|
75
|
+
/**
|
|
76
|
+
* Normalize an external_id to always return the string representation.
|
|
77
|
+
*/
|
|
78
|
+
export declare const normalizeExternalId: (externalId: ExternalId) => string;
|
|
75
79
|
export declare const accountsGateway: <C extends string = "accounts">(initializer: Initializer<C>) => (configProvider: { [_key in C]: ConfigProviderForConfig<Config>; }) => ({ logger }: {
|
|
76
80
|
logger: Logger;
|
|
77
81
|
}) => {
|
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.accountsGateway = void 0;
|
|
6
|
+
exports.accountsGateway = exports.normalizeExternalId = void 0;
|
|
7
7
|
const lodash_1 = require("lodash");
|
|
8
8
|
const query_string_1 = __importDefault(require("query-string"));
|
|
9
9
|
const index_js_1 = require("../../config/index.js");
|
|
@@ -17,6 +17,13 @@ class ApiError extends Error {
|
|
|
17
17
|
this.status = status;
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
|
+
/**
|
|
21
|
+
* Normalize an external_id to always return the string representation.
|
|
22
|
+
*/
|
|
23
|
+
const normalizeExternalId = (externalId) => {
|
|
24
|
+
return typeof externalId === 'string' ? externalId : externalId.external_id;
|
|
25
|
+
};
|
|
26
|
+
exports.normalizeExternalId = normalizeExternalId;
|
|
20
27
|
const accountsGateway = (initializer) => (configProvider) => {
|
|
21
28
|
const config = configProvider[(0, index_js_2.ifDefined)(initializer.configSpace, 'accounts')];
|
|
22
29
|
const accountsBase = (0, helpers_js_1.once)(() => (0, index_js_1.resolveConfigValue)(config.accountsBase));
|
|
@@ -65,7 +72,8 @@ const accountsGateway = (initializer) => (configProvider) => {
|
|
|
65
72
|
const searchUsers = async (payload) => request(index_js_3.METHOD.GET, `users?${query_string_1.default.stringify(payload)}`, {});
|
|
66
73
|
const updateUser = async (token, body) => request(index_js_3.METHOD.PUT, 'user', { body, token });
|
|
67
74
|
const getPlatformUserId = (externalIds, platformId) => {
|
|
68
|
-
|
|
75
|
+
const normalizedIds = externalIds.map(exports.normalizeExternalId);
|
|
76
|
+
for (const externalId of normalizedIds) {
|
|
69
77
|
const [userPlatformId, userId] = externalId.split('/', 2);
|
|
70
78
|
if (userPlatformId === platformId) {
|
|
71
79
|
return userId;
|
|
@@ -11,6 +11,11 @@ export type TokenUser = {
|
|
|
11
11
|
name: string;
|
|
12
12
|
uuid: string;
|
|
13
13
|
};
|
|
14
|
+
export type ExternalId = string | {
|
|
15
|
+
external_id: string;
|
|
16
|
+
user_id?: number;
|
|
17
|
+
role: string;
|
|
18
|
+
};
|
|
14
19
|
export type ApiUser = TokenUser & {
|
|
15
20
|
id: number;
|
|
16
21
|
first_name: string;
|
|
@@ -27,7 +32,7 @@ export type ApiUser = TokenUser & {
|
|
|
27
32
|
name: string;
|
|
28
33
|
roles: string[];
|
|
29
34
|
}>;
|
|
30
|
-
external_ids:
|
|
35
|
+
external_ids: ExternalId[];
|
|
31
36
|
faculty_status: string;
|
|
32
37
|
is_admin: boolean;
|
|
33
38
|
is_not_gdpr_location: boolean;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createHttpMessageVerifier = exports.createHttpMessageSigner = void 0;
|
|
4
|
+
var signer_js_1 = require("./signer.js");
|
|
5
|
+
Object.defineProperty(exports, "createHttpMessageSigner", { enumerable: true, get: function () { return signer_js_1.createHttpMessageSigner; } });
|
|
6
|
+
var verifier_js_1 = require("./verifier.js");
|
|
7
|
+
Object.defineProperty(exports, "createHttpMessageVerifier", { enumerable: true, get: function () { return verifier_js_1.createHttpMessageVerifier; } });
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ConfigProviderForConfig } from '../../config/index.js';
|
|
2
|
+
import { KeyStore } from '../keyStore/index.js';
|
|
3
|
+
type Config = {
|
|
4
|
+
iss: string;
|
|
5
|
+
};
|
|
6
|
+
interface Initializer<C> {
|
|
7
|
+
configSpace?: C;
|
|
8
|
+
}
|
|
9
|
+
export declare const createHttpMessageSigner: <C extends string = "signer">({ configSpace }: Initializer<C>) => (configProvider: { [_key in C]: ConfigProviderForConfig<Config>; }, services: {
|
|
10
|
+
keyStore: KeyStore;
|
|
11
|
+
}) => {
|
|
12
|
+
signRequest: (method: string, url: string, bodyString: string) => Promise<Record<string, string>>;
|
|
13
|
+
};
|
|
14
|
+
export type HttpMessageSigner = ReturnType<ReturnType<typeof createHttpMessageSigner>>;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createHttpMessageSigner = void 0;
|
|
4
|
+
/* spell-checker: ignore httpbis meunier keyid */
|
|
5
|
+
const crypto_1 = require("crypto");
|
|
6
|
+
const http_message_signatures_1 = require("http-message-signatures");
|
|
7
|
+
const index_js_1 = require("../../config/index.js");
|
|
8
|
+
const helpers_js_1 = require("../../misc/helpers.js");
|
|
9
|
+
const createHttpMessageSigner = ({ configSpace }) => (configProvider, services) => {
|
|
10
|
+
const config = configProvider[configSpace !== null && configSpace !== void 0 ? configSpace : 'signer'];
|
|
11
|
+
const getIss = (0, helpers_js_1.once)(async () => (await (0, index_js_1.resolveConfigValue)(config.iss)).replace(/\/+$/, ''));
|
|
12
|
+
const getKey = (0, helpers_js_1.once)(() => services.keyStore.getPrivateKey());
|
|
13
|
+
const getSigner = (0, helpers_js_1.once)(async () => {
|
|
14
|
+
const { pem } = await getKey();
|
|
15
|
+
return (0, http_message_signatures_1.createSigner)(pem, 'rsa-v1_5-sha256');
|
|
16
|
+
});
|
|
17
|
+
return {
|
|
18
|
+
signRequest: async (method, url, bodyString) => {
|
|
19
|
+
const { kid } = await getKey();
|
|
20
|
+
const digest = (0, crypto_1.createHash)('sha256').update(bodyString).digest('base64');
|
|
21
|
+
const key = await getSigner();
|
|
22
|
+
const signed = await http_message_signatures_1.httpbis.signMessage({
|
|
23
|
+
key,
|
|
24
|
+
// draft-meunier-http-message-signatures-directory requires signature-agent
|
|
25
|
+
// to be a covered component alongside the standard RFC 9421 derived components
|
|
26
|
+
fields: ['@method', '@target-uri', 'content-digest', 'signature-agent'],
|
|
27
|
+
params: ['keyid', 'alg'],
|
|
28
|
+
paramValues: { keyid: kid, alg: 'rsa-v1_5-sha256' },
|
|
29
|
+
}, {
|
|
30
|
+
method,
|
|
31
|
+
url,
|
|
32
|
+
headers: {
|
|
33
|
+
// RFC 8941 byte sequence: sha-256=:base64value:
|
|
34
|
+
'Content-Digest': `sha-256=:${digest}:`,
|
|
35
|
+
'Signature-Agent': `${await getIss()}/.well-known/jwks.json`,
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
return signed.headers;
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
exports.createHttpMessageSigner = createHttpMessageSigner;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { JWK } from 'node-jose';
|
|
2
|
+
import { ConfigProviderForConfig } from '../../config/index.js';
|
|
3
|
+
type Config = {
|
|
4
|
+
privateKey: string;
|
|
5
|
+
};
|
|
6
|
+
export type PrivateKey = {
|
|
7
|
+
kid: string;
|
|
8
|
+
pem: string;
|
|
9
|
+
};
|
|
10
|
+
export declare const createKeyStore: (config: ConfigProviderForConfig<Config>) => {
|
|
11
|
+
getPrivateKey: () => Promise<{
|
|
12
|
+
kid: string;
|
|
13
|
+
pem: string;
|
|
14
|
+
}>;
|
|
15
|
+
jwks: () => Promise<{
|
|
16
|
+
keys: JWK.RawKey[];
|
|
17
|
+
}>;
|
|
18
|
+
};
|
|
19
|
+
export type KeyStore = ReturnType<typeof createKeyStore>;
|
|
20
|
+
export {};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createKeyStore = void 0;
|
|
4
|
+
const node_jose_1 = require("node-jose");
|
|
5
|
+
const index_js_1 = require("../../config/index.js");
|
|
6
|
+
const helpers_js_1 = require("../../misc/helpers.js");
|
|
7
|
+
const createKeyStore = (config) => {
|
|
8
|
+
const store = (0, helpers_js_1.once)(async () => {
|
|
9
|
+
const pem = await (0, index_js_1.resolveConfigValue)(config.privateKey);
|
|
10
|
+
const keyStore = node_jose_1.JWK.createKeyStore();
|
|
11
|
+
const { kid } = await keyStore.add(pem, 'pem');
|
|
12
|
+
const keys = [{ kid, pem }];
|
|
13
|
+
return { keyStore, keys };
|
|
14
|
+
});
|
|
15
|
+
return {
|
|
16
|
+
// this method only supports one key for now (always returns the first key)
|
|
17
|
+
getPrivateKey: async () => {
|
|
18
|
+
const { keys } = await store();
|
|
19
|
+
return keys[0];
|
|
20
|
+
},
|
|
21
|
+
jwks: async () => {
|
|
22
|
+
const { keyStore } = await store();
|
|
23
|
+
return keyStore.toJSON(false);
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
exports.createKeyStore = createKeyStore;
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import { JWK } from 'node-jose';
|
|
2
1
|
import { ConfigProviderForConfig } from '../../config/index.js';
|
|
3
2
|
import type { JsonCompatibleStruct } from '../../routing/index.js';
|
|
3
|
+
import { KeyStore } from '../keyStore/index.js';
|
|
4
4
|
type Config = {
|
|
5
5
|
alg: string;
|
|
6
6
|
expiresIn: string;
|
|
7
7
|
iss: string;
|
|
8
|
-
privateKey: string;
|
|
9
8
|
};
|
|
10
9
|
interface Initializer<C> {
|
|
11
10
|
configSpace?: C;
|
|
@@ -13,10 +12,9 @@ interface Initializer<C> {
|
|
|
13
12
|
/**
|
|
14
13
|
* Creates a class that can sign launch params
|
|
15
14
|
*/
|
|
16
|
-
export declare const createLaunchSigner: <C extends string = "launch">({ configSpace }: Initializer<C>) => (configProvider: { [_key in C]: ConfigProviderForConfig<Config>; }
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}>;
|
|
15
|
+
export declare const createLaunchSigner: <C extends string = "launch">({ configSpace }: Initializer<C>) => (configProvider: { [_key in C]: ConfigProviderForConfig<Config>; }, services: {
|
|
16
|
+
keyStore: KeyStore;
|
|
17
|
+
}) => {
|
|
20
18
|
sign: (data: JsonCompatibleStruct, subject: string, maxExp?: number | null) => Promise<string>;
|
|
21
19
|
};
|
|
22
20
|
export type LaunchSigner = ReturnType<ReturnType<typeof createLaunchSigner>>;
|
|
@@ -6,7 +6,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.createLaunchSigner = void 0;
|
|
7
7
|
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
|
|
8
8
|
const ms_1 = __importDefault(require("ms"));
|
|
9
|
-
const node_jose_1 = require("node-jose");
|
|
10
9
|
const index_js_1 = require("../../config/index.js");
|
|
11
10
|
const index_js_2 = require("../../guards/index.js");
|
|
12
11
|
const index_js_3 = require("../../index.js");
|
|
@@ -22,18 +21,12 @@ const assertAlg = (alg) => {
|
|
|
22
21
|
/**
|
|
23
22
|
* Creates a class that can sign launch params
|
|
24
23
|
*/
|
|
25
|
-
const createLaunchSigner = ({ configSpace }) => (configProvider) => {
|
|
24
|
+
const createLaunchSigner = ({ configSpace }) => (configProvider, services) => {
|
|
26
25
|
const config = configProvider[(0, index_js_2.ifDefined)(configSpace, 'launch')];
|
|
27
26
|
const getAlg = (0, index_js_3.once)(async () => assertAlg(await (0, index_js_1.resolveConfigValue)(config.alg)));
|
|
28
27
|
const getExpiresIn = (0, index_js_3.once)(() => (0, index_js_1.resolveConfigValue)(config.expiresIn));
|
|
29
28
|
const getIss = (0, index_js_3.once)(() => (0, index_js_1.resolveConfigValue)(config.iss));
|
|
30
|
-
const
|
|
31
|
-
const getKeyStore = (0, index_js_3.once)(async () => {
|
|
32
|
-
const keystore = node_jose_1.JWK.createKeyStore();
|
|
33
|
-
await keystore.add(await getPrivateKey(), 'pem');
|
|
34
|
-
return keystore;
|
|
35
|
-
});
|
|
36
|
-
const jwks = async () => (await getKeyStore()).toJSON(false);
|
|
29
|
+
const getKey = (0, index_js_3.once)(() => services.keyStore.getPrivateKey());
|
|
37
30
|
const getExpiresInWithMax = async (maxExp) => {
|
|
38
31
|
const expiresIn = await getExpiresIn();
|
|
39
32
|
// The ms library used by jsonwebtoken can handle a value in seconds as well as a string like '1d'
|
|
@@ -46,13 +39,14 @@ const createLaunchSigner = ({ configSpace }) => (configProvider) => {
|
|
|
46
39
|
return Math.min(expiresInSeconds, maxExpSeconds);
|
|
47
40
|
};
|
|
48
41
|
const sign = async (data, subject, maxExp) => {
|
|
42
|
+
const { kid, pem } = await getKey();
|
|
49
43
|
const alg = await getAlg();
|
|
50
44
|
// expiresIn can be a number of seconds or a string like '1h' or '1d'
|
|
51
45
|
const expiresIn = await getExpiresInWithMax(maxExp);
|
|
52
46
|
const iss = await getIss();
|
|
53
|
-
const header = { alg, iss };
|
|
54
|
-
return jsonwebtoken_1.default.sign(data,
|
|
47
|
+
const header = { alg, iss, kid };
|
|
48
|
+
return jsonwebtoken_1.default.sign(data, pem, { algorithm: alg, expiresIn, header, issuer: iss, subject });
|
|
55
49
|
};
|
|
56
|
-
return {
|
|
50
|
+
return { sign };
|
|
57
51
|
};
|
|
58
52
|
exports.createLaunchSigner = createLaunchSigner;
|