@openstax/ts-utils 1.3.2 → 1.4.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.
- package/dist/cjs/config/envConfig.d.ts +1 -1
- package/dist/cjs/services/launchParams/index.d.ts +2 -0
- package/dist/cjs/services/launchParams/index.js +7 -0
- package/dist/cjs/services/launchParams/signer.d.ts +27 -0
- package/dist/cjs/services/launchParams/signer.js +45 -0
- package/dist/cjs/services/launchParams/verifier.d.ts +21 -0
- package/dist/cjs/services/launchParams/verifier.js +58 -0
- package/dist/cjs/services/searchProvider/memorySearchTheBadWay.js +4 -1
- package/dist/cjs/tsconfig.without-specs.cjs.tsbuildinfo +1 -1
- package/dist/esm/config/envConfig.d.ts +1 -1
- package/dist/esm/services/launchParams/index.d.ts +2 -0
- package/dist/esm/services/launchParams/index.js +2 -0
- package/dist/esm/services/launchParams/signer.d.ts +27 -0
- package/dist/esm/services/launchParams/signer.js +38 -0
- package/dist/esm/services/launchParams/verifier.d.ts +21 -0
- package/dist/esm/services/launchParams/verifier.js +51 -0
- package/dist/esm/services/searchProvider/memorySearchTheBadWay.js +4 -1
- package/dist/esm/tsconfig.without-specs.esm.tsbuildinfo +1 -1
- package/package.json +4 -1
|
@@ -21,4 +21,4 @@ export declare const ENV_BUILD_CONFIGS: string[];
|
|
|
21
21
|
*
|
|
22
22
|
* @example const config = { configValue: envConfig('environment_variable_name') };
|
|
23
23
|
*/
|
|
24
|
-
export declare const envConfig: (name: string, type?: 'build' | 'runtime', defaultValue?: string | undefined) => ConfigValueProvider<string>;
|
|
24
|
+
export declare const envConfig: (name: string, type?: 'build' | 'runtime', defaultValue?: ConfigValueProvider<string> | undefined) => ConfigValueProvider<string>;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { JWK } from 'node-jose';
|
|
2
|
+
import { ConfigProviderForConfig } from '../../config';
|
|
3
|
+
declare type Config = {
|
|
4
|
+
alg: string;
|
|
5
|
+
expiresIn: string;
|
|
6
|
+
iss: string;
|
|
7
|
+
privateKey: string;
|
|
8
|
+
};
|
|
9
|
+
interface Initializer<C> {
|
|
10
|
+
configSpace?: C;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Creates a class that can sign launch params
|
|
14
|
+
*/
|
|
15
|
+
export declare const createLaunchSigner: <C extends string = "launch">({ configSpace }: Initializer<C>) => (configProvider: { [key in C]: {
|
|
16
|
+
alg: import("../../config").ConfigValueProvider<string>;
|
|
17
|
+
expiresIn: import("../../config").ConfigValueProvider<string>;
|
|
18
|
+
iss: import("../../config").ConfigValueProvider<string>;
|
|
19
|
+
privateKey: import("../../config").ConfigValueProvider<string>;
|
|
20
|
+
}; }) => {
|
|
21
|
+
jwks: () => Promise<{
|
|
22
|
+
keys: JWK.RawKey[];
|
|
23
|
+
}>;
|
|
24
|
+
sign: (subject: string) => Promise<string>;
|
|
25
|
+
};
|
|
26
|
+
export declare type LaunchSigner = ReturnType<ReturnType<typeof createLaunchSigner>>;
|
|
27
|
+
export {};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import jwt from 'jsonwebtoken';
|
|
2
|
+
import { JWK } from 'node-jose';
|
|
3
|
+
import { once } from '../..';
|
|
4
|
+
import { resolveConfigValue } from '../../config';
|
|
5
|
+
import { ifDefined } from '../../guards';
|
|
6
|
+
const SUPPORTED_ALGORITHMS = [
|
|
7
|
+
'RS256', 'RS384', 'RS512', 'ES256', 'ES384', 'ES512', 'HS256', 'HS384', 'HS512', 'PS256', 'PS384', 'PS512'
|
|
8
|
+
];
|
|
9
|
+
const assertAlg = (alg) => {
|
|
10
|
+
if ((SUPPORTED_ALGORITHMS).includes(alg)) {
|
|
11
|
+
return alg;
|
|
12
|
+
}
|
|
13
|
+
throw new Error(`"${alg}" is not a valid algorithm`);
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Creates a class that can sign launch params
|
|
17
|
+
*/
|
|
18
|
+
export const createLaunchSigner = ({ configSpace }) => (configProvider) => {
|
|
19
|
+
const config = configProvider[ifDefined(configSpace, 'launch')];
|
|
20
|
+
const getAlg = once(async () => assertAlg(await resolveConfigValue(config.alg)));
|
|
21
|
+
const getExpiresIn = once(() => resolveConfigValue(config.expiresIn));
|
|
22
|
+
const getIss = once(() => resolveConfigValue(config.iss));
|
|
23
|
+
const getPrivateKey = once(() => resolveConfigValue(config.privateKey));
|
|
24
|
+
const getKeyStore = once(async () => {
|
|
25
|
+
const keystore = JWK.createKeyStore();
|
|
26
|
+
await keystore.add(await getPrivateKey(), 'pem');
|
|
27
|
+
return keystore;
|
|
28
|
+
});
|
|
29
|
+
const jwks = async () => (await getKeyStore()).toJSON(false);
|
|
30
|
+
const sign = async (subject) => {
|
|
31
|
+
const alg = await getAlg();
|
|
32
|
+
const expiresIn = await getExpiresIn();
|
|
33
|
+
const iss = await getIss();
|
|
34
|
+
const header = { alg, iss };
|
|
35
|
+
return jwt.sign({}, await getPrivateKey(), { algorithm: alg, expiresIn, header, issuer: iss, subject });
|
|
36
|
+
};
|
|
37
|
+
return { jwks, sign };
|
|
38
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { JWK } from 'node-jose';
|
|
2
|
+
import { ConfigProviderForConfig } from '../../config';
|
|
3
|
+
declare type Config = {
|
|
4
|
+
trustedDomain: string;
|
|
5
|
+
};
|
|
6
|
+
interface Initializer<C> {
|
|
7
|
+
configSpace?: C;
|
|
8
|
+
fetcher?: (uri: string) => Promise<{
|
|
9
|
+
keys: JWK.RawKey[];
|
|
10
|
+
}>;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Creates a class that can verify launch params
|
|
14
|
+
*/
|
|
15
|
+
export declare const createLaunchVerifier: <C extends string = "launch">({ configSpace, fetcher }: Initializer<C>) => (configProvider: { [key in C]: {
|
|
16
|
+
trustedDomain: import("../../config").ConfigValueProvider<string>;
|
|
17
|
+
}; }) => {
|
|
18
|
+
verify: (token: string) => Promise<string>;
|
|
19
|
+
};
|
|
20
|
+
export declare type LaunchVerifier = ReturnType<ReturnType<typeof createLaunchVerifier>>;
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import jwt from 'jsonwebtoken';
|
|
2
|
+
import { JwksClient } from 'jwks-rsa';
|
|
3
|
+
import { memoize } from '../..';
|
|
4
|
+
import { resolveConfigValue } from '../../config';
|
|
5
|
+
import { ifDefined } from '../../guards';
|
|
6
|
+
/**
|
|
7
|
+
* Creates a class that can verify launch params
|
|
8
|
+
*/
|
|
9
|
+
export const createLaunchVerifier = ({ configSpace, fetcher }) => (configProvider) => {
|
|
10
|
+
const config = configProvider[ifDefined(configSpace, 'launch')];
|
|
11
|
+
const getJwksClient = memoize((jwksUri) => new JwksClient({ fetcher, jwksUri }));
|
|
12
|
+
const getJwksKey = memoize(async (jwksUri, kid) => {
|
|
13
|
+
const client = getJwksClient(jwksUri);
|
|
14
|
+
const key = await client.getSigningKey(kid);
|
|
15
|
+
return key.getPublicKey();
|
|
16
|
+
});
|
|
17
|
+
const getKey = async (header, callback) => {
|
|
18
|
+
// The JWT spec allows iss in the header as a copy of the iss claim, but we require it
|
|
19
|
+
if (!header.iss) {
|
|
20
|
+
return callback(new Error('JWT header missing iss claim'));
|
|
21
|
+
}
|
|
22
|
+
const { iss, kid } = header;
|
|
23
|
+
try {
|
|
24
|
+
const jwksUrl = new URL('/.well-known/jwks.json', iss);
|
|
25
|
+
const launchDomain = jwksUrl.hostname;
|
|
26
|
+
const trustedDomain = await resolveConfigValue(config.trustedDomain);
|
|
27
|
+
if (launchDomain !== trustedDomain && !launchDomain.endsWith(`.${trustedDomain}`)) {
|
|
28
|
+
return callback(new Error(`Untrusted launch domain: "${launchDomain}"`));
|
|
29
|
+
}
|
|
30
|
+
callback(null, await getJwksKey(jwksUrl.toString(), kid));
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
callback(error);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
const verify = (token) => new Promise((resolve, reject) => jwt.verify(token, getKey, {}, (err, payload) => {
|
|
37
|
+
if (err) {
|
|
38
|
+
reject(err);
|
|
39
|
+
}
|
|
40
|
+
else if (typeof payload !== 'object') {
|
|
41
|
+
reject(new Error('received JWT token with unexpected non-JSON payload'));
|
|
42
|
+
}
|
|
43
|
+
else if (!payload.sub) {
|
|
44
|
+
reject(new Error('JWT payload missing sub claim'));
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
resolve(payload.sub);
|
|
48
|
+
}
|
|
49
|
+
}));
|
|
50
|
+
return { verify };
|
|
51
|
+
};
|
|
@@ -33,8 +33,11 @@ export const memorySearchTheBadWay = ({ loadAllDocumentsTheBadWay }) => {
|
|
|
33
33
|
}
|
|
34
34
|
: (x) => x;
|
|
35
35
|
const hasMatch = coerceArray(field.value).map(coerceValue).some(v => docValues.includes(v));
|
|
36
|
-
|
|
36
|
+
if ((mustMatch === MatchType.Must && !hasMatch) || (mustMatch === MatchType.MustNot && hasMatch)) {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
37
39
|
}
|
|
40
|
+
return true;
|
|
38
41
|
};
|
|
39
42
|
if (options.query !== undefined) {
|
|
40
43
|
for (const field of options.fields) {
|