@blazedpath/commons 0.0.4

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 (224) hide show
  1. package/README.md +3 -0
  2. package/blz-base/health/index.js +215 -0
  3. package/blz-base/index.js +1466 -0
  4. package/blz-cache/LruCache.js +44 -0
  5. package/blz-cache/index.js +29 -0
  6. package/blz-config/index.js +434 -0
  7. package/blz-core/index.js +364 -0
  8. package/blz-cryptography/index.js +54 -0
  9. package/blz-datetimes/index.js +356 -0
  10. package/blz-file/example.dat +2545 -0
  11. package/blz-file/fileService.js +205 -0
  12. package/blz-file/index.js +94 -0
  13. package/blz-file/index.test.js +31 -0
  14. package/blz-file/lab.js +33 -0
  15. package/blz-hazelcast/index.js +189 -0
  16. package/blz-hazelcast/lib/credentials.js +25 -0
  17. package/blz-hazelcast/lib/credentialsFactory.js +12 -0
  18. package/blz-hazelcast/lib/hazelcastCache.js +234 -0
  19. package/blz-iterable/index.js +446 -0
  20. package/blz-json-schema/index.js +11 -0
  21. package/blz-jwt/index.js +121 -0
  22. package/blz-kafka/index.js +522 -0
  23. package/blz-math/index.js +131 -0
  24. package/blz-mongodb/index.js +326 -0
  25. package/blz-rds/__test__/scape.test.js +58 -0
  26. package/blz-rds/blz-rds-executor.js +578 -0
  27. package/blz-rds/blz-rds-helper.js +310 -0
  28. package/blz-rds/commands/core/add.js +13 -0
  29. package/blz-rds/commands/core/and.js +18 -0
  30. package/blz-rds/commands/core/asc.js +10 -0
  31. package/blz-rds/commands/core/avg.js +10 -0
  32. package/blz-rds/commands/core/column-ref.js +8 -0
  33. package/blz-rds/commands/core/count-distinct.js +10 -0
  34. package/blz-rds/commands/core/count.js +10 -0
  35. package/blz-rds/commands/core/decimal.js +8 -0
  36. package/blz-rds/commands/core/desc.js +10 -0
  37. package/blz-rds/commands/core/distinct.js +10 -0
  38. package/blz-rds/commands/core/divide.js +11 -0
  39. package/blz-rds/commands/core/embedded-exists.js +17 -0
  40. package/blz-rds/commands/core/embedded-select.js +17 -0
  41. package/blz-rds/commands/core/equals.js +9 -0
  42. package/blz-rds/commands/core/false.js +8 -0
  43. package/blz-rds/commands/core/greater-or-equal.js +9 -0
  44. package/blz-rds/commands/core/greater.js +9 -0
  45. package/blz-rds/commands/core/in.js +9 -0
  46. package/blz-rds/commands/core/integer.js +8 -0
  47. package/blz-rds/commands/core/is-not-null.js +11 -0
  48. package/blz-rds/commands/core/is-null-or-value.js +10 -0
  49. package/blz-rds/commands/core/is-null.js +11 -0
  50. package/blz-rds/commands/core/less-or-equal.js +9 -0
  51. package/blz-rds/commands/core/less-unary.js +12 -0
  52. package/blz-rds/commands/core/less.js +9 -0
  53. package/blz-rds/commands/core/like.js +12 -0
  54. package/blz-rds/commands/core/max.js +10 -0
  55. package/blz-rds/commands/core/min.js +10 -0
  56. package/blz-rds/commands/core/multiply.js +13 -0
  57. package/blz-rds/commands/core/not-equals.js +9 -0
  58. package/blz-rds/commands/core/not-in.js +9 -0
  59. package/blz-rds/commands/core/not.js +13 -0
  60. package/blz-rds/commands/core/null.js +8 -0
  61. package/blz-rds/commands/core/nvl.js +11 -0
  62. package/blz-rds/commands/core/or.js +13 -0
  63. package/blz-rds/commands/core/parameter.js +34 -0
  64. package/blz-rds/commands/core/remainder.js +16 -0
  65. package/blz-rds/commands/core/string.js +8 -0
  66. package/blz-rds/commands/core/subtract.js +13 -0
  67. package/blz-rds/commands/core/sum.js +10 -0
  68. package/blz-rds/commands/core/true.js +8 -0
  69. package/blz-rds/commands/core/tuple.js +13 -0
  70. package/blz-rds/commands/datetimes/add-days.js +11 -0
  71. package/blz-rds/commands/datetimes/add-hours.js +11 -0
  72. package/blz-rds/commands/datetimes/add-milliseconds.js +11 -0
  73. package/blz-rds/commands/datetimes/add-minutes.js +11 -0
  74. package/blz-rds/commands/datetimes/add-months.js +11 -0
  75. package/blz-rds/commands/datetimes/add-seconds.js +11 -0
  76. package/blz-rds/commands/datetimes/add-years.js +11 -0
  77. package/blz-rds/commands/datetimes/date-diff.js +11 -0
  78. package/blz-rds/commands/datetimes/date.js +12 -0
  79. package/blz-rds/commands/datetimes/datetime-diff.js +11 -0
  80. package/blz-rds/commands/datetimes/datetime.js +15 -0
  81. package/blz-rds/commands/datetimes/day.js +10 -0
  82. package/blz-rds/commands/datetimes/hour.js +10 -0
  83. package/blz-rds/commands/datetimes/millisecond.js +10 -0
  84. package/blz-rds/commands/datetimes/minute.js +10 -0
  85. package/blz-rds/commands/datetimes/month-text.js +10 -0
  86. package/blz-rds/commands/datetimes/month.js +10 -0
  87. package/blz-rds/commands/datetimes/now.js +9 -0
  88. package/blz-rds/commands/datetimes/second.js +10 -0
  89. package/blz-rds/commands/datetimes/subtract-days.js +11 -0
  90. package/blz-rds/commands/datetimes/subtract-hours.js +11 -0
  91. package/blz-rds/commands/datetimes/subtract-milliseconds.js +11 -0
  92. package/blz-rds/commands/datetimes/subtract-minutes.js +11 -0
  93. package/blz-rds/commands/datetimes/subtract-seconds.js +11 -0
  94. package/blz-rds/commands/datetimes/time-diff.js +11 -0
  95. package/blz-rds/commands/datetimes/time.js +13 -0
  96. package/blz-rds/commands/datetimes/today.js +9 -0
  97. package/blz-rds/commands/datetimes/week-day-text.js +10 -0
  98. package/blz-rds/commands/datetimes/week-day.js +10 -0
  99. package/blz-rds/commands/datetimes/week.js +10 -0
  100. package/blz-rds/commands/datetimes/year.js +10 -0
  101. package/blz-rds/commands/math/abs.js +10 -0
  102. package/blz-rds/commands/math/acos.js +10 -0
  103. package/blz-rds/commands/math/asin.js +10 -0
  104. package/blz-rds/commands/math/atan.js +10 -0
  105. package/blz-rds/commands/math/atan2.js +11 -0
  106. package/blz-rds/commands/math/ceil.js +10 -0
  107. package/blz-rds/commands/math/cos.js +10 -0
  108. package/blz-rds/commands/math/cosh.js +10 -0
  109. package/blz-rds/commands/math/exp.js +10 -0
  110. package/blz-rds/commands/math/floor.js +10 -0
  111. package/blz-rds/commands/math/log.js +18 -0
  112. package/blz-rds/commands/math/log10.js +10 -0
  113. package/blz-rds/commands/math/pow.js +11 -0
  114. package/blz-rds/commands/math/random.js +9 -0
  115. package/blz-rds/commands/math/round.js +18 -0
  116. package/blz-rds/commands/math/sign.js +10 -0
  117. package/blz-rds/commands/math/sin.js +10 -0
  118. package/blz-rds/commands/math/sinh.js +10 -0
  119. package/blz-rds/commands/math/sqrt.js +10 -0
  120. package/blz-rds/commands/math/tan.js +10 -0
  121. package/blz-rds/commands/math/tanh.js +10 -0
  122. package/blz-rds/commands/math/trunc.js +18 -0
  123. package/blz-rds/commands/strings/concat.js +20 -0
  124. package/blz-rds/commands/strings/contains.js +12 -0
  125. package/blz-rds/commands/strings/ends-with.js +12 -0
  126. package/blz-rds/commands/strings/index-of.js +11 -0
  127. package/blz-rds/commands/strings/is-null-or-empty.js +11 -0
  128. package/blz-rds/commands/strings/is-null-or-white-space.js +11 -0
  129. package/blz-rds/commands/strings/join.js +22 -0
  130. package/blz-rds/commands/strings/last-index-of.js +11 -0
  131. package/blz-rds/commands/strings/length.js +10 -0
  132. package/blz-rds/commands/strings/pad-left.js +20 -0
  133. package/blz-rds/commands/strings/pad-right.js +20 -0
  134. package/blz-rds/commands/strings/replace.js +12 -0
  135. package/blz-rds/commands/strings/starts-with.js +12 -0
  136. package/blz-rds/commands/strings/substring.js +12 -0
  137. package/blz-rds/commands/strings/to-lower.js +10 -0
  138. package/blz-rds/commands/strings/to-upper.js +10 -0
  139. package/blz-rds/commands/strings/trim-end.js +10 -0
  140. package/blz-rds/commands/strings/trim-start.js +10 -0
  141. package/blz-rds/commands/strings/trim.js +10 -0
  142. package/blz-rds/index.js +744 -0
  143. package/blz-rds-mysql/base.js +857 -0
  144. package/blz-rds-mysql/connection-manager.js +129 -0
  145. package/blz-rds-mysql/execute-bulk-insert.js +35 -0
  146. package/blz-rds-mysql/execute-bulk-merge.js +45 -0
  147. package/blz-rds-mysql/execute-non-query.js +34 -0
  148. package/blz-rds-mysql/execute-query.js +50 -0
  149. package/blz-rds-mysql/index.js +41 -0
  150. package/blz-rds-mysql/stored-procedure.js +207 -0
  151. package/blz-rds-mysql/syntaxis.json +114 -0
  152. package/blz-rds-mysqlx/base.js +846 -0
  153. package/blz-rds-mysqlx/connection-manager.js +141 -0
  154. package/blz-rds-mysqlx/execute-bulk-insert.js +35 -0
  155. package/blz-rds-mysqlx/execute-bulk-merge.js +45 -0
  156. package/blz-rds-mysqlx/execute-non-query.js +29 -0
  157. package/blz-rds-mysqlx/execute-query.js +39 -0
  158. package/blz-rds-mysqlx/index.js +41 -0
  159. package/blz-rds-mysqlx/stored-procedure.js +179 -0
  160. package/blz-rds-mysqlx/syntaxis.json +105 -0
  161. package/blz-rds-oracle/index.js +540 -0
  162. package/blz-rds-oracle/syntaxis.json +112 -0
  163. package/blz-rds-postgres/base.js +861 -0
  164. package/blz-rds-postgres/connection-manager.js +225 -0
  165. package/blz-rds-postgres/execute-bulk-insert.js +81 -0
  166. package/blz-rds-postgres/execute-bulk-merge.js +93 -0
  167. package/blz-rds-postgres/execute-non-query.js +23 -0
  168. package/blz-rds-postgres/execute-query.js +37 -0
  169. package/blz-rds-postgres/index.js +41 -0
  170. package/blz-rds-postgres/result-set.js +51 -0
  171. package/blz-rds-postgres/stored-procedure.js +116 -0
  172. package/blz-rds-postgres/syntaxis.json +114 -0
  173. package/blz-redis/index.js +217 -0
  174. package/blz-redis/lib/redisCache.js +265 -0
  175. package/blz-regex/index.js +25 -0
  176. package/blz-security/.eslintrc.js +15 -0
  177. package/blz-security/__test__/AuthorizationKpn.yaml +1043 -0
  178. package/blz-security/__test__/FinancingSetting.yaml +177 -0
  179. package/blz-security/__test__/KpnConfigPortal.yaml +330 -0
  180. package/blz-security/__test__/OrderManagement.yaml +5190 -0
  181. package/blz-security/__test__/Security.yaml +128 -0
  182. package/blz-security/__test__/autorization.test.js +105 -0
  183. package/blz-security/__test__/orderManagement.test.js +26 -0
  184. package/blz-security/__test__/secureUrl.test.js +79 -0
  185. package/blz-security/__test__/solveMergeRule.test.js +109 -0
  186. package/blz-security/__test__/sqlInjectionGuard.test.js +203 -0
  187. package/blz-security/__test__/xssGuard.test.js +204 -0
  188. package/blz-security/authorizationService.js +536 -0
  189. package/blz-security/config/global.js +8 -0
  190. package/blz-security/config/welcome +8 -0
  191. package/blz-security/doc/README.md +75 -0
  192. package/blz-security/filescanner/index.js +46 -0
  193. package/blz-security/helpers/consts.js +229 -0
  194. package/blz-security/helpers/utils.js +267 -0
  195. package/blz-security/implementations/cache.js +90 -0
  196. package/blz-security/implementations/oidc.js +404 -0
  197. package/blz-security/implementations/pkceCacheStore.js +23 -0
  198. package/blz-security/implementations/saml.js +10 -0
  199. package/blz-security/implementations/uma.js +63 -0
  200. package/blz-security/implementations/webAuthn.js +9 -0
  201. package/blz-security/implementations/wstg.js +72 -0
  202. package/blz-security/index.js +77 -0
  203. package/blz-security/lab/index.js +27 -0
  204. package/blz-security/middleware/HapiServerAzureAd.js +641 -0
  205. package/blz-security/middleware/HapiServerKeycloak.js +840 -0
  206. package/blz-security/middleware/HapiServerSimToken.js +247 -0
  207. package/blz-security/middleware/hapi.js +515 -0
  208. package/blz-security/middleware/hapiServer.js +974 -0
  209. package/blz-security/navigationMemoryRepository.js +15 -0
  210. package/blz-security/navigationMongoDbRepository.js +73 -0
  211. package/blz-security/secureUrlService.js +47 -0
  212. package/blz-security/securityService.js +409 -0
  213. package/blz-security/sqlInjectionGuard.js +162 -0
  214. package/blz-security/templates/forbidden.html +0 -0
  215. package/blz-security/templates/session-iframe-azure-ad.html +7 -0
  216. package/blz-security/templates/session-iframe.html +73 -0
  217. package/blz-security/templates/unauthorized.html +1 -0
  218. package/blz-security/xssGuard.js +87 -0
  219. package/blz-strings/index.js +167 -0
  220. package/blz-uuid/index.js +7 -0
  221. package/blz-yaml/index.js +19 -0
  222. package/index.js +84 -0
  223. package/package.json +97 -0
  224. package/process-managers/index.js +422 -0
