@volcanicminds/backend 0.2.10 → 0.2.12
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/Dockerfile +1 -2
- package/dist/index.js +1 -11
- package/dist/index.js.map +1 -1
- package/index.ts +30 -21
- package/lib/api/auth/controller/auth.ts +27 -0
- package/lib/api/auth/routes.ts +64 -0
- package/lib/api/health/controller/health.ts +5 -0
- package/lib/api/health/routes.ts +30 -0
- package/lib/api/users/controller/user.ts +2 -2
- package/lib/api/users/routes.ts +5 -2
- package/lib/hooks/onError.ts +2 -1
- package/lib/hooks/onRequest.ts +39 -11
- package/lib/hooks/onResponse.ts +9 -6
- package/lib/hooks/preSerialization.ts +1 -1
- package/lib/loader/router.ts +4 -11
- package/lib/loader/schemas.ts +1 -1
- package/lib/middleware/isAdmin.ts +1 -1
- package/lib/middleware/isAuthenticated.ts +0 -1
- package/package.json +2 -1
- package/types/global.d.ts +1 -0
package/Dockerfile
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
FROM node:18-alpine
|
|
1
|
+
FROM --platform=linux/amd64 node:18-alpine
|
|
2
2
|
|
|
3
3
|
LABEL version="0.1.0"
|
|
4
4
|
LABEL description="Volcanic Backend"
|
|
@@ -12,7 +12,6 @@ COPY package*.json yarn.lock ./
|
|
|
12
12
|
COPY lib lib/
|
|
13
13
|
|
|
14
14
|
RUN yarn install
|
|
15
|
-
RUN apk --no-cache add curl
|
|
16
15
|
|
|
17
16
|
# Bundle app source
|
|
18
17
|
COPY . .
|
package/dist/index.js
CHANGED
|
@@ -114,17 +114,7 @@ function addFastifySwagger(fastify) {
|
|
|
114
114
|
docExpansion: 'list',
|
|
115
115
|
deepLinking: true,
|
|
116
116
|
defaultModelsExpandDepth: 1
|
|
117
|
-
}
|
|
118
|
-
uiHooks: {
|
|
119
|
-
onRequest: function (request, reply, next) {
|
|
120
|
-
next();
|
|
121
|
-
},
|
|
122
|
-
preHandler: function (request, reply, next) {
|
|
123
|
-
next();
|
|
124
|
-
}
|
|
125
|
-
},
|
|
126
|
-
staticCSP: true,
|
|
127
|
-
transformStaticCSP: (header) => header
|
|
117
|
+
}
|
|
128
118
|
});
|
|
129
119
|
}
|
|
130
120
|
});
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,YAAY,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEZ,oDAA2B;AAC3B,gBAAM,CAAC,MAAM,EAAE,CAAA;AAEf,uDAA8B;AAC9B,+DAAsC;AACtC,sDAAuC;AACvC,gEAAiD;AACjD,kEAAmD;AACnD,gEAAiD;AACjD,oEAAqD;AAErD,sDAAkD;AAClD,+DAAsC;AACtC,qEAA2C;AAE3C,yDAAgC;AAChC,6DAAoC;AACpC,iEAAwC;AACxC,qEAA2C;AAE3C,2CAA6C;AAC7C,oEAAkF;AAClF,kDAAmE;AACnE,uEAA8C;AAC9C,uEAA6C;AAE7C,MAAM,CAAC,GAAG,GAAG,gBAAM,CAAA;AAEnB,SAAe,YAAY,CAAC,OAAwB;;QAClD,GAAG,CAAC,IAAI,CAAC,gCAAgC,CAAC,CAAA;QAC1C,MAAM,MAAM,GAAG,IAAI,qBAAY,CAAY;YACzC,QAAQ,EAAR,mBAAQ;YACR,SAAS,EAAT,mBAAS;YACT,OAAO,EAAE,CAAC,IAAA,kCAAwB,EAAC,OAAO,CAAC,CAAC;SAC7C,CAAC,CAAA;QAEF,MAAM,MAAM,CAAC,KAAK,EAAE,CAAA;QAEpB,OAAO,MAAM,CAAA;IACf,CAAC;CAAA;AAED,SAAe,gBAAgB,CAAC,OAAwB,EAAE,MAAsC;;QAC9F,IAAI,MAAM,EAAE;YACV,GAAG,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAA;YAC/B,MAAM,OAAO,CAAC,QAAQ,CAAC,IAAA,iBAAa,EAAC,MAAM,CAAC,EAAE;gBAC5C,OAAO,EAAE,2BAAiB;aAC3B,CAAC,CAAA;SASH;IACH,CAAC;CAAA;AAED,SAAe,iBAAiB,CAAC,OAAwB;;QACvD,GAAG,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAA;QAE/B,WAAW,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;QAC1B,aAAa,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;QAE5B,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,EAAE,CAAA;QAClC,MAAM,IAAI,YAAY,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;IAC/C,CAAC;CAAA;AAED,SAAe,iBAAiB,CAAC,OAAwB;;QACvD,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,eAAe,EAAE,kBAAkB,EAAE,YAAY,EAAE,GAChH,OAAO,CAAC,GAAG,CAAA;QAEb,MAAM,WAAW,GAAG,IAAA,YAAE,EAAC,OAAO,EAAE,KAAK,CAAC,CAAA;QACtC,IAAI,WAAW,IAAI,QAAQ,KAAK,YAAY,EAAE;YAC5C,GAAG,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAA;YAE/B,MAAM,OAAO,CAAC,QAAQ,CAAC,iBAAO,EAAE;gBAC9B,OAAO,EAAE;oBACP,IAAI,EAAE;wBACJ,KAAK,EAAE,aAAa,IAAI,mBAAmB;wBAC3C,WAAW,EAAE,mBAAmB,IAAI,2CAA2C;wBAC/E,OAAO,EAAE,eAAe,IAAI,OAAO;qBACpC;oBACD,IAAI,EAAE,YAAY,IAAI,gBAAgB;oBACtC,OAAO,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC;oBAC1B,QAAQ,EAAE,CAAC,kBAAkB,CAAC;oBAC9B,QAAQ,EAAE,CAAC,kBAAkB,CAAC;iBAC/B;aACF,CAAC,CAAA;YAEF,MAAM,OAAO,CAAC,QAAQ,CAAC,oBAAS,EAAE;gBAChC,WAAW,EAAE,kBAAkB,IAAI,gBAAgB;gBACnD,QAAQ,EAAE;oBACR,YAAY,EAAE,MAAM;oBACpB,WAAW,EAAE,IAAI;oBACjB,wBAAwB,EAAE,CAAC;iBAC5B;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"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"}
|
package/index.ts
CHANGED
|
@@ -12,6 +12,7 @@ import * as loaderHooks from './lib/loader/hooks'
|
|
|
12
12
|
import * as loaderSchemas from './lib/loader/schemas'
|
|
13
13
|
|
|
14
14
|
import Fastify, { FastifyInstance } from 'fastify'
|
|
15
|
+
import jwtValidator from '@fastify/jwt'
|
|
15
16
|
import swagger from '@fastify/swagger'
|
|
16
17
|
import swaggerUI from '@fastify/swagger-ui'
|
|
17
18
|
|
|
@@ -69,11 +70,10 @@ async function addFastifyRouting(fastify: FastifyInstance) {
|
|
|
69
70
|
}
|
|
70
71
|
|
|
71
72
|
async function addFastifySwagger(fastify: FastifyInstance) {
|
|
72
|
-
const {
|
|
73
|
-
process.env
|
|
73
|
+
const { SWAGGER, SWAGGER_TITLE, SWAGGER_DESCRIPTION, SWAGGER_VERSION, SWAGGER_PREFIX_URL, SWAGGER_HOST } = process.env
|
|
74
74
|
|
|
75
75
|
const loadSwagger = yn(SWAGGER, false)
|
|
76
|
-
if (loadSwagger
|
|
76
|
+
if (loadSwagger) {
|
|
77
77
|
log.trace('Add swagger plugin')
|
|
78
78
|
|
|
79
79
|
await fastify.register(swagger, {
|
|
@@ -96,17 +96,17 @@ async function addFastifySwagger(fastify: FastifyInstance) {
|
|
|
96
96
|
docExpansion: 'list',
|
|
97
97
|
deepLinking: true,
|
|
98
98
|
defaultModelsExpandDepth: 1
|
|
99
|
-
}
|
|
100
|
-
uiHooks: {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
}
|
|
108
|
-
staticCSP: true,
|
|
109
|
-
transformStaticCSP: (header) => header
|
|
99
|
+
}
|
|
100
|
+
// uiHooks: {
|
|
101
|
+
// onRequest: function (request, reply, next) {
|
|
102
|
+
// next()
|
|
103
|
+
// },
|
|
104
|
+
// preHandler: function (request, reply, next) {
|
|
105
|
+
// next()
|
|
106
|
+
// }
|
|
107
|
+
// }
|
|
108
|
+
// staticCSP: true,
|
|
109
|
+
// transformStaticCSP: (header) => header
|
|
110
110
|
})
|
|
111
111
|
|
|
112
112
|
// await fastify.put(
|
|
@@ -170,13 +170,13 @@ const start = async () => {
|
|
|
170
170
|
const fastify = await Fastify(opts)
|
|
171
171
|
|
|
172
172
|
const { HOST: host = '0.0.0.0', PORT: port = '2230', GRAPHQL } = process.env
|
|
173
|
-
const { SRV_CORS, SRV_HELMET, SRV_RATELIMIT, SRV_COMPRESS } = process.env
|
|
173
|
+
const { SRV_CORS, SRV_HELMET, SRV_RATELIMIT, SRV_COMPRESS, JWT_SECRET, JWT_EXPIRES_IN = '15d' } = process.env
|
|
174
174
|
|
|
175
|
-
const loadApollo = yn(GRAPHQL,
|
|
176
|
-
const addPluginCors = yn(SRV_CORS,
|
|
177
|
-
const addPluginHelmet = yn(SRV_HELMET,
|
|
178
|
-
const addPluginRateLimit = yn(SRV_RATELIMIT,
|
|
179
|
-
const addPluginCompress = yn(SRV_COMPRESS,
|
|
175
|
+
const loadApollo = yn(GRAPHQL, false)
|
|
176
|
+
const addPluginCors = yn(SRV_CORS, false)
|
|
177
|
+
const addPluginHelmet = yn(SRV_HELMET, false)
|
|
178
|
+
const addPluginRateLimit = yn(SRV_RATELIMIT, false)
|
|
179
|
+
const addPluginCompress = yn(SRV_COMPRESS, false)
|
|
180
180
|
|
|
181
181
|
log.t && log.trace(`Attach Apollo Server ${loadApollo}`)
|
|
182
182
|
log.t && log.trace(`Add plugin CORS: ${addPluginCors}`)
|
|
@@ -184,13 +184,22 @@ const start = async () => {
|
|
|
184
184
|
log.t && log.trace(`Add plugin COMPRESS: ${addPluginCompress}`)
|
|
185
185
|
log.t && log.trace(`Add plugin RATELIMIT: ${addPluginRateLimit}`)
|
|
186
186
|
|
|
187
|
-
const apollo = loadApollo ? await attachApollo(fastify) : null
|
|
188
187
|
// Helmet is not usable with Apollo Server
|
|
189
188
|
!loadApollo && addPluginHelmet && (await fastify.register(helmet))
|
|
190
189
|
addPluginRateLimit && (await fastify.register(rateLimit))
|
|
191
190
|
addPluginCors && (await fastify.register(cors))
|
|
192
191
|
addPluginCompress && (await fastify.register(compress))
|
|
193
192
|
|
|
193
|
+
// JWT Validator
|
|
194
|
+
await fastify.register(jwtValidator, {
|
|
195
|
+
secret: JWT_SECRET || 'supersecret',
|
|
196
|
+
sign: { expiresIn: JWT_EXPIRES_IN }
|
|
197
|
+
})
|
|
198
|
+
|
|
199
|
+
log.t && log.trace(`Add JWT - expiresIn: ${JWT_EXPIRES_IN}`)
|
|
200
|
+
|
|
201
|
+
const apollo = loadApollo ? await attachApollo(fastify) : null
|
|
202
|
+
|
|
194
203
|
await addFastifySwagger(fastify)
|
|
195
204
|
await addApolloRouting(fastify, apollo)
|
|
196
205
|
await addFastifyRouting(fastify)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { FastifyReply, FastifyRequest } from 'fastify'
|
|
2
|
+
|
|
3
|
+
export async function login(req: FastifyRequest, reply: FastifyReply) {
|
|
4
|
+
const { username, password } = req.data()
|
|
5
|
+
|
|
6
|
+
// log.debug('username ' + username + ' password ' + password)
|
|
7
|
+
|
|
8
|
+
const roleList = [username === 'admin' ? roles.admin : username === 'vminds' ? roles.backoffice : roles.public]
|
|
9
|
+
const user =
|
|
10
|
+
username !== null
|
|
11
|
+
? {
|
|
12
|
+
sub: 306, // user id
|
|
13
|
+
name: username // optional, username || email
|
|
14
|
+
}
|
|
15
|
+
: null
|
|
16
|
+
|
|
17
|
+
const token = user !== null ? await reply.jwtSign(user) : null
|
|
18
|
+
|
|
19
|
+
// log.debug('token ' + token)
|
|
20
|
+
reply.send({ ok: token !== null, token, roles: roleList.map((r) => r.code) })
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export async function demo(req: FastifyRequest, reply: FastifyReply) {
|
|
24
|
+
// JSON.stringify(req.user)
|
|
25
|
+
|
|
26
|
+
reply.send({ ok: req.user })
|
|
27
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
config: {
|
|
3
|
+
title: 'User useful functions',
|
|
4
|
+
description: 'User useful functions',
|
|
5
|
+
controller: 'controller',
|
|
6
|
+
tags: ['auth'],
|
|
7
|
+
enable: true,
|
|
8
|
+
deprecated: false, // swagger
|
|
9
|
+
version: false // swagger
|
|
10
|
+
},
|
|
11
|
+
routes: [
|
|
12
|
+
{
|
|
13
|
+
method: 'POST',
|
|
14
|
+
path: '/login',
|
|
15
|
+
roles: [],
|
|
16
|
+
handler: 'auth.login',
|
|
17
|
+
middlewares: [],
|
|
18
|
+
config: {
|
|
19
|
+
enable: true,
|
|
20
|
+
title: 'Login', // swagger summary
|
|
21
|
+
description: 'Login', // swagger
|
|
22
|
+
body: {
|
|
23
|
+
type: 'object',
|
|
24
|
+
properties: {
|
|
25
|
+
username: { type: 'string' },
|
|
26
|
+
password: { type: 'string' }
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
response: {
|
|
30
|
+
200: {
|
|
31
|
+
description: 'Default response',
|
|
32
|
+
type: 'object',
|
|
33
|
+
properties: {
|
|
34
|
+
ok: { type: 'boolean' },
|
|
35
|
+
token: { type: 'string' },
|
|
36
|
+
roles: { type: 'array' }
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
} // swagger
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
method: 'GET',
|
|
44
|
+
path: '/demo',
|
|
45
|
+
roles: [roles.backoffice],
|
|
46
|
+
handler: 'auth.demo',
|
|
47
|
+
middlewares: ['global.isAuthenticated'],
|
|
48
|
+
config: {
|
|
49
|
+
title: 'Demo auth',
|
|
50
|
+
description: 'Demo auth',
|
|
51
|
+
enable: true,
|
|
52
|
+
response: {
|
|
53
|
+
200: {
|
|
54
|
+
description: 'Default response',
|
|
55
|
+
type: 'object',
|
|
56
|
+
properties: {
|
|
57
|
+
ok: { type: 'boolean' }
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
} // swagger
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
]
|
|
64
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
config: {
|
|
3
|
+
title: 'Health useful functions',
|
|
4
|
+
description: 'Health useful functions',
|
|
5
|
+
controller: 'controller',
|
|
6
|
+
tags: ['health']
|
|
7
|
+
},
|
|
8
|
+
routes: [
|
|
9
|
+
{
|
|
10
|
+
method: 'GET',
|
|
11
|
+
path: '/',
|
|
12
|
+
roles: [],
|
|
13
|
+
handler: 'health.check',
|
|
14
|
+
middlewares: [],
|
|
15
|
+
config: {
|
|
16
|
+
title: 'Health check service',
|
|
17
|
+
description: 'Health check service',
|
|
18
|
+
response: {
|
|
19
|
+
200: {
|
|
20
|
+
description: 'Default response',
|
|
21
|
+
type: 'object',
|
|
22
|
+
properties: {
|
|
23
|
+
ok: { type: 'boolean' }
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
]
|
|
30
|
+
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { FastifyReply, FastifyRequest } from 'fastify'
|
|
2
2
|
|
|
3
3
|
export async function user(req: FastifyRequest, reply: FastifyReply) {
|
|
4
|
-
reply.send(req.user
|
|
4
|
+
reply.send(req.user ? { ...req.user, roles: req.user.getRoles() } : {})
|
|
5
5
|
}
|
|
6
6
|
|
|
7
7
|
export async function isAdmin(req: FastifyRequest, reply: FastifyReply) {
|
|
8
|
-
reply.send({ isAdmin:
|
|
8
|
+
reply.send({ isAdmin: req.user && req.user.id && req.user.hasRole(roles.admin) })
|
|
9
9
|
}
|
package/lib/api/users/routes.ts
CHANGED
|
@@ -30,7 +30,10 @@ module.exports = {
|
|
|
30
30
|
description: 'Default response',
|
|
31
31
|
type: 'object',
|
|
32
32
|
properties: {
|
|
33
|
-
id: { type: 'number' }
|
|
33
|
+
id: { type: 'number' },
|
|
34
|
+
name: { type: 'string' },
|
|
35
|
+
email: { type: 'string' },
|
|
36
|
+
roles: { type: 'array' }
|
|
34
37
|
}
|
|
35
38
|
}
|
|
36
39
|
} // swagger
|
|
@@ -57,7 +60,7 @@ module.exports = {
|
|
|
57
60
|
description: 'Default response',
|
|
58
61
|
type: 'object',
|
|
59
62
|
properties: {
|
|
60
|
-
|
|
63
|
+
isAdmin: { type: 'boolean' }
|
|
61
64
|
}
|
|
62
65
|
}
|
|
63
66
|
} // swagger
|
package/lib/hooks/onError.ts
CHANGED
package/lib/hooks/onRequest.ts
CHANGED
|
@@ -1,20 +1,48 @@
|
|
|
1
1
|
import { getParams, getData } from '../util/common'
|
|
2
|
+
import { Role } from '../../types/global'
|
|
2
3
|
|
|
3
4
|
module.exports = async (req, reply) => {
|
|
4
|
-
|
|
5
|
+
// request enrichment
|
|
6
|
+
log.i && (req.startedAt = new Date())
|
|
5
7
|
req.data = () => getData(req)
|
|
6
8
|
req.pars = () => getParams(req)
|
|
7
|
-
if (req.user) {
|
|
8
|
-
req.user.getRoles = () => req.user?.roles?.map(({ code }) => code) || []
|
|
9
|
-
}
|
|
10
9
|
|
|
11
|
-
//
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
10
|
+
// authorization
|
|
11
|
+
const auth = req.headers?.authorization || ''
|
|
12
|
+
const [prefix, token] = auth.split(' ')
|
|
13
|
+
if (prefix === 'Bearer' && token != null) {
|
|
14
|
+
const { sub: userId, name, iat, exp } = reply.server.jwt.verify(token)
|
|
15
|
+
|
|
16
|
+
// demo
|
|
17
|
+
if (global.npmDebugServerStarted) {
|
|
18
|
+
req.user = {
|
|
19
|
+
id: userId || 123,
|
|
20
|
+
name: 'Jerry',
|
|
21
|
+
email: 'jerry@george.com',
|
|
22
|
+
password: 'pippolippo',
|
|
23
|
+
// roles: [roles.admin, roles.public]
|
|
24
|
+
roles: [roles.public]
|
|
25
|
+
}
|
|
26
|
+
log.debug('Inject demo user ' + req.user.id)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (req.routeConfig.requiredRoles?.length > 0) {
|
|
30
|
+
const { method, url, requiredRoles } = req.routeConfig
|
|
31
|
+
const userRoles: string[] = req.user?.roles?.map(({ code }) => code) || []
|
|
32
|
+
const resolvedRole = userRoles.length > 0 ? requiredRoles.filter((r) => userRoles.includes(r.code)) : []
|
|
33
|
+
|
|
34
|
+
if (!resolvedRole.length) {
|
|
35
|
+
log.w && log.warn(`Not allowed to call ${method.toUpperCase()} ${url}`)
|
|
36
|
+
return reply
|
|
37
|
+
.code(403)
|
|
38
|
+
.send({ statusCode: 403, code: 'ROLE_NOT_ALLOWED', message: 'Not allowed to call this route' })
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// recall UserManager find / enrichment
|
|
43
|
+
if (req.user) {
|
|
44
|
+
req.user.getRoles = () => (req.user.roles || []).map((role: Role) => role?.code) || []
|
|
45
|
+
req.user.hasRole = (r: Role) => (req.user.roles || []).some((role: Role) => role?.code === r?.code)
|
|
17
46
|
}
|
|
18
|
-
log.debug('Inject demo user ' + JSON.stringify(req.user))
|
|
19
47
|
}
|
|
20
48
|
}
|
package/lib/hooks/onResponse.ts
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
module.exports = async (req, reply) => {
|
|
2
|
-
let
|
|
2
|
+
let extraMessage: string = ''
|
|
3
|
+
if (log.i) {
|
|
4
|
+
const elapsed: number = new Date().getTime() - (req.startedAt?.getTime() || 0)
|
|
5
|
+
extraMessage = `(${elapsed}ms)`
|
|
6
|
+
}
|
|
3
7
|
if (log.t) {
|
|
4
|
-
const reqSize: string = `req
|
|
5
|
-
const replySize: string = reply.payloadSize ? `
|
|
6
|
-
|
|
8
|
+
const reqSize: string = `req ${req.payloadSize || 0}`
|
|
9
|
+
const replySize: string = reply.payloadSize > 0 ? ` res ${reply.payloadSize}` : ''
|
|
10
|
+
extraMessage += `[${reqSize}${replySize} bytes]`
|
|
7
11
|
}
|
|
8
12
|
|
|
9
|
-
const
|
|
10
|
-
const message: string = `${req.method} ${req.url} ${reply.statusCode} (${elapsed}ms)${payloadSizesMessage}`
|
|
13
|
+
const message: string = `${req.method} ${req.url} ${reply.statusCode} ${extraMessage}`
|
|
11
14
|
reply.statusCode < 300 ? log.info(message) : reply.statusCode < 400 ? log.warn(message) : log.error(message)
|
|
12
15
|
}
|
|
@@ -2,7 +2,7 @@ import sizeof from 'object-sizeof'
|
|
|
2
2
|
|
|
3
3
|
module.exports = async (req, reply, payload) => {
|
|
4
4
|
if (log.t) {
|
|
5
|
-
req.payloadSize = sizeof(req.
|
|
5
|
+
req.payloadSize = sizeof(req.body) + sizeof(req.params) + sizeof(req.query)
|
|
6
6
|
reply.payloadSize = sizeof(payload)
|
|
7
7
|
}
|
|
8
8
|
}
|
package/lib/loader/router.ts
CHANGED
|
@@ -137,18 +137,11 @@ export function apply(server: any, routes: ConfiguredRoute[]): void {
|
|
|
137
137
|
path: path,
|
|
138
138
|
schema: doc,
|
|
139
139
|
preHandler: allMiddlewares,
|
|
140
|
-
|
|
140
|
+
config: {
|
|
141
|
+
requiredRoles: roles || []
|
|
142
|
+
},
|
|
143
|
+
handler: function (req: FastifyRequest, reply: FastifyReply) {
|
|
141
144
|
try {
|
|
142
|
-
if (roles?.length > 0) {
|
|
143
|
-
const userRoles: string[] = req.user?.roles?.map(({ code }) => code) || []
|
|
144
|
-
const resolvedRole = userRoles.length > 0 ? roles.filter((r) => userRoles.includes(r.code)) : []
|
|
145
|
-
|
|
146
|
-
if (!!resolvedRole?.length) {
|
|
147
|
-
log.w && log.warn(`Not allowed to call ${method.toUpperCase()} ${path}`)
|
|
148
|
-
return reply.code(403).send()
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
145
|
return require(file)[func](req, reply)
|
|
153
146
|
} catch (err) {
|
|
154
147
|
log.e && log.error(`Cannot find ${file}.js or method ${func}: ${err}`)
|
package/lib/loader/schemas.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { FastifyReply, FastifyRequest } from 'fastify'
|
|
|
3
3
|
const log = global.log
|
|
4
4
|
module.exports = (req: FastifyRequest, res: FastifyReply, next: any) => {
|
|
5
5
|
try {
|
|
6
|
-
if (
|
|
6
|
+
if (req.user && req.user.id && req.user.hasRole(roles.admin)) {
|
|
7
7
|
log.d && log.trace('isAdmin - user id ' + req.user?.id)
|
|
8
8
|
return next()
|
|
9
9
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@volcanicminds/backend",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.12",
|
|
4
4
|
"codename": "turin",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "The volcanic (minds) backend",
|
|
@@ -47,6 +47,7 @@
|
|
|
47
47
|
"@fastify/compress": "^6.1.1",
|
|
48
48
|
"@fastify/cors": "^8.2.0",
|
|
49
49
|
"@fastify/helmet": "^10.0.2",
|
|
50
|
+
"@fastify/jwt": "^6.3.3",
|
|
50
51
|
"@fastify/rate-limit": "^7.5.0",
|
|
51
52
|
"@fastify/swagger": "^8.1.0",
|
|
52
53
|
"@fastify/swagger-ui": "^1.2.0",
|