@openstax/ts-utils 1.15.5 → 1.16.2
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/middleware/apiSlowResponseMiddleware.js +1 -2
- package/dist/cjs/services/authProvider/browser.js +1 -1
- package/dist/cjs/services/authProvider/decryption.d.ts +5 -2
- package/dist/cjs/services/authProvider/decryption.js +15 -4
- package/dist/cjs/services/authProvider/index.d.ts +2 -2
- package/dist/cjs/services/authProvider/utils/decryptAndVerify.d.ts +3 -1
- package/dist/cjs/services/authProvider/utils/decryptAndVerify.js +3 -3
- package/dist/cjs/services/documentStore/unversioned/file-system.js +1 -1
- package/dist/cjs/services/launchParams/signer.d.ts +1 -1
- package/dist/cjs/services/launchParams/signer.js +11 -2
- package/dist/cjs/services/launchParams/verifier.d.ts +2 -1
- package/dist/cjs/services/launchParams/verifier.js +14 -2
- package/dist/cjs/tsconfig.without-specs.cjs.tsbuildinfo +1 -1
- package/dist/esm/middleware/apiSlowResponseMiddleware.js +1 -2
- package/dist/esm/services/authProvider/browser.js +1 -1
- package/dist/esm/services/authProvider/decryption.d.ts +5 -2
- package/dist/esm/services/authProvider/decryption.js +15 -4
- package/dist/esm/services/authProvider/index.d.ts +2 -2
- package/dist/esm/services/authProvider/utils/decryptAndVerify.d.ts +3 -1
- package/dist/esm/services/authProvider/utils/decryptAndVerify.js +3 -3
- package/dist/esm/services/documentStore/unversioned/file-system.js +1 -1
- package/dist/esm/services/launchParams/signer.d.ts +1 -1
- package/dist/esm/services/launchParams/signer.js +11 -2
- package/dist/esm/services/launchParams/verifier.d.ts +2 -1
- package/dist/esm/services/launchParams/verifier.js +14 -2
- package/dist/esm/tsconfig.without-specs.esm.tsbuildinfo +1 -1
- package/package.json +3 -1
|
@@ -35,7 +35,7 @@ const createSlowResponseMiddleware = (config) => {
|
|
|
35
35
|
});
|
|
36
36
|
resolve((0, routing_1.apiTextResponse)(504, '504 Gateway Timeout'));
|
|
37
37
|
}, timeoutAfter));
|
|
38
|
-
const requestPromise = response.
|
|
38
|
+
const requestPromise = response.finally(() => {
|
|
39
39
|
const time = Date.now() - start;
|
|
40
40
|
if (timeout !== undefined) {
|
|
41
41
|
clearTimeout(timeout);
|
|
@@ -46,7 +46,6 @@ const createSlowResponseMiddleware = (config) => {
|
|
|
46
46
|
time,
|
|
47
47
|
});
|
|
48
48
|
}
|
|
49
|
-
return response;
|
|
50
49
|
});
|
|
51
50
|
return timeoutPromise ? Promise.race([timeoutPromise, requestPromise]) : requestPromise;
|
|
52
51
|
});
|
|
@@ -133,7 +133,7 @@ const browserAuthProvider = ({ window, configSpace }) => (configProvider) => {
|
|
|
133
133
|
/**
|
|
134
134
|
* loads current user identity. does not reflect changes in identity after being called the first time.
|
|
135
135
|
*/
|
|
136
|
-
getUser
|
|
136
|
+
getUser,
|
|
137
137
|
};
|
|
138
138
|
};
|
|
139
139
|
exports.browserAuthProvider = browserAuthProvider;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ConfigProviderForConfig } from '../../config';
|
|
2
|
-
import { CookieAuthProvider } from '.';
|
|
2
|
+
import { AuthProvider, CookieAuthProvider } from '.';
|
|
3
3
|
declare type Config = {
|
|
4
4
|
cookieName: string;
|
|
5
5
|
encryptionPrivateKey: string;
|
|
@@ -8,9 +8,12 @@ declare type Config = {
|
|
|
8
8
|
interface Initializer<C> {
|
|
9
9
|
configSpace?: C;
|
|
10
10
|
}
|
|
11
|
+
export declare type DecryptionAuthProvider = AuthProvider & {
|
|
12
|
+
getTokenExpiration: (tokenString?: string) => Promise<number | null | undefined>;
|
|
13
|
+
};
|
|
11
14
|
export declare const decryptionAuthProvider: <C extends string = "decryption">(initializer: Initializer<C>) => (configProvider: { [key in C]: {
|
|
12
15
|
cookieName: import("../../config").ConfigValueProvider<string>;
|
|
13
16
|
encryptionPrivateKey: import("../../config").ConfigValueProvider<string>;
|
|
14
17
|
signaturePublicKey: import("../../config").ConfigValueProvider<string>;
|
|
15
|
-
}; }) => CookieAuthProvider
|
|
18
|
+
}; }) => CookieAuthProvider<DecryptionAuthProvider>;
|
|
16
19
|
export {};
|
|
@@ -21,12 +21,18 @@ const decryptionAuthProvider = (initializer) => (configProvider) => {
|
|
|
21
21
|
}
|
|
22
22
|
return { headers };
|
|
23
23
|
};
|
|
24
|
-
const
|
|
25
|
-
const
|
|
24
|
+
const getPayload = async (tokenString) => {
|
|
25
|
+
const token = tokenString !== null && tokenString !== void 0 ? tokenString : (0, _1.getAuthTokenOrCookie)(request, await cookieName())[0];
|
|
26
26
|
if (!token) {
|
|
27
27
|
return undefined;
|
|
28
28
|
}
|
|
29
|
-
|
|
29
|
+
return (0, decryptAndVerify_1.decryptAndVerify)(token, await encryptionPrivateKey(), await signaturePublicKey());
|
|
30
|
+
};
|
|
31
|
+
const loadUser = async () => {
|
|
32
|
+
const result = await getPayload();
|
|
33
|
+
if (!result) {
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
30
36
|
if ('error' in result && result.error == 'expired token') {
|
|
31
37
|
throw new errors_1.SessionExpiredError();
|
|
32
38
|
}
|
|
@@ -34,12 +40,17 @@ const decryptionAuthProvider = (initializer) => (configProvider) => {
|
|
|
34
40
|
};
|
|
35
41
|
return {
|
|
36
42
|
getAuthorizedFetchConfig,
|
|
43
|
+
getTokenExpiration: async (tokenString) => {
|
|
44
|
+
var _a;
|
|
45
|
+
const payload = await getPayload(tokenString);
|
|
46
|
+
return payload ? ((_a = payload.exp) !== null && _a !== void 0 ? _a : null) : undefined;
|
|
47
|
+
},
|
|
37
48
|
getUser: async () => {
|
|
38
49
|
if (!user) {
|
|
39
50
|
user = await loadUser();
|
|
40
51
|
}
|
|
41
52
|
return user;
|
|
42
|
-
}
|
|
53
|
+
},
|
|
43
54
|
};
|
|
44
55
|
};
|
|
45
56
|
};
|
|
@@ -45,9 +45,9 @@ export declare type CookieAuthProviderRequest = {
|
|
|
45
45
|
headers: HttpHeaders;
|
|
46
46
|
queryStringParameters?: QueryParams;
|
|
47
47
|
};
|
|
48
|
-
export declare type CookieAuthProvider = (inputs: {
|
|
48
|
+
export declare type CookieAuthProvider<T extends AuthProvider = AuthProvider> = (inputs: {
|
|
49
49
|
request: CookieAuthProviderRequest;
|
|
50
|
-
}) =>
|
|
50
|
+
}) => T;
|
|
51
51
|
export declare type StubAuthProvider = (user: User | undefined) => AuthProvider;
|
|
52
52
|
export declare const stubAuthProvider: (user?: User | undefined) => AuthProvider;
|
|
53
53
|
export declare const getAuthTokenOrCookie: (request: CookieAuthProviderRequest, cookieName: string, queryKey?: string) => [string, {
|
|
@@ -17,11 +17,13 @@ export declare const verifyJws: (jws: string, signaturePublicKey: Buffer | strin
|
|
|
17
17
|
* @param token the encrypted token
|
|
18
18
|
* @param encryptionPrivateKey the private key used to encrypt the token
|
|
19
19
|
* @param signaturePublicKey the public key used to verify the decrypted token
|
|
20
|
-
* @returns {user: User} (success) or {error: string} (failure)
|
|
20
|
+
* @returns {user: User; exp: number} (success) or {error: string} (failure)
|
|
21
21
|
*/
|
|
22
22
|
export declare const decryptAndVerify: (token: string, encryptionPrivateKey: string, signaturePublicKey: string) => {
|
|
23
23
|
user: User;
|
|
24
|
+
exp: number;
|
|
24
25
|
} | {
|
|
25
26
|
error: string;
|
|
27
|
+
exp?: number;
|
|
26
28
|
};
|
|
27
29
|
export {};
|
|
@@ -62,7 +62,7 @@ exports.verifyJws = verifyJws;
|
|
|
62
62
|
* @param token the encrypted token
|
|
63
63
|
* @param encryptionPrivateKey the private key used to encrypt the token
|
|
64
64
|
* @param signaturePublicKey the public key used to verify the decrypted token
|
|
65
|
-
* @returns {user: User} (success) or {error: string} (failure)
|
|
65
|
+
* @returns {user: User; exp: number} (success) or {error: string} (failure)
|
|
66
66
|
*/
|
|
67
67
|
const decryptAndVerify = (token, encryptionPrivateKey, signaturePublicKey) => {
|
|
68
68
|
const timestamp = Math.floor(Date.now() / 1000);
|
|
@@ -84,8 +84,8 @@ const decryptAndVerify = (token, encryptionPrivateKey, signaturePublicKey) => {
|
|
|
84
84
|
return { error: 'invalid token' };
|
|
85
85
|
}
|
|
86
86
|
if (payload.exp < timestamp - clockTolerance) {
|
|
87
|
-
return { error: 'expired token' };
|
|
87
|
+
return { error: 'expired token', exp: payload.exp };
|
|
88
88
|
}
|
|
89
|
-
return { user: payload.sub };
|
|
89
|
+
return { user: payload.sub, exp: payload.exp };
|
|
90
90
|
};
|
|
91
91
|
exports.decryptAndVerify = decryptAndVerify;
|
|
@@ -80,7 +80,7 @@ const fileSystemUnversionedDocumentStore = (initializer) => () => (configProvide
|
|
|
80
80
|
await mkTableDir;
|
|
81
81
|
const data = await load(filename);
|
|
82
82
|
if (!data) {
|
|
83
|
-
throw new
|
|
83
|
+
throw new errors_1.NotFoundError(`Item with ${hashKey.toString()} "${id}" does not exist`);
|
|
84
84
|
}
|
|
85
85
|
const newValue = typeof data[attribute] === 'number' ? data[attribute] + 1 : 1;
|
|
86
86
|
const newItem = { ...data, [hashKey]: id, [attribute]: newValue };
|
|
@@ -21,7 +21,7 @@ export declare const createLaunchSigner: <C extends string = "launch">({ configS
|
|
|
21
21
|
jwks: () => Promise<{
|
|
22
22
|
keys: JWK.RawKey[];
|
|
23
23
|
}>;
|
|
24
|
-
sign: (subject: string) => Promise<string>;
|
|
24
|
+
sign: (subject: string, maxExpiresIn?: string | number | null | undefined) => Promise<string>;
|
|
25
25
|
};
|
|
26
26
|
export declare type LaunchSigner = ReturnType<ReturnType<typeof createLaunchSigner>>;
|
|
27
27
|
export {};
|
|
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.createLaunchSigner = void 0;
|
|
7
7
|
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
|
|
8
|
+
const ms_1 = __importDefault(require("ms"));
|
|
8
9
|
const node_jose_1 = require("node-jose");
|
|
9
10
|
const __1 = require("../..");
|
|
10
11
|
const config_1 = require("../../config");
|
|
@@ -33,9 +34,17 @@ const createLaunchSigner = ({ configSpace }) => (configProvider) => {
|
|
|
33
34
|
return keystore;
|
|
34
35
|
});
|
|
35
36
|
const jwks = async () => (await getKeyStore()).toJSON(false);
|
|
36
|
-
const
|
|
37
|
-
const alg = await getAlg();
|
|
37
|
+
const getExpiresInWithMax = async (maxExpiresIn) => {
|
|
38
38
|
const expiresIn = await getExpiresIn();
|
|
39
|
+
const maxExpiresInSeconds = typeof maxExpiresIn === 'number' ? maxExpiresIn :
|
|
40
|
+
typeof maxExpiresIn === 'string' ? Math.floor((0, ms_1.default)(maxExpiresIn) / 1000) :
|
|
41
|
+
undefined;
|
|
42
|
+
return maxExpiresInSeconds ? Math.min(Math.floor((0, ms_1.default)(expiresIn) / 1000), maxExpiresInSeconds) : expiresIn;
|
|
43
|
+
};
|
|
44
|
+
const sign = async (subject, maxExpiresIn) => {
|
|
45
|
+
const alg = await getAlg();
|
|
46
|
+
// expiresIn can be a number of seconds or a string like '1h' or '1d'
|
|
47
|
+
const expiresIn = await getExpiresInWithMax(maxExpiresIn);
|
|
39
48
|
const iss = await getIss();
|
|
40
49
|
const header = { alg, iss };
|
|
41
50
|
return jsonwebtoken_1.default.sign({}, await getPrivateKey(), { algorithm: alg, expiresIn, header, issuer: iss, subject });
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import jwt from 'jsonwebtoken';
|
|
1
2
|
import type { JWK } from 'node-jose';
|
|
2
3
|
import { ConfigProviderForConfig } from '../../config';
|
|
3
4
|
declare type Config = {
|
|
@@ -15,7 +16,7 @@ interface Initializer<C> {
|
|
|
15
16
|
export declare const createLaunchVerifier: <C extends string = "launch">({ configSpace, fetcher }: Initializer<C>) => (configProvider: { [key in C]: {
|
|
16
17
|
trustedDomain: import("../../config").ConfigValueProvider<string>;
|
|
17
18
|
}; }) => {
|
|
18
|
-
verify: (token: string) => Promise<
|
|
19
|
+
verify: <T = undefined>(...[token, validator]: T extends undefined ? [string] : [string, (input: any) => T]) => Promise<T extends undefined ? jwt.JwtPayload : T>;
|
|
19
20
|
};
|
|
20
21
|
export declare type LaunchVerifier = ReturnType<ReturnType<typeof createLaunchVerifier>>;
|
|
21
22
|
export {};
|
|
@@ -60,7 +60,7 @@ const createLaunchVerifier = ({ configSpace, fetcher }) => (configProvider) => {
|
|
|
60
60
|
callback(error);
|
|
61
61
|
}
|
|
62
62
|
};
|
|
63
|
-
const verify = (token) => new Promise((resolve, reject) => jsonwebtoken_1.default.verify(token, getKey, {}, (err, payload) => {
|
|
63
|
+
const verify = (...[token, validator]) => new Promise((resolve, reject) => jsonwebtoken_1.default.verify(token, getKey, {}, (err, payload) => {
|
|
64
64
|
if (err && err instanceof jsonwebtoken_1.TokenExpiredError) {
|
|
65
65
|
reject(new errors_1.SessionExpiredError());
|
|
66
66
|
}
|
|
@@ -74,7 +74,19 @@ const createLaunchVerifier = ({ configSpace, fetcher }) => (configProvider) => {
|
|
|
74
74
|
reject(new Error('JWT payload missing sub claim'));
|
|
75
75
|
}
|
|
76
76
|
else {
|
|
77
|
-
|
|
77
|
+
// we are migrating away from json encoding all the parameters into the `sub` claim
|
|
78
|
+
// and into using separate claims for each parameter. in transition, we check if the sub
|
|
79
|
+
// is json and return it if it is. this is still a breaking change when using this
|
|
80
|
+
// utility because applications no longer need to independently json parse the result
|
|
81
|
+
// starting now.
|
|
82
|
+
const parsed = payload;
|
|
83
|
+
try {
|
|
84
|
+
const jsonSubContents = JSON.parse(payload.sub);
|
|
85
|
+
Object.assign(parsed, jsonSubContents);
|
|
86
|
+
}
|
|
87
|
+
catch (e) { } // eslint-disable-line no-empty
|
|
88
|
+
// conditional return types are annoying
|
|
89
|
+
resolve((validator ? validator(parsed) : parsed));
|
|
78
90
|
}
|
|
79
91
|
}));
|
|
80
92
|
return { verify };
|