dce-reactkit 3.9.2 → 3.9.3

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.
@@ -9,6 +9,12 @@ import LogFunction from '../types/LogFunction';
9
9
  * @param opts.handler function that processes the request
10
10
  * @param [opts.skipSessionCheck] if true, skip the session check (allow users
11
11
  * to not be logged in and launched via LTI)
12
+ * @param [opts.allowedHosts] if included, only allow requests from these hosts
13
+ * (start a hostname with a "*" to only check the end of the hostname)
14
+ * you can include just one string instead of an array
15
+ * @param [opts.bannedHosts] if included, do not allow requests from these hosts
16
+ * (start a hostname with a "*" to only check the end of the hostname)
17
+ * you can include just one string instead of an array
12
18
  * @param [opts.unhandledErrorMessagePrefix] if included, when an error that
13
19
  * is not of type ErrorWithCode is thrown, the client will receive an error
14
20
  * where the error message is prefixed with this string. For example,
@@ -63,6 +69,8 @@ declare const genRouteHandler: (opts: {
63
69
  logServerEvent: LogFunction;
64
70
  }) => any;
65
71
  skipSessionCheck?: boolean | undefined;
72
+ allowedHosts?: string | string[] | undefined;
73
+ bannedHosts?: string | string[] | undefined;
66
74
  unhandledErrorMessagePrefix?: string | undefined;
67
75
  }) => (req: any, res: any, next: () => void) => Promise<undefined>;
68
76
  export default genRouteHandler;
