@openstax/ts-utils 1.21.11 → 1.23.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/assertions/index.d.ts +85 -0
- package/dist/cjs/assertions/index.js +157 -0
- package/dist/cjs/aws/ssmService.d.ts +5 -0
- package/dist/cjs/aws/ssmService.js +9 -0
- package/dist/cjs/config/awsParameterConfig.d.ts +10 -0
- package/dist/cjs/config/awsParameterConfig.js +26 -0
- package/dist/cjs/config/envConfig.d.ts +24 -0
- package/dist/cjs/config/envConfig.js +57 -0
- package/dist/cjs/config/index.d.ts +48 -0
- package/dist/cjs/config/index.js +35 -0
- package/dist/cjs/config/lambdaParameterConfig.d.ts +12 -0
- package/dist/cjs/config/lambdaParameterConfig.js +45 -0
- package/dist/cjs/config/replaceConfig.d.ts +14 -0
- package/dist/cjs/config/replaceConfig.js +22 -0
- package/dist/cjs/config/resolveConfigValue.d.ts +5 -0
- package/dist/cjs/config/resolveConfigValue.js +12 -0
- package/dist/cjs/errors/index.d.ts +77 -0
- package/dist/cjs/errors/index.js +109 -0
- package/dist/cjs/fetch/fetchStatusRetry.d.ts +7 -0
- package/dist/cjs/fetch/fetchStatusRetry.js +16 -0
- package/dist/cjs/fetch/index.d.ts +64 -0
- package/dist/cjs/fetch/index.js +55 -0
- package/dist/cjs/guards/index.d.ts +30 -0
- package/dist/cjs/guards/index.js +35 -0
- package/dist/cjs/index.d.ts +4 -0
- package/dist/cjs/index.js +20 -0
- package/dist/cjs/middleware/apiErrorHandler.d.ts +24 -0
- package/dist/cjs/middleware/apiErrorHandler.js +41 -0
- package/dist/cjs/middleware/apiSlowResponseMiddleware.d.ts +23 -0
- package/dist/cjs/middleware/apiSlowResponseMiddleware.js +54 -0
- package/dist/cjs/middleware/index.d.ts +47 -0
- package/dist/cjs/middleware/index.js +48 -0
- package/dist/cjs/middleware/lambdaCorsResponseMiddleware.d.ts +20 -0
- package/dist/cjs/middleware/lambdaCorsResponseMiddleware.js +42 -0
- package/dist/cjs/middleware/throwNotFoundMiddleware.d.ts +4 -0
- package/dist/cjs/middleware/throwNotFoundMiddleware.js +14 -0
- package/dist/cjs/misc/hashValue.d.ts +10 -0
- package/dist/cjs/misc/hashValue.js +17 -0
- package/dist/cjs/misc/helpers.d.ts +124 -0
- package/dist/cjs/misc/helpers.js +214 -0
- package/dist/cjs/misc/merge.d.ts +21 -0
- package/dist/cjs/misc/merge.js +45 -0
- package/dist/cjs/misc/partitionSequence.d.ts +35 -0
- package/dist/cjs/misc/partitionSequence.js +55 -0
- package/dist/cjs/pagination/index.d.ts +91 -0
- package/dist/cjs/pagination/index.js +83 -0
- package/dist/cjs/routing/helpers.d.ts +57 -0
- package/dist/cjs/routing/helpers.js +90 -0
- package/dist/cjs/routing/index.d.ts +272 -0
- package/dist/cjs/routing/index.js +270 -0
- package/dist/cjs/routing/validators/zod.d.ts +4 -0
- package/dist/cjs/routing/validators/zod.js +12 -0
- package/dist/cjs/services/accountsGateway/index.d.ts +85 -0
- package/dist/cjs/services/accountsGateway/index.js +118 -0
- package/dist/cjs/services/apiGateway/index.d.ts +63 -0
- package/dist/cjs/services/apiGateway/index.js +108 -0
- package/dist/cjs/services/authProvider/browser.d.ts +74 -0
- package/dist/cjs/services/authProvider/browser.js +154 -0
- package/dist/cjs/services/authProvider/decryption.d.ts +19 -0
- package/dist/cjs/services/authProvider/decryption.js +61 -0
- package/dist/cjs/services/authProvider/index.d.ts +61 -0
- package/dist/cjs/services/authProvider/index.js +26 -0
- package/dist/cjs/services/authProvider/subrequest.d.ts +16 -0
- package/dist/cjs/services/authProvider/subrequest.js +50 -0
- package/dist/cjs/services/authProvider/utils/decryptAndVerify.d.ts +29 -0
- package/dist/cjs/services/authProvider/utils/decryptAndVerify.js +91 -0
- package/dist/cjs/services/authProvider/utils/embeddedAuthProvider.d.ts +26 -0
- package/dist/cjs/services/authProvider/utils/embeddedAuthProvider.js +47 -0
- package/dist/cjs/services/authProvider/utils/userRoleValidator.d.ts +13 -0
- package/dist/cjs/services/authProvider/utils/userRoleValidator.js +37 -0
- package/dist/cjs/services/documentStore/dynamoEncoding.d.ts +10 -0
- package/dist/cjs/services/documentStore/dynamoEncoding.js +52 -0
- package/dist/cjs/services/documentStore/index.d.ts +14 -0
- package/dist/cjs/services/documentStore/index.js +2 -0
- package/dist/cjs/services/documentStore/unversioned/dynamodb.d.ts +16 -0
- package/dist/cjs/services/documentStore/unversioned/dynamodb.js +122 -0
- package/dist/cjs/services/documentStore/unversioned/file-system.d.ts +18 -0
- package/dist/cjs/services/documentStore/unversioned/file-system.js +121 -0
- package/dist/cjs/services/documentStore/unversioned/index.d.ts +2 -0
- package/dist/cjs/services/documentStore/unversioned/index.js +2 -0
- package/dist/cjs/services/documentStore/versioned/dynamodb.d.ts +22 -0
- package/dist/cjs/services/documentStore/versioned/dynamodb.js +135 -0
- package/dist/cjs/services/documentStore/versioned/file-system.d.ts +24 -0
- package/dist/cjs/services/documentStore/versioned/file-system.js +62 -0
- package/dist/cjs/services/documentStore/versioned/index.d.ts +17 -0
- package/dist/cjs/services/documentStore/versioned/index.js +2 -0
- package/dist/cjs/services/exercisesGateway/index.d.ts +71 -0
- package/dist/cjs/services/exercisesGateway/index.js +97 -0
- package/dist/cjs/services/fileServer/index.d.ts +17 -0
- package/dist/cjs/services/fileServer/index.js +19 -0
- package/dist/cjs/services/fileServer/localFileServer.d.ts +13 -0
- package/dist/cjs/services/fileServer/localFileServer.js +23 -0
- package/dist/cjs/services/fileServer/s3FileServer.d.ts +16 -0
- package/dist/cjs/services/fileServer/s3FileServer.js +25 -0
- 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 +58 -0
- package/dist/cjs/services/launchParams/verifier.d.ts +22 -0
- package/dist/cjs/services/launchParams/verifier.js +94 -0
- package/dist/cjs/services/logger/console.d.ts +4 -0
- package/dist/cjs/services/logger/console.js +12 -0
- package/dist/cjs/services/logger/index.d.ts +39 -0
- package/dist/cjs/services/logger/index.js +31 -0
- package/dist/cjs/services/lrsGateway/addStatementDefaultFields.d.ts +5 -0
- package/dist/cjs/services/lrsGateway/addStatementDefaultFields.js +21 -0
- package/dist/cjs/services/lrsGateway/attempt-utils.d.ts +70 -0
- package/dist/cjs/services/lrsGateway/attempt-utils.js +258 -0
- package/dist/cjs/services/lrsGateway/file-system.d.ts +17 -0
- package/dist/cjs/services/lrsGateway/file-system.js +140 -0
- package/dist/cjs/services/lrsGateway/index.d.ts +125 -0
- package/dist/cjs/services/lrsGateway/index.js +138 -0
- package/dist/cjs/services/lrsGateway/xapiUtils.d.ts +61 -0
- package/dist/cjs/services/lrsGateway/xapiUtils.js +94 -0
- package/dist/cjs/services/postgresConnection/index.d.ts +35 -0
- package/dist/cjs/services/postgresConnection/index.js +63 -0
- package/dist/cjs/services/searchProvider/index.d.ts +31 -0
- package/dist/cjs/services/searchProvider/index.js +2 -0
- package/dist/cjs/services/searchProvider/memorySearchTheBadWay.d.ts +14 -0
- package/dist/cjs/services/searchProvider/memorySearchTheBadWay.js +89 -0
- package/dist/cjs/tsconfig.without-specs.cjs.tsbuildinfo +1 -0
- package/dist/cjs/types.d.ts +31 -0
- package/dist/cjs/types.js +2 -0
- package/dist/esm/assertions/index.d.ts +85 -0
- package/dist/esm/assertions/index.js +146 -0
- package/dist/esm/aws/ssmService.d.ts +5 -0
- package/dist/esm/aws/ssmService.js +6 -0
- package/dist/esm/config/awsParameterConfig.d.ts +10 -0
- package/dist/esm/config/awsParameterConfig.js +22 -0
- package/dist/esm/config/envConfig.d.ts +24 -0
- package/dist/esm/config/envConfig.js +53 -0
- package/dist/esm/config/index.d.ts +48 -0
- package/dist/esm/config/index.js +17 -0
- package/dist/esm/config/lambdaParameterConfig.d.ts +12 -0
- package/dist/esm/config/lambdaParameterConfig.js +38 -0
- package/dist/esm/config/replaceConfig.d.ts +14 -0
- package/dist/esm/config/replaceConfig.js +18 -0
- package/dist/esm/config/resolveConfigValue.d.ts +5 -0
- package/dist/esm/config/resolveConfigValue.js +8 -0
- package/dist/esm/errors/index.d.ts +77 -0
- package/dist/esm/errors/index.js +99 -0
- package/dist/esm/fetch/fetchStatusRetry.d.ts +7 -0
- package/dist/esm/fetch/fetchStatusRetry.js +12 -0
- package/dist/esm/fetch/index.d.ts +64 -0
- package/dist/esm/fetch/index.js +46 -0
- package/dist/esm/guards/index.d.ts +30 -0
- package/dist/esm/guards/index.js +28 -0
- package/dist/esm/index.d.ts +4 -0
- package/dist/esm/index.js +4 -0
- package/dist/esm/middleware/apiErrorHandler.d.ts +24 -0
- package/dist/esm/middleware/apiErrorHandler.js +37 -0
- package/dist/esm/middleware/apiSlowResponseMiddleware.d.ts +23 -0
- package/dist/esm/middleware/apiSlowResponseMiddleware.js +50 -0
- package/dist/esm/middleware/index.d.ts +47 -0
- package/dist/esm/middleware/index.js +44 -0
- package/dist/esm/middleware/lambdaCorsResponseMiddleware.d.ts +20 -0
- package/dist/esm/middleware/lambdaCorsResponseMiddleware.js +38 -0
- package/dist/esm/middleware/throwNotFoundMiddleware.d.ts +4 -0
- package/dist/esm/middleware/throwNotFoundMiddleware.js +10 -0
- package/dist/esm/misc/hashValue.d.ts +10 -0
- package/dist/esm/misc/hashValue.js +13 -0
- package/dist/esm/misc/helpers.d.ts +124 -0
- package/dist/esm/misc/helpers.js +199 -0
- package/dist/esm/misc/merge.d.ts +21 -0
- package/dist/esm/misc/merge.js +40 -0
- package/dist/esm/misc/partitionSequence.d.ts +35 -0
- package/dist/esm/misc/partitionSequence.js +48 -0
- package/dist/esm/pagination/index.d.ts +91 -0
- package/dist/esm/pagination/index.js +77 -0
- package/dist/esm/routing/helpers.d.ts +57 -0
- package/dist/esm/routing/helpers.js +83 -0
- package/dist/esm/routing/index.d.ts +272 -0
- package/dist/esm/routing/index.js +232 -0
- package/dist/esm/routing/validators/zod.d.ts +4 -0
- package/dist/esm/routing/validators/zod.js +8 -0
- package/dist/esm/services/accountsGateway/index.d.ts +85 -0
- package/dist/esm/services/accountsGateway/index.js +111 -0
- package/dist/esm/services/apiGateway/index.d.ts +63 -0
- package/dist/esm/services/apiGateway/index.js +77 -0
- package/dist/esm/services/authProvider/browser.d.ts +74 -0
- package/dist/esm/services/authProvider/browser.js +150 -0
- package/dist/esm/services/authProvider/decryption.d.ts +19 -0
- package/dist/esm/services/authProvider/decryption.js +57 -0
- package/dist/esm/services/authProvider/index.d.ts +61 -0
- package/dist/esm/services/authProvider/index.js +18 -0
- package/dist/esm/services/authProvider/subrequest.d.ts +16 -0
- package/dist/esm/services/authProvider/subrequest.js +43 -0
- package/dist/esm/services/authProvider/utils/decryptAndVerify.d.ts +29 -0
- package/dist/esm/services/authProvider/utils/decryptAndVerify.js +85 -0
- package/dist/esm/services/authProvider/utils/embeddedAuthProvider.d.ts +26 -0
- package/dist/esm/services/authProvider/utils/embeddedAuthProvider.js +40 -0
- package/dist/esm/services/authProvider/utils/userRoleValidator.d.ts +13 -0
- package/dist/esm/services/authProvider/utils/userRoleValidator.js +33 -0
- package/dist/esm/services/documentStore/dynamoEncoding.d.ts +10 -0
- package/dist/esm/services/documentStore/dynamoEncoding.js +45 -0
- package/dist/esm/services/documentStore/index.d.ts +14 -0
- package/dist/esm/services/documentStore/index.js +1 -0
- package/dist/esm/services/documentStore/unversioned/dynamodb.d.ts +16 -0
- package/dist/esm/services/documentStore/unversioned/dynamodb.js +118 -0
- package/dist/esm/services/documentStore/unversioned/file-system.d.ts +18 -0
- package/dist/esm/services/documentStore/unversioned/file-system.js +91 -0
- package/dist/esm/services/documentStore/unversioned/index.d.ts +2 -0
- package/dist/esm/services/documentStore/unversioned/index.js +1 -0
- package/dist/esm/services/documentStore/versioned/dynamodb.d.ts +22 -0
- package/dist/esm/services/documentStore/versioned/dynamodb.js +131 -0
- package/dist/esm/services/documentStore/versioned/file-system.d.ts +24 -0
- package/dist/esm/services/documentStore/versioned/file-system.js +58 -0
- package/dist/esm/services/documentStore/versioned/index.d.ts +17 -0
- package/dist/esm/services/documentStore/versioned/index.js +1 -0
- package/dist/esm/services/exercisesGateway/index.d.ts +71 -0
- package/dist/esm/services/exercisesGateway/index.js +70 -0
- package/dist/esm/services/fileServer/index.d.ts +17 -0
- package/dist/esm/services/fileServer/index.js +13 -0
- package/dist/esm/services/fileServer/localFileServer.d.ts +13 -0
- package/dist/esm/services/fileServer/localFileServer.js +16 -0
- package/dist/esm/services/fileServer/s3FileServer.d.ts +16 -0
- package/dist/esm/services/fileServer/s3FileServer.js +21 -0
- 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 +51 -0
- package/dist/esm/services/launchParams/verifier.d.ts +22 -0
- package/dist/esm/services/launchParams/verifier.js +67 -0
- package/dist/esm/services/logger/console.d.ts +4 -0
- package/dist/esm/services/logger/console.js +8 -0
- package/dist/esm/services/logger/index.d.ts +39 -0
- package/dist/esm/services/logger/index.js +27 -0
- package/dist/esm/services/lrsGateway/addStatementDefaultFields.d.ts +5 -0
- package/dist/esm/services/lrsGateway/addStatementDefaultFields.js +14 -0
- package/dist/esm/services/lrsGateway/attempt-utils.d.ts +70 -0
- package/dist/esm/services/lrsGateway/attempt-utils.js +236 -0
- package/dist/esm/services/lrsGateway/file-system.d.ts +17 -0
- package/dist/esm/services/lrsGateway/file-system.js +110 -0
- package/dist/esm/services/lrsGateway/index.d.ts +125 -0
- package/dist/esm/services/lrsGateway/index.js +111 -0
- package/dist/esm/services/lrsGateway/xapiUtils.d.ts +61 -0
- package/dist/esm/services/lrsGateway/xapiUtils.js +84 -0
- package/dist/esm/services/postgresConnection/index.d.ts +35 -0
- package/dist/esm/services/postgresConnection/index.js +56 -0
- package/dist/esm/services/searchProvider/index.d.ts +31 -0
- package/dist/esm/services/searchProvider/index.js +1 -0
- package/dist/esm/services/searchProvider/memorySearchTheBadWay.d.ts +14 -0
- package/dist/esm/services/searchProvider/memorySearchTheBadWay.js +85 -0
- package/dist/esm/tsconfig.without-specs.esm.tsbuildinfo +1 -0
- package/dist/esm/types.d.ts +31 -0
- package/dist/esm/types.js +1 -0
- package/package.json +16 -16
- package/script/bin/deploy.bash +8 -0
- package/script/bin/get-env-param.bash +3 -3
- package/script/bin/init-params-script.bash +10 -1
- package/script/bin/upload-params.bash +3 -3
- package/dist/tsconfig.tsbuildinfo +0 -1
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { ConfigProviderForConfig } from '../../config';
|
|
2
|
+
import { FetchConfig, GenericFetch } from '../../fetch';
|
|
3
|
+
import { User } from '.';
|
|
4
|
+
declare type Config = {
|
|
5
|
+
accountsBase: string;
|
|
6
|
+
};
|
|
7
|
+
interface Initializer<C> {
|
|
8
|
+
configSpace?: C;
|
|
9
|
+
window: Window;
|
|
10
|
+
}
|
|
11
|
+
export declare type EventHandler = (e: {
|
|
12
|
+
data: any;
|
|
13
|
+
origin: string;
|
|
14
|
+
source: Pick<Window, 'postMessage'>;
|
|
15
|
+
}) => void;
|
|
16
|
+
export interface Window {
|
|
17
|
+
fetch: GenericFetch;
|
|
18
|
+
parent: Pick<Window, 'postMessage'>;
|
|
19
|
+
location: {
|
|
20
|
+
search: string;
|
|
21
|
+
};
|
|
22
|
+
document: {
|
|
23
|
+
referrer: string;
|
|
24
|
+
};
|
|
25
|
+
postMessage: (data: any, origin: string) => void;
|
|
26
|
+
addEventListener: (event: 'message', callback: EventHandler) => void;
|
|
27
|
+
removeEventListener: (event: 'message', callback: EventHandler) => void;
|
|
28
|
+
}
|
|
29
|
+
export declare type UpdatableUserFields = Partial<Pick<User, 'consent_preferences' | 'first_name' | 'last_name'>>;
|
|
30
|
+
export declare const browserAuthProvider: <C extends string = "auth">({ window, configSpace }: Initializer<C>) => (configProvider: { [key in C]: {
|
|
31
|
+
accountsBase: import("../../config").ConfigValueProvider<string>;
|
|
32
|
+
}; }) => {
|
|
33
|
+
/**
|
|
34
|
+
* gets the authentication token
|
|
35
|
+
*/
|
|
36
|
+
getAuthToken: () => Promise<string | null>;
|
|
37
|
+
/**
|
|
38
|
+
* adds auth parameters to the url. this is only safe to use when using javascript to navigate
|
|
39
|
+
* within the current window, eg `window.location = 'https://my.otherservice.com';` anchors
|
|
40
|
+
* should use getAuthorizedLinkUrl for their href.
|
|
41
|
+
*
|
|
42
|
+
* result unreliable unless `getUser` is resolved first.
|
|
43
|
+
*/
|
|
44
|
+
getAuthorizedUrl: (urlString: string) => string;
|
|
45
|
+
/**
|
|
46
|
+
* all link href-s must be rendered with auth tokens so that they work when opened in a new tab
|
|
47
|
+
*
|
|
48
|
+
* result unreliable unless `getUser` is resolved first.
|
|
49
|
+
*/
|
|
50
|
+
getAuthorizedLinkUrl: (urlString: string) => string;
|
|
51
|
+
/**
|
|
52
|
+
* gets an authorized url for an iframe src. sets params on the url and saves its
|
|
53
|
+
* origin to trust releasing user identity to it
|
|
54
|
+
*/
|
|
55
|
+
getAuthorizedEmbedUrl: (urlString: string, extraParams?: {
|
|
56
|
+
[key: string]: string;
|
|
57
|
+
} | undefined) => string;
|
|
58
|
+
/**
|
|
59
|
+
* gets second argument for `fetch` that has authentication token or cookie
|
|
60
|
+
*/
|
|
61
|
+
getAuthorizedFetchConfig: () => Promise<FetchConfig>;
|
|
62
|
+
/**
|
|
63
|
+
* loads current user identity. does not reflect changes in identity after being called the first time.
|
|
64
|
+
*/
|
|
65
|
+
getUser: () => Promise<User | undefined>;
|
|
66
|
+
/**
|
|
67
|
+
* updates user settings, for example the cookie consent preferences
|
|
68
|
+
*/
|
|
69
|
+
updateUser: (updates: UpdatableUserFields) => Promise<{
|
|
70
|
+
user: User;
|
|
71
|
+
token: string | null;
|
|
72
|
+
}>;
|
|
73
|
+
};
|
|
74
|
+
export {};
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.browserAuthProvider = void 0;
|
|
4
|
+
const __1 = require("../..");
|
|
5
|
+
const config_1 = require("../../config");
|
|
6
|
+
const guards_1 = require("../../guards");
|
|
7
|
+
const routing_1 = require("../../routing");
|
|
8
|
+
const embeddedAuthProvider_1 = require("./utils/embeddedAuthProvider");
|
|
9
|
+
const isUserData = (0, routing_1.unsafePayloadValidator)();
|
|
10
|
+
const browserAuthProvider = ({ window, configSpace }) => (configProvider) => {
|
|
11
|
+
const config = configProvider[(0, guards_1.ifDefined)(configSpace, 'auth')];
|
|
12
|
+
const accountsBase = (0, __1.once)(() => (0, config_1.resolveConfigValue)(config.accountsBase));
|
|
13
|
+
const queryString = window.location.search;
|
|
14
|
+
const queryKey = 'auth';
|
|
15
|
+
const urlSearchParams = new URLSearchParams(queryString);
|
|
16
|
+
const authQuery = urlSearchParams.get(queryKey);
|
|
17
|
+
const referrer = window.document.referrer ? new URL(window.document.referrer) : undefined;
|
|
18
|
+
const isEmbedded = window.parent !== window;
|
|
19
|
+
const trustedParent = isEmbedded && referrer && referrer.hostname.match(/^(openstax\.org|((.*)(\.openstax\.org|local|localhost)))$/) ? referrer : undefined;
|
|
20
|
+
const { embeddedQueryKey, embeddedQueryValue, getAuthorizedEmbedUrl } = (0, embeddedAuthProvider_1.embeddedAuthProvider)(() => getUserData(), { authQuery: { key: queryKey, value: authQuery }, window });
|
|
21
|
+
const embeddedQuery = urlSearchParams.get(embeddedQueryKey);
|
|
22
|
+
let userData = { token: authQuery };
|
|
23
|
+
const getAuthToken = async () => {
|
|
24
|
+
return (await getUserData()).token;
|
|
25
|
+
};
|
|
26
|
+
const getAuthorizedLinkUrl = (urlString) => {
|
|
27
|
+
const url = new URL(urlString);
|
|
28
|
+
if (userData.token) {
|
|
29
|
+
url.searchParams.set(queryKey, userData.token);
|
|
30
|
+
}
|
|
31
|
+
return url.href;
|
|
32
|
+
};
|
|
33
|
+
const getAuthorizedUrl = (urlString) => {
|
|
34
|
+
const url = new URL(urlString);
|
|
35
|
+
if (authQuery) {
|
|
36
|
+
url.searchParams.set(queryKey, authQuery);
|
|
37
|
+
}
|
|
38
|
+
else if (embeddedQuery) {
|
|
39
|
+
url.searchParams.set(queryKey, 'embedded');
|
|
40
|
+
}
|
|
41
|
+
if (embeddedQuery) {
|
|
42
|
+
url.searchParams.set(embeddedQueryKey, embeddedQuery);
|
|
43
|
+
}
|
|
44
|
+
return url.href;
|
|
45
|
+
};
|
|
46
|
+
// *note* that this does not actually prevent cookies from being sent on same-origin
|
|
47
|
+
// requests, i'm not sure if its possible to stop browsers from sending cookies in
|
|
48
|
+
// that case
|
|
49
|
+
const getAuthorizedFetchConfigFromData = (data) => {
|
|
50
|
+
const { token } = data;
|
|
51
|
+
return token ? {
|
|
52
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
53
|
+
} : {
|
|
54
|
+
credentials: 'include',
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
const getAuthorizedFetchConfig = async () => {
|
|
58
|
+
return getAuthorizedFetchConfigFromData(userData.token ? userData : await getUserData());
|
|
59
|
+
};
|
|
60
|
+
/*
|
|
61
|
+
* requests user identity from parent window via postMessage
|
|
62
|
+
*/
|
|
63
|
+
const getParentWindowUser = () => new Promise((resolve, reject) => {
|
|
64
|
+
if (!window.parent || !trustedParent) {
|
|
65
|
+
return reject(new Error('parent window is undefined or not trusted'));
|
|
66
|
+
}
|
|
67
|
+
const handler = (event) => {
|
|
68
|
+
if (event.data.type === embeddedAuthProvider_1.PostMessageTypes.ReceiveUser && event.origin === trustedParent.origin) {
|
|
69
|
+
clearTimeout(timeout);
|
|
70
|
+
window.removeEventListener('message', handler);
|
|
71
|
+
resolve(event.data.userData);
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
window.addEventListener('message', handler);
|
|
75
|
+
window.parent.postMessage({ type: embeddedAuthProvider_1.PostMessageTypes.RequestUser }, trustedParent.origin);
|
|
76
|
+
const timeout = setTimeout(() => {
|
|
77
|
+
window.removeEventListener('message', handler);
|
|
78
|
+
reject(new Error('loading user identity timed out'));
|
|
79
|
+
}, 5000);
|
|
80
|
+
});
|
|
81
|
+
/*
|
|
82
|
+
* requests user identity from accounts api using given token or cookie
|
|
83
|
+
*/
|
|
84
|
+
const getFetchUser = async () => {
|
|
85
|
+
const response = await window.fetch((await accountsBase()).replace(/\/+$/, '') + '/api/user?always_200=true', getAuthorizedFetchConfigFromData(userData));
|
|
86
|
+
if (response.status === 200) {
|
|
87
|
+
const body = await response.json();
|
|
88
|
+
const user = isUserData(body) ? body : undefined;
|
|
89
|
+
return { ...userData, user };
|
|
90
|
+
}
|
|
91
|
+
const message = await response.text();
|
|
92
|
+
throw new Error(`Error response from Accounts ${response.status}: ${message}`);
|
|
93
|
+
};
|
|
94
|
+
const getUserData = (0, __1.once)(async () => {
|
|
95
|
+
// For backwards compatibility
|
|
96
|
+
if (authQuery === 'embedded') {
|
|
97
|
+
return getParentWindowUser();
|
|
98
|
+
}
|
|
99
|
+
// getFetchUser() will throw here if authQuery is not set
|
|
100
|
+
return await (embeddedQuery === embeddedQueryValue ? getParentWindowUser() : getFetchUser());
|
|
101
|
+
});
|
|
102
|
+
const getUser = async () => {
|
|
103
|
+
return (await getUserData()).user;
|
|
104
|
+
};
|
|
105
|
+
const updateUser = async (updates) => {
|
|
106
|
+
const response = await window.fetch((await accountsBase()).replace(/\/+$/, '') + '/api/user', { ...getAuthorizedFetchConfigFromData(userData), method: routing_1.METHOD.PUT, body: JSON.stringify(updates) });
|
|
107
|
+
if (response.status === 200) {
|
|
108
|
+
const user = await response.json();
|
|
109
|
+
if (isUserData(user)) {
|
|
110
|
+
return { ...userData, user };
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
const message = await response.text();
|
|
114
|
+
throw new Error(`Error response from Accounts ${response.status}: ${message}`);
|
|
115
|
+
};
|
|
116
|
+
return {
|
|
117
|
+
/**
|
|
118
|
+
* gets the authentication token
|
|
119
|
+
*/
|
|
120
|
+
getAuthToken,
|
|
121
|
+
/**
|
|
122
|
+
* adds auth parameters to the url. this is only safe to use when using javascript to navigate
|
|
123
|
+
* within the current window, eg `window.location = 'https://my.otherservice.com';` anchors
|
|
124
|
+
* should use getAuthorizedLinkUrl for their href.
|
|
125
|
+
*
|
|
126
|
+
* result unreliable unless `getUser` is resolved first.
|
|
127
|
+
*/
|
|
128
|
+
getAuthorizedUrl,
|
|
129
|
+
/**
|
|
130
|
+
* all link href-s must be rendered with auth tokens so that they work when opened in a new tab
|
|
131
|
+
*
|
|
132
|
+
* result unreliable unless `getUser` is resolved first.
|
|
133
|
+
*/
|
|
134
|
+
getAuthorizedLinkUrl,
|
|
135
|
+
/**
|
|
136
|
+
* gets an authorized url for an iframe src. sets params on the url and saves its
|
|
137
|
+
* origin to trust releasing user identity to it
|
|
138
|
+
*/
|
|
139
|
+
getAuthorizedEmbedUrl,
|
|
140
|
+
/**
|
|
141
|
+
* gets second argument for `fetch` that has authentication token or cookie
|
|
142
|
+
*/
|
|
143
|
+
getAuthorizedFetchConfig,
|
|
144
|
+
/**
|
|
145
|
+
* loads current user identity. does not reflect changes in identity after being called the first time.
|
|
146
|
+
*/
|
|
147
|
+
getUser,
|
|
148
|
+
/**
|
|
149
|
+
* updates user settings, for example the cookie consent preferences
|
|
150
|
+
*/
|
|
151
|
+
updateUser,
|
|
152
|
+
};
|
|
153
|
+
};
|
|
154
|
+
exports.browserAuthProvider = browserAuthProvider;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ConfigProviderForConfig } from '../../config';
|
|
2
|
+
import { AuthProvider, CookieAuthProvider } from '.';
|
|
3
|
+
declare type Config = {
|
|
4
|
+
cookieName: string;
|
|
5
|
+
encryptionPrivateKey: string;
|
|
6
|
+
signaturePublicKey: string;
|
|
7
|
+
};
|
|
8
|
+
interface Initializer<C> {
|
|
9
|
+
configSpace?: C;
|
|
10
|
+
}
|
|
11
|
+
export declare type DecryptionAuthProvider = AuthProvider & {
|
|
12
|
+
getTokenExpiration: (tokenString?: string) => Promise<number | null | undefined>;
|
|
13
|
+
};
|
|
14
|
+
export declare const decryptionAuthProvider: <C extends string = "decryption">(initializer: Initializer<C>) => (configProvider: { [key in C]: {
|
|
15
|
+
cookieName: import("../../config").ConfigValueProvider<string>;
|
|
16
|
+
encryptionPrivateKey: import("../../config").ConfigValueProvider<string>;
|
|
17
|
+
signaturePublicKey: import("../../config").ConfigValueProvider<string>;
|
|
18
|
+
}; }) => CookieAuthProvider<DecryptionAuthProvider>;
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.decryptionAuthProvider = void 0;
|
|
4
|
+
const resolveConfigValue_1 = require("../../config/resolveConfigValue");
|
|
5
|
+
const errors_1 = require("../../errors");
|
|
6
|
+
const guards_1 = require("../../guards");
|
|
7
|
+
const helpers_1 = require("../../misc/helpers");
|
|
8
|
+
const decryptAndVerify_1 = require("./utils/decryptAndVerify");
|
|
9
|
+
const _1 = require(".");
|
|
10
|
+
const decryptionAuthProvider = (initializer) => (configProvider) => {
|
|
11
|
+
const config = configProvider[(0, guards_1.ifDefined)(initializer.configSpace, 'decryption')];
|
|
12
|
+
const cookieName = (0, helpers_1.once)(() => (0, resolveConfigValue_1.resolveConfigValue)(config.cookieName));
|
|
13
|
+
const encryptionPrivateKey = (0, helpers_1.once)(() => (0, resolveConfigValue_1.resolveConfigValue)(config.encryptionPrivateKey));
|
|
14
|
+
const signaturePublicKey = (0, helpers_1.once)(() => (0, resolveConfigValue_1.resolveConfigValue)(config.signaturePublicKey));
|
|
15
|
+
return ({ request, logger }) => {
|
|
16
|
+
let user;
|
|
17
|
+
const getAuthorizedFetchConfig = async () => {
|
|
18
|
+
const [token, headers] = (0, _1.getAuthTokenOrCookie)(request, await cookieName());
|
|
19
|
+
if (!token) {
|
|
20
|
+
return {};
|
|
21
|
+
}
|
|
22
|
+
return { headers };
|
|
23
|
+
};
|
|
24
|
+
const getPayload = async (tokenString) => {
|
|
25
|
+
const token = tokenString !== null && tokenString !== void 0 ? tokenString : (0, _1.getAuthTokenOrCookie)(request, await cookieName())[0];
|
|
26
|
+
if (!token) {
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
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
|
+
}
|
|
36
|
+
if ('error' in result && result.error == 'expired token') {
|
|
37
|
+
throw new errors_1.SessionExpiredError();
|
|
38
|
+
}
|
|
39
|
+
if ('user' in result) {
|
|
40
|
+
logger.setContext({ user: result.user.uuid });
|
|
41
|
+
return result.user;
|
|
42
|
+
}
|
|
43
|
+
return undefined;
|
|
44
|
+
};
|
|
45
|
+
return {
|
|
46
|
+
getAuthorizedFetchConfig,
|
|
47
|
+
getTokenExpiration: async (tokenString) => {
|
|
48
|
+
var _a;
|
|
49
|
+
const payload = await getPayload(tokenString);
|
|
50
|
+
return payload ? ((_a = payload.exp) !== null && _a !== void 0 ? _a : null) : undefined;
|
|
51
|
+
},
|
|
52
|
+
getUser: async () => {
|
|
53
|
+
if (!user) {
|
|
54
|
+
user = await loadUser();
|
|
55
|
+
}
|
|
56
|
+
return user;
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
exports.decryptionAuthProvider = decryptionAuthProvider;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { FetchConfig } from '../../fetch';
|
|
2
|
+
import type { HttpHeaders, QueryParams } from '../../routing';
|
|
3
|
+
import type { Logger } from '../logger';
|
|
4
|
+
export declare type ConsentPreferences = {
|
|
5
|
+
consent_preferences: {
|
|
6
|
+
accepted: string[];
|
|
7
|
+
rejected: string[];
|
|
8
|
+
};
|
|
9
|
+
};
|
|
10
|
+
export declare type TokenUser = {
|
|
11
|
+
id: number;
|
|
12
|
+
name: string;
|
|
13
|
+
first_name: string;
|
|
14
|
+
last_name: string;
|
|
15
|
+
full_name: string;
|
|
16
|
+
uuid: string;
|
|
17
|
+
faculty_status: string;
|
|
18
|
+
is_administrator: boolean;
|
|
19
|
+
} & Partial<ConsentPreferences>;
|
|
20
|
+
export interface ApiUser extends TokenUser {
|
|
21
|
+
contact_infos: Array<{
|
|
22
|
+
type: string;
|
|
23
|
+
value: string;
|
|
24
|
+
is_verified: boolean;
|
|
25
|
+
is_guessed_preferred: boolean;
|
|
26
|
+
}>;
|
|
27
|
+
applications: Array<{
|
|
28
|
+
id: number;
|
|
29
|
+
name: string;
|
|
30
|
+
roles: string[];
|
|
31
|
+
}>;
|
|
32
|
+
external_ids: string[];
|
|
33
|
+
is_not_gdpr_location: boolean;
|
|
34
|
+
self_reported_role: string;
|
|
35
|
+
signed_contract_names: string[];
|
|
36
|
+
using_openstax: boolean;
|
|
37
|
+
}
|
|
38
|
+
export declare type User = TokenUser | ApiUser;
|
|
39
|
+
export declare type AuthProvider = {
|
|
40
|
+
getUser: () => Promise<User | undefined>;
|
|
41
|
+
/**
|
|
42
|
+
* gets second argument for `fetch` that has authentication token or cookie
|
|
43
|
+
*/
|
|
44
|
+
getAuthorizedFetchConfig: () => Promise<FetchConfig>;
|
|
45
|
+
};
|
|
46
|
+
export declare type CookieAuthProviderRequest = {
|
|
47
|
+
cookies?: string[];
|
|
48
|
+
headers: HttpHeaders;
|
|
49
|
+
queryStringParameters?: QueryParams;
|
|
50
|
+
};
|
|
51
|
+
export declare type CookieAuthProvider<T extends AuthProvider = AuthProvider> = (inputs: {
|
|
52
|
+
request: CookieAuthProviderRequest;
|
|
53
|
+
logger: Logger;
|
|
54
|
+
}) => T;
|
|
55
|
+
export declare type StubAuthProvider = (user: User | undefined) => AuthProvider;
|
|
56
|
+
export declare const stubAuthProvider: (user?: User | undefined) => AuthProvider;
|
|
57
|
+
export declare const getAuthTokenOrCookie: (request: CookieAuthProviderRequest, cookieName: string, queryKey?: string) => [string, {
|
|
58
|
+
Authorization: string;
|
|
59
|
+
}] | [string, {
|
|
60
|
+
cookie: string;
|
|
61
|
+
}];
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getAuthTokenOrCookie = exports.stubAuthProvider = void 0;
|
|
7
|
+
const cookie_1 = __importDefault(require("cookie"));
|
|
8
|
+
const helpers_1 = require("../../misc/helpers");
|
|
9
|
+
const helpers_2 = require("../../routing/helpers");
|
|
10
|
+
const stubAuthProvider = (user) => ({
|
|
11
|
+
getUser: () => Promise.resolve(user),
|
|
12
|
+
getAuthorizedFetchConfig: () => Promise.resolve(user ? { headers: { Authorization: user.uuid } } : {})
|
|
13
|
+
});
|
|
14
|
+
exports.stubAuthProvider = stubAuthProvider;
|
|
15
|
+
const getAuthTokenOrCookie = (request, cookieName, queryKey = 'auth') => {
|
|
16
|
+
var _a, _b;
|
|
17
|
+
const authParam = request.queryStringParameters ? request.queryStringParameters[queryKey] : undefined;
|
|
18
|
+
const authHeader = (0, helpers_2.getHeader)(request.headers, 'authorization');
|
|
19
|
+
const cookieValue = cookie_1.default.parse((_b = (_a = request.cookies) === null || _a === void 0 ? void 0 : _a.join('; ')) !== null && _b !== void 0 ? _b : '')[cookieName];
|
|
20
|
+
return typeof authParam === 'string'
|
|
21
|
+
? (0, helpers_1.tuple)(authParam, { Authorization: `Bearer ${authParam}` })
|
|
22
|
+
: authHeader && authHeader.length >= 8 && authHeader.startsWith('Bearer ')
|
|
23
|
+
? (0, helpers_1.tuple)(authHeader.slice(7), { Authorization: authHeader })
|
|
24
|
+
: (0, helpers_1.tuple)(cookieValue, { cookie: cookie_1.default.serialize(cookieName, cookieValue) });
|
|
25
|
+
};
|
|
26
|
+
exports.getAuthTokenOrCookie = getAuthTokenOrCookie;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { ConfigProviderForConfig } from '../../config';
|
|
2
|
+
import { GenericFetch } from '../../fetch';
|
|
3
|
+
import { CookieAuthProvider } from '.';
|
|
4
|
+
declare type Config = {
|
|
5
|
+
cookieName: string;
|
|
6
|
+
accountsBase: string;
|
|
7
|
+
};
|
|
8
|
+
interface Initializer<C> {
|
|
9
|
+
configSpace?: C;
|
|
10
|
+
fetch: GenericFetch;
|
|
11
|
+
}
|
|
12
|
+
export declare const subrequestAuthProvider: <C extends string = "subrequest">(initializer: Initializer<C>) => (configProvider: { [key in C]: {
|
|
13
|
+
cookieName: import("../../config").ConfigValueProvider<string>;
|
|
14
|
+
accountsBase: import("../../config").ConfigValueProvider<string>;
|
|
15
|
+
}; }) => CookieAuthProvider;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.subrequestAuthProvider = void 0;
|
|
7
|
+
const cookie_1 = __importDefault(require("cookie"));
|
|
8
|
+
const __1 = require("../..");
|
|
9
|
+
const config_1 = require("../../config");
|
|
10
|
+
const guards_1 = require("../../guards");
|
|
11
|
+
const _1 = require(".");
|
|
12
|
+
const subrequestAuthProvider = (initializer) => (configProvider) => {
|
|
13
|
+
const config = configProvider[(0, guards_1.ifDefined)(initializer.configSpace, 'subrequest')];
|
|
14
|
+
const cookieName = (0, __1.once)(() => (0, config_1.resolveConfigValue)(config.cookieName));
|
|
15
|
+
const accountsBase = (0, __1.once)(() => (0, config_1.resolveConfigValue)(config.accountsBase));
|
|
16
|
+
return ({ request, logger }) => {
|
|
17
|
+
let user;
|
|
18
|
+
const getAuthorizedFetchConfig = async () => {
|
|
19
|
+
const [token, headers] = (0, _1.getAuthTokenOrCookie)(request, await cookieName());
|
|
20
|
+
if (!token) {
|
|
21
|
+
return {};
|
|
22
|
+
}
|
|
23
|
+
return { headers };
|
|
24
|
+
};
|
|
25
|
+
const loadUser = async () => {
|
|
26
|
+
const resolvedCookieName = await cookieName();
|
|
27
|
+
const [token] = (0, _1.getAuthTokenOrCookie)(request, resolvedCookieName);
|
|
28
|
+
if (!token) {
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
const headers = { cookie: cookie_1.default.serialize(resolvedCookieName, token) };
|
|
32
|
+
const user = await initializer.fetch((await accountsBase()).replace(/\/+$/, '') + '/api/user', { headers })
|
|
33
|
+
.then(response => response.json());
|
|
34
|
+
if (user) {
|
|
35
|
+
logger.setContext({ user: user.uuid });
|
|
36
|
+
}
|
|
37
|
+
return user;
|
|
38
|
+
};
|
|
39
|
+
return {
|
|
40
|
+
getAuthorizedFetchConfig,
|
|
41
|
+
getUser: async () => {
|
|
42
|
+
if (!user) {
|
|
43
|
+
user = await loadUser();
|
|
44
|
+
}
|
|
45
|
+
return user;
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
exports.subrequestAuthProvider = subrequestAuthProvider;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import type { User } from '..';
|
|
3
|
+
export declare const decryptJwe: (jwe: string, encryptionPrivateKey: Buffer | string) => string | undefined;
|
|
4
|
+
declare type MaybeAccountsSSOToken = {
|
|
5
|
+
iss?: string;
|
|
6
|
+
sub?: User | string;
|
|
7
|
+
aud?: string;
|
|
8
|
+
exp?: number;
|
|
9
|
+
nbf?: number;
|
|
10
|
+
iat?: number;
|
|
11
|
+
jti?: string;
|
|
12
|
+
};
|
|
13
|
+
export declare const verifyJws: (jws: string, signaturePublicKey: Buffer | string) => MaybeAccountsSSOToken | undefined;
|
|
14
|
+
/**
|
|
15
|
+
* Decrypts and verifies a SSO cookie.
|
|
16
|
+
*
|
|
17
|
+
* @param token the encrypted token
|
|
18
|
+
* @param encryptionPrivateKey the private key used to encrypt the token
|
|
19
|
+
* @param signaturePublicKey the public key used to verify the decrypted token
|
|
20
|
+
* @returns {user: User; exp: number} (success) or {error: string} (failure)
|
|
21
|
+
*/
|
|
22
|
+
export declare const decryptAndVerify: (token: string, encryptionPrivateKey: string, signaturePublicKey: string) => {
|
|
23
|
+
user: User;
|
|
24
|
+
exp: number;
|
|
25
|
+
} | {
|
|
26
|
+
error: string;
|
|
27
|
+
exp?: number;
|
|
28
|
+
};
|
|
29
|
+
export {};
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.decryptAndVerify = exports.verifyJws = exports.decryptJwe = void 0;
|
|
4
|
+
const crypto_1 = require("crypto");
|
|
5
|
+
const guards_1 = require("../../../guards");
|
|
6
|
+
const decryptJwe = (jwe, encryptionPrivateKey) => {
|
|
7
|
+
const jweParts = jwe.split('.', 6);
|
|
8
|
+
if (jweParts.length !== 5 || jweParts[1]) {
|
|
9
|
+
return undefined;
|
|
10
|
+
} // Invalid/unsupported JWE
|
|
11
|
+
const header = JSON.parse(Buffer.from(jweParts[0], 'base64url').toString());
|
|
12
|
+
if (header.alg !== 'dir' || header.enc !== 'A256GCM') {
|
|
13
|
+
// Unsupported signature/encryption algorithm
|
|
14
|
+
return undefined;
|
|
15
|
+
}
|
|
16
|
+
const aad = Buffer.from(jweParts[0]);
|
|
17
|
+
const iv = Buffer.from(jweParts[2], 'base64url');
|
|
18
|
+
const cipherText = Buffer.from(jweParts[3], 'base64url');
|
|
19
|
+
const authTag = Buffer.from(jweParts[4], 'base64url');
|
|
20
|
+
// Verify token signature and decrypt
|
|
21
|
+
const decipher = (0, crypto_1.createDecipheriv)('aes-256-gcm', encryptionPrivateKey, iv, { authTagLength: 16 });
|
|
22
|
+
decipher.setAAD(aad, { plaintextLength: cipherText.length });
|
|
23
|
+
try {
|
|
24
|
+
decipher.setAuthTag(authTag);
|
|
25
|
+
return `${decipher.update(cipherText)}${decipher.final()}`;
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
// Invalid cipherText or authTag
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
exports.decryptJwe = decryptJwe;
|
|
33
|
+
const issuer = 'OpenStax Accounts';
|
|
34
|
+
const audience = 'OpenStax';
|
|
35
|
+
const clockTolerance = 300; // 5 minutes
|
|
36
|
+
const verifyJws = (jws, signaturePublicKey) => {
|
|
37
|
+
const jwsParts = jws.split('.', 4);
|
|
38
|
+
if (jwsParts.length !== 3) {
|
|
39
|
+
return undefined;
|
|
40
|
+
} // Invalid JWS
|
|
41
|
+
const header = JSON.parse(Buffer.from(jwsParts[0], 'base64url').toString());
|
|
42
|
+
if (header.alg !== 'RS256' || header.typ !== 'JWT') {
|
|
43
|
+
return undefined;
|
|
44
|
+
} // Unsupported JWS
|
|
45
|
+
const signedContent = Buffer.from(`${jwsParts[0]}.${jwsParts[1]}`);
|
|
46
|
+
const signature = Buffer.from(jwsParts[2], 'base64url');
|
|
47
|
+
if (!(0, crypto_1.verify)('RSA-SHA256', signedContent, signaturePublicKey, signature)) {
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
const payload = Buffer.from(jwsParts[1], 'base64url').toString();
|
|
51
|
+
try {
|
|
52
|
+
return JSON.parse(payload);
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
exports.verifyJws = verifyJws;
|
|
59
|
+
/**
|
|
60
|
+
* Decrypts and verifies a SSO cookie.
|
|
61
|
+
*
|
|
62
|
+
* @param token the encrypted token
|
|
63
|
+
* @param encryptionPrivateKey the private key used to encrypt the token
|
|
64
|
+
* @param signaturePublicKey the public key used to verify the decrypted token
|
|
65
|
+
* @returns {user: User; exp: number} (success) or {error: string} (failure)
|
|
66
|
+
*/
|
|
67
|
+
const decryptAndVerify = (token, encryptionPrivateKey, signaturePublicKey) => {
|
|
68
|
+
const timestamp = Math.floor(Date.now() / 1000);
|
|
69
|
+
const jws = (0, exports.decryptJwe)(token, encryptionPrivateKey);
|
|
70
|
+
if (!jws) {
|
|
71
|
+
return { error: 'invalid token' };
|
|
72
|
+
}
|
|
73
|
+
const payload = (0, exports.verifyJws)(jws, signaturePublicKey);
|
|
74
|
+
// Ensure payload contains all the claims we expect
|
|
75
|
+
// Normally "sub" would be a string but Accounts uses an object for it instead
|
|
76
|
+
if (!(0, guards_1.isPlainObject)(payload) ||
|
|
77
|
+
!(0, guards_1.isPlainObject)(payload.sub) || !payload.sub.uuid ||
|
|
78
|
+
payload.iss !== issuer ||
|
|
79
|
+
payload.aud !== audience ||
|
|
80
|
+
!payload.exp ||
|
|
81
|
+
!payload.nbf || payload.nbf > timestamp + clockTolerance ||
|
|
82
|
+
!payload.iat || payload.iat > timestamp + clockTolerance ||
|
|
83
|
+
!payload.jti) {
|
|
84
|
+
return { error: 'invalid token' };
|
|
85
|
+
}
|
|
86
|
+
if (payload.exp < timestamp - clockTolerance) {
|
|
87
|
+
return { error: 'expired token', exp: payload.exp };
|
|
88
|
+
}
|
|
89
|
+
return { user: payload.sub, exp: payload.exp };
|
|
90
|
+
};
|
|
91
|
+
exports.decryptAndVerify = decryptAndVerify;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { User } from '..';
|
|
2
|
+
import { Window } from '../browser';
|
|
3
|
+
export declare type UserData = {
|
|
4
|
+
user?: User;
|
|
5
|
+
token: string | null;
|
|
6
|
+
};
|
|
7
|
+
declare type UserDataLoader = () => Promise<UserData>;
|
|
8
|
+
export declare enum PostMessageTypes {
|
|
9
|
+
ReceiveUser = "receive-user",
|
|
10
|
+
RequestUser = "request-user"
|
|
11
|
+
}
|
|
12
|
+
export declare const embeddedAuthProvider: (getUserData: UserDataLoader, { authQuery, window }: {
|
|
13
|
+
authQuery?: {
|
|
14
|
+
key: string;
|
|
15
|
+
value: string | null;
|
|
16
|
+
} | undefined;
|
|
17
|
+
window: Window;
|
|
18
|
+
}) => {
|
|
19
|
+
embeddedQueryKey: string;
|
|
20
|
+
embeddedQueryValue: string;
|
|
21
|
+
getAuthorizedEmbedUrl: (urlString: string, extraParams?: {
|
|
22
|
+
[key: string]: string;
|
|
23
|
+
} | undefined) => string;
|
|
24
|
+
unmount: () => void;
|
|
25
|
+
};
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.embeddedAuthProvider = exports.PostMessageTypes = void 0;
|
|
7
|
+
const query_string_1 = __importDefault(require("query-string"));
|
|
8
|
+
var PostMessageTypes;
|
|
9
|
+
(function (PostMessageTypes) {
|
|
10
|
+
PostMessageTypes["ReceiveUser"] = "receive-user";
|
|
11
|
+
PostMessageTypes["RequestUser"] = "request-user";
|
|
12
|
+
})(PostMessageTypes = exports.PostMessageTypes || (exports.PostMessageTypes = {}));
|
|
13
|
+
const embeddedAuthProvider = (getUserData, { authQuery, window }) => {
|
|
14
|
+
const trustedEmbeds = new Set();
|
|
15
|
+
const embeddedQueryKey = 'embedded';
|
|
16
|
+
const embeddedQueryValue = 'true';
|
|
17
|
+
const messageHandler = event => {
|
|
18
|
+
if (event.data.type === PostMessageTypes.RequestUser && trustedEmbeds.has(event.origin)) {
|
|
19
|
+
getUserData().then(data => {
|
|
20
|
+
event.source.postMessage({ type: PostMessageTypes.ReceiveUser, userData: data }, event.origin);
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
window.addEventListener('message', messageHandler);
|
|
25
|
+
const getAuthorizedEmbedUrl = (urlString, extraParams) => {
|
|
26
|
+
const url = new URL(urlString);
|
|
27
|
+
trustedEmbeds.add(url.origin);
|
|
28
|
+
const params = query_string_1.default.parse(url.search);
|
|
29
|
+
url.search = query_string_1.default.stringify({
|
|
30
|
+
...params,
|
|
31
|
+
...extraParams,
|
|
32
|
+
...(authQuery && authQuery.value ? { [authQuery.key]: authQuery.value } : { auth: 'embedded' }),
|
|
33
|
+
[embeddedQueryKey]: embeddedQueryValue,
|
|
34
|
+
subcontent: 'true',
|
|
35
|
+
});
|
|
36
|
+
return url.href;
|
|
37
|
+
};
|
|
38
|
+
return {
|
|
39
|
+
embeddedQueryKey,
|
|
40
|
+
embeddedQueryValue,
|
|
41
|
+
getAuthorizedEmbedUrl,
|
|
42
|
+
unmount: () => {
|
|
43
|
+
window.removeEventListener('message', messageHandler);
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
exports.embeddedAuthProvider = embeddedAuthProvider;
|