dce-reactkit 3.9.2 → 3.9.4-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cjs/index.js CHANGED
@@ -59,7 +59,7 @@ function __awaiter(thisArg, _arguments, P, generator) {
59
59
  });
60
60
  }
61
61
 
62
- // Highest error code = DRK16
62
+ // Highest error code = DRK18
63
63
  /**
64
64
  * List of error codes built into the react kit
65
65
  * @author Gabe Abrams
@@ -71,6 +71,8 @@ var ReactKitErrorCode;
71
71
  ReactKitErrorCode["SessionExpired"] = "DRK3";
72
72
  ReactKitErrorCode["MissingParameter"] = "DRK4";
73
73
  ReactKitErrorCode["InvalidParameter"] = "DRK5";
74
+ ReactKitErrorCode["HostNotAllowed"] = "DRK17";
75
+ ReactKitErrorCode["HostBanned"] = "DRK18";
74
76
  ReactKitErrorCode["WrongCourse"] = "DRK6";
75
77
  ReactKitErrorCode["NoCACCLSendRequestFunction"] = "DRK7";
76
78
  ReactKitErrorCode["NoCACCLGetLaunchInfoFunction"] = "DRK8";
@@ -184,6 +186,7 @@ var ModalButtonType$1 = ModalButtonType;
184
186
  var ModalType;
185
187
  (function (ModalType) {
186
188
  ModalType["Okay"] = "okay";
189
+ ModalType["Cancel"] = "cancel";
187
190
  ModalType["OkayCancel"] = "okay-cancel";
188
191
  ModalType["YesNo"] = "yes-no";
189
192
  ModalType["YesNoCancel"] = "yes-no-cancel";
@@ -338,6 +341,9 @@ const modalTypeToModalButtonTypes = {
338
341
  [ModalType$1.Okay]: [
339
342
  ModalButtonType$1.Okay,
340
343
  ],
344
+ [ModalType$1.Cancel]: [
345
+ ModalButtonType$1.Cancel,
346
+ ],
341
347
  [ModalType$1.OkayCancel]: [
342
348
  ModalButtonType$1.Okay,
343
349
  ModalButtonType$1.Cancel,
@@ -1078,6 +1084,11 @@ const confirm = (title, text, opts) => __awaiter(void 0, void 0, void 0, functio
1078
1084
  });
1079
1085
  });
1080
1086
  /*----------------------------------------*/
1087
+ /* --------------- Prompt -------------- */
1088
+ /*----------------------------------------*/
1089
+ // Stored copies of setters
1090
+ let setPromptInfo;
1091
+ /*----------------------------------------*/
1081
1092
  /* ------------- Fatal Error ------------ */
1082
1093
  /*----------------------------------------*/
1083
1094
  // Stored copies of setters
@@ -1093,14 +1104,14 @@ const fatalErrorHandlers = [];
1093
1104
  * @param [errorTitle] title of the error box
1094
1105
  */
1095
1106
  const showFatalError = (error, errorTitle = 'An Error Occurred') => __awaiter(void 0, void 0, void 0, function* () {
1096
- var _a, _b;
1107
+ var _b, _c;
1097
1108
  // Determine message and code
1098
1109
  const message = (typeof error === 'string'
1099
1110
  ? error.trim()
1100
- : String((_a = error.message) !== null && _a !== void 0 ? _a : 'An unknown error occurred.'));
1111
+ : String((_b = error.message) !== null && _b !== void 0 ? _b : 'An unknown error occurred.'));
1101
1112
  const code = (typeof error === 'string'
1102
1113
  ? ReactKitErrorCode$1.NoCode
1103
- : String((_b = error.code) !== null && _b !== void 0 ? _b : ReactKitErrorCode$1.NoCode));
1114
+ : String((_c = error.code) !== null && _c !== void 0 ? _c : ReactKitErrorCode$1.NoCode));
1104
1115
  // Call all fatal error listeners
