exframe-middleware 1.3.0 → 1.4.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/.eslintrc.json CHANGED
@@ -1,33 +1,3 @@
1
1
  {
2
- "env": {
3
- "es6": true,
4
- "node": true
5
- },
6
- "extends": "airbnb-base",
7
- "parserOptions": {
8
- "ecmaVersion": 2018
9
- },
10
- "rules": {
11
- "comma-dangle": [2, "never"],
12
- "no-underscore-dangle": "off",
13
- "consistent-return": "off",
14
- "import/no-unresolved": [2, { "commonjs": true }],
15
- "max-len": [1, { "code": 250 }],
16
- "linebreak-style": "off",
17
- "strict": [0, "global"],
18
- "no-restricted-syntax": "off",
19
- "global-require": "off",
20
- "no-nested-ternary": "off",
21
- "no-confusing-arrow": "off",
22
- "arrow-body-style": "off",
23
- "arrow-parens": "off",
24
- "brace-style": "off",
25
- "nonblock-statement-body-position": "off",
26
- "curly": "off",
27
- "no-use-before-define": "off",
28
- "no-plusplus": "off",
29
- "func-names": "off",
30
- "no-continue": "off",
31
- "array-bracket-spacing": [1, "always"]
32
- }
33
- }
2
+ "extends": "exzeo/base"
3
+ }
package/index.js CHANGED
@@ -7,10 +7,7 @@ const authorizeUser = require('./lib/authorizeUser');
7
7
  const buildCspFromHeader = require('./lib/buildCspFromHeaders');
8
8
 
