@openstax/ts-utils 1.1.32 → 1.1.34

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.
@@ -1,5 +1,5 @@
1
- import { ConfigProviderForConfig } from '../../config';
2
- import { CookieAuthProvider } from '.';
1
+ import type { ConfigProviderForConfig } from '../../config';
2
+ import { CookieAuthProvider, User } from '.';
3
3
  declare type Config = {
4
4
  cookieName: string;
5
5
  encryptionPrivateKey: string;
@@ -8,6 +8,9 @@ declare type Config = {
8
8
  interface Initializer<C> {
9
9
  configSpace?: C;
10
10
  }
11
+ export declare type Jwt = {
12
+ sub?: User;
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>;
@@ -1,29 +1,16 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.decryptionAuthProvider = void 0;
4
- const jose_1 = require("jose");
5
4
  const resolveConfigValue_1 = require("../../config/resolveConfigValue");
6
5
  const guards_1 = require("../../guards");
7
6
  const helpers_1 = require("../../misc/helpers");
7
+ const decryptAndVerify_1 = require("./utils/decryptAndVerify");
8
8
  const _1 = require(".");
9
9
  const decryptionAuthProvider = (initializer) => (configProvider) => {
10
10
  const config = configProvider[(0, guards_1.ifDefined)(initializer.configSpace, 'decryption')];
11
11
  const cookieName = (0, helpers_1.once)(() => (0, resolveConfigValue_1.resolveConfigValue)(config.cookieName));
12
12
  const encryptionPrivateKey = (0, helpers_1.once)(() => (0, resolveConfigValue_1.resolveConfigValue)(config.encryptionPrivateKey));
13
13
  const signaturePublicKey = (0, helpers_1.once)(() => (0, resolveConfigValue_1.resolveConfigValue)(config.signaturePublicKey));
14
- const decryptAndVerify = async (jwt) => {
15
- try {
16
- // Decrypt SSO cookie
17
- const { plaintext } = await (0, jose_1.compactDecrypt)(jwt, Buffer.from(await encryptionPrivateKey()), // Note: Buffer.from() is node-js only
18
- { contentEncryptionAlgorithms: ['A256GCM'], keyManagementAlgorithms: ['dir'] });
19
- // Verify SSO cookie signature
20
- const { payload } = await (0, jose_1.compactVerify)(plaintext, await (0, jose_1.importSPKI)(await signaturePublicKey(), 'RS256'), { algorithms: ['RS256'] });
21
- return payload;
22
- }
23
- catch {
24
- return undefined;
25
- }
26
- };
27
14
  return ({ request, profile }) => {
28
15
  let user;
29
16
  const getAuthorizedFetchConfig = profile.track('getAuthorizedFetchConfig', () => async () => {
@@ -38,18 +25,7 @@ const decryptionAuthProvider = (initializer) => (configProvider) => {
38
25
  if (!token) {
39
26
  return undefined;
40
27
  }
41
- const payload = await decryptAndVerify(token);
42
- if (!payload) {
43
- return undefined;
44
- }
45
- // Note: Uint8Array.toString() returns text in node-js only
46
- // The browser version is new TextDecoder().decode(payload)
47
- const jwt = JSON.parse(payload.toString());
48
- // Allow clock skew up to 5 minutes
49
- if (!jwt.sub || !jwt.sub.uuid || (jwt.exp && jwt.exp < Math.floor(Date.now() / 1000) - 300)) {
50
- return undefined;
51
- }
52
- return jwt.sub;
28
+ return (0, decryptAndVerify_1.decryptAndVerify)(token, await encryptionPrivateKey(), await signaturePublicKey());
53
29
  });
54
30
  return {
55
31
  getAuthorizedFetchConfig,
@@ -1,6 +1,6 @@
1
- import { FetchConfig } from '../../fetch';
2
- import { Track } from '../../profile';
3
- import { HttpHeaders } from '../../routing';
1
+ import type { FetchConfig } from '../../fetch';
2
+ import type { Track } from '../../profile';
3
+ import type { HttpHeaders } from '../../routing';
4
4
  export interface User {
5
5
  id: number;
6
6
  name: string;
@@ -5,8 +5,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.getAuthTokenOrCookie = exports.stubAuthProvider = void 0;
7
7
  const cookie_1 = __importDefault(require("cookie"));
8
- const __1 = require("../..");
9
- const routing_1 = require("../../routing");
8
+ const helpers_1 = require("../../misc/helpers");
9
+ const helpers_2 = require("../../routing/helpers");
10
10
  const stubAuthProvider = (user) => ({
11
11
  getUser: () => Promise.resolve(user),
12
12
  getAuthorizedFetchConfig: () => Promise.resolve(user ? { headers: { Authorization: user.uuid } } : {})
@@ -14,10 +14,10 @@ const stubAuthProvider = (user) => ({
14
14
  exports.stubAuthProvider = stubAuthProvider;
15
15
  const getAuthTokenOrCookie = (request, cookieName) => {
16
16
  var _a;
17
- const authHeader = (0, routing_1.getHeader)(request.headers, 'authorization');
17
+ const authHeader = (0, helpers_2.getHeader)(request.headers, 'authorization');
18
18
  const cookieValue = cookie_1.default.parse(((_a = request.cookies) === null || _a === void 0 ? void 0 : _a.join('; ')) || '')[cookieName];
19
19
  return authHeader && authHeader.length >= 8 && authHeader.startsWith('Bearer ')
20
- ? (0, __1.tuple)(authHeader.slice(7), { Authorization: authHeader })
21
- : (0, __1.tuple)(cookieValue, { cookie: cookie_1.default.serialize(cookieName, cookieValue) });
20
+ ? (0, helpers_1.tuple)(authHeader.slice(7), { Authorization: authHeader })
21
+ : (0, helpers_1.tuple)(cookieValue, { cookie: cookie_1.default.serialize(cookieName, cookieValue) });
22
22
  };
23
23
  exports.getAuthTokenOrCookie = getAuthTokenOrCookie;
@@ -0,0 +1,2 @@
1
+ import { User } from '..';
2
+ export declare const decryptAndVerify: (token: string, encryptionPrivateKey: string, signaturePublicKey: string) => User | undefined;
@@ -0,0 +1,66 @@
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 __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ exports.decryptAndVerify = void 0;
30
+ const crypto = __importStar(require("crypto"));
31
+ const util_1 = require("util");
32
+ const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
33
+ const guards_1 = require("../../../guards");
34
+ const decrypt = (input, key) => {
35
+ const splitInput = input.split('.');
36
+ const aad = new util_1.TextEncoder().encode(splitInput[0]);
37
+ const iv = Buffer.from(splitInput[2], 'base64');
38
+ const ciphertext = Buffer.from(splitInput[3], 'base64');
39
+ const tag = Buffer.from(splitInput[4], 'base64');
40
+ const decipher = crypto.createDecipheriv('aes-256-gcm', Buffer.from(key), iv, { authTagLength: 16 });
41
+ decipher.setAAD(aad, { plaintextLength: ciphertext.length });
42
+ decipher.setAuthTag(tag);
43
+ const result = Buffer.concat([
44
+ decipher.update(ciphertext),
45
+ decipher.final(),
46
+ ]);
47
+ return result.toString('utf-8');
48
+ };
49
+ const decryptAndVerify = (token, encryptionPrivateKey, signaturePublicKey) => {
50
+ try {
51
+ // Decrypt SSO cookie
52
+ const plaintext = decrypt(token, encryptionPrivateKey);
53
+ const payload = jsonwebtoken_1.default.verify(plaintext, signaturePublicKey, {
54
+ clockTolerance: 300 // 5 minutes
55
+ });
56
+ if (!(0, guards_1.isPlainObject)(payload) || !(0, guards_1.isPlainObject)(payload.sub) || !payload.sub.uuid) {
57
+ return undefined;
58
+ }
59
+ // TS is confused because the library types the `sub` as a string
60
+ return payload.sub;
61
+ }
62
+ catch {
63
+ return undefined;
64
+ }
65
+ };
66
+ exports.decryptAndVerify = decryptAndVerify;