@volcanicminds/backend 2.3.2 → 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.
Files changed (173) hide show
  1. package/README.md +221 -28
  2. package/dist/index.d.ts +3 -2
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +24 -36
  5. package/dist/index.js.map +1 -1
  6. package/dist/lib/api/auth/controller/auth.d.ts.map +1 -1
  7. package/dist/lib/api/auth/controller/auth.js +14 -7
  8. package/dist/lib/api/auth/controller/auth.js.map +1 -1
  9. package/dist/lib/api/health/controller/health.d.ts +1 -1
  10. package/dist/lib/api/health/controller/health.d.ts.map +1 -1
  11. package/dist/lib/api/health/controller/health.js +1 -1
  12. package/dist/lib/api/health/controller/health.js.map +1 -1
  13. package/dist/lib/api/health/routes.d.ts +1 -0
  14. package/dist/lib/api/health/routes.d.ts.map +1 -1
  15. package/dist/lib/api/health/routes.js +1 -0
  16. package/dist/lib/api/health/routes.js.map +1 -1
  17. package/dist/lib/api/tenants/controller/tenants.d.ts +17 -0
  18. package/dist/lib/api/tenants/controller/tenants.d.ts.map +1 -0
  19. package/dist/lib/api/tenants/controller/tenants.js +150 -0
  20. package/dist/lib/api/tenants/controller/tenants.js.map +1 -0
  21. package/dist/lib/api/tenants/routes.d.ts +167 -0
  22. package/dist/lib/api/tenants/routes.d.ts.map +1 -0
  23. package/dist/lib/api/tenants/routes.js +143 -0
  24. package/dist/lib/api/tenants/routes.js.map +1 -0
  25. package/dist/lib/config/plugins.js +1 -1
  26. package/dist/lib/config/plugins.js.map +1 -1
  27. package/dist/lib/database/typeorm/entities/change.d.ts +11 -0
  28. package/dist/lib/database/typeorm/entities/change.d.ts.map +1 -0
  29. package/dist/lib/database/typeorm/entities/change.js +4 -0
  30. package/dist/lib/database/typeorm/entities/change.js.map +1 -0
  31. package/dist/lib/database/typeorm/entities/tenant.d.ts +13 -0
  32. package/dist/lib/database/typeorm/entities/tenant.d.ts.map +1 -0
  33. package/dist/lib/database/typeorm/entities/tenant.js +4 -0
  34. package/dist/lib/database/typeorm/entities/tenant.js.map +1 -0
  35. package/dist/lib/database/typeorm/entities/token.d.ts +16 -0
  36. package/dist/lib/database/typeorm/entities/token.d.ts.map +1 -0
  37. package/dist/lib/database/typeorm/entities/token.js +4 -0
  38. package/dist/lib/database/typeorm/entities/token.js.map +1 -0
  39. package/dist/lib/database/typeorm/entities/user.d.ts +28 -0
  40. package/dist/lib/database/typeorm/entities/user.d.ts.map +1 -0
  41. package/dist/lib/database/typeorm/entities/user.js +4 -0
  42. package/dist/lib/database/typeorm/entities/user.js.map +1 -0
  43. package/dist/lib/database/typeorm/loader/dataBaseManager.d.ts +6 -0
  44. package/dist/lib/database/typeorm/loader/dataBaseManager.d.ts.map +1 -0
  45. package/dist/lib/database/typeorm/loader/dataBaseManager.js +73 -0
  46. package/dist/lib/database/typeorm/loader/dataBaseManager.js.map +1 -0
  47. package/dist/lib/database/typeorm/loader/entities.d.ts +6 -0
  48. package/dist/lib/database/typeorm/loader/entities.d.ts.map +1 -0
  49. package/dist/lib/database/typeorm/loader/entities.js +37 -0
  50. package/dist/lib/database/typeorm/loader/entities.js.map +1 -0
  51. package/dist/lib/database/typeorm/loader/tenantManager.d.ts +17 -0
  52. package/dist/lib/database/typeorm/loader/tenantManager.d.ts.map +1 -0
  53. package/dist/lib/database/typeorm/loader/tenantManager.js +193 -0
  54. package/dist/lib/database/typeorm/loader/tenantManager.js.map +1 -0
  55. package/dist/lib/database/typeorm/loader/tokenManager.d.ts +23 -0
  56. package/dist/lib/database/typeorm/loader/tokenManager.d.ts.map +1 -0
  57. package/dist/lib/database/typeorm/loader/tokenManager.js +131 -0
  58. package/dist/lib/database/typeorm/loader/tokenManager.js.map +1 -0
  59. package/dist/lib/database/typeorm/loader/userManager.d.ts +39 -0
  60. package/dist/lib/database/typeorm/loader/userManager.d.ts.map +1 -0
  61. package/dist/lib/database/typeorm/loader/userManager.js +358 -0
  62. package/dist/lib/database/typeorm/loader/userManager.js.map +1 -0
  63. package/dist/lib/database/typeorm/query/builder.d.ts +2 -0
  64. package/dist/lib/database/typeorm/query/builder.d.ts.map +1 -0
  65. package/dist/lib/database/typeorm/query/builder.js +33 -0
  66. package/dist/lib/database/typeorm/query/builder.js.map +1 -0
  67. package/dist/lib/database/typeorm/query/parser.d.ts +2 -0
  68. package/dist/lib/database/typeorm/query/parser.d.ts.map +1 -0
  69. package/dist/lib/database/typeorm/query/parser.js +27 -0
  70. package/dist/lib/database/typeorm/query/parser.js.map +1 -0
  71. package/dist/lib/database/typeorm/query.d.ts +36 -0
  72. package/dist/lib/database/typeorm/query.d.ts.map +1 -0
  73. package/dist/lib/database/typeorm/query.js +259 -0
  74. package/dist/lib/database/typeorm/query.js.map +1 -0
  75. package/dist/lib/database/typeorm/util/crypto.d.ts +3 -0
  76. package/dist/lib/database/typeorm/util/crypto.d.ts.map +1 -0
  77. package/dist/lib/database/typeorm/util/crypto.js +46 -0
  78. package/dist/lib/database/typeorm/util/crypto.js.map +1 -0
  79. package/dist/lib/database/typeorm/util/error.d.ts +5 -0
  80. package/dist/lib/database/typeorm/util/error.d.ts.map +1 -0
  81. package/dist/lib/database/typeorm/util/error.js +8 -0
  82. package/dist/lib/database/typeorm/util/error.js.map +1 -0
  83. package/dist/lib/database/typeorm/util/logger.d.ts +7 -0
  84. package/dist/lib/database/typeorm/util/logger.d.ts.map +1 -0
  85. package/dist/lib/database/typeorm/util/logger.js +31 -0
  86. package/dist/lib/database/typeorm/util/logger.js.map +1 -0
  87. package/dist/lib/database/typeorm/util/yn.d.ts +2 -0
  88. package/dist/lib/database/typeorm/util/yn.d.ts.map +1 -0
  89. package/dist/lib/database/typeorm/util/yn.js +15 -0
  90. package/dist/lib/database/typeorm/util/yn.js.map +1 -0
  91. package/dist/lib/defaults/managers.d.ts.map +1 -1
  92. package/dist/lib/defaults/managers.js +186 -58
  93. package/dist/lib/defaults/managers.js.map +1 -1
  94. package/dist/lib/hooks/onRequest.d.ts.map +1 -1
  95. package/dist/lib/hooks/onRequest.js +11 -48
  96. package/dist/lib/hooks/onRequest.js.map +1 -1
  97. package/dist/lib/loader/router.d.ts.map +1 -1
  98. package/dist/lib/loader/router.js +92 -83
  99. package/dist/lib/loader/router.js.map +1 -1
  100. package/dist/lib/loader/tenant.d.ts.map +1 -1
  101. package/dist/lib/loader/tenant.js +18 -1
  102. package/dist/lib/loader/tenant.js.map +1 -1
  103. package/dist/lib/locales/en.json +12 -0
  104. package/dist/lib/locales/it.json +12 -0
  105. package/dist/lib/schemas/tenant.d.ts +88 -0
  106. package/dist/lib/schemas/tenant.d.ts.map +1 -0
  107. package/dist/lib/schemas/tenant.js +45 -0
  108. package/dist/lib/schemas/tenant.js.map +1 -0
  109. package/dist/lib/util/regexp.d.ts +2 -0
  110. package/dist/lib/util/regexp.d.ts.map +1 -1
  111. package/dist/lib/util/regexp.js +5 -3
  112. package/dist/lib/util/regexp.js.map +1 -1
  113. package/dist/lib/util/secret.d.ts +11 -0
  114. package/dist/lib/util/secret.d.ts.map +1 -0
  115. package/dist/lib/util/secret.js +70 -0
  116. package/dist/lib/util/secret.js.map +1 -0
  117. package/dist/server.js +4 -1
  118. package/dist/server.js.map +1 -1
  119. package/dist/typeorm.d.ts +15 -0
  120. package/dist/typeorm.d.ts.map +1 -0
  121. package/dist/typeorm.js +86 -0
  122. package/dist/typeorm.js.map +1 -0
  123. package/dist/types/database/typeorm/global.d.ts +56 -0
  124. package/dist/types/database/typeorm/global.d.ts.map +1 -0
  125. package/dist/types/database/typeorm/global.js +2 -0
  126. package/dist/types/database/typeorm/global.js.map +1 -0
  127. package/dist/types/global.d.ts +318 -0
  128. package/dist/types/orm.d.ts +22 -0
  129. package/lib/api/auth/controller/auth.ts +28 -12
  130. package/lib/api/health/controller/health.ts +1 -1
  131. package/lib/api/health/routes.ts +1 -0
  132. package/lib/api/tenants/controller/tenants.ts +211 -0
  133. package/lib/api/tenants/routes.ts +145 -0
  134. package/lib/config/plugins.ts +1 -1
  135. package/lib/database/typeorm/entities/change.ts +11 -0
  136. package/lib/database/typeorm/entities/tenant.ts +20 -0
  137. package/lib/database/typeorm/entities/token.ts +18 -0
  138. package/lib/database/typeorm/entities/user.ts +33 -0
  139. package/lib/database/typeorm/loader/dataBaseManager.ts +89 -0
  140. package/lib/database/typeorm/loader/entities.ts +47 -0
  141. package/lib/database/typeorm/loader/tenantManager.ts +260 -0
  142. package/lib/database/typeorm/loader/tokenManager.ts +157 -0
  143. package/lib/database/typeorm/loader/userManager.ts +432 -0
  144. package/lib/database/typeorm/query/builder.ts +39 -0
  145. package/lib/database/typeorm/query/parser.ts +29 -0
  146. package/lib/database/typeorm/query.ts +326 -0
  147. package/lib/database/typeorm/util/crypto.ts +52 -0
  148. package/lib/database/typeorm/util/error.ts +7 -0
  149. package/lib/database/typeorm/util/logger.ts +35 -0
  150. package/lib/database/typeorm/util/yn.ts +20 -0
  151. package/lib/defaults/managers.ts +191 -64
  152. package/lib/hooks/onRequest.ts +12 -64
  153. package/lib/loader/router.ts +133 -110
  154. package/lib/loader/tenant.ts +29 -13
  155. package/lib/schemas/tenant.ts +49 -0
  156. package/lib/util/regexp.ts +31 -8
  157. package/lib/util/secret.ts +113 -0
  158. package/package.json +54 -13
  159. package/dist/lib/apollo/context.d.ts +0 -6
  160. package/dist/lib/apollo/context.d.ts.map +0 -1
  161. package/dist/lib/apollo/context.js +0 -5
  162. package/dist/lib/apollo/context.js.map +0 -1
  163. package/dist/lib/apollo/resolvers.d.ts +0 -8
  164. package/dist/lib/apollo/resolvers.d.ts.map +0 -1
  165. package/dist/lib/apollo/resolvers.js +0 -8
  166. package/dist/lib/apollo/resolvers.js.map +0 -1
  167. package/dist/lib/apollo/type-defs.d.ts +0 -3
  168. package/dist/lib/apollo/type-defs.d.ts.map +0 -1
  169. package/dist/lib/apollo/type-defs.js +0 -8
  170. package/dist/lib/apollo/type-defs.js.map +0 -1
  171. package/lib/apollo/context.ts +0 -11
  172. package/lib/apollo/resolvers.ts +0 -12
  173. package/lib/apollo/type-defs.ts +0 -9
