@thzero/library_server_fastify 0.15.32 → 0.15.33

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/boot/index.js CHANGED
@@ -1,9 +1,11 @@
1
1
  import path from 'path';
2
2
 
3
3
  import Fastify from 'fastify';
4
- import fastifyAuth from 'fastify-auth';
4
+ // import fastifyAuth from 'fastify-auth';
5
+ import fastifyAuth from '../plugins/auth';
5
6
  import fastifyCors from 'fastify-cors';
6
7
  import fastifyHelmet from 'fastify-helmet';
8
+ import fastifyRoutes from 'fastify-routes';
7
9
  import fastifyStatic from 'fastify-static';
8
10
 
9
11
  import LibraryConstants from '@thzero/library_server/constants';
@@ -17,6 +19,9 @@ import pluginResponseTime from '@thzero/library_server_fastify/plugins/responseT
17
19
  import pluginSettings from '@thzero/library_server_fastify/plugins/settings';
18
20
  import pluginUsageMetrics from '@thzero/library_server_fastify/plugins/usageMetrics';
19
21
 
22
+ import authenticationDefault from '../middleware/authentication';
23
+ import authorizationDefault from '../middleware/authorization';
24
+
20
25
  class FastifyBootMain extends BootMain {
21
26
  async _initApp(args, plugins) {
22
27
 
@@ -32,6 +37,8 @@ class FastifyBootMain extends BootMain {
32
37
  const fastify = Fastify({ logger: true });
33
38
  const serverHttp = fastify.server;
34
39
 
40
+ await fastify.register(fastifyRoutes);
41
+
35
42
  // // https://github.com/koajs/cors
36
43
  // app.use(koaCors({
37
44
  // allowMethods: 'GET,POST,DELETE',
@@ -41,23 +48,37 @@ class FastifyBootMain extends BootMain {
41
48
  // origin: '*'
42
49
  // }));
43
50
  // https://github.com/fastify/fastify-cors
44
- fastify.register(fastifyCors, {
45
- allowMethods: 'GET,POST,DELETE',
46
- maxAge : 7200,
47
- allowHeaders: `${LibraryConstants.Headers.AuthKeys.API}, ${LibraryConstants.Headers.AuthKeys.AUTH}, ${LibraryConstants.Headers.CorrelationId}, Content-Type`,
51
+ // fastify.register(fastifyCors, {
52
+ // allowMethods: 'GET,POST,DELETE',
53
+ // maxAge : 7200,
54
+ // allowHeaders: `${LibraryConstants.Headers.AuthKeys.API}, ${LibraryConstants.Headers.AuthKeys.AUTH}, ${LibraryConstants.Headers.CorrelationId}, Content-Type`,
55
+ // credentials: true,
56
+ // origin: '*'
57
+ // });
58
+ const corsOptionsDefault = this._initCors({
59
+ allowHeaders: [ LibraryConstants.Headers.AuthKeys.API, LibraryConstants.Headers.AuthKeys.AUTH, LibraryConstants.Headers.CorrelationId, 'Content-Type' ],
48
60
  credentials: true,
61
+ maxAge : 7200,
62
+ methods: ['GET', 'POST', 'DELETE'],
49
63
  origin: '*'
50
64
  });
65
+ await fastify.register(fastifyCors, (instance) => {
66
+ return (req, callback) => {
67
+ let corsOptions = corsOptionsDefault;
68
+ callback(null, corsOptions) // callback expects two parameters: error and options
69
+ }
70
+ });
51
71
 
52
72
  // // https://www.npmjs.com/package/koa-helmet
53
73
  // app.use(koaHelmet());
54
74
  // https://github.com/fastify/fastify-helmet
55
- fastify.register(
56
- fastifyHelmet,
75
+ const helmetOptions = this._initHelmet({
57
76
  // Example disables the `contentSecurityPolicy` middleware but keeps the rest.
58
- {
59
- // contentSecurityPolicy: false
60
- }
77
+ // contentSecurityPolicy: false
78
+ });
79
+ await fastify.register(
80
+ fastifyHelmet,
81
+ helmetOptions
61
82
  );
62
83
 
63
84
  // // error
@@ -77,7 +98,7 @@ class FastifyBootMain extends BootMain {
77
98
  // });
78
99
  // }
79
100
  // });
80
- fastify.register(async (instance, opts, done) => {
101
+ await fastify.register(async (instance, opts, done) => {
81
102
  // try {
82
103
  // done();
83
104
  // }
@@ -117,7 +138,7 @@ class FastifyBootMain extends BootMain {
117
138
 
118
139
  // done();
119
140
  // });
120
- fastify.register(pluginSettings, {
141
+ await fastify.register(pluginSettings, {
121
142
  config: this._appConfig
122
143
  });
123
144
 
@@ -136,14 +157,14 @@ class FastifyBootMain extends BootMain {
136
157
  // ctx.set(ResponseTime, delta);
137
158
  // });
138
159
  // https://github.com/lolo32/fastify-response-time
139
- fastify.register(pluginResponseTime, {
160
+ await fastify.register(pluginResponseTime, {
140
161
  logger: this.loggerServiceI
141
162
  });
142
163
 
143
164
  // app.use(koaStatic('./public'));
144
165
  // https://github.com/fastify/fastify-static
145
166
  const __dirname = path.resolve();
146
- fastify.register(fastifyStatic, {
167
+ await fastify.register(fastifyStatic, {
147
168
  root: path.join(__dirname, 'public'),
148
169
  prefix: '/public/', // optional: default '/'
149
170
  });
@@ -218,15 +239,20 @@ class FastifyBootMain extends BootMain {
218
239
 
219
240
  // done();
220
241
  // });
221
- fastify.register(pluginApiKey, {
242
+ await fastify.register(pluginApiKey, {
222
243
  logger: this.loggerServiceI,
223
244
  usageMetrics: this.usageMetricsServiceI
224
245
  });
225
246
 
226
- fastify.register(fastifyAuth, {
227
- logger: this.loggerServiceI,
228
- usageMetrics: this.usageMetricsServiceI
229
- });
247
+ await fastify.register(fastifyAuth);
248
+
249
+ const capitalize = (word) => {
250
+ return word[0].toUpperCase() + word.slice(1).toLowerCase();
251
+ };
252
+ for (let [key, value] of this._initAuthentication(new Map()).entries())
253
+ fastify.decorate('authentication' + capitalize(key), value);
254
+ for (let [key, value] of this._initAuthorization(new Map()).entries())
255
+ fastify.decorate('authorization' + capitalize(key), value);
230
256
 
231
257
  this._initPostAuth(fastify);
232
258
 
@@ -242,15 +268,18 @@ class FastifyBootMain extends BootMain {
242
268
  console.log();
243
269
 
244
270
  for (const route of this._routes) {
271
+ console.log(route);
245
272
  await route.init(injector, fastify, this._appConfig);
273
+ }
246
274
 
247
- console.log([ route.id ]);
248
-
249
- // for (let i = 0; i < route.router.stack.length; i++)
250
- // console.log([ route.router.stack[i].path, route.router.stack[i].methods ]);
251
-
252
- console.log();
275
+ let methods;
276
+ for (let [key, value] of fastify.routes.entries()) {
277
+ methods = [];
278
+ for (let item of value)
279
+ methods.push(item.method);
280
+ console.log([ key, methods ]);
253
281
  }
282
+ console.log();
254
283
 
255
284
  // // usage metrics
256
285
  // app.use(async (ctx, next) => {
@@ -259,7 +288,7 @@ class FastifyBootMain extends BootMain {
259
288
  // this.loggerServiceI.error('KoaBootMain', 'start', 'usageMetrics', err);
260
289
  // });
261
290
  // });
262
- fastify.register(pluginUsageMetrics, {
291
+ await fastify.register(pluginUsageMetrics, {
263
292
  logger: this.loggerServiceI,
264
293
  usageMetrics: this.usageMetricsServiceI
265
294
  });
@@ -267,6 +296,16 @@ class FastifyBootMain extends BootMain {
267
296
  return { app: fastify, server: serverHttp, listen: fastify.listen };
268
297
  }
269
298
 
299
+ _initAuthentication(map) {
300
+ map.set('default', authenticationDefault);
301
+ return map;
302
+ }
303
+
304
+ _initAuthorization(map) {
305
+ map.set('default', authorizationDefault);
306
+ return map;
307
+ }
308
+
270
309
  _initAppListen(app, server, port, err) {
271
310
  app.listen(port, err);
272
311
  }
@@ -275,6 +314,15 @@ class FastifyBootMain extends BootMain {
275
314
  this._initPostRoutes(app);
276
315
  }
277
316
 
317
+ _initCors(options) {
318
+ // https://github.com/fastify/fastify-cors
319
+ return options;
320
+ }
321
+
322
+ _initHelmet(options) {
323
+ return options;
324
+ }
325
+
278
326
  _initRoute(route) {
279
327
  this._routes.push(route);
280
328
  }
@@ -1,8 +1,18 @@
1
1
  import BaseApiFrontBootPlugin from '@thzero/library_server/boot/plugins/apiFront';
2
2
 
3
+ import homeRoute from '../../routes/home';
3
4
  import utilityRoute from '../../routes/utility';
5
+ import versionRoute from '../../routes/version';
4
6
 
5
7
  class FrontApiBootPlugin extends BaseApiFrontBootPlugin {
8
+ _initRoutesHome() {
9
+ return new homeRoute();
10
+ }
11
+
12
+ _initRoutesVersion() {
13
+ return new versionRoute();
14
+ }
15
+
6
16
  _initRoutesUtility() {
7
17
  return new utilityRoute();
8
18
  }
@@ -1,11 +1,6 @@
1
1
  import BaseExtendedUsersApiBootPlugin from '@thzero/library_server/boot/plugins/usersExtended';
2
2
 
3
- import plansService from '../../service/plans';
4
-
5
3
  class ExtendedUsersApiBootPlugin extends BaseExtendedUsersApiBootPlugin {
6
- _initServicesPlans() {
7
- return new plansService();
8
- }
9
4
  }
10
5
 
11
6
  export default ExtendedUsersApiBootPlugin;
@@ -0,0 +1,78 @@
1
+ import LibraryConstants from '@thzero/library_server/constants';
2
+ import LibraryCommonServiceConstants from '@thzero/library_common_service/constants';
3
+
4
+ import injector from '@thzero/library_common/utility/injector';
5
+
6
+ const separator = ': ';
7
+
8
+ function getAuthToken(request, logger) {
9
+ if (!request)
10
+ return null;
11
+ if (!logger)
12
+ return null;
13
+
14
+ const token = request.headers[LibraryConstants.Headers.AuthKeys.AUTH];
15
+ logger.debug('middleware', 'getAuthToken', 'token', token, request.correlationId);
16
+ const split = token.split(LibraryConstants.Headers.AuthKeys.AUTH_BEARER + separator);
17
+ logger.debug('middleware', 'getAuthToken', 'split', split, request.correlationId);
18
+ logger.debug('middleware', 'getAuthToken', 'split.length', split.length, request.correlationId);
19
+ if (split.length > 1)
20
+ return split[1];
21
+
22
+ logger.debug('middleware', 'getAuthToken', 'fail', null, request.correlationId);
23
+ return null;
24
+ }
25
+
26
+ export default async (request, reply, done, options) => {
27
+ const logger = injector.getService(LibraryCommonServiceConstants.InjectorKeys.SERVICE_LOGGER);
28
+
29
+ const required = options && (options.required !== null) && (options.required !== undefined) ? options.required : true;
30
+
31
+ const token = getAuthToken(request, logger);
32
+ logger.debug('middleware', 'authentication', 'token', token, request.correlationId);
33
+ logger.debug('middleware', 'authentication', 'required', required, request.correlationId);
34
+ const valid = ((required && !String.isNullOrEmpty(token)) || !required);
35
+ logger.debug('middleware', 'authentication', 'valid', valid, request.correlationId);
36
+ if (valid) {
37
+ if (!String.isNullOrEmpty(token)) {
38
+ const service = injector.getService(LibraryConstants.InjectorKeys.SERVICE_AUTH);
39
+ const results = await service.verifyToken(request.correlationId, token);
40
+ logger.debug('middleware', 'authentication', 'results', results, request.correlationId);
41
+ if (!results || !results.success) {
42
+ logger.warn('middleware', 'authentication', 'Unauthenticated... invalid token', null, request.correlationId);
43
+ ctx.throw(401);
44
+ return;
45
+ }
46
+
47
+ request.token = token;
48
+ request.user = results.user;
49
+ request.claims = results.claims;
50
+ }
51
+
52
+ // done(); // not for async
53
+ return;
54
+ }
55
+
56
+ (async () => {
57
+ const usageMetrics = {
58
+ url: request.routerPath,
59
+ correlationId: request.correlationId,
60
+ href: request.url,
61
+ headers: request.headers,
62
+ host: request.hostname,
63
+ hostname: request.hostname,
64
+ querystring: request.query,
65
+ token: request.token
66
+ };
67
+ const serviceUsageMetrics = injector.getService(LibraryConstants.InjectorKeys.SERVICE_USAGE_METRIC);
68
+ await serviceUsageMetrics.register(usageMetrics).catch((err) => {
69
+ // const logger = injector.getService(LibraryCommonServiceConstants.InjectorKeys.SERVICE_LOGGER);
70
+ logger.error('middleware', 'authentication', err, null, request.correlationId);
71
+ });
72
+ })();
73
+
74
+ logger.warn('middleware', 'authentication', 'Unauthorized... authentication unknown', null, request.correlationId);
75
+ // reply.code(401);
76
+ // done(new Error('Unauthorized... authentication unknown')); // not for async
77
+ throw new Error('Unauthorized... authentication unknown');
78
+ }
@@ -0,0 +1,200 @@
1
+ import LibraryConstants from '@thzero/library_server/constants';
2
+ import LibraryCommonServiceConstants from '@thzero/library_common_service/constants';
3
+
4
+ import injector from '@thzero/library_common/utility/injector';
5
+
6
+ // require('../utility/string.cjs');
7
+ String.isNullOrEmpty = function(value) {
8
+ //return !(typeof value === 'string' && value.length > 0)
9
+ return !value;
10
+ }
11
+
12
+ String.isString = function(value) {
13
+ return (typeof value === "string" || value instanceof String);
14
+ }
15
+
16
+ String.trim = function(value) {
17
+ if (!value || !String.isString(value))
18
+ return value;
19
+ return value.trim();
20
+ }
21
+
22
+ const logicalAnd = 'and';
23
+ const logicalOr = 'or';
24
+
25
+ const authorizationCheckClaims = async (request, success, logical, security, logger) => {
26
+ if (!request)
27
+ return false;
28
+ if (!(request.claims && Array.isArray(request.claims)))
29
+ return false;
30
+
31
+ let result;
32
+ let roleAct;
33
+ let roleObj;
34
+ let roleParts;
35
+ for (const claim of request.claims) {
36
+ logger.debug('middleware', 'authorization', 'authorization.claim', claim, request.correlationId);
37
+
38
+ for (const role of request.roles) {
39
+ logger.debug('middleware', 'authorization', 'role', role, request.correlationId);
40
+
41
+ roleParts = role.split('.');
42
+ if (roleParts && roleParts.length < 1)
43
+ success = false;
44
+
45
+ roleObj = roleParts[0];
46
+ roleAct = roleParts.length >= 2 ? roleParts[1] : null
47
+
48
+ result = await security.validate(claim, null, roleObj, roleAct);
49
+ logger.debug('middleware', 'authorization', 'result', result, request.correlationId);
50
+ if (logical === logicalOr)
51
+ success = success || result;
52
+ else
53
+ success = success && result;
54
+ }
55
+ }
56
+
57
+ return success;
58
+ }
59
+
60
+ const authorizationCheckRoles = async (request, success, logical, security, logger) => {
61
+ if (!request)
62
+ return false;
63
+
64
+ logger.debug('middleware', 'authorizationCheckRoles', 'user', request.user, request.correlationId);
65
+ if (!(request.user && request.user.roles && Array.isArray(request.user.roles)))
66
+ return false;
67
+
68
+ logger.debug('middleware', 'authorizationCheckRoles', 'logical', logical, request.correlationId);
69
+
70
+ let result;
71
+ let roleAct;
72
+ let roleObj;
73
+ let roleParts;
74
+ for (const userRole of request.user.roles) {
75
+ logger.debug('middleware', 'authorizationCheckRoles', 'userRole', userRole, request.correlationId);
76
+
77
+ for (const role of request.roles) {
78
+ logger.debug('middleware', 'authorizationCheckRoles', 'role', role, request.correlationId);
79
+
80
+ roleParts = role.split('.');
81
+ if (roleParts && roleParts.length < 1)
82
+ success = false;
83
+
84
+ roleObj = roleParts[0];
85
+ roleAct = roleParts.length >= 2 ? roleParts[1] : null
86
+
87
+ result = await security.validate(userRole, null, roleObj, roleAct);
88
+ logger.debug('middleware', 'authorizationCheckRoles', 'result', result, request.correlationId);
89
+ if (logical === logicalOr) {
90
+ if (result)
91
+ return result;
92
+
93
+ success = false;
94
+ }
95
+ else
96
+ success = success && result;
97
+ }
98
+ }
99
+
100
+ return success;
101
+ }
102
+
103
+ const initalizeRoles = (request, roles, logger) => {
104
+ if (Array.isArray(roles)) {
105
+ // logger.debug('middleware', 'initalizeRoles', 'roles1a', roles);
106
+ request.roles = roles;
107
+ }
108
+ else if ((typeof(roles) === 'string') || (roles instanceof String)) {
109
+ // logger.debug('middleware', 'initalizeRoles', 'roles1b', roles);
110
+ request.roles = roles.split(',');
111
+ request.roles.map(item => item ? item.trim() : item);
112
+ }
113
+ }
114
+
115
+ // const authorization = (roles, logical) => {
116
+ // if (String.isNullOrEmpty(logical) || (logical !== logicalAnd) || (logical !== logicalOr))
117
+ // logical = logicalOr;
118
+
119
+ export default async (request, reply, done, options) => {
120
+ let logical = logicalOr;
121
+ let roles = [];
122
+ if (options) {
123
+ logical = options.logical;
124
+ if (String.isNullOrEmpty(logical) || (logical !== logicalAnd) || (logical !== logicalOr))
125
+ logical = logicalOr;
126
+
127
+ if (options.roles && Array.isArray(options.roles) && (options.roles.length > 0))
128
+ roles = options.roles;
129
+ }
130
+
131
+ const config = injector.getService(LibraryCommonServiceConstants.InjectorKeys.SERVICE_CONFIG);
132
+ const logger = injector.getService(LibraryCommonServiceConstants.InjectorKeys.SERVICE_LOGGER);
133
+ const security = injector.getService(LibraryConstants.InjectorKeys.SERVICE_SECURITY);
134
+
135
+ // logger.debug('token', request.token);
136
+ logger.debug('middleware', 'authorization', 'user', request.user, request.correlationId);
137
+ logger.debug('middleware', 'authorization', 'claims', request.claims, request.correlationId);
138
+ logger.debug('middleware', 'authorization', 'roles1', roles, request.correlationId);
139
+ request.roles = [];
140
+ if (roles) {
141
+ // logger.debug('authorization.roles1', roles);
142
+ // logger.debug('authorization.roles1', (typeof roles));
143
+ // logger.debug('authorization.roles1', Array.isArray(roles));
144
+ // logger.debug('authorization.roles1', ((typeof(roles) === 'string') || (roles instanceof String)));
145
+ // if (Array.isArray(roles)) {
146
+ // // logger.debug('authorization.roles1a', roles);
147
+ // request.roles = roles;
148
+ // }
149
+ // else if ((typeof(roles) === 'string') || (roles instanceof String)) {
150
+ // // logger.debug('authorization.roles1b', roles);
151
+ // request.roles = roles.split(',');
152
+ // request.roles.map(item => item ? item.trim() : item);
153
+ // }
154
+ initalizeRoles(request, roles, logger);
155
+ }
156
+ logger.debug('middleware', 'authorization', 'roles2', request.roles, request.correlationId);
157
+
158
+ let success = false; //(logical === logicalOr ? false : true);
159
+ if (request.roles && Array.isArray(request.roles) && (request.roles.length > 0)) {
160
+ const auth = config.get('auth');
161
+ if (auth) {
162
+ logger.debug('middleware', 'authorization', 'auth.claims', auth.claims, request.correlationId);
163
+ logger.debug('middleware', 'authorization', 'auth.claims.check', auth.claims.check, request.correlationId);
164
+ }
165
+ if (auth && auth.claims && auth.claims.check)
166
+ success = await authorizationCheckClaims(request, (logical === logicalOr ? false : true), logical, security, logger);
167
+
168
+ if (!success)
169
+ success = await authorizationCheckRoles(request, (logical === logicalOr ? false : true), logical, security, logger);
170
+ }
171
+
172
+ logger.debug('middleware', 'authorization', 'success', null, request.success, request.correlationId);
173
+ if (success) {
174
+ // done(); // not for async
175
+ return;
176
+ }
177
+
178
+ (async () => {
179
+ const usageMetrics = {
180
+ url: request.routerPath,
181
+ correlationId: request.correlationId,
182
+ href: request.url,
183
+ headers: request.headers,
184
+ host: request.hostname,
185
+ hostname: request.hostname,
186
+ querystring: request.query,
187
+ token: request.token
188
+ };
189
+ const serviceUsageMetrics = injector.getService(LibraryConstants.InjectorKeys.SERVICE_USAGE_METRIC);
190
+ await serviceUsageMetrics.register(usageMetrics).catch((err) => {
191
+ // const logger = injector.getService(LibraryCommonServiceConstants.InjectorKeys.SERVICE_LOGGER);
192
+ logger.error('middleware', 'authorization', err, null, request.correlationId);
193
+ });
194
+ })();
195
+
196
+ logger.warn('middleware', 'authorization', 'Unauthorized... authorization unknown', null, request.correlationId);
197
+ // reply.code(401);
198
+ // done(new Error('Unauthorized... authentication unknown')); // not for async
199
+ throw new Error('Unauthorized... authentication unknown');
200
+ }
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@thzero/library_server_fastify",
3
3
  "type": "module",
4
- "version": "0.15.32",
4
+ "version": "0.15.33",
5
5
  "version_major": 0,
6
6
  "version_minor": 15,
7
- "version_patch": 32,
8
- "version_date": "04/18/2022",
7
+ "version_patch": 33,
8
+ "version_date": "04/19/2022",
9
9
  "description": "An opinionated library of common functionality to bootstrap a Fastify based API application.",
10
10
  "author": "thZero",
11
11
  "license": "MIT",
@@ -31,11 +31,9 @@
31
31
  "fastify-auth": "^1.1.0",
32
32
  "fastify-cors": "^6.0.3",
33
33
  "fastify-helmet": "^7.0.1",
34
+ "fastify-routes": "^3.1.0",
34
35
  "fastify-static": "^4.6.1"
35
36
  },
36
- "devDependencies": {
37
- "@thzero/library_cli": "^0.15"
38
- },
39
37
  "peerDependencies": {
40
38
  "@thzero/library_common": "^0.15",
41
39
  "@thzero/library_common_service": "^0.15"
@@ -0,0 +1,123 @@
1
+ 'use strict'
2
+
3
+ // const fp = require('fastify-plugin')
4
+ import fp from 'fastify-plugin'
5
+ // const reusify = require('reusify')
6
+ import reusify from 'reusify'
7
+
8
+ function checkAuth (fastify, opts, next) {
9
+ fastify.decorate('auth', auth)
10
+ next()
11
+ }
12
+
13
+ function auth (functions, opts) {
14
+ if (!Array.isArray(functions)) {
15
+ throw new Error('You must give an array of functions to the auth function')
16
+ }
17
+ if (!functions.length) {
18
+ throw new Error('Missing auth functions')
19
+ }
20
+
21
+ const options = Object.assign({
22
+ relation: 'or',
23
+ run: null
24
+ }, opts)
25
+
26
+ if (options.relation !== 'or' && options.relation !== 'and') {
27
+ throw new Error('The value of options.relation should be one of [\'or\', \'and\']')
28
+ }
29
+ if (options.run && options.run !== 'all') {
30
+ throw new Error('The value of options.run must be \'all\'')
31
+ }
32
+
33
+ /* eslint-disable-next-line no-var */
34
+ for (var i = 0; i < functions.length; i++) {
35
+ functions[i] = functions[i].bind(this)
36
+ }
37
+
38
+ const instance = reusify(Auth)
39
+
40
+ function _auth (request, reply, done) {
41
+ const obj = instance.get()
42
+
43
+ obj.request = request
44
+ obj.reply = reply
45
+ obj.done = done
46
+ obj.functions = this.functions
47
+ obj.options = this.options
48
+ obj.i = 0
49
+ obj.start = true
50
+ obj.firstResult = null
51
+
52
+ obj.nextAuth()
53
+ }
54
+
55
+ return _auth.bind({ functions, options })
56
+
57
+ function Auth () {
58
+ this.next = null
59
+ this.i = 0
60
+ this.start = true
61
+ this.functions = []
62
+ this.options = {}
63
+ this.request = null
64
+ this.reply = null
65
+ this.done = null
66
+ this.firstResult = null
67
+
68
+ const that = this
69
+
70
+ this.nextAuth = function nextAuth (err) {
71
+ const func = that.functions[that.i++]
72
+
73
+ if (!func) {
74
+ that.completeAuth(err)
75
+ return
76
+ }
77
+
78
+ const maybePromise = func(that.request, that.reply, that.onAuth, that.options)
79
+
80
+ if (maybePromise && typeof maybePromise.then === 'function') {
81
+ maybePromise.then(results => that.onAuth(null, results), that.onAuth)
82
+ }
83
+ }
84
+
85
+ this.onAuth = function onAuth (err, results) {
86
+ if (that.options.relation === 'or') {
87
+ if (err) {
88
+ return that.nextAuth(err)
89
+ }
90
+
91
+ return that.completeAuth()
92
+ } else {
93
+ if (err) {
94
+ return that.completeAuth(err)
95
+ }
96
+
97
+ return that.nextAuth(err)
98
+ }
99
+ }
100
+
101
+ this.completeAuth = function (err) {
102
+ if (that.start) {
103
+ that.start = false
104
+ that.firstResult = err
105
+ }
106
+
107
+ if (that.options.run === 'all' && that.i < that.functions.length) {
108
+ return that.nextAuth(err)
109
+ }
110
+
111
+ if (that.firstResult && (!that.reply.raw.statusCode || that.reply.raw.statusCode < 400)) {
112
+ that.reply.code(401)
113
+ } else if (!that.firstResult && that.reply.raw.statusCode && that.reply.raw.statusCode >= 400) {
114
+ that.reply.code(200)
115
+ }
116
+
117
+ that.done(that.firstResult)
118
+ instance.release(that)
119
+ }
120
+ }
121
+ }
122
+
123
+ export default fp(checkAuth, '3.x')
@@ -65,24 +65,29 @@ export default fastifyPlugin((instance, opts, done) => {
65
65
 
66
66
  // Hook to be triggered just before response to be send
67
67
  instance.addHook('onSend', (request, reply, payload, next) => {
68
+ const headers = [];
69
+
68
70
  // check if Server-Timing need to be added
69
71
  const serverTiming = (reply.raw ? reply.raw[symbolServerTiming] : reply.res[symbolServerTiming]);
70
- const headers = [];
71
- for (const name of Object.keys(serverTiming)) {
72
- headers.push(serverTiming[name]);
73
- }
74
- if (headers.length) {
75
- reply.header('Server-Timing', headers.join(','));
72
+ if (serverTiming) {
73
+ for (const name of Object.keys(serverTiming)) {
74
+ headers.push(serverTiming[name]);
75
+ }
76
+ if (headers.length) {
77
+ reply.header('Server-Timing', headers.join(','));
78
+ }
76
79
  }
77
80
 
78
81
  // Calculate the duration, in nanoseconds …
79
82
  const hrDuration = (request.raw ? request.raw[symbolRequestTime] : request.req[symbolRequestTime]);
80
- // convert it to milliseconds …
81
- const duration = (hrDuration[0] * 1e3 + hrDuration[1] / 1e6).toFixed(opts.digits);
82
- // add the header to the response
83
- reply.header(opts.header, duration);
83
+ if (hrDuration) {
84
+ // convert it to milliseconds
85
+ const duration = (hrDuration[0] * 1e3 + hrDuration[1] / 1e6).toFixed(opts.digits);
86
+ // … add the header to the response
87
+ reply.header(opts.header, duration);
84
88
 
85
- opts.logger.info2(`${request.method} ${request.url} - ${duration}`);
89
+ opts.logger.info2(`${request.method} ${request.url} - ${duration}`);
90
+ }
86
91
 
87
92
  next();
88
93
  });
@@ -1,12 +1,7 @@
1
- import koaBody from 'koa-body';
2
-
3
- import Utility from '@thzero/library_common/utility';
1
+ import LibraryUtility from '@thzero/library_common/utility';
4
2
 
5
3
  import BaseRoute from '../index';
6
4
 
7
- import authentication from '../../middleware/authentication';
8
- import authorization from '../../middleware/authorization';
9
-
10
5
  class AdminBaseRoute extends BaseRoute {
11
6
  constructor(urlFragment, role, serviceKey) {
12
7
  if (!urlFragment)
@@ -22,10 +17,9 @@ class AdminBaseRoute extends BaseRoute {
22
17
  // this._service = null;
23
18
  }
24
19
 
25
- async init(injector, config) {
26
- const router = await super.init(injector, config);
27
- router.service = injector.getService(this._options.serviceKey);
28
- // this._service = injector.getService(this._options.serviceKey);
20
+ async init(injector, app, config) {
21
+ await super.init(injector, app, config);
22
+ this._inject(app, injector, this._options.serviceKey, this._options.serviceKey);
29
23
  }
30
24
 
31
25
  _allowsCreate() {
@@ -42,51 +36,67 @@ class AdminBaseRoute extends BaseRoute {
42
36
 
43
37
  _initializeRoutesCreate(router) {
44
38
  const self = this;
45
- router.post('/',
46
- authentication(true),
47
- authorization([ `${self._options.role}.create` ]),
48
- koaBody({
49
- text: false,
50
- }),
39
+ router.post(this._join('/'),
40
+ // authentication(true),
41
+ // authorization([ `${self._options.role}.create` ]),
42
+ {
43
+ preHandler: router.auth([
44
+ router.authenticationDefault,
45
+ router.authorizationDefault
46
+ ],
47
+ {
48
+ relation: 'and',
49
+ roles: [ `${self._options.role}.create` ]
50
+ }),
51
+ },
51
52
  // eslint-disable-next-line
52
- async (ctx, next) => {
53
- // const service = this._injector.getService(this._options.serviceKey);
54
- // const response = (await router.service.create(ctx.correlationId, ctx.state.user, ctx.request.body)).check(ctx);
55
- const response = (await ctx.router.service.create(ctx.correlationId, ctx.state.user, ctx.request.body)).check(ctx);
56
- this._jsonResponse(ctx, Utility.stringify(response));
53
+ async (request, reply) => {
54
+ const response = (await router[this._options.serviceKey].create(request.correlationId, request.user, request.body)).check(request);
55
+ this._jsonResponse(reply, LibraryUtility.stringify(response));
57
56
  }
58
57
  );
59
58
  }
60
59
 
61
60
  _initializeRoutesDelete(router) {
62
- const self = this;
63
- router.delete('/:id',
64
- authentication(true),
65
- authorization([ `${self._options.role}.delete` ]),
61
+ router.delete(this._join('/:id'),
62
+ // authentication(true),
63
+ // authorization([ `${this._options.role}.delete` ]),
64
+ {
65
+ preHandler: router.auth([
66
+ router.authenticationDefault,
67
+ router.authorizationDefault
68
+ ],
69
+ {
70
+ relation: 'and',
71
+ roles: [ `${this._options.role}.delete` ]
72
+ }),
73
+ },
66
74
  // eslint-disable-next-line
67
- async (ctx, next) => {
68
- // const service = this._injector.getService(this._options.serviceKey);
69
- // const response = (await service.delete(ctx.correlationId, ctx.state.user, ctx.params.id)).check(ctx);
70
- const response = (await ctx.router.service.delete(ctx.correlationId, ctx.state.user, ctx.params.id)).check(ctx);
71
- this._jsonResponse(ctx, Utility.stringify(response));
75
+ async (request, reply) => {
76
+ const response = (await router[this._options.serviceKey].delete(request.correlationId, request.user, request.params.id)).check(request);
77
+ this._jsonResponse(reply, LibraryUtility.stringify(response));
72
78
  }
73
79
  );
74
80
  }
75
81
 
76
82
  _initializeRoutesUpdate(router) {
77
- const self = this;
78
- router.post('/:id',
79
- authentication(true),
80
- authorization([ `${self._options.role}.update` ]),
81
- koaBody({
82
- text: false,
83
- }),
83
+ router.post(this._join('/:id'),
84
+ // authentication(true),
85
+ // authorization([ `${this._options.role}.update` ]),
86
+ {
87
+ preHandler: router.auth([
88
+ router.authenticationDefault,
89
+ router.authorizationDefault
90
+ ],
91
+ {
92
+ relation: 'and',
93
+ roles: [ `${this._options.role}.update` ]
94
+ }),
95
+ },
84
96
  // eslint-disable-next-line
85
- async (ctx, next) => {
86
- // const service = this._injector.getService(this._options.serviceKey);
87
- // const response = (await service.update(ctx.correlationId, ctx.state.user, ctx.params.id, ctx.request.body)).check(ctx);
88
- const response = (await ctx.router.service.update(ctx.correlationId, ctx.state.user, ctx.params.id, ctx.request.body)).check(ctx);
89
- this._jsonResponse(ctx, Utility.stringify(response));
97
+ async (request, reply) => {
98
+ const response = (await router[this._options.serviceKey].update(request.correlationId, request.user, request.params.id, request.body)).check(request);
99
+ this._jsonResponse(reply, LibraryUtility.stringify(response));
90
100
  }
91
101
  );
92
102
  }
@@ -95,18 +105,23 @@ class AdminBaseRoute extends BaseRoute {
95
105
  if (this._allowsDelete)
96
106
  this._initializeRoutesDelete(router);
97
107
 
98
- router.post('/search',
99
- authentication(true),
100
- authorization([ `${this._options.role}.search` ]),
101
- koaBody({
102
- text: false,
103
- }),
108
+ router.post(this._join('/search'),
109
+ // authentication(true),
110
+ // authorization([ `${this._options.role}.search` ]),
111
+ {
112
+ preHandler: router.auth([
113
+ router.authenticationDefault,
114
+ router.authorizationDefault
115
+ ],
116
+ {
117
+ relation: 'and',
118
+ roles: [ `${this._options.role}.search` ]
119
+ }),
120
+ },
104
121
  // eslint-disable-next-line
105
- async (ctx, next) => {
106
- // const service = this._injector.getService(this._options.serviceKey);
107
- // const response = (await service.search(ctx.correlationId, ctx.state.user, ctx.request.body)).check(ctx);
108
- const response = (await ctx.router.service.search(ctx.correlationId, ctx.state.user, ctx.request.body)).check(ctx);
109
- this._jsonResponse(ctx, Utility.stringify(response));
122
+ async (request, reply) => {
123
+ const response = (await router[this._options.serviceKey].search(request.correlationId, request.user, request.body)).check(request);
124
+ this._jsonResponse(reply, LibraryUtility.stringify(response));
110
125
  }
111
126
  );
112
127
 
@@ -1,4 +1,4 @@
1
- import LibraryConstants from '../../constants';
1
+ import LibraryConstants from '@thzero/library_server/constants';
2
2
 
3
3
  import AdminRoute from './index'
4
4
 
@@ -1,4 +1,4 @@
1
- import LibraryConstants from '../../constants';
1
+ import LibraryConstants from '@thzero/library_server/constants';
2
2
 
3
3
  import AdminRoute from './index'
4
4
 
@@ -1,11 +1,9 @@
1
- import LibraryConstants from '../constants';
1
+ import LibraryConstants from '@thzero/library_server/constants';
2
2
 
3
3
  import Utility from '@thzero/library_common/utility';
4
4
 
5
5
  import BaseRoute from './index';
6
6
 
7
- import authentication from '../middleware/authentication';
8
-
9
7
  class BaseNewsRoute extends BaseRoute {
10
8
  constructor(prefix, version) {
11
9
  super(prefix ? prefix : '/news');
@@ -24,12 +22,22 @@ class BaseNewsRoute extends BaseRoute {
24
22
  }
25
23
 
26
24
  _initializeRoutes(router) {
27
- // authentication(false),
28
25
  router.get(this._join('/latest/:date'),
26
+ // authentication(false),
27
+ {
28
+ preHandler: router.auth([
29
+ router.authenticationDefault,
30
+ // router.authorizationDefault
31
+ ],
32
+ {
33
+ relation: 'and',
34
+ required: false,
35
+ roles: [ 'news' ]
36
+ }),
37
+ },
29
38
  async (request, reply) => {
30
39
  // const service = this._injector.getService(LibraryConstants.InjectorKeys.SERVICE_NEWS);
31
- // const response = (await service.latest(ctx.correlationId, ctx.state.user, parseInt(ctx.params.date))).check(ctx);
32
- const response = (await request.serviceNews.latest(request.correlationId, request.user, parseInt(request.params.date))).check(request);
40
+ const response = (await router[LibraryConstants.InjectorKeys.SERVICE_NEWS].latest(request.correlationId, request.user, parseInt(request.params.date))).check(request);
33
41
  this._jsonResponse(reply, Utility.stringify(response));
34
42
  });
35
43
  }
@@ -1,14 +1,9 @@
1
- import koaBody from 'koa-body';
2
-
3
- import LibraryConstants from '../constants';
1
+ import LibraryConstants from '@thzero/library_server/constants';
4
2
 
5
3
  import Utility from '@thzero/library_common/utility';
6
4
 
7
5
  import BaseRoute from './index';
8
6
 
9
- import authentication from '../middleware/authentication';
10
- import authorization from '../middleware/authorization';
11
-
12
7
  class BaseUsersRoute extends BaseRoute {
13
8
  constructor(prefix, version) {
14
9
  super(prefix ? prefix : '/users');
@@ -35,9 +30,20 @@ class BaseUsersRoute extends BaseRoute {
35
30
  }
36
31
 
37
32
  _initializeRoutesGamerById(router) {
38
- return router.get('/gamerId/:gamerId',
33
+ return router.get(this._join('/gamerId/:gamerId'),
39
34
  // authentication(false),
40
35
  // // authorization('user'),
36
+ {
37
+ preHandler: router.auth([
38
+ router.authenticationDefault,
39
+ // router.authorizationDefault
40
+ ],
41
+ {
42
+ relation: 'and',
43
+ required: false,
44
+ roles: [ 'user' ]
45
+ }),
46
+ },
41
47
  // eslint-disable-next-line
42
48
  async (request, reply) => {
43
49
  // const service = this._injector.getService(LibraryConstants.InjectorKeys.SERVICE_USERS);
@@ -48,9 +54,20 @@ class BaseUsersRoute extends BaseRoute {
48
54
  }
49
55
 
50
56
  _initializeRoutesGamerByTag(router) {
51
- return router.get('/gamerTag/:gamerTag',
57
+ return router.get(this._join('/gamerTag/:gamerTag'),
52
58
  // authentication(false),
53
59
  // // authorization('user'),
60
+ {
61
+ preHandler: router.auth([
62
+ router.authenticationDefault,
63
+ // router.authorizationDefault
64
+ ],
65
+ {
66
+ relation: 'and',
67
+ required: false,
68
+ roles: [ 'user' ]
69
+ }),
70
+ },
54
71
  // eslint-disable-next-line
55
72
  async (request, reply) => {
56
73
  // const service = this._injector.getService(LibraryConstants.InjectorKeys.SERVICE_USERS);
@@ -61,9 +78,19 @@ class BaseUsersRoute extends BaseRoute {
61
78
  }
62
79
 
63
80
  _initializeRoutesRefreshSettings(router) {
64
- return router.post('/refresh/settings',
81
+ return router.post(this._join('/refresh/settings'),
65
82
  // authentication(true),
66
83
  // authorization('user'),
84
+ {
85
+ preHandler: router.auth([
86
+ router.authenticationDefault,
87
+ router.authorizationDefault
88
+ ],
89
+ {
90
+ relation: 'and',
91
+ roles: [ 'user' ]
92
+ }),
93
+ },
67
94
  // eslint-disable-next-line
68
95
  async (request, reply) => {
69
96
  // const service = this._injector.getService(LibraryConstants.InjectorKeys.SERVICE_USERS);
@@ -74,9 +101,19 @@ class BaseUsersRoute extends BaseRoute {
74
101
  }
75
102
 
76
103
  _initializeRoutesUpdate(router) {
77
- return router.post('/update',
104
+ return router.post(this._join('/update'),
78
105
  // authentication(true),
79
106
  // authorization('user'),
107
+ {
108
+ preHandler: router.auth([
109
+ router.authenticationDefault,
110
+ // router.authorizationDefault
111
+ ],
112
+ {
113
+ relation: 'and',
114
+ roles: [ 'user' ]
115
+ }),
116
+ },
80
117
  // eslint-disable-next-line
81
118
  async (request, reply) => {
82
119
  // const service = this._injector.getService(LibraryConstants.InjectorKeys.SERVICE_USERS);
@@ -87,9 +124,19 @@ class BaseUsersRoute extends BaseRoute {
87
124
  }
88
125
 
89
126
  _initializeRoutesUpdateSettings(router) {
90
- return router.post('/update/settings',
127
+ return router.post(this._join('/update/settings'),
91
128
  // authentication(true),
92
129
  // authorization('user'),
130
+ {
131
+ preHandler: router.auth([
132
+ router.authenticationDefault,
133
+ router.authorizationDefault
134
+ ],
135
+ {
136
+ relation: 'and',
137
+ roles: [ 'user' ]
138
+ }),
139
+ },
93
140
  // eslint-disable-next-line
94
141
  async (request, reply) => {
95
142
  // const service = this._injector.getService(LibraryConstants.InjectorKeys.SERVICE_USERS);
package/routes/plans.js CHANGED
@@ -1,4 +1,4 @@
1
- import LibraryConstants from '../constants';
1
+ import LibraryConstants from '@thzero/library_server/constants';
2
2
 
3
3
  import Utility from '@thzero/library_common/utility';
4
4
 
@@ -24,9 +24,9 @@ class PlansRoute extends BaseRoute {
24
24
  _initializeRoutes(router) {
25
25
  router.get(this._join('/'),
26
26
  // eslint-disable-next-line
27
- async (ctx, next) => {
27
+ async (request, reply) => {
28
28
  // const service = this._injector.getService(LibraryConstants.InjectorKeys.SERVICE_PLANS);
29
- const response = (await router[LibraryConstants.InjectorKeys.SERVICE_PLANS].logger(request.correlationI)).check(request);
29
+ const response = (await router[LibraryConstants.InjectorKeys.SERVICE_PLANS].listing(request.correlationId, request.body)).check(request);
30
30
  this._jsonResponse(reply, Utility.stringify(response));
31
31
  }
32
32
  );
package/routes/utility.js CHANGED
@@ -1,14 +1,9 @@
1
- import koaBody from 'koa-body';
2
-
3
- import LibraryConstants from '../constants';
1
+ import LibraryConstants from '@thzero/library_server/constants';
4
2
 
5
3
  import Utility from '@thzero/library_common/utility';
6
4
 
7
5
  import BaseRoute from './index';
8
6
 
9
- import authentication from '../middleware/authentication';
10
- // import authorization from '../middleware/authorization';
11
-
12
7
  class UtilityRoute extends BaseRoute {
13
8
  constructor(prefix) {
14
9
  super(prefix ? prefix : '/utility');
@@ -28,16 +23,23 @@ class UtilityRoute extends BaseRoute {
28
23
 
29
24
  _initializeRoutes(router) {
30
25
  router.post('/logger',
31
- authentication(false),
32
- // authorization('utility'),
33
- // eslint-disable-next-line,
34
- koaBody({
35
- text: false,
36
- }),
37
- async (ctx, next) => {
26
+ // authentication(false),
27
+ // // authorization('utility'),
28
+ {
29
+ preHandler: router.auth([
30
+ router.authenticationDefault,
31
+ // router.authorizationDefault
32
+ ],
33
+ {
34
+ relation: 'and',
35
+ required: false,
36
+ roles: [ 'utility' ]
37
+ }),
38
+ },
39
+ // eslint-disable-next-line
40
+ async (request, reply) => {
38
41
  // const service = this._injector.getService(LibraryConstants.InjectorKeys.SERVICE_UTILITY);
39
- // const response = (await service.logger(ctx.correlationId, ctx.request.body)).check(ctx);
40
- const response = (await router[LibraryConstants.InjectorKeys.SERVICE_UTILITY].logger(request.correlationI, request.body)).check(request);
42
+ const response = (await router[LibraryConstants.InjectorKeys.SERVICE_UTILITY].logger(request.correlationId, request.body)).check(request);
41
43
  this._jsonResponse(reply, Utility.stringify(response));
42
44
  }
43
45
  );