@volcanicminds/backend 2.3.1 → 3.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.
- package/README.md +240 -28
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +24 -36
- package/dist/index.js.map +1 -1
- package/dist/lib/api/auth/controller/auth.d.ts.map +1 -1
- package/dist/lib/api/auth/controller/auth.js +14 -7
- package/dist/lib/api/auth/controller/auth.js.map +1 -1
- package/dist/lib/api/health/controller/health.d.ts +1 -1
- package/dist/lib/api/health/controller/health.d.ts.map +1 -1
- package/dist/lib/api/health/controller/health.js +1 -1
- package/dist/lib/api/health/controller/health.js.map +1 -1
- package/dist/lib/api/health/routes.d.ts +1 -0
- package/dist/lib/api/health/routes.d.ts.map +1 -1
- package/dist/lib/api/health/routes.js +1 -0
- package/dist/lib/api/health/routes.js.map +1 -1
- package/dist/lib/api/tenants/controller/tenants.d.ts +17 -0
- package/dist/lib/api/tenants/controller/tenants.d.ts.map +1 -0
- package/dist/lib/api/tenants/controller/tenants.js +150 -0
- package/dist/lib/api/tenants/controller/tenants.js.map +1 -0
- package/dist/lib/api/tenants/routes.d.ts +167 -0
- package/dist/lib/api/tenants/routes.d.ts.map +1 -0
- package/dist/lib/api/tenants/routes.js +143 -0
- package/dist/lib/api/tenants/routes.js.map +1 -0
- package/dist/lib/config/plugins.js +1 -1
- package/dist/lib/config/plugins.js.map +1 -1
- package/dist/lib/database/typeorm/entities/change.d.ts +11 -0
- package/dist/lib/database/typeorm/entities/change.d.ts.map +1 -0
- package/dist/lib/database/typeorm/entities/change.js +4 -0
- package/dist/lib/database/typeorm/entities/change.js.map +1 -0
- package/dist/lib/database/typeorm/entities/tenant.d.ts +13 -0
- package/dist/lib/database/typeorm/entities/tenant.d.ts.map +1 -0
- package/dist/lib/database/typeorm/entities/tenant.js +4 -0
- package/dist/lib/database/typeorm/entities/tenant.js.map +1 -0
- package/dist/lib/database/typeorm/entities/token.d.ts +16 -0
- package/dist/lib/database/typeorm/entities/token.d.ts.map +1 -0
- package/dist/lib/database/typeorm/entities/token.js +4 -0
- package/dist/lib/database/typeorm/entities/token.js.map +1 -0
- package/dist/lib/database/typeorm/entities/user.d.ts +28 -0
- package/dist/lib/database/typeorm/entities/user.d.ts.map +1 -0
- package/dist/lib/database/typeorm/entities/user.js +4 -0
- package/dist/lib/database/typeorm/entities/user.js.map +1 -0
- package/dist/lib/database/typeorm/loader/dataBaseManager.d.ts +6 -0
- package/dist/lib/database/typeorm/loader/dataBaseManager.d.ts.map +1 -0
- package/dist/lib/database/typeorm/loader/dataBaseManager.js +73 -0
- package/dist/lib/database/typeorm/loader/dataBaseManager.js.map +1 -0
- package/dist/lib/database/typeorm/loader/entities.d.ts +6 -0
- package/dist/lib/database/typeorm/loader/entities.d.ts.map +1 -0
- package/dist/lib/database/typeorm/loader/entities.js +37 -0
- package/dist/lib/database/typeorm/loader/entities.js.map +1 -0
- package/dist/lib/database/typeorm/loader/tenantManager.d.ts +17 -0
- package/dist/lib/database/typeorm/loader/tenantManager.d.ts.map +1 -0
- package/dist/lib/database/typeorm/loader/tenantManager.js +193 -0
- package/dist/lib/database/typeorm/loader/tenantManager.js.map +1 -0
- package/dist/lib/database/typeorm/loader/tokenManager.d.ts +23 -0
- package/dist/lib/database/typeorm/loader/tokenManager.d.ts.map +1 -0
- package/dist/lib/database/typeorm/loader/tokenManager.js +131 -0
- package/dist/lib/database/typeorm/loader/tokenManager.js.map +1 -0
- package/dist/lib/database/typeorm/loader/userManager.d.ts +39 -0
- package/dist/lib/database/typeorm/loader/userManager.d.ts.map +1 -0
- package/dist/lib/database/typeorm/loader/userManager.js +358 -0
- package/dist/lib/database/typeorm/loader/userManager.js.map +1 -0
- package/dist/lib/database/typeorm/query/builder.d.ts +2 -0
- package/dist/lib/database/typeorm/query/builder.d.ts.map +1 -0
- package/dist/lib/database/typeorm/query/builder.js +33 -0
- package/dist/lib/database/typeorm/query/builder.js.map +1 -0
- package/dist/lib/database/typeorm/query/parser.d.ts +2 -0
- package/dist/lib/database/typeorm/query/parser.d.ts.map +1 -0
- package/dist/lib/database/typeorm/query/parser.js +27 -0
- package/dist/lib/database/typeorm/query/parser.js.map +1 -0
- package/dist/lib/database/typeorm/query.d.ts +36 -0
- package/dist/lib/database/typeorm/query.d.ts.map +1 -0
- package/dist/lib/database/typeorm/query.js +259 -0
- package/dist/lib/database/typeorm/query.js.map +1 -0
- package/dist/lib/database/typeorm/util/crypto.d.ts +3 -0
- package/dist/lib/database/typeorm/util/crypto.d.ts.map +1 -0
- package/dist/lib/database/typeorm/util/crypto.js +46 -0
- package/dist/lib/database/typeorm/util/crypto.js.map +1 -0
- package/dist/lib/database/typeorm/util/error.d.ts +5 -0
- package/dist/lib/database/typeorm/util/error.d.ts.map +1 -0
- package/dist/lib/database/typeorm/util/error.js +8 -0
- package/dist/lib/database/typeorm/util/error.js.map +1 -0
- package/dist/lib/database/typeorm/util/logger.d.ts +7 -0
- package/dist/lib/database/typeorm/util/logger.d.ts.map +1 -0
- package/dist/lib/database/typeorm/util/logger.js +31 -0
- package/dist/lib/database/typeorm/util/logger.js.map +1 -0
- package/dist/lib/database/typeorm/util/yn.d.ts +2 -0
- package/dist/lib/database/typeorm/util/yn.d.ts.map +1 -0
- package/dist/lib/database/typeorm/util/yn.js +15 -0
- package/dist/lib/database/typeorm/util/yn.js.map +1 -0
- package/dist/lib/defaults/managers.d.ts.map +1 -1
- package/dist/lib/defaults/managers.js +186 -58
- package/dist/lib/defaults/managers.js.map +1 -1
- package/dist/lib/hooks/onRequest.d.ts.map +1 -1
- package/dist/lib/hooks/onRequest.js +11 -48
- package/dist/lib/hooks/onRequest.js.map +1 -1
- package/dist/lib/loader/router.d.ts.map +1 -1
- package/dist/lib/loader/router.js +92 -83
- package/dist/lib/loader/router.js.map +1 -1
- package/dist/lib/loader/tenant.d.ts.map +1 -1
- package/dist/lib/loader/tenant.js +25 -2
- package/dist/lib/loader/tenant.js.map +1 -1
- package/dist/lib/locales/en.json +12 -0
- package/dist/lib/locales/it.json +12 -0
- package/dist/lib/schemas/tenant.d.ts +88 -0
- package/dist/lib/schemas/tenant.d.ts.map +1 -0
- package/dist/lib/schemas/tenant.js +45 -0
- package/dist/lib/schemas/tenant.js.map +1 -0
- package/dist/lib/util/regexp.d.ts +2 -0
- package/dist/lib/util/regexp.d.ts.map +1 -1
- package/dist/lib/util/regexp.js +5 -3
- package/dist/lib/util/regexp.js.map +1 -1
- package/dist/lib/util/secret.d.ts +11 -0
- package/dist/lib/util/secret.d.ts.map +1 -0
- package/dist/lib/util/secret.js +70 -0
- package/dist/lib/util/secret.js.map +1 -0
- package/dist/server.js +4 -1
- package/dist/server.js.map +1 -1
- package/dist/typeorm.d.ts +15 -0
- package/dist/typeorm.d.ts.map +1 -0
- package/dist/typeorm.js +86 -0
- package/dist/typeorm.js.map +1 -0
- package/dist/types/database/typeorm/global.d.ts +56 -0
- package/dist/types/database/typeorm/global.d.ts.map +1 -0
- package/dist/types/database/typeorm/global.js +2 -0
- package/dist/types/database/typeorm/global.js.map +1 -0
- package/dist/types/global.d.ts +318 -0
- package/dist/types/orm.d.ts +22 -0
- package/lib/api/auth/controller/auth.ts +28 -12
- package/lib/api/health/controller/health.ts +1 -1
- package/lib/api/health/routes.ts +1 -0
- package/lib/api/tenants/controller/tenants.ts +211 -0
- package/lib/api/tenants/routes.ts +145 -0
- package/lib/config/plugins.ts +1 -1
- package/lib/database/typeorm/entities/change.ts +11 -0
- package/lib/database/typeorm/entities/tenant.ts +20 -0
- package/lib/database/typeorm/entities/token.ts +18 -0
- package/lib/database/typeorm/entities/user.ts +33 -0
- package/lib/database/typeorm/loader/dataBaseManager.ts +89 -0
- package/lib/database/typeorm/loader/entities.ts +47 -0
- package/lib/database/typeorm/loader/tenantManager.ts +260 -0
- package/lib/database/typeorm/loader/tokenManager.ts +157 -0
- package/lib/database/typeorm/loader/userManager.ts +432 -0
- package/lib/database/typeorm/query/builder.ts +39 -0
- package/lib/database/typeorm/query/parser.ts +29 -0
- package/lib/database/typeorm/query.ts +326 -0
- package/lib/database/typeorm/util/crypto.ts +52 -0
- package/lib/database/typeorm/util/error.ts +7 -0
- package/lib/database/typeorm/util/logger.ts +35 -0
- package/lib/database/typeorm/util/yn.ts +20 -0
- package/lib/defaults/managers.ts +191 -64
- package/lib/hooks/onRequest.ts +12 -64
- package/lib/loader/router.ts +133 -110
- package/lib/loader/tenant.ts +37 -14
- package/lib/schemas/tenant.ts +49 -0
- package/lib/util/regexp.ts +31 -8
- package/lib/util/secret.ts +113 -0
- package/package.json +54 -13
- package/dist/lib/apollo/context.d.ts +0 -6
- package/dist/lib/apollo/context.d.ts.map +0 -1
- package/dist/lib/apollo/context.js +0 -5
- package/dist/lib/apollo/context.js.map +0 -1
- package/dist/lib/apollo/resolvers.d.ts +0 -8
- package/dist/lib/apollo/resolvers.d.ts.map +0 -1
- package/dist/lib/apollo/resolvers.js +0 -8
- package/dist/lib/apollo/resolvers.js.map +0 -1
- package/dist/lib/apollo/type-defs.d.ts +0 -3
- package/dist/lib/apollo/type-defs.d.ts.map +0 -1
- package/dist/lib/apollo/type-defs.js +0 -8
- package/dist/lib/apollo/type-defs.js.map +0 -1
- package/lib/apollo/context.ts +0 -11
- package/lib/apollo/resolvers.ts +0 -12
- package/lib/apollo/type-defs.ts +0 -9
package/lib/defaults/managers.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
MfaManagement,
|
|
1
|
+
import {
|
|
2
|
+
UserManagement,
|
|
3
|
+
TokenManagement,
|
|
4
|
+
DataBaseManagement,
|
|
5
|
+
MfaManagement,
|
|
7
6
|
TransferManagement,
|
|
8
7
|
TenantManagement,
|
|
9
8
|
TransferCallback
|
|
@@ -12,77 +11,205 @@ import { FastifyReply, FastifyRequest } from 'fastify'
|
|
|
12
11
|
|
|
13
12
|
// Default implementations that throw errors or return not implemented
|
|
14
13
|
export const defaultTenantManager: TenantManagement = {
|
|
15
|
-
isImplemented() {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
14
|
+
isImplemented() {
|
|
15
|
+
return false
|
|
16
|
+
},
|
|
17
|
+
resolveTenant(_req) {
|
|
18
|
+
throw new Error('Not implemented')
|
|
19
|
+
},
|
|
20
|
+
switchContext(_tenant, _db?) {
|
|
21
|
+
throw new Error('Not implemented')
|
|
22
|
+
},
|
|
23
|
+
createTenant(_data) {
|
|
24
|
+
throw new Error('Not implemented')
|
|
25
|
+
},
|
|
26
|
+
deleteTenant(_id) {
|
|
27
|
+
throw new Error('Not implemented')
|
|
28
|
+
},
|
|
29
|
+
listTenants() {
|
|
30
|
+
throw new Error('Not implemented')
|
|
31
|
+
},
|
|
32
|
+
getTenant(_id) {
|
|
33
|
+
throw new Error('Not implemented')
|
|
34
|
+
},
|
|
35
|
+
updateTenant(_id, _data) {
|
|
36
|
+
throw new Error('Not implemented')
|
|
37
|
+
},
|
|
38
|
+
restoreTenant(_id) {
|
|
39
|
+
throw new Error('Not implemented')
|
|
40
|
+
}
|
|
20
41
|
}
|
|
21
42
|
|
|
22
43
|
export const defaultUserManager: UserManagement = {
|
|
23
|
-
isImplemented() {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
44
|
+
isImplemented() {
|
|
45
|
+
return false
|
|
46
|
+
},
|
|
47
|
+
isValidUser(_data: unknown) {
|
|
48
|
+
throw new Error('Not implemented.')
|
|
49
|
+
},
|
|
50
|
+
createUser(_data: unknown) {
|
|
51
|
+
throw new Error('Not implemented.')
|
|
52
|
+
},
|
|
53
|
+
deleteUser(_data: unknown) {
|
|
54
|
+
throw new Error('Not implemented.')
|
|
55
|
+
},
|
|
56
|
+
resetExternalId(_data: unknown) {
|
|
57
|
+
throw new Error('Not implemented.')
|
|
58
|
+
},
|
|
59
|
+
updateUserById(_id: string, _user: unknown) {
|
|
60
|
+
throw new Error('Not implemented.')
|
|
61
|
+
},
|
|
62
|
+
retrieveUserById(_id: string) {
|
|
63
|
+
throw new Error('Not implemented.')
|
|
64
|
+
},
|
|
65
|
+
retrieveUserByEmail(_email: string) {
|
|
66
|
+
throw new Error('Not implemented.')
|
|
67
|
+
},
|
|
68
|
+
retrieveUserByConfirmationToken(_code: string) {
|
|
69
|
+
throw new Error('Not implemented.')
|
|
70
|
+
},
|
|
71
|
+
retrieveUserByResetPasswordToken(_code: string) {
|
|
72
|
+
throw new Error('Not implemented.')
|
|
73
|
+
},
|
|
74
|
+
retrieveUserByUsername(_username: string) {
|
|
75
|
+
throw new Error('Not implemented.')
|
|
76
|
+
},
|
|
77
|
+
retrieveUserByExternalId(_externalId: string) {
|
|
78
|
+
throw new Error('Not implemented.')
|
|
79
|
+
},
|
|
80
|
+
retrieveUserByPassword(_email: string, _password: string) {
|
|
81
|
+
throw new Error('Not implemented.')
|
|
82
|
+
},
|
|
83
|
+
changePassword(_email: string, _password: string, _oldPassword: string) {
|
|
84
|
+
throw new Error('Not implemented.')
|
|
85
|
+
},
|
|
86
|
+
forgotPassword(_email: string) {
|
|
87
|
+
throw new Error('Not implemented.')
|
|
88
|
+
},
|
|
89
|
+
userConfirmation(_user: unknown) {
|
|
90
|
+
throw new Error('Not implemented.')
|
|
91
|
+
},
|
|
92
|
+
resetPassword(_user: unknown, _password: string) {
|
|
93
|
+
throw new Error('Not implemented.')
|
|
94
|
+
},
|
|
95
|
+
blockUserById(_id: string, _reason: string) {
|
|
96
|
+
throw new Error('Not implemented.')
|
|
97
|
+
},
|
|
98
|
+
unblockUserById(_data: unknown) {
|
|
99
|
+
throw new Error('Not implemented.')
|
|
100
|
+
},
|
|
101
|
+
countQuery(_data: unknown) {
|
|
102
|
+
throw new Error('Not implemented.')
|
|
103
|
+
},
|
|
104
|
+
findQuery(_data: unknown) {
|
|
105
|
+
throw new Error('Not implemented.')
|
|
106
|
+
},
|
|
107
|
+
disableUserById(_id: string) {
|
|
108
|
+
throw new Error('Not implemented.')
|
|
109
|
+
},
|
|
110
|
+
saveMfaSecret(_userId: string, _secret: string) {
|
|
111
|
+
throw new Error('Not implemented.')
|
|
112
|
+
},
|
|
113
|
+
retrieveMfaSecret(_userId: string) {
|
|
114
|
+
throw new Error('Not implemented.')
|
|
115
|
+
},
|
|
116
|
+
enableMfa(_userId: string) {
|
|
117
|
+
throw new Error('Not implemented.')
|
|
118
|
+
},
|
|
119
|
+
disableMfa(_userId: string) {
|
|
120
|
+
throw new Error('Not implemented.')
|
|
121
|
+
},
|
|
122
|
+
forceDisableMfaForAdmin(_email: string) {
|
|
123
|
+
throw new Error('Not implemented.')
|
|
124
|
+
}
|
|
50
125
|
}
|
|
51
126
|
|
|
52
127
|
export const defaultTokenManager: TokenManagement = {
|
|
53
|
-
isImplemented() {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
128
|
+
isImplemented() {
|
|
129
|
+
return false
|
|
130
|
+
},
|
|
131
|
+
isValidToken(_data: unknown) {
|
|
132
|
+
throw new Error('Not implemented.')
|
|
133
|
+
},
|
|
134
|
+
createToken(_data: unknown) {
|
|
135
|
+
throw new Error('Not implemented.')
|
|
136
|
+
},
|
|
137
|
+
resetExternalId(_id: string) {
|
|
138
|
+
throw new Error('Not implemented.')
|
|
139
|
+
},
|
|
140
|
+
updateTokenById(_id: string, _token: unknown) {
|
|
141
|
+
throw new Error('Not implemented.')
|
|
142
|
+
},
|
|
143
|
+
retrieveTokenById(_id: string) {
|
|
144
|
+
throw new Error('Not implemented.')
|
|
145
|
+
},
|
|
146
|
+
retrieveTokenByExternalId(_id: string) {
|
|
147
|
+
throw new Error('Not implemented.')
|
|
148
|
+
},
|
|
149
|
+
blockTokenById(_id: string, _reason: string) {
|
|
150
|
+
throw new Error('Not implemented.')
|
|
151
|
+
},
|
|
152
|
+
unblockTokenById(_id: string) {
|
|
153
|
+
throw new Error('Not implemented.')
|
|
154
|
+
},
|
|
155
|
+
countQuery(_data: unknown) {
|
|
156
|
+
throw new Error('Not implemented.')
|
|
157
|
+
},
|
|
158
|
+
findQuery(_data: unknown) {
|
|
159
|
+
throw new Error('Not implemented.')
|
|
160
|
+
},
|
|
161
|
+
removeTokenById(_id: string) {
|
|
162
|
+
throw new Error('Not implemented.')
|
|
163
|
+
}
|
|
65
164
|
}
|
|
66
165
|
|
|
67
166
|
export const defaultDataBaseManager: DataBaseManagement = {
|
|
68
|
-
isImplemented() {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
167
|
+
isImplemented() {
|
|
168
|
+
return false
|
|
169
|
+
},
|
|
170
|
+
synchronizeSchemas() {
|
|
171
|
+
throw new Error('Not implemented.')
|
|
172
|
+
},
|
|
173
|
+
retrieveBy(_entityName, _entityId) {
|
|
174
|
+
throw new Error('Not implemented.')
|
|
175
|
+
},
|
|
176
|
+
addChange(_entityName, _entityId, _status, _userId, _contents, _changeEntity) {
|
|
177
|
+
throw new Error('Not implemented.')
|
|
178
|
+
}
|
|
72
179
|
}
|
|
73
180
|
|
|
74
181
|
export const defaultMfaManager: MfaManagement = {
|
|
75
|
-
generateSetup(_appName: string, _email: string) {
|
|
76
|
-
|
|
182
|
+
generateSetup(_appName: string, _email: string) {
|
|
183
|
+
throw new Error('Not implemented.')
|
|
184
|
+
},
|
|
185
|
+
verify(_token: string, _secret: string) {
|
|
186
|
+
throw new Error('Not implemented.')
|
|
187
|
+
}
|
|
77
188
|
}
|
|
78
189
|
|
|
79
190
|
export const defaultTransferManager: TransferManagement = {
|
|
80
|
-
isImplemented() {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
191
|
+
isImplemented() {
|
|
192
|
+
return false
|
|
193
|
+
},
|
|
194
|
+
getPath() {
|
|
195
|
+
throw new Error('Not implemented.')
|
|
196
|
+
},
|
|
197
|
+
getServer() {
|
|
198
|
+
throw new Error('Not implemented.')
|
|
199
|
+
},
|
|
200
|
+
onUploadCreate(_callback: TransferCallback) {
|
|
201
|
+
throw new Error('Not implemented.')
|
|
202
|
+
},
|
|
203
|
+
onUploadFinish(_callback: TransferCallback) {
|
|
204
|
+
throw new Error('Not implemented.')
|
|
205
|
+
},
|
|
206
|
+
onUploadTerminate(_callback: TransferCallback) {
|
|
207
|
+
throw new Error('Not implemented.')
|
|
208
|
+
},
|
|
209
|
+
handle(_req: FastifyRequest, _res: FastifyReply) {
|
|
210
|
+
throw new Error('Not implemented.')
|
|
211
|
+
},
|
|
212
|
+
isValid(_req: FastifyRequest) {
|
|
213
|
+
throw new Error('Not implemented.')
|
|
214
|
+
}
|
|
88
215
|
}
|
package/lib/hooks/onRequest.ts
CHANGED
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
import { getParams, getData } from '../util/common.js'
|
|
3
3
|
import type { AuthenticatedUser, AuthenticatedToken, Role, TransferManagement } from '../../types/global.js'
|
|
4
4
|
|
|
5
|
-
const { embedded_auth = true } = global.config?.options || {}
|
|
6
|
-
|
|
7
5
|
const MFA_SETUP_WHITELIST = ['/auth/mfa/setup', '/auth/mfa/enable', '/auth/mfa/verify', '/auth/logout']
|
|
8
6
|
|
|
9
7
|
const normalizeRoles = (rolesArray: any[] | undefined): string[] => {
|
|
@@ -23,63 +21,6 @@ const normalizeRoles = (rolesArray: any[] | undefined): string[] => {
|
|
|
23
21
|
export default async (req, reply) => {
|
|
24
22
|
if (log.i) req.startedAt = new Date()
|
|
25
23
|
|
|
26
|
-
const { multi_tenant } = global.config?.options || {}
|
|
27
|
-
|
|
28
|
-
if (multi_tenant?.enabled) {
|
|
29
|
-
let tenantSlug: string | undefined
|
|
30
|
-
|
|
31
|
-
if (multi_tenant.resolver === 'subdomain') {
|
|
32
|
-
const host = req.headers.host || ''
|
|
33
|
-
const parts = host.split('.')
|
|
34
|
-
if (parts.length >= 2) {
|
|
35
|
-
// FIXME: Improve subdomain extraction strategy. Currently assumes [slug].[domain].[tld] or [slug].localhost
|
|
36
|
-
if (parts[0] !== 'www') {
|
|
37
|
-
tenantSlug = parts[0]
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
} else if (multi_tenant.resolver === 'header') {
|
|
41
|
-
tenantSlug = req.headers[multi_tenant?.header_key || 'x-tenant-id'] as string
|
|
42
|
-
} else if (multi_tenant.resolver === 'query') {
|
|
43
|
-
tenantSlug = (req.query as any)[multi_tenant?.query_key || 'tid']
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
if (!tenantSlug) {
|
|
47
|
-
return reply.code(400).send({ statusCode: 400, error: 'Tenant ID missing', message: 'Tenant ID is required' })
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
if (!global.repository?.tenants) {
|
|
51
|
-
log.error('Multi-tenant enabled but global.repository.tenants not found')
|
|
52
|
-
return reply.code(500).send({ statusCode: 500, error: 'Internal Server Error' })
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
const tenant = await global.repository.tenants.findOneBy({ slug: tenantSlug })
|
|
56
|
-
|
|
57
|
-
if (!tenant) {
|
|
58
|
-
return reply
|
|
59
|
-
.code(404)
|
|
60
|
-
.send({ statusCode: 404, error: 'Tenant Not Found', message: `Tenant '${tenantSlug}' not found` })
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
if (tenant.status !== 'active') {
|
|
64
|
-
return reply.code(403).send({ statusCode: 403, error: 'Tenant Inactive', message: 'Tenant is not active' })
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// Tenant Context Setup
|
|
68
|
-
const runner = global.connection.createQueryRunner()
|
|
69
|
-
await runner.connect()
|
|
70
|
-
|
|
71
|
-
// Validate schema name safety
|
|
72
|
-
if (!/^[a-z0-9_]+$/i.test(tenant.schema)) {
|
|
73
|
-
await runner.release()
|
|
74
|
-
return reply.code(400).send({ statusCode: 400, error: 'Invalid Schema Name' })
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
await runner.query(`SET search_path TO "${tenant.schema}", "public"`)
|
|
78
|
-
|
|
79
|
-
req.runner = runner
|
|
80
|
-
req.tenant = tenant
|
|
81
|
-
}
|
|
82
|
-
|
|
83
24
|
req.data = () => getData(req)
|
|
84
25
|
req.parameters = () => getParams(req)
|
|
85
26
|
|
|
@@ -102,6 +43,8 @@ export default async (req, reply) => {
|
|
|
102
43
|
}
|
|
103
44
|
}
|
|
104
45
|
|
|
46
|
+
const { embedded_auth = true } = global.config?.options || {}
|
|
47
|
+
|
|
105
48
|
if (embedded_auth) {
|
|
106
49
|
req.roles = () => [roles.public.code]
|
|
107
50
|
req.hasRole = (r: Role) => req.roles().includes(r?.code)
|
|
@@ -133,7 +76,14 @@ export default async (req, reply) => {
|
|
|
133
76
|
|
|
134
77
|
// Validate Tenant Access
|
|
135
78
|
const { multi_tenant } = global.config?.options || {}
|
|
136
|
-
if (multi_tenant?.enabled &&
|
|
79
|
+
if (multi_tenant?.enabled && cfg.tenantContext !== false) {
|
|
80
|
+
if (!req.tenant || !tokenData.tid) {
|
|
81
|
+
return reply.status(403).send({
|
|
82
|
+
statusCode: 403,
|
|
83
|
+
code: 'TENANT_NOT_FOUND',
|
|
84
|
+
message: 'Token does not belong to this tenant'
|
|
85
|
+
})
|
|
86
|
+
}
|
|
137
87
|
if (tokenData.tid !== req.tenant.id) {
|
|
138
88
|
return reply.status(403).send({
|
|
139
89
|
statusCode: 403,
|
|
@@ -168,7 +118,7 @@ export default async (req, reply) => {
|
|
|
168
118
|
let token: null | AuthenticatedToken = null
|
|
169
119
|
|
|
170
120
|
if (req.server['userManager']?.isImplemented()) {
|
|
171
|
-
user = await req.server['userManager'].retrieveUserByExternalId(subjectId)
|
|
121
|
+
user = await req.server['userManager'].retrieveUserByExternalId(subjectId, req.db)
|
|
172
122
|
if (user) {
|
|
173
123
|
const isValid = await req.server['userManager'].isValidUser(user)
|
|
174
124
|
if (!isValid) {
|
|
@@ -181,7 +131,7 @@ export default async (req, reply) => {
|
|
|
181
131
|
}
|
|
182
132
|
|
|
183
133
|
if (!user && req.server['tokenManager']?.isImplemented()) {
|
|
184
|
-
token = await req.server['tokenManager'].retrieveTokenByExternalId(subjectId)
|
|
134
|
+
token = await req.server['tokenManager'].retrieveTokenByExternalId(subjectId, req.db)
|
|
185
135
|
if (token) {
|
|
186
136
|
const isValid = await req.server['tokenManager'].isValidToken(token)
|
|
187
137
|
if (!isValid) {
|
|
@@ -223,5 +173,3 @@ export default async (req, reply) => {
|
|
|
223
173
|
}
|
|
224
174
|
}
|
|
225
175
|
}
|
|
226
|
-
|
|
227
|
-
|
package/lib/loader/router.ts
CHANGED
|
@@ -61,6 +61,132 @@ async function loadMiddlewares(base: string, middlewares: string[] = []) {
|
|
|
61
61
|
return midds
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
+
|
|
65
|
+
function processRoute(
|
|
66
|
+
route: Route,
|
|
67
|
+
index: number,
|
|
68
|
+
file: string,
|
|
69
|
+
dir: string,
|
|
70
|
+
base: string,
|
|
71
|
+
defaultConfig: any,
|
|
72
|
+
authMiddlewares: string[],
|
|
73
|
+
validRoutes: ConfiguredRoute[]
|
|
74
|
+
): ConfiguredRoute | null {
|
|
75
|
+
const errors: string[] = []
|
|
76
|
+
const {
|
|
77
|
+
method: methodCase,
|
|
78
|
+
path: pathName = '/',
|
|
79
|
+
handler,
|
|
80
|
+
roles: rs = [],
|
|
81
|
+
config = {} as RouteConfig,
|
|
82
|
+
middlewares = [],
|
|
83
|
+
rateLimit
|
|
84
|
+
} = route
|
|
85
|
+
|
|
86
|
+
const rsp = !rs.length ? [roles.public] : rs
|
|
87
|
+
let requiredRoles: Role[] = []
|
|
88
|
+
|
|
89
|
+
try {
|
|
90
|
+
requiredRoles = rsp.some((r) => r.code === roles.admin.code) ? rsp : [...rsp, roles.admin]
|
|
91
|
+
} catch (err) {
|
|
92
|
+
if (log.e) log.error(`Error in loading roles for ${methodCase} ${pathName} (${handler})`)
|
|
93
|
+
if (log.t) log.trace(err)
|
|
94
|
+
config.enable = false
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const reqAuth: boolean =
|
|
98
|
+
middlewares.some((m) => authMiddlewares.includes(m)) ||
|
|
99
|
+
requiredRoles.every((r) => r.code !== roles.public.code)
|
|
100
|
+
|
|
101
|
+
if (!config?.security && reqAuth) {
|
|
102
|
+
config.security = 'bearer'
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const {
|
|
106
|
+
title = '',
|
|
107
|
+
description = '',
|
|
108
|
+
enable = yn(defaultConfig.enable, true),
|
|
109
|
+
deprecated = yn(defaultConfig.deprecated, false),
|
|
110
|
+
tenantContext = yn(defaultConfig.tenantContext, true),
|
|
111
|
+
tags = defaultConfig.tags,
|
|
112
|
+
version = defaultConfig.version || '',
|
|
113
|
+
security = defaultConfig.security,
|
|
114
|
+
query,
|
|
115
|
+
params,
|
|
116
|
+
body,
|
|
117
|
+
response,
|
|
118
|
+
consumes,
|
|
119
|
+
rawBody = false
|
|
120
|
+
} = config || {}
|
|
121
|
+
|
|
122
|
+
const endpoint = `${dir}${pathName.replace(/\/+$/, '')}`
|
|
123
|
+
const method = methodCase.toUpperCase()
|
|
124
|
+
const num = index + 1
|
|
125
|
+
const handlerParts = handler.split('.')
|
|
126
|
+
|
|
127
|
+
if (enable) {
|
|
128
|
+
if (!pathName.startsWith('/')) errors.push(`Error in [${file}] bad path [${pathName}] at route n. ${num}`)
|
|
129
|
+
if (!methods.includes(method)) errors.push(`Error in [${file}] bad method [${method}] at route n. ${num}`)
|
|
130
|
+
if (handlerParts.length !== 2) errors.push(`Error in [${file}] bad handler [${handler}] at route n. ${num}`)
|
|
131
|
+
|
|
132
|
+
const key = method + endpoint + version
|
|
133
|
+
if (validRoutes.some((r) => `${r.method}${r.path}${r.doc?.version}` === key)) {
|
|
134
|
+
errors.push(`Error in [${file}] duplicated path [${pathName}] at route n. ${num}`)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (errors.length > 0) {
|
|
138
|
+
if (log.e) errors.forEach((error) => log.error(error))
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const toAdd = enable && errors.length === 0
|
|
143
|
+
if (toAdd) {
|
|
144
|
+
if (log.t)
|
|
145
|
+
log.trace(
|
|
146
|
+
`* Method [${method}] path ${endpoint} handler ${handler} enabled with ${
|
|
147
|
+
middlewares?.length || 0
|
|
148
|
+
} middlewares`
|
|
149
|
+
)
|
|
150
|
+
} else {
|
|
151
|
+
if (log.w) log.warn(`* Method [${method}] path ${endpoint} handler ${handler} disabled. Skip.`)
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (toAdd) {
|
|
155
|
+
const doc = {
|
|
156
|
+
summary: title,
|
|
157
|
+
description,
|
|
158
|
+
deprecated,
|
|
159
|
+
tags,
|
|
160
|
+
version,
|
|
161
|
+
security: security === 'bearer' ? [{ Bearer: [] }] : security,
|
|
162
|
+
response
|
|
163
|
+
} as any
|
|
164
|
+
|
|
165
|
+
if (query) doc.querystring = query
|
|
166
|
+
if (params) doc.params = params
|
|
167
|
+
if (body) doc.body = body
|
|
168
|
+
if (consumes) doc.consumes = consumes
|
|
169
|
+
|
|
170
|
+
return {
|
|
171
|
+
handler,
|
|
172
|
+
method,
|
|
173
|
+
path: '/' + endpoint,
|
|
174
|
+
middlewares,
|
|
175
|
+
roles: requiredRoles,
|
|
176
|
+
enable,
|
|
177
|
+
tenantContext,
|
|
178
|
+
rawBody,
|
|
179
|
+
rateLimit,
|
|
180
|
+
base,
|
|
181
|
+
file: path.join(base, defaultConfig.controller || 'controller', handlerParts[0]),
|
|
182
|
+
func: handlerParts[1],
|
|
183
|
+
doc: doc
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return null
|
|
188
|
+
}
|
|
189
|
+
|
|
64
190
|
async function load(): Promise<ConfiguredRoute[]> {
|
|
65
191
|
const validRoutes: ConfiguredRoute[] = []
|
|
66
192
|
const patterns = normalizePatterns(['..', 'api', '**', 'routes.{ts,js}'], ['src', 'api', '**', 'routes.{ts,js}'])
|
|
@@ -84,114 +210,9 @@ async function load(): Promise<ConfiguredRoute[]> {
|
|
|
84
210
|
if (log.t) log.trace(`* Add ${routes.length} routes from ${file}`)
|
|
85
211
|
|
|
86
212
|
routes.forEach((route: Route, index: number) => {
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
path: pathName = '/',
|
|
91
|
-
handler,
|
|
92
|
-
roles: rs = [],
|
|
93
|
-
config = {} as RouteConfig,
|
|
94
|
-
middlewares = [],
|
|
95
|
-
rateLimit
|
|
96
|
-
} = route
|
|
97
|
-
|
|
98
|
-
const rsp = !rs.length ? [roles.public] : rs
|
|
99
|
-
let requiredRoles: Role[] = []
|
|
100
|
-
|
|
101
|
-
try {
|
|
102
|
-
requiredRoles = rsp.some((r) => r.code === roles.admin.code) ? rsp : [...rsp, roles.admin]
|
|
103
|
-
} catch (err) {
|
|
104
|
-
if (log.e) log.error(`Error in loading roles for ${methodCase} ${pathName} (${handler})`)
|
|
105
|
-
if (log.t) log.trace(err)
|
|
106
|
-
config.enable = false
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
const reqAuth: boolean =
|
|
110
|
-
middlewares.some((m) => authMiddlewares.includes(m)) ||
|
|
111
|
-
requiredRoles.every((r) => r.code !== roles.public.code)
|
|
112
|
-
|
|
113
|
-
if (!config?.security && reqAuth) {
|
|
114
|
-
config.security = 'bearer'
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
const {
|
|
118
|
-
title = '',
|
|
119
|
-
description = '',
|
|
120
|
-
enable = yn(defaultConfig.enable, true),
|
|
121
|
-
deprecated = yn(defaultConfig.deprecated, false),
|
|
122
|
-
tags = defaultConfig.tags,
|
|
123
|
-
version = defaultConfig.version || '',
|
|
124
|
-
security = defaultConfig.security,
|
|
125
|
-
query,
|
|
126
|
-
params,
|
|
127
|
-
body,
|
|
128
|
-
response,
|
|
129
|
-
consumes,
|
|
130
|
-
rawBody = false
|
|
131
|
-
} = config || {}
|
|
132
|
-
|
|
133
|
-
const endpoint = `${dir}${pathName.replace(/\/+$/, '')}`
|
|
134
|
-
const method = methodCase.toUpperCase()
|
|
135
|
-
const num = index + 1
|
|
136
|
-
const handlerParts = handler.split('.')
|
|
137
|
-
|
|
138
|
-
if (enable) {
|
|
139
|
-
if (!pathName.startsWith('/')) errors.push(`Error in [${file}] bad path [${pathName}] at route n. ${num}`)
|
|
140
|
-
if (!methods.includes(method)) errors.push(`Error in [${file}] bad method [${method}] at route n. ${num}`)
|
|
141
|
-
if (handlerParts.length !== 2) errors.push(`Error in [${file}] bad handler [${handler}] at route n. ${num}`)
|
|
142
|
-
|
|
143
|
-
const key = method + endpoint + version
|
|
144
|
-
if (validRoutes.some((r) => `${r.method}${r.path}${r.doc?.version}` === key)) {
|
|
145
|
-
errors.push(`Error in [${file}] duplicated path [${pathName}] at route n. ${num}`)
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
if (errors.length > 0) {
|
|
149
|
-
if (log.e) errors.forEach((error) => log.error(error))
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
const toAdd = enable && errors.length === 0
|
|
154
|
-
if (toAdd) {
|
|
155
|
-
if (log.t)
|
|
156
|
-
log.trace(
|
|
157
|
-
`* Method [${method}] path ${endpoint} handler ${handler} enabled with ${
|
|
158
|
-
middlewares?.length || 0
|
|
159
|
-
} middlewares`
|
|
160
|
-
)
|
|
161
|
-
} else {
|
|
162
|
-
if (log.w) log.warn(`* Method [${method}] path ${endpoint} handler ${handler} disabled. Skip.`)
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
if (toAdd) {
|
|
166
|
-
const doc = {
|
|
167
|
-
summary: title,
|
|
168
|
-
description,
|
|
169
|
-
deprecated,
|
|
170
|
-
tags,
|
|
171
|
-
version,
|
|
172
|
-
security: security === 'bearer' ? [{ Bearer: [] }] : security,
|
|
173
|
-
response
|
|
174
|
-
} as any
|
|
175
|
-
|
|
176
|
-
if (query) doc.querystring = query
|
|
177
|
-
if (params) doc.params = params
|
|
178
|
-
if (body) doc.body = body
|
|
179
|
-
if (consumes) doc.consumes = consumes
|
|
180
|
-
|
|
181
|
-
validRoutes.push({
|
|
182
|
-
handler,
|
|
183
|
-
method,
|
|
184
|
-
path: '/' + endpoint,
|
|
185
|
-
middlewares,
|
|
186
|
-
roles: requiredRoles,
|
|
187
|
-
enable,
|
|
188
|
-
rawBody,
|
|
189
|
-
rateLimit,
|
|
190
|
-
base,
|
|
191
|
-
file: path.join(base, defaultConfig.controller || 'controller', handlerParts[0]),
|
|
192
|
-
func: handlerParts[1],
|
|
193
|
-
doc: doc
|
|
194
|
-
})
|
|
213
|
+
const configuredRoute = processRoute(route, index, file, dir, base, defaultConfig, authMiddlewares, validRoutes)
|
|
214
|
+
if (configuredRoute) {
|
|
215
|
+
validRoutes.push(configuredRoute)
|
|
195
216
|
}
|
|
196
217
|
})
|
|
197
218
|
}
|
|
@@ -211,7 +232,8 @@ async function applyRoutes(server: any, routes: ConfiguredRoute[]): Promise<void
|
|
|
211
232
|
let countRoutes = 0
|
|
212
233
|
for (const route of routes) {
|
|
213
234
|
if (route?.enable) {
|
|
214
|
-
const { handler, method, path, middlewares, roles, rawBody, rateLimit, base, file, func, doc } =
|
|
235
|
+
const { handler, method, path, middlewares, roles, rawBody, rateLimit, base, file, func, doc, tenantContext } =
|
|
236
|
+
route
|
|
215
237
|
|
|
216
238
|
if (log.d) log.debug(`* Add path ${method} ${path} on handle ${handler}`)
|
|
217
239
|
const midds = await loadMiddlewares(base, middlewares)
|
|
@@ -224,7 +246,8 @@ async function applyRoutes(server: any, routes: ConfiguredRoute[]): Promise<void
|
|
|
224
246
|
config: {
|
|
225
247
|
requiredRoles: roles || [],
|
|
226
248
|
rawBody: rawBody || false,
|
|
227
|
-
rateLimit: rateLimit || undefined
|
|
249
|
+
rateLimit: rateLimit || undefined,
|
|
250
|
+
tenantContext: tenantContext
|
|
228
251
|
},
|
|
229
252
|
handler: async function (req: FastifyRequest, reply: FastifyReply) {
|
|
230
253
|
let module
|