@@ -0,0 +1,326 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ /* eslint-disable prefer-const */
3
+ import {
4
+ Not,
5
+ Like,
6
+ ILike,
7
+ Raw,
8
+ Equal,
9
+ IsNull,
10
+ In,
11
+ Between,
12
+ MoreThan,
13
+ MoreThanOrEqual,
14
+ LessThan,
15
+ LessThanOrEqual,
16
+ QueryRunner
17
+ } from 'typeorm'
18
+ import yn from './util/yn.js'
19
+ import * as log from './util/logger.js'
20
+ import { parseLogicExpression } from './query/parser.js'
21
+ import { buildWhereFromAst } from './query/builder.js'
22
+
23
+ let sensitiveFields = ['password', 'mfaSecret', 'resetPasswordToken', 'confirmationToken']
24
+
25
+ export const configureSensitiveFields = (fields: string[]) => {
26
+ if (fields && Array.isArray(fields)) {
27
+ log.info(`Volcanic-TypeORM: Overrided sensitive fields: ${fields.join(', ')}`)
28
+ sensitiveFields = fields
29
+ }
30
+ }
31
+
32
+ const evalOrder = (val: string = '') => (['desc', 'd', 'false', '1'].includes(val.toLowerCase()) ? 'desc' : 'asc')
33
+
34
+ const escapeRegExp = (str: string) => {
35
+ return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
36
+ }
37
+
38
+ const isValidIdentifier = (str: string) => /^[a-zA-Z0-9_.]+$/.test(str)
39
+
40
+ const hasProtoRisk = (str: string) => ['__proto__', 'constructor', 'prototype'].includes(str)
41
+
42
+ export const useOrder = (order: string[] = []) => {
43
+ const result = {}
44
+ order
45
+ .filter((o) => !!o)
46
+ .forEach((o: string) => {
47
+ const parts = o.split(':')
48
+ const fieldFullPath = parts[0].split('.')
49
+
50
+ // Controllo sicurezza identificatore
51
+ if (!isValidIdentifier(parts[0])) {
52
+ log.warn(`Volcanic-TypeORM: Invalid sort field skipped: ${parts[0]}`)
53
+ return
54
+ }
55
+
56
+ const sortType = evalOrder(parts[1])
57
+
58
+ let target = result
59
+ while (fieldFullPath.length > 1) {
60
+ const fieldPath: string = fieldFullPath.shift() || ''
61
+ if (hasProtoRisk(fieldPath)) {
62
+ continue
63
+ }
64
+
65
+ target = target[fieldPath] = target[fieldPath] || {}
66
+ }
67
+
68
+ const fieldName = fieldFullPath[0]
69
+ if (hasProtoRisk(fieldName)) {
70
+ return
71
+ }
72
+
73
+ target[fieldName] = sortType
74
+ })
75
+
76
+ return result
77
+ }
78
+
79
+ const typecastValue = (value: any) => {
80
+ if (typeof value !== 'string') return value
81
+ const lowerValue = value.toLowerCase()
82
+ if (lowerValue === 'true') return true
83
+ if (lowerValue === 'false') return false
84
+ if (lowerValue === 'null') return null
85
+ return value
86
+ }
87
+
88
+ export const useWhere = (where: any, repo?: any) => {
89
+ const aliasMap = new Map<string, any>()
90
+ const isTargetMongo = isMongo(repo)
91
+ const val = (v) => v || 'notFound'
92
+
93
+ const reservedOperators = {
94
+ ':null': (v) => (typecastValue(v) === false ? Not(IsNull()) : IsNull()),
95
+ ':notNull': (v) => (typecastValue(v) === true ? Not(IsNull()) : IsNull()),
96
+ ':in': (v) => In(val(v).split(',').map(typecastValue)),
97
+ ':nin': (v) => Not(In(val(v).split(',').map(typecastValue))),
98
+ ':likei': (v) => (isTargetMongo ? new RegExp(escapeRegExp(val(v)), 'i') : ILike(`%${val(v)}%`)),
99
+ ':containsi': (v) => (isTargetMongo ? new RegExp(escapeRegExp(val(v)), 'i') : ILike(`%${val(v)}%`)),
100
+ ':ncontainsi': (v) => (isTargetMongo ? Not(new RegExp(escapeRegExp(val(v)), 'i')) : Not(ILike(`%${val(v)}%`))),
101
+ ':startsi': (v) => (isTargetMongo ? new RegExp(`^${escapeRegExp(val(v))}`, 'i') : ILike(`${val(v)}%`)),
102
+ ':endsi': (v) => (isTargetMongo ? new RegExp(`${escapeRegExp(val(v))}$`, 'i') : ILike(`%${val(v)}`)),
103
+ ':eqi': (v) => (isTargetMongo ? new RegExp(`^${escapeRegExp(val(v))}$`, 'i') : ILike(v)),
104
+ ':neqi': (v) => (isTargetMongo ? Not(new RegExp(`^${escapeRegExp(val(v))}$`, 'i')) : Not(ILike(v))),
105
+ ':like': (v) => Like(`${val(v)}`),
106
+ ':contains': (v) => Like(`%${val(v)}%`),
107
+ ':ncontains': (v) => Not(Like(`%${val(v)}%`)),
108
+ ':starts': (v) => Like(`${val(v)}%`),
109
+ ':ends': (v) => Like(`%${val(v)}`),
110
+ ':eq': (v) => {
111
+ const typedValue = typecastValue(v)
112
+ if (typedValue === null) return IsNull()
113
+ return isTargetMongo ? typedValue : Equal(typedValue)
114
+ },
115
+ ':neq': (v) => Not(Equal(typecastValue(v))),
116
+ ':gt': (v) => MoreThan(v),
117
+ ':ge': (v) => MoreThanOrEqual(v),
118
+ ':lt': (v) => LessThan(v),
119
+ ':le': (v) => LessThanOrEqual(v),
120
+ ':between': (v) => {
121
+ const s = v?.split(':')
122
+ return s?.length == 2 ? Between(s[0], s[1]) : v
123
+ },
124
+ ':overlap': (v) => {
125
+ const values = val(v).split(',').map(typecastValue)
126
+ if (isTargetMongo) {
127
+ return { $in: values }
128
+ }
129
+ return Raw((alias) => `${alias} && ARRAY[:...overlapValues]::text[]`, { overlapValues: values })
130
+ }
131
+ }
132
+
133
+ if (yn(process.env.VOLCANIC_CUSTOM_QUERY_OPERATORS, false)) {
134
+ log.warn('Volcanic-TypeORM: Custom query operators (:raw) enabled. SECURITY RISK!')
135
+ reservedOperators[':raw'] = (v) => Raw((alias) => `${alias} ${v}`)
136
+ }
137
+
138
+ const reservedWords = Object.keys(reservedOperators).join('|')
139
+ const aliasRegex = /\[([^\]]+)\]$/
140
+
141
+ const allConditions = {}
142
+
143
+ for (const rawKey in where) {
144
+ let alias = ''
145
+ let key = rawKey
146
+ if (hasProtoRisk(rawKey)) {
147
+ continue
148
+ }
149
+
150
+ const aliasMatch = rawKey.match(aliasRegex)
151
+ if (aliasMatch) {
152
+ alias = aliasMatch[1]
153
+ key = rawKey.replace(aliasRegex, '')
154
+ } else {
155
+ alias = key
156
+ }
157
+
158
+ const m = key.match(new RegExp(`(${reservedWords})\\b`, 'ig'))
159
+ const operator = m?.length ? m[0] : ':eq'
160
+ const fullPath = key.replace(operator, '')
161
+
162
+ if (!isValidIdentifier(fullPath)) {
163
+ log.warn(`Volcanic-TypeORM: Invalid filter field skipped: ${fullPath}`)
164
+ continue
165
+ }
166
+
167
+ const parts = fullPath.split('.')
168
+
169
+ if (sensitiveFields.some((field) => fullPath.includes(field))) {
170
+ continue
171
+ }
172
+
173
+ let value = where[rawKey]
174
+ if (operator && reservedOperators[operator]) {
175
+ value = reservedOperators[operator](value)
176
+ }
177
+
178
+ let condition = {}
179
+ let target = condition
180
+ while (parts.length > 1) {
181
+ const part: string = parts.shift() || ''
182
+ if (hasProtoRisk(part)) {
183
+ break
184
+ }
185
+
186
+ target = target[part] = target[part] || {}
187
+ }
188
+
189
+ const finalFieldName = parts[0]
190
+ if (!hasProtoRisk(finalFieldName)) {
191
+ target[finalFieldName] = value
192
+ aliasMap.set(alias, condition)
193
+ Object.assign(allConditions, condition)
194
+ }
195
+ }
196
+
197
+ return { allConditions, aliasMap }
198
+ }
199
+
200
+ export function applyQuery(data, extraWhere, repo) {
201
+ const { page: p = 1, pageSize = 25, skip: sk = 0, take: tk = 0, sort: s, _logic, ...where } = data
202
+ const page: number = (p < 1 ? 1 : p) - 1
203
+ const take: number = tk || pageSize
204
+ const skip: number = sk || page * pageSize
205
+ const order: string[] = !Array.isArray(s) ? [s] : s
206
+
207
+ const query = {} as {
208
+ skip?: number
209
+ take?: number
210
+ order?: object
211
+ where?: object | object[]
212
+ }
213
+
214
+ if (skip) query.skip = skip
215
+ if (take) query.take = take
216
+ if (order) query.order = useOrder(order)
217
+
218
+ const { allConditions, aliasMap } = useWhere(where, repo)
219
+
220
+ if (_logic) {
221
+ try {
222
+ const ast = parseLogicExpression(_logic)
223
+ query.where = buildWhereFromAst(ast, aliasMap, isMongo(repo))
224
+ } catch (e) {
225
+ console.error('Volcanic-TypeORM: Error parsing _logic parameter.', e)
226
+ query.where = allConditions
227
+ }
228
+ } else {
229
+ query.where = allConditions
230
+ }
231
+
232
+ if (extraWhere) {
233
+ const { allConditions: extraConditions } = useWhere(extraWhere, repo)
234
+ if (query.where && Object.keys(query.where).length > 0) {
235
+ if (isMongo(repo)) {
236
+ query.where = { $and: [query.where, extraConditions] }
237
+ } else {
238
+ if (Array.isArray(query.where)) {
239
+ query.where = query.where.map((condition) => ({
240
+ ...condition,
241
+ ...extraConditions
242
+ }))
243
+ } else {
244
+ query.where = { ...query.where, ...extraConditions }
245
+ }
246
+ }
247
+ } else {
248
+ query.where = extraConditions
249
+ }
250
+ }
251
+
252
+ return query
253
+ }
254
+
255
+ export async function executeFindQuery(
256
+ repo: any,
257
+ relations: any = {},
258
+ data: any = {},
259
+ extraWhere: any = {},
260
+ extraOptions: any = {}
261
+ ) {
262
+ const extra = applyQuery(data, extraWhere, repo)
263
+
264
+ const [records = [], totalCount] = await repo.findAndCount({
265
+ relations: relations,
266
+ ...extra,
267
+ ...extraOptions
268
+ })
269
+
270
+ return {
271
+ records,
272
+ headers: {
273
+ 'v-count': records.length,
274
+ 'v-total': totalCount,
275
+ 'v-page': data.page || 1,
276
+ 'v-pageSize': extra.take,
277
+ 'v-pageCount': Math.ceil(extra.take ? totalCount / extra.take : 1)
278
+ }
279
+ }
280
+ }
281
+
282
+ export async function executeFindView(
283
+ viewEntity: any,
284
+ data: any = {},
285
+ extraWhere: any = {},
286
+ extraOptions: any = {},
287
+ runner?: QueryRunner
288
+ ) {
289
+ const extra = applyQuery(data, extraWhere, null)
290
+ const manager = runner ? runner.manager : global.connection.manager
291
+
292
+ const [records = [], totalCount] = await manager.findAndCount(viewEntity, {
293
+ ...extra,
294
+ ...extraOptions
295
+ })
296
+
297
+ return {
298
+ records,
299
+ headers: {
300
+ 'v-count': records.length,
301
+ 'v-total': totalCount,
302
+ 'v-page': data.page || 1,
303
+ 'v-pageSize': extra.take,
304
+ 'v-pageCount': Math.ceil(extra.take ? totalCount / extra.take : 1)
305
+ }
306
+ }
307
+ }
308
+
309
+ export async function executeCountQuery(repo: any, data = {}, extraWhere: any = {}) {
310
+ const { where = {} } = applyQuery(data, extraWhere, repo)
311
+ return await repo.count(isMongo(repo) ? where : { where: where })
312
+ }
313
+
314
+ export async function executeCountView(viewEntity: any, data = {}, extraWhere: any = {}, runner?: QueryRunner) {
315
+ const { where = {} } = applyQuery(data, extraWhere, null)
316
+ const manager = runner ? runner.manager : global.connection.manager
317
+ return await manager.count(viewEntity, { where: where })
318
+ }
319
+
320
+ function getType(repo) {
321
+ return repo?.manager?.connection?.options?.type || 'pg'
322
+ }
323
+
324
+ function isMongo(repo) {
325
+ return getType(repo) === 'mongodb'
326
+ }
@@ -0,0 +1,52 @@
1
+ import * as crypto from 'crypto'
2
+
3
+ const ALGORITHM_NEW = 'aes-256-gcm'
4
+ const ALGORITHM_OLD = 'aes-256-cbc'
5
+ const SECRET_KEY = process.env.MFA_DB_SECRET || process.env.JWT_SECRET
6
+ const IV_LENGTH_NEW = 12
7
+
8
+ function getKey() {
9
+ if (!SECRET_KEY) {
10
+ throw new Error('Secret key is not defined in environment variables.')
11
+ }
12
+ return crypto.createHash('sha256').update(String(SECRET_KEY)).digest('base64').substring(0, 32)
13
+ }
14
+
15
+ export function encrypt(text: string): string {
16
+ if (!text) return text
17
+ const iv = crypto.randomBytes(IV_LENGTH_NEW)
18
+ const cipher = crypto.createCipheriv(ALGORITHM_NEW, Buffer.from(getKey()), iv)
19
+ let encrypted = cipher.update(text, 'utf8')
20
+ encrypted = Buffer.concat([encrypted, cipher.final()])
21
+ const authTag = cipher.getAuthTag()
22
+ return iv.toString('hex') + ':' + authTag.toString('hex') + ':' + encrypted.toString('hex')
23
+ }
24
+
25
+ export function decrypt(text: string): string {
26
+ if (!text) return text
27
+ const textParts = text.split(':')
28
+
29
+ if (textParts.length === 2) {
30
+ const iv = Buffer.from(textParts[0], 'hex')
31
+ const encryptedText = Buffer.from(textParts[1], 'hex')
32
+ const decipher = crypto.createDecipheriv(ALGORITHM_OLD, Buffer.from(getKey()), iv)
33
+ let decrypted = decipher.update(encryptedText)
34
+ decrypted = Buffer.concat([decrypted, decipher.final()])
35
+ return decrypted.toString()
36
+ }
37
+
38
+ if (textParts.length === 3) {
39
+ const iv = Buffer.from(textParts[0], 'hex')
40
+ const authTag = Buffer.from(textParts[1], 'hex')
41
+ const encryptedText = Buffer.from(textParts[2], 'hex')
42
+
43
+ const decipher = crypto.createDecipheriv(ALGORITHM_NEW, Buffer.from(getKey()), iv)
44
+ decipher.setAuthTag(authTag)
45
+
46
+ let decrypted = decipher.update(encryptedText, undefined, 'utf8')
47
+ decrypted += decipher.final('utf8')
48
+ return decrypted
49
+ }
50
+
51
+ return text
52
+ }
@@ -0,0 +1,7 @@
1
+ export class ServiceError extends Error {
2
+ statusCode: number
3
+ constructor(message: string, statusCode: number = 500) {
4
+ super(message)
5
+ this.statusCode = statusCode
6
+ }
7
+ }
@@ -0,0 +1,35 @@
1
+ export function trace(data) {
2
+ if (global.isLoggingEnabled && global.log?.trace) {
3
+ global.log.trace(data)
4
+ }
5
+ }
6
+
7
+ export function debug(data) {
8
+ if (global.isLoggingEnabled && global.log?.debug) {
9
+ global.log.debug(data)
10
+ }
11
+ }
12
+
13
+ export function info(data) {
14
+ if (global.isLoggingEnabled && global.log?.info) {
15
+ global.log.info(data)
16
+ }
17
+ }
18
+
19
+ export function warn(data) {
20
+ if (global.isLoggingEnabled && global.log?.warn) {
21
+ global.log.warn(data)
22
+ }
23
+ }
24
+
25
+ export function error(data) {
26
+ if (global.isLoggingEnabled && global.log?.error) {
27
+ global.log.error(data)
28
+ }
29
+ }
30
+
31
+ export function fatal(data) {
32
+ if (global.isLoggingEnabled && global.log?.fatal) {
33
+ global.log.fatal(data)
34
+ }
35
+ }
@@ -0,0 +1,20 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ 'use strict'
3
+
4
+ export default function yn(value: any, defaultValue: boolean): boolean {
5
+ if (value === undefined || value === null) {
6
+ return defaultValue
7
+ }
8
+
9
+ const val = String(value).trim()
10
+
11
+ if (/^(?:y|yes|true|1|on)$/i.test(val)) {
12
+ return true
13
+ }
14
+
15
+ if (/^(?:n|no|false|0|off)$/i.test(val)) {
16
+ return false
17
+ }
18
+
19
+ return defaultValue || false
20
+ }