1105
1116
  try {
1106
1117
  fatalErrorHandlers.forEach((handler) => {
@@ -1227,6 +1238,9 @@ const AppWrapper = (props) => {
1227
1238
  // Confirm
1228
1239
  const [confirmInfo, setConfirmInfoInner,] = React.useState(undefined);
1229
1240
  setConfirmInfo = setConfirmInfoInner;
1241
+ // Prompt
1242
+ const [promptInfo, setPromptInfoInner] = React.useState(undefined);
1243
+ setPromptInfo = setPromptInfoInner;
1230
1244
  // Session expired
1231
1245
  const [sessionHasExpired, setSessionHasExpiredInner,] = React.useState(false);
1232
1246
  setSessionHasExpired = setSessionHasExpiredInner;
@@ -1257,6 +1271,34 @@ const AppWrapper = (props) => {
1257
1271
  }
1258
1272
  }, onTopOfOtherModals: true, dontAllowBackdropExit: true }, confirmInfo.text));
1259
1273
  }
1274
+ /* ------------- Prompt ------------ */
1275
+ if (promptInfo) {
1276
+ // Run min char validation
1277
+ const minNumCharsValidationError = ((promptInfo.opts.minNumChars
1278
+ && promptInfo.currentInputFieldText.length < promptInfo.opts.minNumChars)
1279
+ ? `Please enter at least ${promptInfo.opts.minNumChars} characters.`
1280
+ : undefined);
1281
+ // Run custom validation
1282
+ const customValidationError = (promptInfo.opts.findValidationError
1283
+ && promptInfo.opts.findValidationError(promptInfo.currentInputFieldText));
1284
+ modal = (React__default["default"].createElement(Modal, { key: `prompt-${promptInfo.title}-${promptInfo.text}`, title: promptInfo.title,
1285
+ // only show the cancel button if there is a validation error
1286
+ type: ((customValidationError || minNumCharsValidationError)
1287
+ ? ModalType$1.Cancel
1288
+ : ModalType$1.OkayCancel), okayLabel: promptInfo.opts.confirmButtonText, okayVariant: promptInfo.opts.confirmButtonVariant, cancelLabel: promptInfo.opts.cancelButtonText, cancelVariant: promptInfo.opts.cancelButtonVariant, onClose: (buttonType) => {
1289
+ (buttonType === ModalButtonType$1.Okay
1290
+ ? promptInfo.currentInputFieldText
1291
+ : null);
1292
+ setPromptInfo(undefined);
1293
+ }, onTopOfOtherModals: true, dontAllowBackdropExit: true },
1294
+ React__default["default"].createElement("div", { className: "d-flex flex-column align-items-center" },
1295
+ React__default["default"].createElement("p", null, promptInfo.text),
1296
+ React__default["default"].createElement("input", { type: "text", placeholder: promptInfo.opts.placeholder, value: promptInfo.currentInputFieldText, onChange: (e) => {
1297
+ return setPromptInfo(Object.assign(Object.assign({}, promptInfo), { currentInputFieldText: e.target.value }));
1298
+ } }),
1299
+ minNumCharsValidationError && (React__default["default"].createElement("div", { className: "text-danger bg-danger bg-opacity-25 p-2 m-1 rounded" }, minNumCharsValidationError)),
1300
+ customValidationError && (React__default["default"].createElement("div", { className: "text-danger bg-danger bg-opacity-25 p-2 m-1 rounded" }, customValidationError)))));
1301
+ }
1260
1302
  /* ------ Custom Modal Portals ------ */
1261
1303
  // Custom modal portals
1262
1304
  const customModalPortals = [];