@@ -0,0 +1,536 @@
1
+ #!/usr/bin/env node
2
+ module.exports = class AuthorizationService {
3
+ constructor (utils, logger) {
4
+ this.utils = utils
5
+ this.logger = logger
6
+ this.config = { roles: [], permissions: [] }
7
+ this.WIDGET_SEPARATOR = '|'
8
+ this.WIDGET_SEPARATOR_REPLACE = new RegExp(this.WIDGET_SEPARATOR + '.*$')
9
+ }
10
+
11
+ extendConfig (config) {
12
+ // extend permissions
13
+ for (const permission of config.permissions) {
14
+ if (permission.extends && !permission._completed) {
15
+ this.extendPermission(config, permission)
16
+ }
17
+ }
18
+ // extend roles
19
+ for (const role of config.roles) {
20
+ if (role.extends && !role._completed) {
21
+ this.extendRole(config, role)
22
+ }
23
+ }
24
+ // remove flags
25
+ for (const permission of config.permissions) {
26
+ delete permission._completed
27
+ }
28
+ for (const role of config.roles) {
29
+ delete role._completed
30
+ }
31
+ }
32
+
33
+ extendPermission (config, permission) {
34
+ for (const extend of permission.extends) {
35
+ const base = config.permissions.find(p => p.name === extend)
36
+ if (!base) {
37
+ throw new Error(`Permission ${permission.name} extends ${extend} but not exists`)
38
+ }
39
+ if (base.extends && base.extends.includes(base.name)) {
40
+ throw new Error(`Permission ${permission.name} extends ${base.name} but it is a circular reference`)
41
+ }
42
+ if (base.extends && !base._completed) {
43
+ this.extendPermission(config, base)
44
+ }
45
+ // Agrega las reglas que existen en el permiso base y no en el actual
46
+ for (const rule of base.rules) {
47
+ const exists = permission.rules.find(p => p.path === rule.path && p.actions === rule.actions)
48
+ if (!exists) {
49
+ permission.rules.push(rule)
50
+ }
51
+ }
52
+ }
53
+ permission._completed = true
54
+ }
55
+
56
+ extendRole (config, role) {
57
+ for (const extend of role.extends) {
58
+ const base = config.roles.find(p => p.name === extend)
59
+ if (!base) {
60
+ throw new Error(`Role ${role.name} extends ${extend} but not exists`)
61
+ }
62
+ if (base.extends && base.extends.includes(base.name)) {
63
+ throw new Error(`Rome ${role.name} extends ${base.name} but it is a circular reference`)
64
+ }
65
+ if (base.extends && !base._completed) {
66
+ this.extendRole(config, base)
67
+ }
68
+ // Agrega los permisos que existen en el role base y no en el actual
69
+ for (const permission of base.permissions) {
70
+ if (!role.permissions.includes(permission)) {
71
+ role.permissions.push(permission)
72
+ }
73
+ }
74
+ }
75
+ role._completed = true
76
+ }
77
+
78
+
79
+ importSecurityConfig (config) {
80
+ this._solveRoleId(config)
81
+ this._validateAndNormalizeConfig(config)
82
+ this.extendConfig(config)
83
+ this._solveRulesByRole(config)
84
+ this._solveMergeRulesByRole(config)
85
+ this.config = config
86
+ let defaultUserRole = process.env.blz_defaultUserRole;
87
+ if (defaultUserRole)
88
+ this.config.defaultUserRole = defaultUserRole;
89
+ return this.config
90
+ }
91
+
92
+ getFrontendSecurityRules (roles, domains) {
93
+ const _roles = this._getRoles(roles)
94
+ const frontendRules = []
95
+ for (const role of _roles) {
96
+ const rules = this._getSecurityRulesByRole(role, 'frontend', domains)
97
+ for (const rule of rules) {
98
+ const previousRule = frontendRules.find(p => p.path === rule.path && p.actions === rule.actions)
99
+ if (!previousRule) {
100
+ frontendRules.push(rule)
101
+ } else if (!previousRule.enable && rule.enable) {
102
+ previousRule.enable = rule.enable
103
+ }
104
+ }
105
+ }
106
+ const arr = []
107
+ // Resuelve las reglas por acciones
108
+ for (const rule of frontendRules) {
109
+ if (rule.actions && rule.actions.trim() !== '') {
110
+ const actions = rule.actions.split(',')
111
+ for (const action of actions) {
112
+ arr.push({ path: rule.path.trim() + '|' + action.trim(), enable: rule.enable })
113
+ }
114
+ }
115
+ }
116
+ // Resuelve las reglas sin acciones a nivel de path
117
+ for (const rule of frontendRules) {
118
+ if (!rule.actions || rule.actions.trim() === '') {
119
+ const enableRule = arr.some(p => p.path.split('|')[0] === rule.path && p.enable)
120
+ const previousRule = arr.find(p => p.path === rule.path && (!p.actions || p.actions.trim() === ''))
121
+ if (!previousRule) {
122
+ // Si no existe una regla previa, se agrega
123
+ arr.push({ path: rule.path.trim(), enable: enableRule || rule.enable })
124
+ } else if (previousRule && !previousRule.enable && enableRule) {
125
+ // Si existe una regla previa que habilita el path, se habilita
126
+ previousRule.enable = true
127
+ }
128
+ }
129
+ }
130
+
131
+ const map = new Map();
132
+ arr.forEach(item => {
133
+ // Si no existe el path en el mapa, lo agregamos.
134
+ if (!map.has(item.path)) {
135
+ map.set(item.path, item);
136
+ } else {
137
+ // Si ya existe, verificamos el flag enable.
138
+ const existing = map.get(item.path);
139
+ // Si el existente es false y el nuevo es true, reemplazamos.
140
+ if (!existing.enable && item.enable) {
141
+ map.set(item.path, item);
142
+ }
143
+ // En caso contrario, dejamos el existente.
144
+ }
145
+ });
146
+ // Convertimos el mapa a un array.
147
+ const result = Array.from(map.values());
148
+ return result
149
+ }
150
+
151
+ getSecurityRules (roles, side, domains) {
152
+ const rules = []
153
+ for (const role of roles) {
154
+ const rulesByRole = this._getSecurityRulesByRole(role, side, domains)
155
+ for (const rule of rulesByRole) {
156
+ if (!rules.map(p => p.path).includes(rule.path)) {
157
+ rules.push(rule)
158
+ }
159
+ }
160
+ }
161
+ return rules
162
+ }
163
+
164
+ getPermissions () {
165
+ if (!this.config || !this.config.permissions || this.config.permissions.length === 0) {
166
+ return []
167
+ }
168
+ return this.config.permissions.filter(p => p.visible || p.visible === null || p.visible === undefined ).map(p => p.name).sort()
169
+ }
170
+
171
+ authorized (path, action, roles) {
172
+ if (this.config.defaultUserRole)
173
+ roles.push(this.config.defaultUserRole);
174
+ if (path.startsWith('/api')) {
175
+ return this._checkApi(path, action, roles)
176
+ } else {
177
+ if (!action || action.trim() === '') {
178
+ return this._checkPath(path, roles)
179
+ } else {
180
+ return this._checkWidget(path, action, roles)
181
+ }
182
+ }
183
+ }
184
+
185
+ defaultAuthorized (path, action, roles) {
186
+ const result = this.authorized(path, action, roles)
187
+ if (result === null || result === undefined) {
188
+ return true
189
+ }
190
+ return result
191
+ }
192
+
193
+ // Private methods //////////////////////////////////////////////////////////////////////////////////////////////
194
+
195
+ _getSecurityRulesByRole (roleId, side, domains) {
196
+ const role = this.config.roles.find(p => p.externalId === roleId)
197
+ if (!role || !role.rules) {
198
+ return []
199
+ }
200
+ const securityRules = role.rules[side]
201
+ if (!securityRules) {
202
+ return []
203
+ }
204
+ if (!domains || domains.length === 0) {
205
+ return securityRules
206
+ }
207
+ return securityRules.filter(p => domains.includes(p.domain))
208
+ }
209
+
210
+
211
+ _solveRulesByRole (config) {
212
+ for (const role of config.roles) {
213
+ role.rules = { backend: [], frontend: [] }
214
+ for (const permissionName of role.permissions) {
215
+ const permission = config.permissions.find(p => p.name === permissionName)
216
+ if (!permission) {
217
+ continue
218
+ }
219
+ for (const rule of permission.rules) {
220
+ if (rule.path.startsWith('/api')) {
221
+ const exists = role.rules.backend.find(p => p.path === rule.path && p.actions === rule.actions && p.enable === rule.enable)
222
+ if (!exists) {
223
+ rule.domain = permission.domain || 'default'
224
+ role.rules.backend.push(rule)
225
+ }
226
+ } else {
227
+ const exists = role.rules.frontend.find(p => p.path === rule.path && p.actions === rule.actions && p.enable === rule.enable)
228
+ if (!exists) {
229
+ rule.domain = permission.domain || 'default'
230
+ role.rules.frontend.push(rule)
231
+ }
232
+ }
233
+ }
234
+ }
235
+ }
236
+ }
237
+
238
+ _solveMergeRulesByRole (config) {
239
+ for (const role of config.roles) {
240
+ for (const rule of role.rules.frontend) {
241
+ role.rules.frontend = this._solveMergeRule(role.rules.frontend, rule)
242
+ }
243
+ for (const rule of role.rules.backend) {
244
+ role.rules.backend = this._solveMergeRule(role.rules.backend, rule)
245
+ }
246
+ }
247
+ }
248
+
249
+ _solveRoleId (config) {
250
+ for (const role of config.roles) {
251
+ if (!role.externalId) {
252
+ role.externalId = role.name
253
+ }
254
+ }
255
+ }
256
+
257
+ _getRoles (roles) {
258
+ // If you do not have roles assigned, the default roles are assigned.
259
+ const _roles = !roles || roles.length === 0 ? this.config.roles.filter(p => p.default).map(p => p.name) : roles
260
+ // If there are roles that apply to all, they are added
261
+ const applyToAll = this.config.roles.filter(p => p.applyToAll)
262
+ if (applyToAll && applyToAll.length > 0) {
263
+ for (const roleToAdd of applyToAll) {
264
+ if (!_roles.includes(roleToAdd.name)) {
265
+ _roles.push(roleToAdd.name)
266
+ }
267
+ }
268
+ }
269
+ return _roles
270
+ }
271
+
272
+ _getBackendSecurityRules (roles, action, domains) {
273
+ let rules = []
274
+ const _roles = this._getRoles(roles)
275
+ for (const role of _roles) {
276
+ const securityRules = this._getSecurityRulesByRole(role, 'backend', domains)
277
+ const _rules = securityRules.filter(p => p.actions.includes('*') || p.actions.includes(action))
278
+ for (const rule of _rules) {
279
+ rules = this._solveMergeRule(rules, rule)
280
+ }
281
+ }
282
+ return rules.sort((a, b) => (a.path > b.path) ? 1 : -1)
283
+ }
284
+
285
+ _solveMergeRule (rules, rule) {
286
+ let _rules = JSON.parse(JSON.stringify(rules))
287
+ const previousRules = _rules.filter(p => p.path === rule.path)
288
+ if (!previousRules.length === 0) {
289
+ _rules.push(rule)
290
+ } else {
291
+ if (previousRules.some(p => p.actions.includes('*') && p.enable)) {
292
+ // If a rule already exists that enables all paths
293
+ return _rules
294
+ } else if (rule.actions.includes('*') && rule.enable) {
295
+ // remove rules with the same path and add rule with all actions
296
+ _rules = _rules.filter(p => p.path !== rule.path)
297
+ _rules.push(rule)
298
+ } else if (rule.actions.includes('*') && !rule.enable) {
299
+ // If the rule denies all permissions, it replaces the previous rules that it overrides with this one.
300
+ _rules = _rules.filter(p => !(p.path === rule.path && p.enable === rule.enable))
301
+ _rules.push(rule)
302
+ } else if (!rule.enable && previousRules.some(p => p.actions.includes('*') && !p.enable)) {
303
+ // If the rule disables and a disabling rule already exists, it does not exclude the rule
304
+ return _rules
305
+ } else {
306
+ for (const action of rule.actions.split(',')) {
307
+ const previousRules = _rules.filter(p => p.path === rule.path)
308
+ if (previousRules.some(p => (p.actions.includes('*') || p.actions.includes(action)) && (p.enable || (p.enable === rule.enable)))) {
309
+ // If the action already exists in the previous rule with the same enable state, it is not added
310
+ // If the action exists in the previous rule and is enabled
311
+ continue
312
+ } else if (previousRules.some(p => (p.actions.includes(action) && !p.enable && rule.enable))) {
313
+ // If the action is included but with a disable status and the new rule is enabled, it must be extracted from the previous one and added to the new rule
314
+ const ruleToRemoveAction = previousRules.find(p => (p.actions.includes(action) && !p.enable))
315
+ const newActions = ruleToRemoveAction.actions.split(',').filter(p => p !== action)
316
+ if (newActions.length === 0) {
317
+ // Remove the previous rule
318
+ _rules = _rules.filter(p => !(p.path === rule.path && p.actions === action && !p.enable))
319
+ } else {
320
+ ruleToRemoveAction.actions = newActions.join(',')
321
+ }
322
+ // Search if there is a rule with the same path and enable state
323
+ const previousEnableRule = previousRules.find(p => p.enable === rule.enable)
324
+ if (previousEnableRule) {
325
+ // If it exists, the action is added
326
+ previousEnableRule.actions = previousEnableRule.actions + ',' + action
327
+ } else {
328
+ // If it does not exist, the rule is added
329
+ _rules.push({ path: rule.path, actions: action, enable: rule.enable })
330
+ }
331
+ } else if (previousRules.some(p => (!p.actions.includes(action) && p.enable === rule.enable))) {
332
+ // If the action is not included and the enable state is the same, the action will be added
333
+ const previousRule = previousRules.find(p => p.enable === rule.enable)
334
+ previousRule.actions = previousRule.actions + ',' + action
335
+ } else {
336
+ // Search if there is a rule with the same path and enable state
337
+ const previousEnableRule = previousRules.find(p => p.enable === rule.enable)
338
+ if (previousEnableRule) {
339
+ // If it exists, the action is added
340
+ previousEnableRule.actions = previousEnableRule.actions + ',' + action
341
+ } else {
342
+ // If it does not exist, the rule is added
343
+ _rules.push({ path: rule.path, actions: action, enable: rule.enable })
344
+ }
345
+ }
346
+ }
347
+ }
348
+ }
349
+ return _rules
350
+ }
351
+
352
+ _cleanPath (fullUrl) {
353
+ const indexOfQuestionMark = fullUrl.indexOf('?')
354
+ return indexOfQuestionMark !== -1 ? fullUrl.substring(0, indexOfQuestionMark) : fullUrl
355
+ }
356
+
357
+ _cretaeExpression (route) {
358
+ if (this.utils.isRegExp(route)) {
359
+ return route
360
+ }
361
+
362
+ // Verifica si la ruta termina con "/**"
363
+ if (route.endsWith('/**')) {
364
+ const baseRoute = route
365
+ .replace(/\|.*$/gm, '') // Remueve los parámetros
366
+ .replace(/\/\*\*$/, ''); // Elimina el "/**" del final
367
+
368
+ // Crea la expresión regular que incluye la ruta base y cualquier subruta
369
+ return new RegExp(`^${baseRoute}(\/.*)?$`);
370
+ }
371
+
372
+ const expression = (
373
+ route
374
+ /**
375
+ * Remueve todos los parámetros (si es que existen) que se pasan a la URL:
376
+ * "/customers|add" -> "/customers"
377
+ * "/customers|*" -> "/customers"
378
+ * "/customers|" -> "/customers"
379
+ * "/customers" -> "/customers"
380
+ */
381
+ .replace(/\|.*$/gm, '')
382
+ /**
383
+ * Remueve todos los "/" que tiene al final la URL
384
+ * "/customers////" -> "/customers"
385
+ * "/customers/" -> "/customers"
386
+ * "/customers" -> "/customers"
387
+ */
388
+ .replace(/\/+$/, '')
389
+ /**
390
+ * Remueve todos los "/" que tiene al principio la URL y lo lo reemplaza por
391
+ * '^/':
392
+ * "/customers////" -> "/customers"
393
+ * "/customers/" -> "/customers"
394
+ * "/customers" -> "/customers"
395
+ */
396
+ .replace(/^\/+/, '^/')
397
+ )
398
+ return expression
399
+ }
400
+
401
+ _replaceDynamicURLParts (route) {
402
+ let regexp = null
403
+ if (this.utils.isRegExp(route)) {
404
+ regexp = route
405
+ } else {
406
+ regexp = new RegExp(
407
+ route
408
+ .replace(/\*\*/gm, '.*')
409
+ .replace(/\*/gm, function (match, offset, string) {
410
+ if (string[offset - 1] === '.') {
411
+ return '*'
412
+ }
413
+ return '[^/]*'
414
+ }) + '$',
415
+ ''
416
+ )
417
+ }
418
+ return { regexp }
419
+ }
420
+
421
+ _findMatchedRoutes (url, routes = []) {
422
+ const cleanUrl = url.replace(/^\/+/, '/')
423
+ return routes
424
+ .map((route) => {
425
+ const pathExpression = this._cretaeExpression(route.path)
426
+ const { regexp } = this._replaceDynamicURLParts(pathExpression)
427
+ const match = regexp.test(cleanUrl)
428
+ return match ? route : false
429
+ })
430
+ .filter((route) => route)
431
+ }
432
+
433
+ _checkApi (path, action, roles) {
434
+ const cleanedPath = this._cleanPath(path)
435
+ const _action = action.toUpperCase()
436
+ const securityRules = this._getBackendSecurityRules(roles, _action)
437
+ const matchedRoutes = this._findMatchedRoutes(cleanedPath, securityRules)
438
+ const list = this.utils
439
+ .chain(matchedRoutes)
440
+ .filter(p => p.actions.includes('*') || p.actions.includes(_action))
441
+ .value()
442
+ const enabled = list.some(p => p.enable)
443
+ const disabled = list.some(p => !p.enable)
444
+ if (enabled || (!enabled && !disabled)) {
445
+ return true
446
+ }
447
+ if (disabled) {
448
+ this.logger.error(`can't access to ${action} ${path}`)
449
+ return false
450
+ }
451
+ return null
452
+ }
453
+
454
+ _checkPath (path, roles) {
455
+ const securityRules = this.getFrontendSecurityRules(roles)
456
+ const list = this.utils
457
+ .chain(this._findMatchedRoutes(path, securityRules))
458
+ .value()
459
+ const enabled = list.some(p => p.enable)
460
+ const disabled = list.some(p => !p.enable)
461
+ if (enabled || (!enabled && !disabled)) {
462
+ return true
463
+ }
464
+ if (disabled) {
465
+ return false
466
+ }
467
+ return null
468
+ }
469
+
470
+ _checkWidget (path, securityOption, roles) {
471
+ const _securityOption = securityOption.toUpperCase()
472
+ const securityRules = this.getFrontendSecurityRules(roles)
473
+ const rules = this.utils
474
+ .chain(this._findMatchedRoutes(path, securityRules))
475
+ .filter(({ path }) => path.includes(this.WIDGET_SEPARATOR))
476
+ .filter(({ path }) => {
477
+ const expression = path.substring(path.indexOf(this.WIDGET_SEPARATOR) + 1).replace(/\*\*/gm, '.*')
478
+ return new RegExp(`^${expression}$`, 'gm').test(_securityOption)
479
+ })
480
+ .value()
481
+ const allActions = rules.find(p => p.path === path + '|**' && p.enable)
482
+ if (allActions) {
483
+ return true
484
+ }
485
+ const exactlyAction = rules.find(p => p.path === path + '|' + _securityOption)
486
+ if (exactlyAction) {
487
+ return exactlyAction.enable
488
+ }
489
+ const last = this.utils.chain(rules).reverse().first().value()
490
+ if (last) {
491
+ return last.enable
492
+ }
493
+ return null
494
+ }
495
+
496
+ _validateAndNormalizeConfig (config) {
497
+ if (!config) {
498
+ throw new Error('config is undefined')
499
+ }
500
+ if (config.roles === undefined || config.roles === null || config.roles.length === 0) {
501
+ throw new Error('config.roles is undefined')
502
+ }
503
+ if (config.permissions === undefined || config.permissions === null || config.permissions.length === 0) {
504
+ throw new Error('config.permissions is undefined')
505
+ }
506
+ // Validation and normalization of permissions
507
+ for (const permission of config.permissions) {
508
+ if (!permission.name) {
509
+ throw new Error('Permission has not name')
510
+ }
511
+ if (!permission.rules) {
512
+ permission.rules = []
513
+ }
514
+ if (!permission.visible) {
515
+ permission.visible = true
516
+ }
517
+ for (const rule of permission.rules) {
518
+ if (rule.enable === undefined || rule.enable === null) {
519
+ rule.enable = true
520
+ }
521
+ if (rule.actions === undefined || rule.actions === null) {
522
+ rule.actions = rule.path.startsWith('/api') ? '*' : ''
523
+ } else {
524
+ rule.actions = rule.actions.toUpperCase()
525
+ }
526
+ if (!rule.path) {
527
+ throw new Error(`Rule in permission ${permission.name} has not path`)
528
+ }
529
+ }
530
+ }
531
+ // initialize permissions in roles
532
+ for (const role of config.roles) {
533
+ if (!role.permissions)role.permissions = []
534
+ }
535
+ }
536
+ }
@@ -0,0 +1,8 @@
1
+ module.exports = {
2
+ startupBoxOptions: {
3
+ padding: 1,
4
+ margin: 1,
5
+ borderStyle: 'round',
6
+ borderColor: 'yellow'
7
+ }
8
+ }
@@ -0,0 +1,8 @@
1
+
2
+ ██████╗ ██╗ █████╗ ███████╗███████╗██████╗ ██████╗ █████╗ ████████╗██╗ ██╗
3
+ ██╔══██╗██║ ██╔══██╗╚══███╔╝██╔════╝██╔══██╗██╔══██╗██╔══██╗╚══██╔══╝██║ ██║
4
+ ██████╔╝██║ ███████║ ███╔╝ █████╗ ██║ ██║██████╔╝███████║ ██║ ███████║
5
+ ██╔══██╗██║ ██╔══██║ ███╔╝ ██╔══╝ ██║ ██║██╔═══╝ ██╔══██║ ██║ ██╔══██║
6
+ ██████╔╝███████╗██║ ██║███████╗███████╗██████╔╝██║ ██║ ██║ ██║ ██║ ██║
7
+ ╚═════╝ ╚══════╝╚═╝ ╚═╝╚══════╝╚══════╝╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝
8
+
@@ -0,0 +1,75 @@
1
+ # Security
2
+
3
+ ## Actual solution
4
+
5
+ - Se establece un conjunto de permisos de acuerdo a security rules.
6
+ - Estos security rules permiten habilitar o denegar el acceso vinculado a un path.
7
+ - este path incluye la ruta del web-component y una security option.
8
+ - esa security option puede estar asociado a un widget, una action o una parte de ese widget.
9
+
10
+ ### Detected problems
11
+
12
+ - La configuración de seguridad como su resolución están del lado del cliente, por lo cual es vulnerable a ataques.
13
+ - El widget al que se aplica seguridad siempre debe tener definido un path.
14
+ - No se puede definir seguridad en sub-componentes, los cuales no tienen una ruta asociada y pueden ser incluidos en otros componentes.
15
+ - No hay un mecanismo de configuración masivo de seguridad.
16
+ - En IPLAN se estableció una estrategia agregando la configuración en archivos de recursos
17
+
18
+ ## Proposal
19
+
20
+ ### Requirements
21
+
22
+ - Establecer un conjunto de permisos de acuerdo a un role.
23
+ - Establecer diferentes estrategias de como obtener los roles asociados a un usuario.
24
+ - Una de estas estrategias sera a traves de jwt.
25
+ - Establecer diferentes estrategias de como obtener la configuración de seguridad.
26
+ - A traves de un archivo de recursos (Del lado del servidor)
27
+ - A traves de consumir un servicio rest.
28
+
29
+ - Permitir definir seguridad en sub-componentes.
30
+ - Permitir definir seguridad en componentes que no tienen una ruta asociada.
31
+
32
+ - Establecer funcionalidad de importar y exportar configuración de seguridad
33
+ - Agregar UI para administrar la configuración de seguridad.
34
+ - Lo mas probable es que esta UI este en un paquete aparte.
35
+
36
+ ## Se modifica comando para que se pueda consumir desde el backend
37
+
38
+ - Se modifica la definición del comando para que se pueda consumir desde el backend
39
+ - path: ~/blazedapth/blz/blz-suite/frontend/suite/javascripts/descriptors/commands/set-security-rule.js
40
+ - path: ~/blazedapth/blz/blz-suite/frontend/suite/javascripts/descriptors/commands/reset-security-rules.js
41
+ - Se Renombra SecurityClient por BlzSecurity
42
+ - path: ~/blazedapth/blz/blz-builder/burners/web-frontend/sources/startup/index.js
43
+ - path: ~/blazedapth/blz/blz-suite/backend/servers/web-frontend/index.js
44
+ - Se modifica Blz.setSecurityRule por BlzSecurity.setSecurityRule
45
+ - path: ~/blazedapth/blz/blz-shared/js-generator/commands/set-security-rule.js
46
+ - Se modifica Blz.clearSecurityRules por BlzSecurity.clearSecurityRules
47
+ - path: ~/blazedapth/blz/blz-shared/js-generator/commands/reset-security-rules.js
48
+ - Se agrega BlzSecurity en Blz_controls_RouteResolver
49
+ - path: ~/blazedapth/blz/blz-ui/assets/js/blz-wrappers/Blz_controls_RouteResolver.js
50
+
51
+ ## Agregar archivo de seguridad para importación masiva
52
+
53
+ ## Update blzUi
54
+
55
+ Build Dev:
56
+
57
+ ```sh
58
+ cd blz-ui/
59
+ grunt prod-dev
60
+ ```
61
+
62
+ Build Prod:
63
+
64
+ ```sh
65
+ cd blz-ui/
66
+ grunt prod-prod
67
+ ```
68
+
69
+ ## References
70
+
71
+ - Documentation
72
+ - [security rules and options](https://docs-blz.bsn-dev.beesion.team/#/doc/security-rules-and-options)
73
+ - Demo
74
+ - [DemoAuth](~/blazedapth/blz/blz-shared/essentials/solutions/DemoAuth)
75
+
@@ -0,0 +1,46 @@
1
+ const clamav = require('clamav.js');
2
+ const path = require('path');
3
+
4
+ /**
5
+ * Scans a readable stream for viruses using ClamAV over TCP.
6
+ *
7
+ * @param {ReadableStream} stream - A Node.js readable stream to scan.
8
+ * @param {Object} [options]
9
+ * @param {number} [options.port=3310] - TCP port where clamd is listening.
10
+ * @param {string} [options.host='127.0.0.1'] - Clamd host.
11
+ * @param {number} [options.timeout=60000] - Timeout in milliseconds.
12
+ * @returns {Promise<{ clean: boolean, name: string }>} - Scan result.
13
+ */
14
+ async function scanStream(stream, options = {}) {
15
+ const port = options.port || 3310;
16
+ const host = options.host || '127.0.0.1';
17
+ const timeout = options.timeout || 60000;
18
+
19
+ const scanner = clamav.createScanner(port, host, timeout);
20
+
21
+ return new Promise((resolve, reject) => {
22
+ scanner.scan(stream, (err, name, isInfected) => {
23
+ if (err) return reject(err);
24
+ resolve({
25
+ clean: !isInfected,
26
+ name,
27
+ });
28
+ });
29
+ });
30
+ }
31
+
32
+ /**
33
+ * Checks if a file extension is allowed.
34
+ * @param {string} filename - Name of the file to check.
35
+ * @returns {boolean}
36
+ */
37
+ function fileExtensionAllowed(filename) {
38
+ const ext = path.extname(filename).toLowerCase();
39
+ const allowed = process.env.blz_fileScannerAllowedExtension;
40
+ return allowed ? allowed.split(',').includes(ext) : true;
41
+ }
42
+
43
+ module.exports = {
44
+ scanStream,
45
+ fileExtensionAllowed,
46
+ };