@openstax/ts-utils 1.9.1 → 1.12.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/config/envConfig.d.ts +2 -2
- package/dist/cjs/config/envConfig.js +13 -6
- package/dist/cjs/config/resolveConfigValue.d.ts +1 -1
- package/dist/cjs/errors/index.js +4 -4
- package/dist/cjs/services/authProvider/browser.js +30 -9
- package/dist/cjs/services/authProvider/decryption.js +6 -1
- package/dist/cjs/services/authProvider/utils/decryptAndVerify.d.ts +20 -4
- package/dist/cjs/services/authProvider/utils/decryptAndVerify.js +74 -62
- package/dist/cjs/services/authProvider/utils/embeddedAuthProvider.d.ts +6 -2
- package/dist/cjs/services/authProvider/utils/embeddedAuthProvider.js +10 -3
- package/dist/cjs/services/exercisesGateway/index.js +2 -1
- 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/tsconfig.without-specs.cjs.tsbuildinfo +1 -1
- package/dist/esm/config/envConfig.d.ts +2 -2
- package/dist/esm/config/envConfig.js +12 -5
- package/dist/esm/config/resolveConfigValue.d.ts +1 -1
- package/dist/esm/errors/index.js +2 -2
- package/dist/esm/services/authProvider/browser.js +30 -9
- package/dist/esm/services/authProvider/decryption.js +6 -1
- package/dist/esm/services/authProvider/utils/decryptAndVerify.d.ts +20 -4
- package/dist/esm/services/authProvider/utils/decryptAndVerify.js +72 -36
- package/dist/esm/services/authProvider/utils/embeddedAuthProvider.d.ts +6 -2
- package/dist/esm/services/authProvider/utils/embeddedAuthProvider.js +10 -3
- package/dist/esm/services/exercisesGateway/index.js +2 -1
- 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/tsconfig.without-specs.esm.tsbuildinfo +1 -1
- package/package.json +19 -3
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ConfigValueProvider } from '.';
|
|
1
|
+
import type { ConfigValueProvider } from '.';
|
|
2
2
|
/**
|
|
3
3
|
* A list of environment variables that were requested at build time. Used by webpack to
|
|
4
4
|
* capture build-time environment variables values.
|
|
@@ -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?:
|
|
24
|
+
export declare const envConfig: (name: string, type?: "build" | "runtime" | undefined, defaultValue?: ConfigValueProvider<string> | undefined) => ConfigValueProvider<string>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.envConfig = exports.ENV_BUILD_CONFIGS = void 0;
|
|
4
|
-
const
|
|
4
|
+
const resolveConfigValue_1 = require("./resolveConfigValue");
|
|
5
5
|
/**
|
|
6
6
|
* A list of environment variables that were requested at build time. Used by webpack to
|
|
7
7
|
* capture build-time environment variables values.
|
|
@@ -24,7 +24,12 @@ exports.ENV_BUILD_CONFIGS = [];
|
|
|
24
24
|
*
|
|
25
25
|
* @example const config = { configValue: envConfig('environment_variable_name') };
|
|
26
26
|
*/
|
|
27
|
-
const envConfig = (name, type
|
|
27
|
+
const envConfig = (name, type, defaultValue) => {
|
|
28
|
+
// this doesn't use a default parameter value because of a:
|
|
29
|
+
// "Regular parameters should not come after default parameters."
|
|
30
|
+
// error that occurs when the defaultValue optional default of `undefined`
|
|
31
|
+
// gets optimized out, causing a problem in cloudfront functions.
|
|
32
|
+
type !== null && type !== void 0 ? type : (type = 'build');
|
|
28
33
|
if (type === 'build') {
|
|
29
34
|
exports.ENV_BUILD_CONFIGS.push(name);
|
|
30
35
|
}
|
|
@@ -33,17 +38,19 @@ const envConfig = (name, type = 'build', defaultValue) => {
|
|
|
33
38
|
// @ts-ignore - hack to get around the way webpack/define works
|
|
34
39
|
// - https://github.com/webpack/webpack/issues/14800
|
|
35
40
|
// - https://github.com/webpack/webpack/issues/5392
|
|
36
|
-
|
|
37
|
-
|
|
41
|
+
// also, spread operator not supported in cloudfront functions
|
|
42
|
+
const envs = Object.assign({}, process.env, typeof __PROCESS_ENV !== 'undefined' ? __PROCESS_ENV : {});
|
|
43
|
+
const value = envs[name];
|
|
44
|
+
if (value === undefined) {
|
|
38
45
|
if (defaultValue === undefined) {
|
|
39
46
|
throw new Error(`expected to find environment variable with name: ${name}`);
|
|
40
47
|
}
|
|
41
48
|
else {
|
|
42
|
-
return (0,
|
|
49
|
+
return (0, resolveConfigValue_1.resolveConfigValue)(defaultValue);
|
|
43
50
|
}
|
|
44
51
|
}
|
|
45
52
|
else {
|
|
46
|
-
return
|
|
53
|
+
return value;
|
|
47
54
|
}
|
|
48
55
|
};
|
|
49
56
|
};
|
package/dist/cjs/errors/index.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SessionExpiredError = exports.NotFoundError = exports.UnauthorizedError = exports.InvalidRequestError = exports.isAppError = void 0;
|
|
2
4
|
/*
|
|
3
5
|
* if code is split into multiple bundles, sometimes each bundle
|
|
4
6
|
* will get its own definition of this module and then instanceof checks
|
|
@@ -11,10 +13,8 @@
|
|
|
11
13
|
* error instanceof InvalidRequestError
|
|
12
14
|
*
|
|
13
15
|
*/
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const errorIsType = ({ TYPE }) => (e) => e instanceof Error
|
|
17
|
-
&& e.constructor.TYPE === TYPE;
|
|
16
|
+
const errorIsType = (t) => (e) => e instanceof Error
|
|
17
|
+
&& e.constructor.TYPE === t.TYPE;
|
|
18
18
|
/**
|
|
19
19
|
* Returns true if the error is defined in this library
|
|
20
20
|
*/
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.browserAuthProvider = void 0;
|
|
4
|
+
const lodash_1 = require("lodash");
|
|
4
5
|
const __1 = require("../..");
|
|
5
6
|
const config_1 = require("../../config");
|
|
7
|
+
const errors_1 = require("../../errors");
|
|
6
8
|
const guards_1 = require("../../guards");
|
|
7
9
|
const helpers_1 = require("../../routing/helpers");
|
|
8
10
|
const embeddedAuthProvider_1 = require("./utils/embeddedAuthProvider");
|
|
@@ -12,14 +14,14 @@ const browserAuthProvider = ({ window, configSpace }) => (configProvider) => {
|
|
|
12
14
|
const accountsBase = (0, __1.once)(() => (0, config_1.resolveConfigValue)(config.accountsBase));
|
|
13
15
|
const queryString = window.location.search;
|
|
14
16
|
const queryKey = 'auth';
|
|
15
|
-
const
|
|
17
|
+
const urlSearchParams = new URLSearchParams(queryString);
|
|
18
|
+
const authQuery = urlSearchParams.get(queryKey);
|
|
16
19
|
const referrer = window.document.referrer ? new URL(window.document.referrer) : undefined;
|
|
17
20
|
const isEmbedded = window.parent !== window;
|
|
18
21
|
const trustedParent = isEmbedded && referrer && referrer.hostname.match(/^(openstax\.org|((.*)(\.openstax\.org|local|localhost)))$/) ? referrer : undefined;
|
|
19
|
-
const { embeddedQueryValue, getAuthorizedEmbedUrl } = (0, embeddedAuthProvider_1.embeddedAuthProvider)(() => getUserData(), { queryKey, window });
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
};
|
|
22
|
+
const { embeddedQueryKey, embeddedQueryValue, getAuthorizedEmbedUrl } = (0, embeddedAuthProvider_1.embeddedAuthProvider)(() => getUserData(), { authQuery: { key: queryKey, value: authQuery }, window });
|
|
23
|
+
const embeddedQuery = urlSearchParams.get(embeddedQueryKey);
|
|
24
|
+
let userData = { token: authQuery };
|
|
23
25
|
const getAuthToken = async () => {
|
|
24
26
|
return (await getUserData()).token;
|
|
25
27
|
};
|
|
@@ -35,6 +37,12 @@ const browserAuthProvider = ({ window, configSpace }) => (configProvider) => {
|
|
|
35
37
|
if (authQuery) {
|
|
36
38
|
url.searchParams.set(queryKey, authQuery);
|
|
37
39
|
}
|
|
40
|
+
else if (embeddedQuery) {
|
|
41
|
+
url.searchParams.set(queryKey, 'embedded');
|
|
42
|
+
}
|
|
43
|
+
if (embeddedQuery) {
|
|
44
|
+
url.searchParams.set(embeddedQueryKey, embeddedQuery);
|
|
45
|
+
}
|
|
38
46
|
return url.href;
|
|
39
47
|
};
|
|
40
48
|
// *note* that this does not actually prevent cookies from being sent on same-origin
|
|
@@ -86,10 +94,23 @@ const browserAuthProvider = ({ window, configSpace }) => (configProvider) => {
|
|
|
86
94
|
throw new Error(`Error response from Accounts ${response.status}: ${message}`);
|
|
87
95
|
};
|
|
88
96
|
const getUserData = (0, __1.once)(async () => {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
97
|
+
// For backwards compatibility
|
|
98
|
+
if (authQuery === 'embedded') {
|
|
99
|
+
return getParentWindowUser();
|
|
100
|
+
}
|
|
101
|
+
// getFetchUser() will throw here if authQuery is not set
|
|
102
|
+
if (embeddedQuery !== embeddedQueryValue) {
|
|
103
|
+
return getFetchUser();
|
|
104
|
+
}
|
|
105
|
+
const userDataFromParentWindow = await getParentWindowUser();
|
|
106
|
+
if (!authQuery) {
|
|
107
|
+
return userDataFromParentWindow;
|
|
108
|
+
}
|
|
109
|
+
const userDataFromAuthQuery = await getFetchUser();
|
|
110
|
+
if ((0, lodash_1.isEqual)(userDataFromAuthQuery, userDataFromParentWindow)) {
|
|
111
|
+
return userDataFromAuthQuery;
|
|
112
|
+
}
|
|
113
|
+
throw new errors_1.UnauthorizedError();
|
|
93
114
|
});
|
|
94
115
|
const getUser = async () => {
|
|
95
116
|
return (await getUserData()).user;
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.decryptionAuthProvider = void 0;
|
|
4
4
|
const resolveConfigValue_1 = require("../../config/resolveConfigValue");
|
|
5
|
+
const errors_1 = require("../../errors");
|
|
5
6
|
const guards_1 = require("../../guards");
|
|
6
7
|
const helpers_1 = require("../../misc/helpers");
|
|
7
8
|
const decryptAndVerify_1 = require("./utils/decryptAndVerify");
|
|
@@ -25,7 +26,11 @@ const decryptionAuthProvider = (initializer) => (configProvider) => {
|
|
|
25
26
|
if (!token) {
|
|
26
27
|
return undefined;
|
|
27
28
|
}
|
|
28
|
-
|
|
29
|
+
const result = (0, decryptAndVerify_1.decryptAndVerify)(token, await encryptionPrivateKey(), await signaturePublicKey());
|
|
30
|
+
if ('error' in result && result.error == 'expired token') {
|
|
31
|
+
throw new errors_1.SessionExpiredError();
|
|
32
|
+
}
|
|
33
|
+
return 'user' in result ? result.user : undefined;
|
|
29
34
|
};
|
|
30
35
|
return {
|
|
31
36
|
getAuthorizedFetchConfig,
|
|
@@ -1,11 +1,27 @@
|
|
|
1
|
-
|
|
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;
|
|
2
14
|
/**
|
|
3
15
|
* Decrypts and verifies a SSO cookie.
|
|
4
16
|
*
|
|
5
17
|
* @param token the encrypted token
|
|
6
18
|
* @param encryptionPrivateKey the private key used to encrypt the token
|
|
7
19
|
* @param signaturePublicKey the public key used to verify the decrypted token
|
|
8
|
-
* @
|
|
9
|
-
* @returns User (success) or undefined (failure)
|
|
20
|
+
* @returns {user: User} (success) or {error: string} (failure)
|
|
10
21
|
*/
|
|
11
|
-
export declare const decryptAndVerify: (token: string, encryptionPrivateKey: string, signaturePublicKey: string) =>
|
|
22
|
+
export declare const decryptAndVerify: (token: string, encryptionPrivateKey: string, signaturePublicKey: string) => {
|
|
23
|
+
user: User;
|
|
24
|
+
} | {
|
|
25
|
+
error: string;
|
|
26
|
+
};
|
|
27
|
+
export {};
|
|
@@ -1,79 +1,91 @@
|
|
|
1
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
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
-
exports.decryptAndVerify = void 0;
|
|
30
|
-
const
|
|
31
|
-
const util_1 = require("util");
|
|
32
|
-
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
|
|
33
|
-
const errors_1 = require("../../../errors");
|
|
3
|
+
exports.decryptAndVerify = exports.verifyJws = exports.decryptJwe = void 0;
|
|
4
|
+
const crypto_1 = require("crypto");
|
|
34
5
|
const guards_1 = require("../../../guards");
|
|
35
|
-
const
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
const
|
|
41
|
-
|
|
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 });
|
|
42
22
|
decipher.setAAD(aad, { plaintextLength: cipherText.length });
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
decipher.update(cipherText)
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
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
|
+
}
|
|
49
57
|
};
|
|
58
|
+
exports.verifyJws = verifyJws;
|
|
50
59
|
/**
|
|
51
60
|
* Decrypts and verifies a SSO cookie.
|
|
52
61
|
*
|
|
53
62
|
* @param token the encrypted token
|
|
54
63
|
* @param encryptionPrivateKey the private key used to encrypt the token
|
|
55
64
|
* @param signaturePublicKey the public key used to verify the decrypted token
|
|
56
|
-
* @
|
|
57
|
-
* @returns User (success) or undefined (failure)
|
|
65
|
+
* @returns {user: User} (success) or {error: string} (failure)
|
|
58
66
|
*/
|
|
59
67
|
const decryptAndVerify = (token, encryptionPrivateKey, signaturePublicKey) => {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
clockTolerance: 300 // 5 minutes
|
|
65
|
-
});
|
|
66
|
-
if (!(0, guards_1.isPlainObject)(payload) || !(0, guards_1.isPlainObject)(payload.sub) || !payload.sub.uuid) {
|
|
67
|
-
return undefined;
|
|
68
|
-
}
|
|
69
|
-
// TS is confused because the library types the `sub` as a string
|
|
70
|
-
return payload.sub;
|
|
68
|
+
const timestamp = Math.floor(Date.now() / 1000);
|
|
69
|
+
const jws = (0, exports.decryptJwe)(token, encryptionPrivateKey);
|
|
70
|
+
if (!jws) {
|
|
71
|
+
return { error: 'invalid token' };
|
|
71
72
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
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' };
|
|
77
88
|
}
|
|
89
|
+
return { user: payload.sub };
|
|
78
90
|
};
|
|
79
91
|
exports.decryptAndVerify = decryptAndVerify;
|
|
@@ -9,10 +9,14 @@ export declare enum PostMessageTypes {
|
|
|
9
9
|
ReceiveUser = "receive-user",
|
|
10
10
|
RequestUser = "request-user"
|
|
11
11
|
}
|
|
12
|
-
export declare const embeddedAuthProvider: (getUserData: UserDataLoader, {
|
|
13
|
-
|
|
12
|
+
export declare const embeddedAuthProvider: (getUserData: UserDataLoader, { authQuery, window }: {
|
|
13
|
+
authQuery?: {
|
|
14
|
+
key: string;
|
|
15
|
+
value: string | null;
|
|
16
|
+
} | undefined;
|
|
14
17
|
window: Window;
|
|
15
18
|
}) => {
|
|
19
|
+
embeddedQueryKey: string;
|
|
16
20
|
embeddedQueryValue: string;
|
|
17
21
|
getAuthorizedEmbedUrl: (urlString: string, extraParams?: {
|
|
18
22
|
[key: string]: string;
|
|
@@ -10,9 +10,10 @@ var PostMessageTypes;
|
|
|
10
10
|
PostMessageTypes["ReceiveUser"] = "receive-user";
|
|
11
11
|
PostMessageTypes["RequestUser"] = "request-user";
|
|
12
12
|
})(PostMessageTypes = exports.PostMessageTypes || (exports.PostMessageTypes = {}));
|
|
13
|
-
const embeddedAuthProvider = (getUserData, {
|
|
13
|
+
const embeddedAuthProvider = (getUserData, { authQuery, window }) => {
|
|
14
14
|
const trustedEmbeds = new Set();
|
|
15
|
-
const
|
|
15
|
+
const embeddedQueryKey = 'embedded';
|
|
16
|
+
const embeddedQueryValue = 'true';
|
|
16
17
|
const messageHandler = event => {
|
|
17
18
|
if (event.data.type === PostMessageTypes.RequestUser && trustedEmbeds.has(event.origin)) {
|
|
18
19
|
getUserData().then(data => {
|
|
@@ -25,10 +26,16 @@ const embeddedAuthProvider = (getUserData, { queryKey = 'auth', window }) => {
|
|
|
25
26
|
const url = new URL(urlString);
|
|
26
27
|
trustedEmbeds.add(url.origin);
|
|
27
28
|
const params = query_string_1.default.parse(url.search);
|
|
28
|
-
url.search = query_string_1.default.stringify({
|
|
29
|
+
url.search = query_string_1.default.stringify({
|
|
30
|
+
...params,
|
|
31
|
+
...extraParams,
|
|
32
|
+
...(authQuery && authQuery.value ? { [authQuery.key]: authQuery.value } : {}),
|
|
33
|
+
[embeddedQueryKey]: embeddedQueryValue
|
|
34
|
+
});
|
|
29
35
|
return url.href;
|
|
30
36
|
};
|
|
31
37
|
return {
|
|
38
|
+
embeddedQueryKey,
|
|
32
39
|
embeddedQueryValue,
|
|
33
40
|
getAuthorizedEmbedUrl,
|
|
34
41
|
unmount: () => {
|
|
@@ -51,7 +51,8 @@ const exercisesGateway = (initializer) => (configProvider) => {
|
|
|
51
51
|
question.collaborator_solutions = [
|
|
52
52
|
{ solution_type: 'detailed', images: [], content_html: defaultHint }
|
|
53
53
|
];
|
|
54
|
-
for (
|
|
54
|
+
for (let index = 0; index < question.answers.length; index++) {
|
|
55
|
+
const answer = question.answers[index];
|
|
55
56
|
answer.correctness = defaultCorrectIndex === index ? '1.0' : '0.0';
|
|
56
57
|
answer.feedback_html = defaultCorrectIndex === index ? 'This is the good one!' : defaultHint;
|
|
57
58
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
export declare type FileValue = {
|
|
3
|
+
dataType: 'file';
|
|
4
|
+
mimeType: string;
|
|
5
|
+
path: string;
|
|
6
|
+
label: string;
|
|
7
|
+
};
|
|
8
|
+
export declare type FolderValue = {
|
|
9
|
+
dataType: 'folder';
|
|
10
|
+
files: FileValue[];
|
|
11
|
+
};
|
|
12
|
+
export declare const isFileValue: (thing: any) => thing is FileValue;
|
|
13
|
+
export declare const isFolderValue: (thing: any) => thing is FolderValue;
|
|
14
|
+
export interface FileServerAdapter {
|
|
15
|
+
getFileContent: (source: FileValue) => Promise<Buffer>;
|
|
16
|
+
}
|
|
17
|
+
export declare const isFileOrFolder: (thing: any) => thing is FileValue | FolderValue;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isFileOrFolder = exports.isFolderValue = exports.isFileValue = void 0;
|
|
4
|
+
const guards_1 = require("../../guards");
|
|
5
|
+
const isFileValue = (thing) => (0, guards_1.isPlainObject)(thing)
|
|
6
|
+
&& Object.keys(thing).every(key => ['dataType', 'path', 'label', 'mimeType'].includes(key))
|
|
7
|
+
&& thing.dataType === 'file'
|
|
8
|
+
&& typeof thing.mimeType === 'string'
|
|
9
|
+
&& typeof thing.path === 'string'
|
|
10
|
+
&& typeof thing.label === 'string';
|
|
11
|
+
exports.isFileValue = isFileValue;
|
|
12
|
+
const isFolderValue = (thing) => (0, guards_1.isPlainObject)(thing)
|
|
13
|
+
&& Object.keys(thing).every(key => ['dataType', 'files'].includes(key))
|
|
14
|
+
&& thing.dataType === 'folder'
|
|
15
|
+
&& thing.files instanceof Array
|
|
16
|
+
&& thing.files.every(exports.isFileValue);
|
|
17
|
+
exports.isFolderValue = isFolderValue;
|
|
18
|
+
const isFileOrFolder = (thing) => (0, exports.isFileValue)(thing) || (0, exports.isFolderValue)(thing);
|
|
19
|
+
exports.isFileOrFolder = isFileOrFolder;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ConfigProviderForConfig } from '../../config';
|
|
2
|
+
import { FileServerAdapter } from '.';
|
|
3
|
+
export declare type Config = {
|
|
4
|
+
storagePrefix: string;
|
|
5
|
+
};
|
|
6
|
+
interface Initializer<C> {
|
|
7
|
+
dataDir: string;
|
|
8
|
+
configSpace?: C;
|
|
9
|
+
}
|
|
10
|
+
export declare const localFileServer: <C extends string = "local">(initializer: Initializer<C>) => (configProvider: { [key in C]: {
|
|
11
|
+
storagePrefix: import("../../config").ConfigValueProvider<string>;
|
|
12
|
+
}; }) => FileServerAdapter;
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,23 @@
|
|
|
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.localFileServer = void 0;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const config_1 = require("../../config");
|
|
10
|
+
const guards_1 = require("../../guards");
|
|
11
|
+
const localFileServer = (initializer) => (configProvider) => {
|
|
12
|
+
const config = configProvider[(0, guards_1.ifDefined)(initializer.configSpace, 'local')];
|
|
13
|
+
const storagePrefix = (0, config_1.resolveConfigValue)(config.storagePrefix);
|
|
14
|
+
const fileDir = storagePrefix.then((prefix) => path_1.default.join(initializer.dataDir, prefix));
|
|
15
|
+
const getFileContent = async (source) => {
|
|
16
|
+
const filePath = path_1.default.join(await fileDir, source.path);
|
|
17
|
+
return fs_1.default.promises.readFile(filePath);
|
|
18
|
+
};
|
|
19
|
+
return {
|
|
20
|
+
getFileContent,
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
exports.localFileServer = localFileServer;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { S3Client } from '@aws-sdk/client-s3';
|
|
2
|
+
import { ConfigProviderForConfig } from '../../config';
|
|
3
|
+
import { FileServerAdapter } from '.';
|
|
4
|
+
export declare type Config = {
|
|
5
|
+
bucketName: string;
|
|
6
|
+
bucketRegion: string;
|
|
7
|
+
};
|
|
8
|
+
interface Initializer<C> {
|
|
9
|
+
configSpace?: C;
|
|
10
|
+
s3Client?: typeof S3Client;
|
|
11
|
+
}
|
|
12
|
+
export declare const s3FileServer: <C extends string = "deployed">(initializer: Initializer<C>) => (configProvider: { [key in C]: {
|
|
13
|
+
bucketName: import("../../config").ConfigValueProvider<string>;
|
|
14
|
+
bucketRegion: import("../../config").ConfigValueProvider<string>;
|
|
15
|
+
}; }) => FileServerAdapter;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.s3FileServer = void 0;
|
|
4
|
+
const client_s3_1 = require("@aws-sdk/client-s3");
|
|
5
|
+
const __1 = require("../..");
|
|
6
|
+
const assertions_1 = require("../../assertions");
|
|
7
|
+
const config_1 = require("../../config");
|
|
8
|
+
const guards_1 = require("../../guards");
|
|
9
|
+
const s3FileServer = (initializer) => (configProvider) => {
|
|
10
|
+
const config = configProvider[(0, guards_1.ifDefined)(initializer.configSpace, 'deployed')];
|
|
11
|
+
const bucketName = (0, __1.once)(() => (0, config_1.resolveConfigValue)(config.bucketName));
|
|
12
|
+
const bucketRegion = (0, __1.once)(() => (0, config_1.resolveConfigValue)(config.bucketRegion));
|
|
13
|
+
const client = (0, guards_1.ifDefined)(initializer.s3Client, client_s3_1.S3Client);
|
|
14
|
+
const s3Service = (0, __1.once)(async () => new client({ apiVersion: '2012-08-10', region: await bucketRegion() }));
|
|
15
|
+
const getFileContent = async (source) => {
|
|
16
|
+
const bucket = await bucketName();
|
|
17
|
+
const command = new client_s3_1.GetObjectCommand({ Bucket: bucket, Key: source.path });
|
|
18
|
+
const response = await (await s3Service()).send(command);
|
|
19
|
+
return Buffer.from(await (0, assertions_1.assertDefined)(response.Body, new Error('Invalid Response from s3')).transformToByteArray());
|
|
20
|
+
};
|
|
21
|
+
return {
|
|
22
|
+
getFileContent,
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
exports.s3FileServer = s3FileServer;
|