@@ -14469,6 +14511,12 @@ const parseUserAgent = (userAgent) => {
14469
14511
  * @param opts.handler function that processes the request
14470
14512
  * @param [opts.skipSessionCheck] if true, skip the session check (allow users
14471
14513
  * to not be logged in and launched via LTI)
14514
+ * @param [opts.allowedHosts] if included, only allow requests from these hosts
14515
+ * (start a hostname with a "*" to only check the end of the hostname)
14516
+ * you can include just one string instead of an array
14517
+ * @param [opts.bannedHosts] if included, do not allow requests from these hosts
14518
+ * (start a hostname with a "*" to only check the end of the hostname)
14519
+ * you can include just one string instead of an array
14472
14520
  * @param [opts.unhandledErrorMessagePrefix] if included, when an error that
14473
14521
  * is not of type ErrorWithCode is thrown, the client will receive an error
14474
14522
  * where the error message is prefixed with this string. For example,
@@ -14500,6 +14548,72 @@ const genRouteHandler = (opts) => {
14500
14548
  // Output params
14501
14549
  const output = {};
14502
14550
  /*----------------------------------------*/
14551
+ /* ----------- Hostname Check ----------- */
14552
+ /*----------------------------------------*/
14553
+ // Get hostnames
14554
+ const originURL = String(req.get('origin')
14555
+ || req.headers.origin
14556
+ || req.headers.referer);
14557
+ const originHostname = (originURL
14558
+ // Remove protocol
14559
+ .replace(/(^\w+:|^)\/\//, '')
14560
+ // Remove port
14561
+ .replace(/:\d+$/, ''));
14562
+ const serverHostname = String(req.hostname);
14563
+ // Check allowed
14564
+ if (opts.allowedHosts) {
14565
+ // Only accept requests from allowed hosts
14566
+ const allowedArray = (Array.isArray(opts.allowedHosts)
14567
+ ? opts.allowedHosts
14568
+ : [opts.allowedHosts]);
14569
+ // Check if server is localhost
14570
+ if (serverHostname === 'localhost') {
14571
+ // Allow localhost
14572
+ allowedArray.push('localhost');
14573
+ }
14574
+ // Check if current host is allowed
14575
+ const allowed = allowedArray.some((allowedHost) => {
14576
+ if (allowedHost.startsWith('*')) {
14577
+ // Check end of hostname
14578
+ return originHostname.endsWith(allowedHost.substring(1));
14579
+ }
14580
+ // Check full hostname
14581
+ return originHostname.toLowerCase() === allowedHost.toLowerCase();
14582
+ });
14583
+ // If not allowed, return error
14584
+ if (!allowed) {
14585
+ return handleError(res, {
14586
+ message: 'You are not allowed to access this endpoint.',
14587
+ code: ReactKitErrorCode$1.HostNotAllowed,
14588
+ status: 403,
14589
+ });
14590
+ }
14591
+ }
14592
+ // Check banned
14593
+ if (opts.bannedHosts) {
14594
+ // Do not allow requests from banned hosts
14595
+ const bannedArray = (Array.isArray(opts.bannedHosts)
14596
+ ? opts.bannedHosts
14597
+ : [opts.bannedHosts]);
14598
+ // Check if current host is banned
14599
+ const banned = bannedArray.some((bannedHost) => {
14600
+ if (bannedHost.startsWith('*')) {
14601
+ // Check end of hostname
14602
+ return originHostname.endsWith(bannedHost.substring(1));
14603
+ }
14604
+ // Check full hostname
14605
+ return originHostname.toLowerCase() === bannedHost.toLowerCase();
14606
+ });
14607
+ // If banned, return error
14608
+ if (banned) {
14609
+ return handleError(res, {
14610
+ message: 'You are not allowed to access this endpoint.',
14611
+ code: ReactKitErrorCode$1.HostBanned,
14612
+ status: 403,
14613
+ });
14614
+ }
14615
+ }
14616
+ /*----------------------------------------*/
14503
14617
  /* ------------ Parse Params ------------ */
14504
14618
  /*----------------------------------------*/
14505
14619
  // Process items one by one