@@ -8,6 +8,8 @@ declare enum ReactKitErrorCode {
8
8
  SessionExpired = "DRK3",
9
9
  MissingParameter = "DRK4",
10
10
  InvalidParameter = "DRK5",
11
+ HostNotAllowed = "DRK17",
12
+ HostBanned = "DRK18",
11
13
  WrongCourse = "DRK6",
12
14
  NoCACCLSendRequestFunction = "DRK7",
13
15
  NoCACCLGetLaunchInfoFunction = "DRK8",
package/dist/index.d.ts CHANGED
@@ -1044,6 +1044,12 @@ type LogFunction = (opts: ({
1044
1044
  * @param opts.handler function that processes the request
1045
1045
  * @param [opts.skipSessionCheck] if true, skip the session check (allow users
1046
1046
  * to not be logged in and launched via LTI)
1047
+ * @param [opts.allowedHosts] if included, only allow requests from these hosts
1048
+ * (start a hostname with a "*" to only check the end of the hostname)
1049
+ * you can include just one string instead of an array
1050
+ * @param [opts.bannedHosts] if included, do not allow requests from these hosts
1051
+ * (start a hostname with a "*" to only check the end of the hostname)
1052
+ * you can include just one string instead of an array
1047
1053
  * @param [opts.unhandledErrorMessagePrefix] if included, when an error that
1048
1054
  * is not of type ErrorWithCode is thrown, the client will receive an error
1049
1055
  * where the error message is prefixed with this string. For example,
@@ -1098,6 +1104,8 @@ declare const genRouteHandler: (opts: {
1098
1104
  logServerEvent: LogFunction;
1099
1105
  }) => any;
1100
1106
  skipSessionCheck?: boolean | undefined;
1107
+ allowedHosts?: string | string[] | undefined;
1108
+ bannedHosts?: string | string[] | undefined;
1101
1109
  unhandledErrorMessagePrefix?: string | undefined;
1102
1110
  }) => (req: any, res: any, next: () => void) => Promise<undefined>;
1103
1111
 
@@ -1637,6 +1645,8 @@ declare enum ReactKitErrorCode {
1637
1645
  SessionExpired = "DRK3",
1638
1646
  MissingParameter = "DRK4",
1639
1647
  InvalidParameter = "DRK5",
1648
+ HostNotAllowed = "DRK17",
1649
+ HostBanned = "DRK18",
1640
1650
  WrongCourse = "DRK6",
1641
1651
  NoCACCLSendRequestFunction = "DRK7",
1642
1652
  NoCACCLGetLaunchInfoFunction = "DRK8",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dce-reactkit",
3
- "version": "3.9.2",
3
+ "version": "3.9.3",
4
4
  "description": "Shared components for Harvard DCE apps",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",
@@ -39,6 +39,12 @@ import LogLevel from '../types/LogLevel';
39
39
  * @param opts.handler function that processes the request
40
40
  * @param [opts.skipSessionCheck] if true, skip the session check (allow users
41
41
  * to not be logged in and launched via LTI)
42
+ * @param [opts.allowedHosts] if included, only allow requests from these hosts
43
+ * (start a hostname with a "*" to only check the end of the hostname)
44
+ * you can include just one string instead of an array
45
+ * @param [opts.bannedHosts] if included, do not allow requests from these hosts
46
+ * (start a hostname with a "*" to only check the end of the hostname)
47
+ * you can include just one string instead of an array
42
48
  * @param [opts.unhandledErrorMessagePrefix] if included, when an error that
43
49
  * is not of type ErrorWithCode is thrown, the client will receive an error
44
50
  * where the error message is prefixed with this string. For example,
@@ -102,6 +108,8 @@ const genRouteHandler = (
102
108
  },
103
109
  ) => any,
104
110
  skipSessionCheck?: boolean,
111
+ allowedHosts?: string[] | string,
112
+ bannedHosts?: string[] | string,
105
113
  unhandledErrorMessagePrefix?: string,
106
114
  },
107
115
  ) => {
@@ -110,6 +118,97 @@ const genRouteHandler = (
110
118
  // Output params
111
119
  const output: { [k in string]: any } = {};
112
120
 
121
+ /*----------------------------------------*/
122
+ /* ----------- Hostname Check ----------- */
123
+ /*----------------------------------------*/
124
+
125
+ // Get hostnames
126
+ const originURL = String(
127
+ req.get('origin')
128
+ || req.headers.origin
129
+ || req.headers.referer
130
+ );
131
+ const originHostname = (
132
+ originURL
133
+ // Remove protocol
134
+ .replace(/(^\w+:|^)\/\//, '')
135
+ // Remove port
136
+ .replace(/:\d+$/, '')
137
+ );
138
+ const serverHostname = String(req.hostname);
139
+
140
+ // Check allowed
141
+ if (opts.allowedHosts) {
142
+ // Only accept requests from allowed hosts
143
+ const allowedArray = (
144
+ Array.isArray(opts.allowedHosts)
145
+ ? opts.allowedHosts
146
+ : [opts.allowedHosts]
147
+ );
148
+
149
+ // Check if server is localhost
150
+ if (serverHostname === 'localhost') {
151
+ // Allow localhost
152
+ allowedArray.push('localhost');
153
+ }
154
+
155
+ // Check if current host is allowed
156
+ const allowed = allowedArray.some((allowedHost) => {
157
+ if (allowedHost.startsWith('*')) {
158
+ // Check end of hostname
159
+ return originHostname.endsWith(allowedHost.substring(1));
160
+ }
161
+
162
+ // Check full hostname
163
+ return originHostname.toLowerCase() === allowedHost.toLowerCase();
164
+ });
165
+
166
+ // If not allowed, return error
167
+ if (!allowed) {
168
+ return handleError(
169
+ res,
170
+ {
171
+ message: 'You are not allowed to access this endpoint.',
172
+ code: ReactKitErrorCode.HostNotAllowed,
173
+ status: 403,
174
+ },
175
+ );
176
+ }
177
+ }
178
+
179
+ // Check banned
180
+ if (opts.bannedHosts) {
181
+ // Do not allow requests from banned hosts
182
+ const bannedArray = (
183
+ Array.isArray(opts.bannedHosts)
184
+ ? opts.bannedHosts
185
+ : [opts.bannedHosts]
186
+ );
187
+
188
+ // Check if current host is banned
189
+ const banned = bannedArray.some((bannedHost) => {
190
+ if (bannedHost.startsWith('*')) {
191
+ // Check end of hostname
192
+ return originHostname.endsWith(bannedHost.substring(1));
193
+ }
194
+
195
+ // Check full hostname
196
+ return originHostname.toLowerCase() === bannedHost.toLowerCase();
197
+ });
198
+
199
+ // If banned, return error
200
+ if (banned) {
201
+ return handleError(
202
+ res,
203
+ {
204
+ message: 'You are not allowed to access this endpoint.',
205
+ code: ReactKitErrorCode.HostBanned,
206
+ status: 403,
207
+ },
208
+ );
209
+ }
210
+ }
211
+
113
212
  /*----------------------------------------*/
114
213
  /* ------------ Parse Params ------------ */
115
214
  /*----------------------------------------*/
@@ -1,4 +1,4 @@
1
- // Highest error code = DRK16
1
+ // Highest error code = DRK18
2
2
 
3
3
  /**
4
4
  * List of error codes built into the react kit
@@ -10,6 +10,8 @@ enum ReactKitErrorCode {
10
10
  SessionExpired = 'DRK3',
11
11
  MissingParameter = 'DRK4',
12
12
  InvalidParameter = 'DRK5',
13
+ HostNotAllowed = 'DRK17',
14
+ HostBanned = 'DRK18',
13
15
  WrongCourse = 'DRK6',
14
16
  NoCACCLSendRequestFunction = 'DRK7',
15
17
  NoCACCLGetLaunchInfoFunction = 'DRK8',