9
9
  module.exports = {
10
- /**
11
- * @param {Object} config the configuration object
12
- */
13
- handleErrors: (config = {}) => ({ // eslint-disable-line no-unused-vars
10
+ handleErrors: () => ({
14
11
  mq: async (error, context, message) => handleErrors(context, error, message),
15
12
  express: (error, request, response, next) => {
16
13
  if (!error) return next();
@@ -33,20 +30,15 @@ module.exports = {
33
30
  authorizeUser: {
34
31
  mq: authorizeUser,
35
32
  express: (req, res, next) => {
36
- authorizeUser(req);
33
+ const user = req?.user || req?.context?.user;
34
+ authorizeUser({ user });
37
35
  next();
38
36
  }
39
37
  },
40
-
41
- /**
42
- * @param {Object} config
43
- * @param {Boolean} [config.cspIsRequired] should throw error when csp parts do not exist -- default true
44
- */
45
- buildCsp: (config = {}) => ({ // eslint-disable-line no-unused-vars
46
- // eslint-disable-next-line no-param-reassign
38
+ buildCsp: () => ({
47
39
  mq: context => { context.csp = context.csp || {}; },
48
40
  express: (req, res, next) => {
49
- buildCspFromHeader(req, config);
41
+ buildCspFromHeader(req, {});
50
42
  next();
51
43
  }
52
44
  }),
@@ -2,7 +2,10 @@
2
2
 
3
3
  const errors = require('exframe-errors');
4
4
 
5
- module.exports = context => {
6
- if (!context.user)
7
- throw new errors.Unauthorized('Could not authorize user');
5
+ /**
6
+ * @param {Object} context
7
+ * @param {Object} context.user
8
+ */
9
+ module.exports = ({ user }) => {
10
+ if (!user) { throw new errors.Unauthorized('Could not authorize user'); }
8
11
  };
@@ -1,15 +1,14 @@
1
1
  'use strict';
2
2
 
3
- /* eslint-disable no-param-reassign */
4
-
5
3
  const errors = require('exframe-errors');
6
4
 
7
5
  module.exports = (req, { cspIsRequired = true }) => {
8
6
  const csp = req.headers['harmony-csp'] || '';
9
- if (cspIsRequired && !/^[A-Z]+:[A-Z]{2}:[A-Z\d]+$/.test(csp))
7
+ if (cspIsRequired && csp && !/^[A-Z]+:[A-Z]{2}:[A-Z\d]+$/.test(csp)) {
10
8
  throw new errors.Forbidden('CSP is required');
9
+ }
11
10
 
12
- const [ companyCode, state, product ] = csp.split(/:/g);
11
+ const [companyCode, state, product] = csp.split(/:/g);
13
12
  req.csp = {
14
13
  // in instance of csp === '', only companyCode will not default to ''
15
14
  companyCode: companyCode || undefined,
@@ -13,8 +13,11 @@ module.exports = (context, rawError, optionalIncomingMessage) => {
13
13
  // not complete errors and represent each schema validation error from a single request. These objects will not
14
14
  // have a "statusCode" property and is the reason for the check here to keep them out of the workflow error logic.
15
15
  if (Array.isArray(rawError.errors) && rawError.errors.length > 0 && rawError.errors[0].statusCode !== undefined) {
16
- if (rawError.errors.length > 1) error = rawError.errors;
17
- else error = rawError.errors[0] || rawError;
16
+ if (rawError.errors.length > 1) {
17
+ error = rawError.errors;
18
+ } else {
19
+ error = rawError.errors[0] || rawError;
20
+ }
18
21
  }
19
22
 
20
23
  const { errorCode } = error;
@@ -25,39 +28,45 @@ module.exports = (context, rawError, optionalIncomingMessage) => {
25
28
  // uses statusCode hierarchy of buckets a, else b, else c
26
29
  if (Array.isArray(error) && error.length !== 0) {
27
30
  message = `multiple errors occured: [${error.map(v => v.message).join(', ')}]`;
31
+ const errorsToCheck = error.filter(({ statusCode }) => statusCode >= 400);
28
32
 
29
33
  const a = new Set(); // 401 or 403
30
34
  const b = new Set(); // 500
31
35
  const c = new Set(); // other 400s
32
36
 
33
- for (const { statusCode } of error) {
34
- if (statusCode < 400) continue;
35
- if (statusCode === 401 || statusCode === 403)
37
+ for (const { statusCode } of errorsToCheck) {
38
+ if (statusCode === 401 || statusCode === 403) {
36
39
  a.add(statusCode);
37
- else if (statusCode > 499)
40
+ } else if (statusCode > 499) {
38
41
  b.add(statusCode);
39
- else c.add(statusCode);
42
+ } else {
43
+ c.add(statusCode);
44
+ }
40
45
  }
41
46
 
42
- if (a.size) status = a.has(403) ? 403 : 401;
43
- else if (b.size) {
44
- if (b.size === 1)
47
+ if (a.size) {
48
+ status = a.has(403) ? 403 : 401;
49
+ } else if (b.size) {
50
+ if (b.size === 1) {
45
51
  status = b.values().next().value;
46
- else status = 500;
47
- }
48
- else { // eslint-disable-next-line no-lonely-if
49
- if (c.size === 1)
50
- status = c.values().next().value;
51
- else status = 400;
52
+ } else {
53
+ status = 500;
54
+ }
55
+ } else if (c.size === 1) {
56
+ status = c.values().next().value;
57
+ } else {
58
+ status = 400;
52
59
  }
60
+ } else {
61
+ status = error.statusCode || error.status || 500;
53
62
  }
54
- else status = error.statusCode || error.status || 500;
55
63
 
56
64
  if (status === 500) {
57
65
  context.log.error('An error occurred', { errorDetails: error });
58
66
  message = error.message || 'Internal Server Error';
67
+ } else {
68
+ context.log.warn('There was an issue with the client request', { message: optionalIncomingMessage || error.message, errorDetails: error });
59
69
  }
60
- else context.log.warn('There was an issue with the client request', { message: optionalIncomingMessage || error.message, errorDetails: error });
61
70
 
62
71
  return { status, message, errorCode };
63
72
  };
@@ -13,14 +13,12 @@ module.exports = (result, isSingleItemResponse = true) => {
13
13
  status = 404;
14
14
  message = 'not found';
15
15
  result = undefined; // eslint-disable-line no-param-reassign
16
- }
17
- else {
16
+ } else {
18
17
  status = 200;
19
18
  message = 'ok';
20
19
  result = []; // eslint-disable-line no-param-reassign
21
20
  }
22
- }
23
- else {
21
+ } else {
24
22
  status = 200;
25
23
  message = 'ok';
26
24
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "exframe-middleware",
3
- "version": "1.3.0",
3
+ "version": "1.4.1",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "config": {
@@ -23,8 +23,8 @@
23
23
  "devDependencies": {
24
24
  "chai": "*",
25
25
  "eslint": "*",
26
- "eslint-config-airbnb-base": "*",
27
- "eslint-plugin-import": "^2.22.0",
26
+ "eslint-config-exzeo": "*",
27
+ "eslint-plugin-import": "*",
28
28
  "mocha": "*",
29
29
  "mocha-exzeo-reporter": "*",
30
30
  "nyc": "*",
@@ -33,5 +33,8 @@
33
33
  "dependencies": {
34
34
  "exframe-errors": "^1.2.0"
35
35
  },
36
- "gitHead": "1959247957f1a308c44d4c5210712125ab6e5573"
36
+ "engines": {
37
+ "node": ">=14.0.0"
38
+ },
39
+ "gitHead": "ef87c842aa08c54cbcb03ee075db8463ebc8fd43"
37
40
  }
@@ -1,5 +1,3 @@
1
1
  {
2
- "env": {
3
- "mocha": true
4
- }
5
- }
2
+ "extends": "exzeo/mocha"
3
+ }
@@ -6,26 +6,61 @@ const errors = require('exframe-errors');
6
6
  const { authorizeUser } = require('../index');
7
7
 
8
8
  context('authorizeUser', () => {
9
- it('throws unauthorized error when no user', () => {
10
- try { authorizeUser.mq({}); }
11
- catch (e) {
12
- expect(e).to.be.an.instanceOf(errors.Unauthorized);
13
- return;
14
- }
15
-
16
- expect.fail('authorizeUser should have thrown an Unauthorized error');
17
- });
9
+ describe('mq', () => {
10
+ it('throws unauthorized error when no user', () => {
11
+ try { authorizeUser.mq({}); }
12
+ catch (e) {
13
+ expect(e).to.be.an.instanceOf(errors.Unauthorized);
14
+ return;
15
+ }
16
+
17
+ expect.fail('authorizeUser should have thrown an Unauthorized error');
18
+ });
18
19
 
19
- it('does not throw an error when there is a user', () => {
20
- try { authorizeUser.mq({ user: 'something' }); }
21
- catch (e) { expect.fail('authorizeUser should not have thrown an error'); }
20
+ it('does not throw an error when there is a user', () => {
21
+ try { authorizeUser.mq({ user: 'something' }); }
22
+ catch (e) { expect.fail('authorizeUser should not have thrown an error'); }
23
+ });
22
24
  });
23
25
 
24
- it('works when there is a user and calls next when using express version', () => {
25
- let called = 0;
26
- const next = () => ++called;
27
- authorizeUser.express({ user: {} }, {}, next);
26
+ describe('express - user exists directly on the request object', () => {
27
+ it('calls the next function when there is a user', () => {
28
+ let called = 0;
29
+ const next = () => ++called;
30
+ authorizeUser.express({ user: {} }, {}, next);
31
+
32
+ expect(called).to.equal(1);
33
+ });
34
+ it('throws unauthorized error when there is no user', () => {
35
+ let called = 0;
36
+ const next = () => ++called;
37
+ try { authorizeUser.express({ }, {}, next); }
38
+ catch (e) {
39
+ expect(e).to.be.an.instanceOf(errors.Unauthorized);
40
+ return;
41
+ }
42
+ expect.fail('authorizeUser should have thrown an Unauthorized error');
43
+ expect(called).to.equal(0);
44
+ });
45
+ });
28
46
 
29
- expect(called).to.equal(1);
47
+ describe('express - user exists within the context on the request object', () => {
48
+ it('calls the next function when there is a user', () => {
49
+ let called = 0;
50
+ const next = () => ++called;
51
+ authorizeUser.express({ context: { user: {} } }, {}, next);
52
+ expect(called).to.equal(1);
53
+ });
54
+ it('throws unauthorized error when there is no user', () => {
55
+ let called = 0;
56
+ const next = () => ++called;
57
+ try { authorizeUser.express({ context: {} }, {}, next); }
58
+ catch (e) {
59
+ expect(e).to.be.an.instanceOf(errors.Unauthorized);
60
+ return;
61
+ }
62
+ expect.fail('authorizeUser should have thrown an Unauthorized error');
63
+ expect(called).to.equal(0);
64
+ });
30
65
  });
31
66
  });