lesgo 0.7.8 → 1.0.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.
@@ -1,5 +1,4 @@
1
1
  import client from 'Config/client'; // eslint-disable-line import/no-unresolved
2
- import { errorHttpResponseAfterHandler } from './errorHttpResponseMiddleware';
3
2
  import validateFields from '../utils/validateFields';
4
3
  import { LesgoException } from '../exceptions';
5
4
 
@@ -7,7 +6,7 @@ const FILE = 'Middlewares/clientAuthMiddleware';
7
6
 
8
7
  const validateParams = params => {
9
8
  const validFields = [
10
- { key: 'x-client-id', type: 'string', required: true },
9
+ { key: 'clientKey', type: 'string', required: true },
11
10
  { key: 'client', type: 'object', required: true },
12
11
  ];
13
12
 
@@ -21,8 +20,28 @@ const validateParams = params => {
21
20
  };
22
21
 
23
22
  const getClientKey = event => {
24
- if (typeof event.headers['x-client-id'] === 'string') {
25
- return event.headers['x-client-id'];
23
+ const foundExistingKey = client.headerKeys.find(headerKey => {
24
+ if (event.headers && typeof event.headers[headerKey] === 'string') {
25
+ return true;
26
+ }
27
+
28
+ if (
29
+ event.queryStringParameters &&
30
+ typeof event.queryStringParameters[headerKey] === 'string'
31
+ ) {
32
+ return true;
33
+ }
34
+
35
+ return false;
36
+ });
37
+
38
+ if (foundExistingKey) {
39
+ if (event.headers && event.headers[foundExistingKey]) {
40
+ return event.headers[foundExistingKey];
41
+ }
42
+
43
+ // There will always be one where this is found existing
44
+ return event.queryStringParameters[foundExistingKey];
26
45
  }
27
46
 
28
47
  if (event.input && typeof event.input.clientid === 'string') {
@@ -32,20 +51,23 @@ const getClientKey = event => {
32
51
  return undefined;
33
52
  };
34
53
 
35
- export const clientAuthMiddlewareBeforeHandler = (
54
+ export const clientAuthMiddlewareBeforeHandler = async (
36
55
  handler,
37
56
  next,
38
- opt = undefined
57
+ opt = {}
39
58
  ) => {
40
- const validated = validateParams({
41
- 'x-client-id': getClientKey(handler.event),
42
- client,
43
- });
59
+ const { clients, callback } = {
60
+ ...client,
61
+ ...(typeof opt === 'function' ? { callback: opt } : opt),
62
+ };
44
63
 
45
- const clientKey = validated['x-client-id'];
64
+ const { client: validatedClient, clientKey } = validateParams({
65
+ clientKey: getClientKey(handler.event),
66
+ client: clients,
67
+ });
46
68
 
47
- const platform = Object.keys(validated.client).filter(clientPlatform => {
48
- return validated.client[clientPlatform].key === clientKey;
69
+ const platform = Object.keys(validatedClient).filter(clientPlatform => {
70
+ return validatedClient[clientPlatform].key === clientKey;
49
71
  });
50
72
 
51
73
  if (platform.length === 0) {
@@ -58,13 +80,13 @@ export const clientAuthMiddlewareBeforeHandler = (
58
80
  }
59
81
 
60
82
  // eslint-disable-next-line no-param-reassign,prefer-destructuring
61
- handler.event.platform = platform[0];
83
+ handler.event.platform = {
84
+ id: platform[0],
85
+ ...client.clients[platform[0]],
86
+ };
62
87
 
63
- if (typeof opt === 'function') {
64
- opt(handler);
65
- } else if (typeof opt === 'object') {
66
- const { callback } = opt;
67
- if (typeof callback === 'function') callback(handler);
88
+ if (typeof callback === 'function') {
89
+ await callback(handler);
68
90
  }
69
91
 
70
92
  next();
@@ -75,7 +97,6 @@ const clientAuthMiddleware = opt => {
75
97
  return {
76
98
  before: (handler, next) =>
77
99
  clientAuthMiddlewareBeforeHandler(handler, next, opt),
78
- onError: (handler, next) => errorHttpResponseAfterHandler(handler, next),
79
100
  };
80
101
  };
81
102
 
@@ -66,7 +66,9 @@ export const errorHttpResponseHandler = async opts => {
66
66
  return {
67
67
  headers: options.headers,
68
68
  statusCode,
69
- body: JSON.stringify(jsonBody),
69
+ body: options.formatError
70
+ ? options.formatError(options)
71
+ : JSON.stringify(jsonBody),
70
72
  };
71
73
  };
72
74
 
@@ -3,15 +3,19 @@ import { normalizeHttpRequestBeforeHandler } from './normalizeHttpRequestMiddlew
3
3
  import { successHttpResponseHandler } from './successHttpResponseMiddleware';
4
4
  import { errorHttpResponseHandler } from './errorHttpResponseMiddleware';
5
5
 
6
+ const allowResponse = () => {
7
+ return app.debug;
8
+ };
9
+
6
10
  const successHttpNoOutputResponseHandler = async opts => {
7
11
  const { queryStringParameters } = opts.event;
8
- const debug =
9
- queryStringParameters && queryStringParameters.debug && app.debug;
12
+ const debug = queryStringParameters && queryStringParameters.debug;
10
13
  const response = await successHttpResponseHandler(opts);
14
+ const shouldAllowResponse = opts.allowResponse || allowResponse;
11
15
 
12
16
  /* istanbul ignore next */
13
- if (!debug && !opts.allowResponse(opts)) {
14
- response.body = null;
17
+ if (!debug || !shouldAllowResponse(opts)) {
18
+ response.body = '';
15
19
  }
16
20
 
17
21
  return response;
@@ -25,7 +29,7 @@ export const successHttpNoOutputResponseAfterHandler = async (
25
29
  const defaults = {
26
30
  response: handler.response,
27
31
  event: handler.event,
28
- allowResponse: () => false,
32
+ allowResponse,
29
33
  };
30
34
  const options = { ...defaults, ...opts };
31
35
 
@@ -38,16 +42,16 @@ export const successHttpNoOutputResponseAfterHandler = async (
38
42
 
39
43
  const errorHttpResponseNoOutputHandler = async opts => {
40
44
  const { queryStringParameters } = opts.event;
41
- const debug =
42
- queryStringParameters && queryStringParameters.debug && app.debug;
45
+ const debug = queryStringParameters && queryStringParameters.debug;
43
46
  const response = await errorHttpResponseHandler({
44
47
  ...opts,
45
48
  debugMode: opts.debugMode || debug,
46
49
  });
50
+ const shouldAllowResponse = opts.allowResponse || allowResponse;
47
51
 
48
- if (!debug && !opts.allowResponse(opts)) {
52
+ if (!debug || !shouldAllowResponse(opts)) {
49
53
  response.statusCode = 200;
50
- response.body = null;
54
+ response.body = '';
51
55
  }
52
56
 
53
57
  return response;
@@ -62,7 +66,7 @@ export const errorHttpNoOutputResponseAfterHandler = async (
62
66
  error: handler.error,
63
67
  event: handler.event,
64
68
  logger: console.error, // eslint-disable-line no-console
65
- allowResponse: () => false,
69
+ allowResponse,
66
70
  };
67
71
 
68
72
  const options = { ...defaults, ...opts };
@@ -4,6 +4,8 @@ import successHttpResponseMiddleware from './successHttpResponseMiddleware';
4
4
  import errorHttpResponseMiddleware from './errorHttpResponseMiddleware';
5
5
  import normalizeSQSMessageMiddleware from './normalizeSQSMessageMiddleware';
6
6
  import verifyJwtMiddleware from './verifyJwtMiddleware';
7
+ import basicAuthMiddleware from './basicAuthMiddleware';
8
+ import clientAuthMiddleware from './clientAuthMiddleware';
7
9
 
8
10
  export {
9
11
  httpMiddleware,
@@ -12,4 +14,6 @@ export {
12
14
  errorHttpResponseMiddleware,
13
15
  normalizeSQSMessageMiddleware,
14
16
  verifyJwtMiddleware,
17
+ basicAuthMiddleware,
18
+ clientAuthMiddleware,
15
19
  };
@@ -43,11 +43,13 @@ export const successHttpResponseHandler = async opts => {
43
43
  return {
44
44
  headers: options.headers,
45
45
  statusCode: options.statusCode,
46
- body: JSON.stringify({
47
- status: 'success',
48
- data: options.response,
49
- _meta: options.debugMode ? options.event : {},
50
- }),
46
+ body: options.formatSuccess
47
+ ? options.formatSuccess(options)
48
+ : JSON.stringify({
49
+ status: 'success',
50
+ data: options.response,
51
+ _meta: options.debugMode ? options.event : {},
52
+ }),
51
53
  };
52
54
  };
53
55
 
@@ -26,7 +26,7 @@ export const token = headers => {
26
26
  return parsed[1];
27
27
  };
28
28
 
29
- export const verifyJwtMiddlewareBeforeHandler = (handler, next, opts) => {
29
+ export const verifyJwtMiddlewareBeforeHandler = async (handler, next, opts) => {
30
30
  const { headers } = handler.event;
31
31
 
32
32
  const finalConfig =
@@ -34,18 +34,29 @@ export const verifyJwtMiddlewareBeforeHandler = (handler, next, opts) => {
34
34
  ? opts.jwtConfig
35
35
  : config;
36
36
 
37
+ const { secret, callback } = finalConfig;
38
+
37
39
  try {
38
- const service = new JwtService(token(headers), finalConfig);
40
+ const service = new JwtService(token(headers), {
41
+ ...finalConfig,
42
+ ...{
43
+ secret: typeof secret === 'function' ? secret(handler) : secret,
44
+ },
45
+ });
39
46
 
40
47
  // eslint-disable-next-line no-param-reassign
41
48
  handler.event.decodedJwt = service.validate().decoded;
42
49
 
50
+ if (typeof callback === 'function') {
51
+ await callback(handler);
52
+ }
53
+
43
54
  next();
44
55
  } catch (err) {
45
56
  if (err.name === 'JsonWebTokenError') {
46
- throw new LesgoException(err.message, 'JWT_ERROR', 403);
57
+ throw new LesgoException(err.message, 'JWT_ERROR', 403, err);
47
58
  } else if (err.name === 'TokenExpiredError') {
48
- throw new LesgoException(err.message, 'JWT_EXPIRED', 403);
59
+ throw new LesgoException(err.message, 'JWT_EXPIRED', 403, err);
49
60
  } else {
50
61
  throw err;
51
62
  }
@@ -30,8 +30,9 @@ export default class LoggerService {
30
30
  this.logLevels = {
31
31
  error: 0,
32
32
  warn: 1,
33
- info: 2,
34
- debug: 3,
33
+ notice: 2,
34
+ info: 3,
35
+ debug: 4,
35
36
  };
36
37
  }
37
38
 
@@ -63,6 +64,10 @@ export default class LoggerService {
63
64
  this.log('debug', message, extra);
64
65
  }
65
66
 
67
+ notice(message, extra = {}) {
68
+ this.log('notice', message, extra);
69
+ }
70
+
66
71
  addMeta(meta = {}) {
67
72
  this.meta = {
68
73
  ...this.meta,
@@ -73,7 +78,9 @@ export default class LoggerService {
73
78
  consoleLogger(level, message) {
74
79
  if (!this.checkIsLogRequired('console', level)) return null;
75
80
  const refinedMessage = this.refineMessagePerTransport('console', message);
76
- return console[level](JSON.stringify(refinedMessage)); // eslint-disable-line no-console
81
+ const consoleFunc = level === 'notice' ? 'log' : level;
82
+
83
+ return console[consoleFunc](JSON.stringify(refinedMessage)); // eslint-disable-line no-console
77
84
  }
78
85
 
79
86
  checkIsLogRequired(transportName, level) {
@@ -13,8 +13,9 @@ describe('ServicesGroup: test LoggerService instantiation', () => {
13
13
  expect(logger.logLevels).toMatchObject({
14
14
  error: 0,
15
15
  warn: 1,
16
- info: 2,
17
- debug: 3,
16
+ notice: 2,
17
+ info: 3,
18
+ debug: 4,
18
19
  });
19
20
  });
20
21
 
@@ -146,6 +147,20 @@ describe('ServicesGroup: test log LoggerService with console transport', () => {
146
147
  );
147
148
  });
148
149
 
150
+ it('test log with notice level', () => {
151
+ const logger = new LoggerService({ transports: [{ logType: 'console' }] });
152
+ logger.notice('some notice log');
153
+
154
+ expect(console.log).toHaveBeenCalledWith(
155
+ JSON.stringify({
156
+ level: 'notice',
157
+ message: 'some notice log',
158
+ logger: 'lesgo-logger',
159
+ extra: {},
160
+ })
161
+ );
162
+ });
163
+
149
164
  it('test log with error level', () => {
150
165
  const logger = new LoggerService({ transports: [{ logType: 'console' }] });
151
166
  logger.error('some error log');
package/CHANGELOG.md DELETED
@@ -1,9 +0,0 @@
1
- # Changes as of November 11, 2019:
2
- - Added DatabaseService
3
- - where you could connect thru your own sql server (mysql, posgres and etc.)
4
- - Added ElasticSearchService
5
- - this service provides a connection that can connect thru local or AWS' ElasticSearch as of the moment.
6
- - Added JwtService
7
- - to validate jwt access token, and custom claims.
8
- - Added ElastiCacheService
9
- - a service that can use memcached/redis for in-memory key-value search.
@@ -1,170 +0,0 @@
1
- import serverAuthMiddleware, {
2
- serverAuthBeforeHandler,
3
- } from '../serverAuthMiddleware';
4
- import { generateBasicAuthorizationHash } from '../basicAuthMiddleware';
5
- import client from '../../../tests/__mocks__/config/client';
6
-
7
- describe('test serverAuthMiddleware middleware', () => {
8
- test.each`
9
- clientObj
10
- ${undefined}
11
- ${{}}
12
- ${{
13
- default: {
14
- key: '1111-1111-1111-1111',
15
- secret: '1111-1111-1111-1111',
16
- },
17
- }}
18
- `('should return object', ({ clientObj }) => {
19
- const result = serverAuthMiddleware({
20
- client: clientObj,
21
- });
22
-
23
- expect(result).toHaveProperty('before');
24
- expect(result).toHaveProperty('onError');
25
- });
26
- });
27
-
28
- // eslint-disable-next-line
29
- const next = () => {};
30
-
31
- describe('test serverAuthBeforeHandler with valid credentials', () => {
32
- const validBasicAuth = Buffer.from(
33
- generateBasicAuthorizationHash(
34
- client.platform_2.key,
35
- client.platform_2.secret
36
- )
37
- ).toString('base64');
38
-
39
- test.each`
40
- clientObj
41
- ${undefined}
42
- ${{}}
43
- ${{
44
- platform_2: {
45
- key: '2222-2222-2222-2222',
46
- secret: '2222-2222-2222-2222',
47
- },
48
- }}
49
- `('should return undefined when successful', ({ clientObj }) => {
50
- const handler = {
51
- event: {
52
- headers: {
53
- Authorization: `basic ${validBasicAuth}`,
54
- },
55
- site: {
56
- id: 'platform_2',
57
- },
58
- },
59
- };
60
-
61
- let hasError = false;
62
-
63
- try {
64
- serverAuthBeforeHandler(handler, next, {
65
- client: clientObj,
66
- });
67
- } catch (e) {
68
- hasError = true;
69
- }
70
-
71
- expect(hasError).toBeFalsy();
72
- });
73
-
74
- test.each`
75
- Authorization | blacklistMode
76
- ${undefined} | ${false}
77
- ${`basic ${validBasicAuth}`} | ${false}
78
- ${`Basic ${validBasicAuth}`} | ${false}
79
- ${`basic ${validBasicAuth}`} | ${true}
80
- ${`Basic ${validBasicAuth}`} | ${true}
81
- `(
82
- 'test Exception with valid credentials',
83
- ({ Authorization, blacklistMode }) => {
84
- const handler = {
85
- event: {
86
- headers: {
87
- Authorization,
88
- },
89
- site: {
90
- id: 'platform_2',
91
- },
92
- },
93
- };
94
-
95
- let hasError = false;
96
-
97
- try {
98
- serverAuthBeforeHandler(handler, next, {
99
- blacklistMode,
100
- });
101
- } catch (e) {
102
- hasError = true;
103
- }
104
-
105
- expect(hasError).toBeFalsy();
106
- }
107
- );
108
- });
109
-
110
- describe('test serverAuthBeforeHandler error handling', () => {
111
- const invalidClientKey = Buffer.from('client_key:secret_key').toString(
112
- 'base64'
113
- );
114
- const invalidSecretKey = Buffer.from(
115
- `${client.platform_2.key}:secret_key`
116
- ).toString('base64');
117
-
118
- test.each`
119
- headers | errorName | errorMessage | errorStatusCode | errorCode | blacklistMode
120
- ${{}} | ${'LesgoException'} | ${'Authorization Header is required!'} | ${403} | ${'JWT_MISSING_AUTHORIZATION_HEADER'} | ${undefined}
121
- ${{ Authorization: 'auth' }} | ${'LesgoException'} | ${'Missing Bearer token!'} | ${403} | ${'JWT_MISSING_BEARER_TOKEN'} | ${undefined}
122
- ${{ Authorization: 'basic ' }} | ${'LesgoException'} | ${'Empty basic authentication hash provided'} | ${403} | ${'Middlewares/basicAuthMiddleware::AUTH_EMPTY_BASIC_HASH'} | ${undefined}
123
- ${{ Authorization: `basic ${invalidClientKey}` }} | ${'LesgoException'} | ${'Invalid client key or secret provided'} | ${403} | ${'Middlewares/basicAuthMiddleware::AUTH_INVALID_CLIENT_OR_SECRET_KEY'} | ${undefined}
124
- ${{ Authorization: `basic ${invalidSecretKey}` }} | ${'LesgoException'} | ${'Invalid client key or secret provided'} | ${403} | ${'Middlewares/basicAuthMiddleware::AUTH_INVALID_CLIENT_OR_SECRET_KEY'} | ${undefined}
125
- ${{ Authorization: `Basic ${invalidSecretKey}` }} | ${'LesgoException'} | ${'Invalid client key or secret provided'} | ${403} | ${'Middlewares/basicAuthMiddleware::AUTH_INVALID_CLIENT_OR_SECRET_KEY'} | ${undefined}
126
- ${{}} | ${'LesgoException'} | ${'Authorization Header is required!'} | ${403} | ${'JWT_MISSING_AUTHORIZATION_HEADER'} | ${true}
127
- ${{ Authorization: 'auth' }} | ${'LesgoException'} | ${'Missing Bearer token!'} | ${403} | ${'JWT_MISSING_BEARER_TOKEN'} | ${true}
128
- ${{ Authorization: 'basic ' }} | ${'LesgoException'} | ${'Empty basic authentication hash provided'} | ${403} | ${'Middlewares/basicAuthMiddleware::AUTH_EMPTY_BASIC_HASH'} | ${true}
129
- ${{ Authorization: `basic ${invalidClientKey}` }} | ${'LesgoException'} | ${'Invalid client key or secret provided'} | ${403} | ${'Middlewares/basicAuthMiddleware::AUTH_INVALID_CLIENT_OR_SECRET_KEY'} | ${true}
130
- ${{ Authorization: `basic ${invalidSecretKey}` }} | ${'LesgoException'} | ${'Invalid client key or secret provided'} | ${403} | ${'Middlewares/basicAuthMiddleware::AUTH_INVALID_CLIENT_OR_SECRET_KEY'} | ${true}
131
- ${{ Authorization: `Basic ${invalidSecretKey}` }} | ${'LesgoException'} | ${'Invalid client key or secret provided'} | ${403} | ${'Middlewares/basicAuthMiddleware::AUTH_INVALID_CLIENT_OR_SECRET_KEY'} | ${true}
132
- ${{ Authorization: 'auth' }} | ${'LesgoException'} | ${'Missing Bearer token!'} | ${403} | ${'JWT_MISSING_BEARER_TOKEN'} | ${false}
133
- ${{ Authorization: 'basic ' }} | ${'LesgoException'} | ${'Empty basic authentication hash provided'} | ${403} | ${'Middlewares/basicAuthMiddleware::AUTH_EMPTY_BASIC_HASH'} | ${false}
134
- ${{ Authorization: `basic ${invalidClientKey}` }} | ${'LesgoException'} | ${'Invalid client key or secret provided'} | ${403} | ${'Middlewares/basicAuthMiddleware::AUTH_INVALID_CLIENT_OR_SECRET_KEY'} | ${false}
135
- ${{ Authorization: `basic ${invalidSecretKey}` }} | ${'LesgoException'} | ${'Invalid client key or secret provided'} | ${403} | ${'Middlewares/basicAuthMiddleware::AUTH_INVALID_CLIENT_OR_SECRET_KEY'} | ${false}
136
- ${{ Authorization: `Basic ${invalidSecretKey}` }} | ${'LesgoException'} | ${'Invalid client key or secret provided'} | ${403} | ${'Middlewares/basicAuthMiddleware::AUTH_INVALID_CLIENT_OR_SECRET_KEY'} | ${false}
137
- `(
138
- 'should throw $errorMessage when authorization header is $headers',
139
- async ({
140
- headers,
141
- errorName,
142
- errorMessage,
143
- errorStatusCode,
144
- errorCode,
145
- blacklistMode,
146
- }) => {
147
- const handler = {
148
- event: {
149
- headers,
150
- site: {
151
- id: 'platform_1',
152
- },
153
- },
154
- };
155
-
156
- try {
157
- expect(
158
- serverAuthBeforeHandler(handler, next, {
159
- blacklistMode,
160
- })
161
- ).toThrow();
162
- } catch (error) {
163
- expect(error.name).toBe(errorName);
164
- expect(error.message).toBe(errorMessage);
165
- expect(error.statusCode).toBe(errorStatusCode);
166
- expect(error.code).toBe(errorCode);
167
- }
168
- }
169
- );
170
- });
@@ -1,29 +0,0 @@
1
- import { verifyBasicAuthBeforeHandler } from './basicAuthMiddleware';
2
- import { verifyJwtMiddlewareBeforeHandler } from './verifyJwtMiddleware';
3
- import { errorHttpResponseAfterHandler } from './errorHttpResponseMiddleware';
4
-
5
- export const serverAuthBeforeHandler = (handler, next, opts) => {
6
- try {
7
- return verifyBasicAuthBeforeHandler(handler, next, opts);
8
- } catch (e) {
9
- if (
10
- e.code !==
11
- `Middlewares/basicAuthMiddleware::AUTH_INVALID_AUTHORIZATION_TYPE` &&
12
- e.code !==
13
- `Middlewares/basicAuthMiddleware::AUTHORIZATION_HEADER_NOT_FOUND`
14
- )
15
- throw e;
16
- }
17
-
18
- return verifyJwtMiddlewareBeforeHandler(handler, next, opts);
19
- };
20
-
21
- /* istanbul ignore next */
22
- const serverAuthMiddleware = opts => {
23
- return {
24
- before: (handler, next) => serverAuthBeforeHandler(handler, next, opts),
25
- onError: (handler, next) => errorHttpResponseAfterHandler(handler, next),
26
- };
27
- };
28
-
29
- export default serverAuthMiddleware;