@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.
- package/README.md +3 -0
- package/blz-base/health/index.js +215 -0
- package/blz-base/index.js +1466 -0
- package/blz-cache/LruCache.js +44 -0
- package/blz-cache/index.js +29 -0
- package/blz-config/index.js +434 -0
- package/blz-core/index.js +364 -0
- package/blz-cryptography/index.js +54 -0
- package/blz-datetimes/index.js +356 -0
- package/blz-file/example.dat +2545 -0
- package/blz-file/fileService.js +205 -0
- package/blz-file/index.js +94 -0
- package/blz-file/index.test.js +31 -0
- package/blz-file/lab.js +33 -0
- package/blz-hazelcast/index.js +189 -0
- package/blz-hazelcast/lib/credentials.js +25 -0
- package/blz-hazelcast/lib/credentialsFactory.js +12 -0
- package/blz-hazelcast/lib/hazelcastCache.js +234 -0
- package/blz-iterable/index.js +446 -0
- package/blz-json-schema/index.js +11 -0
- package/blz-jwt/index.js +121 -0
- package/blz-kafka/index.js +522 -0
- package/blz-math/index.js +131 -0
- package/blz-mongodb/index.js +326 -0
- package/blz-rds/__test__/scape.test.js +58 -0
- package/blz-rds/blz-rds-executor.js +578 -0
- package/blz-rds/blz-rds-helper.js +310 -0
- package/blz-rds/commands/core/add.js +13 -0
- package/blz-rds/commands/core/and.js +18 -0
- package/blz-rds/commands/core/asc.js +10 -0
- package/blz-rds/commands/core/avg.js +10 -0
- package/blz-rds/commands/core/column-ref.js +8 -0
- package/blz-rds/commands/core/count-distinct.js +10 -0
- package/blz-rds/commands/core/count.js +10 -0
- package/blz-rds/commands/core/decimal.js +8 -0
- package/blz-rds/commands/core/desc.js +10 -0
- package/blz-rds/commands/core/distinct.js +10 -0
- package/blz-rds/commands/core/divide.js +11 -0
- package/blz-rds/commands/core/embedded-exists.js +17 -0
- package/blz-rds/commands/core/embedded-select.js +17 -0
- package/blz-rds/commands/core/equals.js +9 -0
- package/blz-rds/commands/core/false.js +8 -0
- package/blz-rds/commands/core/greater-or-equal.js +9 -0
- package/blz-rds/commands/core/greater.js +9 -0
- package/blz-rds/commands/core/in.js +9 -0
- package/blz-rds/commands/core/integer.js +8 -0
- package/blz-rds/commands/core/is-not-null.js +11 -0
- package/blz-rds/commands/core/is-null-or-value.js +10 -0
- package/blz-rds/commands/core/is-null.js +11 -0
- package/blz-rds/commands/core/less-or-equal.js +9 -0
- package/blz-rds/commands/core/less-unary.js +12 -0
- package/blz-rds/commands/core/less.js +9 -0
- package/blz-rds/commands/core/like.js +12 -0
- package/blz-rds/commands/core/max.js +10 -0
- package/blz-rds/commands/core/min.js +10 -0
- package/blz-rds/commands/core/multiply.js +13 -0
- package/blz-rds/commands/core/not-equals.js +9 -0
- package/blz-rds/commands/core/not-in.js +9 -0
- package/blz-rds/commands/core/not.js +13 -0
- package/blz-rds/commands/core/null.js +8 -0
- package/blz-rds/commands/core/nvl.js +11 -0
- package/blz-rds/commands/core/or.js +13 -0
- package/blz-rds/commands/core/parameter.js +34 -0
- package/blz-rds/commands/core/remainder.js +16 -0
- package/blz-rds/commands/core/string.js +8 -0
- package/blz-rds/commands/core/subtract.js +13 -0
- package/blz-rds/commands/core/sum.js +10 -0
- package/blz-rds/commands/core/true.js +8 -0
- package/blz-rds/commands/core/tuple.js +13 -0
- package/blz-rds/commands/datetimes/add-days.js +11 -0
- package/blz-rds/commands/datetimes/add-hours.js +11 -0
- package/blz-rds/commands/datetimes/add-milliseconds.js +11 -0
- package/blz-rds/commands/datetimes/add-minutes.js +11 -0
- package/blz-rds/commands/datetimes/add-months.js +11 -0
- package/blz-rds/commands/datetimes/add-seconds.js +11 -0
- package/blz-rds/commands/datetimes/add-years.js +11 -0
- package/blz-rds/commands/datetimes/date-diff.js +11 -0
- package/blz-rds/commands/datetimes/date.js +12 -0
- package/blz-rds/commands/datetimes/datetime-diff.js +11 -0
- package/blz-rds/commands/datetimes/datetime.js +15 -0
- package/blz-rds/commands/datetimes/day.js +10 -0
- package/blz-rds/commands/datetimes/hour.js +10 -0
- package/blz-rds/commands/datetimes/millisecond.js +10 -0
- package/blz-rds/commands/datetimes/minute.js +10 -0
- package/blz-rds/commands/datetimes/month-text.js +10 -0
- package/blz-rds/commands/datetimes/month.js +10 -0
- package/blz-rds/commands/datetimes/now.js +9 -0
- package/blz-rds/commands/datetimes/second.js +10 -0
- package/blz-rds/commands/datetimes/subtract-days.js +11 -0
- package/blz-rds/commands/datetimes/subtract-hours.js +11 -0
- package/blz-rds/commands/datetimes/subtract-milliseconds.js +11 -0
- package/blz-rds/commands/datetimes/subtract-minutes.js +11 -0
- package/blz-rds/commands/datetimes/subtract-seconds.js +11 -0
- package/blz-rds/commands/datetimes/time-diff.js +11 -0
- package/blz-rds/commands/datetimes/time.js +13 -0
- package/blz-rds/commands/datetimes/today.js +9 -0
- package/blz-rds/commands/datetimes/week-day-text.js +10 -0
- package/blz-rds/commands/datetimes/week-day.js +10 -0
- package/blz-rds/commands/datetimes/week.js +10 -0
- package/blz-rds/commands/datetimes/year.js +10 -0
- package/blz-rds/commands/math/abs.js +10 -0
- package/blz-rds/commands/math/acos.js +10 -0
- package/blz-rds/commands/math/asin.js +10 -0
- package/blz-rds/commands/math/atan.js +10 -0
- package/blz-rds/commands/math/atan2.js +11 -0
- package/blz-rds/commands/math/ceil.js +10 -0
- package/blz-rds/commands/math/cos.js +10 -0
- package/blz-rds/commands/math/cosh.js +10 -0
- package/blz-rds/commands/math/exp.js +10 -0
- package/blz-rds/commands/math/floor.js +10 -0
- package/blz-rds/commands/math/log.js +18 -0
- package/blz-rds/commands/math/log10.js +10 -0
- package/blz-rds/commands/math/pow.js +11 -0
- package/blz-rds/commands/math/random.js +9 -0
- package/blz-rds/commands/math/round.js +18 -0
- package/blz-rds/commands/math/sign.js +10 -0
- package/blz-rds/commands/math/sin.js +10 -0
- package/blz-rds/commands/math/sinh.js +10 -0
- package/blz-rds/commands/math/sqrt.js +10 -0
- package/blz-rds/commands/math/tan.js +10 -0
- package/blz-rds/commands/math/tanh.js +10 -0
- package/blz-rds/commands/math/trunc.js +18 -0
- package/blz-rds/commands/strings/concat.js +20 -0
- package/blz-rds/commands/strings/contains.js +12 -0
- package/blz-rds/commands/strings/ends-with.js +12 -0
- package/blz-rds/commands/strings/index-of.js +11 -0
- package/blz-rds/commands/strings/is-null-or-empty.js +11 -0
- package/blz-rds/commands/strings/is-null-or-white-space.js +11 -0
- package/blz-rds/commands/strings/join.js +22 -0
- package/blz-rds/commands/strings/last-index-of.js +11 -0
- package/blz-rds/commands/strings/length.js +10 -0
- package/blz-rds/commands/strings/pad-left.js +20 -0
- package/blz-rds/commands/strings/pad-right.js +20 -0
- package/blz-rds/commands/strings/replace.js +12 -0
- package/blz-rds/commands/strings/starts-with.js +12 -0
- package/blz-rds/commands/strings/substring.js +12 -0
- package/blz-rds/commands/strings/to-lower.js +10 -0
- package/blz-rds/commands/strings/to-upper.js +10 -0
- package/blz-rds/commands/strings/trim-end.js +10 -0
- package/blz-rds/commands/strings/trim-start.js +10 -0
- package/blz-rds/commands/strings/trim.js +10 -0
- package/blz-rds/index.js +744 -0
- package/blz-rds-mysql/base.js +857 -0
- package/blz-rds-mysql/connection-manager.js +129 -0
- package/blz-rds-mysql/execute-bulk-insert.js +35 -0
- package/blz-rds-mysql/execute-bulk-merge.js +45 -0
- package/blz-rds-mysql/execute-non-query.js +34 -0
- package/blz-rds-mysql/execute-query.js +50 -0
- package/blz-rds-mysql/index.js +41 -0
- package/blz-rds-mysql/stored-procedure.js +207 -0
- package/blz-rds-mysql/syntaxis.json +114 -0
- package/blz-rds-mysqlx/base.js +846 -0
- package/blz-rds-mysqlx/connection-manager.js +141 -0
- package/blz-rds-mysqlx/execute-bulk-insert.js +35 -0
- package/blz-rds-mysqlx/execute-bulk-merge.js +45 -0
- package/blz-rds-mysqlx/execute-non-query.js +29 -0
- package/blz-rds-mysqlx/execute-query.js +39 -0
- package/blz-rds-mysqlx/index.js +41 -0
- package/blz-rds-mysqlx/stored-procedure.js +179 -0
- package/blz-rds-mysqlx/syntaxis.json +105 -0
- package/blz-rds-oracle/index.js +540 -0
- package/blz-rds-oracle/syntaxis.json +112 -0
- package/blz-rds-postgres/base.js +861 -0
- package/blz-rds-postgres/connection-manager.js +225 -0
- package/blz-rds-postgres/execute-bulk-insert.js +81 -0
- package/blz-rds-postgres/execute-bulk-merge.js +93 -0
- package/blz-rds-postgres/execute-non-query.js +23 -0
- package/blz-rds-postgres/execute-query.js +37 -0
- package/blz-rds-postgres/index.js +41 -0
- package/blz-rds-postgres/result-set.js +51 -0
- package/blz-rds-postgres/stored-procedure.js +116 -0
- package/blz-rds-postgres/syntaxis.json +114 -0
- package/blz-redis/index.js +217 -0
- package/blz-redis/lib/redisCache.js +265 -0
- package/blz-regex/index.js +25 -0
- package/blz-security/.eslintrc.js +15 -0
- package/blz-security/__test__/AuthorizationKpn.yaml +1043 -0
- package/blz-security/__test__/FinancingSetting.yaml +177 -0
- package/blz-security/__test__/KpnConfigPortal.yaml +330 -0
- package/blz-security/__test__/OrderManagement.yaml +5190 -0
- package/blz-security/__test__/Security.yaml +128 -0
- package/blz-security/__test__/autorization.test.js +105 -0
- package/blz-security/__test__/orderManagement.test.js +26 -0
- package/blz-security/__test__/secureUrl.test.js +79 -0
- package/blz-security/__test__/solveMergeRule.test.js +109 -0
- package/blz-security/__test__/sqlInjectionGuard.test.js +203 -0
- package/blz-security/__test__/xssGuard.test.js +204 -0
- package/blz-security/authorizationService.js +536 -0
- package/blz-security/config/global.js +8 -0
- package/blz-security/config/welcome +8 -0
- package/blz-security/doc/README.md +75 -0
- package/blz-security/filescanner/index.js +46 -0
- package/blz-security/helpers/consts.js +229 -0
- package/blz-security/helpers/utils.js +267 -0
- package/blz-security/implementations/cache.js +90 -0
- package/blz-security/implementations/oidc.js +404 -0
- package/blz-security/implementations/pkceCacheStore.js +23 -0
- package/blz-security/implementations/saml.js +10 -0
- package/blz-security/implementations/uma.js +63 -0
- package/blz-security/implementations/webAuthn.js +9 -0
- package/blz-security/implementations/wstg.js +72 -0
- package/blz-security/index.js +77 -0
- package/blz-security/lab/index.js +27 -0
- package/blz-security/middleware/HapiServerAzureAd.js +641 -0
- package/blz-security/middleware/HapiServerKeycloak.js +840 -0
- package/blz-security/middleware/HapiServerSimToken.js +247 -0
- package/blz-security/middleware/hapi.js +515 -0
- package/blz-security/middleware/hapiServer.js +974 -0
- package/blz-security/navigationMemoryRepository.js +15 -0
- package/blz-security/navigationMongoDbRepository.js +73 -0
- package/blz-security/secureUrlService.js +47 -0
- package/blz-security/securityService.js +409 -0
- package/blz-security/sqlInjectionGuard.js +162 -0
- package/blz-security/templates/forbidden.html +0 -0
- package/blz-security/templates/session-iframe-azure-ad.html +7 -0
- package/blz-security/templates/session-iframe.html +73 -0
- package/blz-security/templates/unauthorized.html +1 -0
- package/blz-security/xssGuard.js +87 -0
- package/blz-strings/index.js +167 -0
- package/blz-uuid/index.js +7 -0
- package/blz-yaml/index.js +19 -0
- package/index.js +84 -0
- package/package.json +97 -0
- package/process-managers/index.js +422 -0
|
@@ -0,0 +1,578 @@
|
|
|
1
|
+
const toString = Object.prototype.toString;
|
|
2
|
+
const { z } = require('zod');
|
|
3
|
+
const logger = require('pino')();
|
|
4
|
+
class SqlInjectionGuard {
|
|
5
|
+
constructor(logger = console) {
|
|
6
|
+
this.logger = logger;
|
|
7
|
+
this._initialized = false;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
_initialize() {
|
|
11
|
+
if (this._initialized) return;
|
|
12
|
+
this._initialized = true;
|
|
13
|
+
const allowedPatternsEnv = process.env.blz_securityApiSanitizeAllowedSqlInputPatterns;
|
|
14
|
+
const paramPatternsEnv = process.env.blz_securityApiSanitizeDangerousParamPatterns;
|
|
15
|
+
const sqlPatternsEnv = process.env.blz_securityApiSanitizeDangerousSqlPatterns;
|
|
16
|
+
this.onlyLog = process.env.blz_securityApiSanitizeOnlyLog === 'true';
|
|
17
|
+
const parseRegexArray = (input) => {
|
|
18
|
+
try {
|
|
19
|
+
if (input == undefined || input == null) return null
|
|
20
|
+
const rawList = JSON.parse(input); // must be an array of strings type ["--", "\\bselect\\b.+\\bfrom\\b"]
|
|
21
|
+
return rawList.map(pattern => new RegExp(pattern, 'i'));
|
|
22
|
+
} catch {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
this.dangerousParamPatterns =
|
|
27
|
+
parseRegexArray(paramPatternsEnv) || [
|
|
28
|
+
/--/i,
|
|
29
|
+
/\/\*/i,
|
|
30
|
+
/\*\//i,
|
|
31
|
+
/\bor\b\s+\w+\s*=/i,
|
|
32
|
+
/\bor\b\s+.*?=.*?/i,
|
|
33
|
+
/\bor\b\s+'.*?'\s*=\s*'.*?'/i,
|
|
34
|
+
/\bor\b\s+\w+\s*like/i,
|
|
35
|
+
/\band\b\s+\w+\s*=/i,
|
|
36
|
+
/\band\b\s+\w+\s*like/i,
|
|
37
|
+
/\bselect\b[\s\S]+?\bfrom\b/i,
|
|
38
|
+
/\bunion\s+select\b/i,
|
|
39
|
+
/\bdrop\s+table\b/i,
|
|
40
|
+
/\binsert\s+into\b/i,
|
|
41
|
+
/\bupdate\b\s+\w+\s+\bset\b[\s\S]*?=/i,
|
|
42
|
+
/\bdelete\s+from\b/i,
|
|
43
|
+
/\bpg_sleep\s*\(/i,
|
|
44
|
+
/\bdbms_lock\.sleep\s*\(/i,
|
|
45
|
+
/\bexec\s*\(/i,
|
|
46
|
+
/\bexecute\s*\(/i
|
|
47
|
+
];
|
|
48
|
+
this.dangerousSqlPatterns =
|
|
49
|
+
parseRegexArray(sqlPatternsEnv) || [
|
|
50
|
+
/;\s*drop\b/i,
|
|
51
|
+
/;\s*truncate\b/i,
|
|
52
|
+
/\bpg_sleep\s*\(/i,
|
|
53
|
+
/\bdbms_lock\.sleep\s*\(/i,
|
|
54
|
+
/\bexec(ute)?\s*(\(|\s)/i,
|
|
55
|
+
/\binformation_schema\b/i,
|
|
56
|
+
/\bpg_catalog\b/i,
|
|
57
|
+
];
|
|
58
|
+
this.allowedInputPatterns =
|
|
59
|
+
parseRegexArray(allowedPatternsEnv) || [
|
|
60
|
+
new RegExp('^[^<>]*<$', 'i'),
|
|
61
|
+
new RegExp('^>[^<>]*$', 'i')
|
|
62
|
+
];
|
|
63
|
+
// Define a schema for each param object
|
|
64
|
+
this.paramSchema = z.object({
|
|
65
|
+
name: z.string(),
|
|
66
|
+
value: z.any(), // value can be string, number, etc.
|
|
67
|
+
});
|
|
68
|
+
// Schema for the full list
|
|
69
|
+
this.paramsSchema = z.array(this.paramSchema);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
isAllowedByWhitelist(value) {
|
|
73
|
+
return this.allowedInputPatterns.some(pattern => pattern.test(value));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
validateParamValue(name, value) {
|
|
77
|
+
this. _initialize()
|
|
78
|
+
if (typeof value !== 'string') return;
|
|
79
|
+
const trimmed = value.trim();
|
|
80
|
+
if (this.isAllowedByWhitelist(trimmed)) return
|
|
81
|
+
// Always check for dangerous SQL injection patterns
|
|
82
|
+
for (const pattern of this.dangerousParamPatterns) {
|
|
83
|
+
if (pattern.test(trimmed)) {
|
|
84
|
+
const message = `Potential SQL injection in parameter "${name}": ${value}`;
|
|
85
|
+
if (this.onlyLog) {
|
|
86
|
+
this.logger?.warn?.(`[SQLInjectionGuard] ${message}`);
|
|
87
|
+
} else {
|
|
88
|
+
const err = new Error('Potential SQL injection');
|
|
89
|
+
err.code = 'SQLInjection';
|
|
90
|
+
err.data = message;
|
|
91
|
+
throw err;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
validateParamList(params) {
|
|
98
|
+
this. _initialize()
|
|
99
|
+
this.paramsSchema.parse(params); // Validate structure with Zod
|
|
100
|
+
for (const param of params) {
|
|
101
|
+
this.validateParamValue(param.name, param.value);
|
|
102
|
+
}
|
|
103
|
+
return params;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
validateRawSql(sql) {
|
|
107
|
+
this. _initialize()
|
|
108
|
+
if (typeof sql !== 'string') return false;
|
|
109
|
+
for (const pattern of this.dangerousSqlPatterns) {
|
|
110
|
+
if (pattern.test(sql.toLowerCase())) {
|
|
111
|
+
const message = `Potential SQL injection in "${sql}" pattern:${pattern}`;
|
|
112
|
+
if (this.onlyLog) {
|
|
113
|
+
this.logger.warn(`[SQLInjectionGuard] ${message}`);
|
|
114
|
+
} else {
|
|
115
|
+
const err = new Error('Potential SQL injection');
|
|
116
|
+
err.code = 'SQLInjection';
|
|
117
|
+
err.data = message;
|
|
118
|
+
throw err;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return sql
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
validateObject(obj) {
|
|
126
|
+
this. _initialize()
|
|
127
|
+
const checkValue = (value) => {
|
|
128
|
+
if (typeof value === 'string') {
|
|
129
|
+
const trimmed = value.trim();
|
|
130
|
+
if (!this.isAllowedByWhitelist(trimmed)) {
|
|
131
|
+
for (const pattern of this.dangerousParamPatterns) {
|
|
132
|
+
if (pattern.test(trimmed)) {
|
|
133
|
+
const message = `Value "${value}" violates SQL injection policy.`;
|
|
134
|
+
if (this.onlyLog) {
|
|
135
|
+
this.logger.warn(`[SQLInjectionGuard] ${message}`);
|
|
136
|
+
} else {
|
|
137
|
+
const err = new Error('Potential SQL injection');
|
|
138
|
+
err.code = 'BadRequest';
|
|
139
|
+
err.data = message;
|
|
140
|
+
throw err;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
} else if (Array.isArray(value)) {
|
|
146
|
+
for (const item of value) checkValue(item);
|
|
147
|
+
} else if (typeof value === 'object' && value !== null) {
|
|
148
|
+
for (const key in value) {
|
|
149
|
+
if (Object.hasOwn(value, key)) {
|
|
150
|
+
checkValue(value[key]);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
checkValue(obj);
|
|
157
|
+
return obj;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
// Instantiate guard once (e.g., globally or per module)
|
|
161
|
+
const guard = new SqlInjectionGuard(logger);
|
|
162
|
+
|
|
163
|
+
let adjustTypes = function (row, types) {
|
|
164
|
+
if (types) {
|
|
165
|
+
for (let i = 0; i < types.length; i++) {
|
|
166
|
+
if (i < row.length) {
|
|
167
|
+
let type = types[i];
|
|
168
|
+
switch (type) {
|
|
169
|
+
case 'string':
|
|
170
|
+
row[i] = convertToString(row[i]);
|
|
171
|
+
break;
|
|
172
|
+
case 'integer':
|
|
173
|
+
row[i] = convertToInteger(row[i]);
|
|
174
|
+
break;
|
|
175
|
+
case 'decimal':
|
|
176
|
+
row[i] = convertToDecimal(row[i]);
|
|
177
|
+
break;
|
|
178
|
+
case 'boolean':
|
|
179
|
+
row[i] = convertToBoolean(row[i]);
|
|
180
|
+
break;
|
|
181
|
+
case 'datetime':
|
|
182
|
+
row[i] = convertToDatetime(row[i]);
|
|
183
|
+
break;
|
|
184
|
+
case 'date':
|
|
185
|
+
row[i] = convertToDate(row[i]);
|
|
186
|
+
break;
|
|
187
|
+
case 'time':
|
|
188
|
+
row[i] = convertToTime(row[i]);
|
|
189
|
+
break;
|
|
190
|
+
case 'binary':
|
|
191
|
+
row[i] = convertToBinary(row[i]);
|
|
192
|
+
break;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
let convertToString = function (value) {
|
|
199
|
+
if (value === null)
|
|
200
|
+
return null;
|
|
201
|
+
let valueType = toString.call(value);
|
|
202
|
+
if (valueType === '[object String]')
|
|
203
|
+
return value;
|
|
204
|
+
if (valueType === '[object Number]')
|
|
205
|
+
return value.toString();
|
|
206
|
+
if (valueType === '[object Boolean]')
|
|
207
|
+
return value ? 'true' : 'false';
|
|
208
|
+
if (valueType === '[object Date]')
|
|
209
|
+
return value.toJSON();
|
|
210
|
+
throw errorInvalidConversion(value, 'string');
|
|
211
|
+
};
|
|
212
|
+
let convertToInteger = function (value) {
|
|
213
|
+
if (value === null)
|
|
214
|
+
return null;
|
|
215
|
+
let valueType = toString.call(value);
|
|
216
|
+
if (valueType === '[object String]' && !isNaN(value))
|
|
217
|
+
return Math.round(Number(value));
|
|
218
|
+
if (valueType === '[object Number]')
|
|
219
|
+
return Math.round(value);
|
|
220
|
+
if (valueType === '[object Boolean]')
|
|
221
|
+
return value ? 1 : 0;
|
|
222
|
+
throw errorInvalidConversion(value, 'integer');
|
|
223
|
+
};
|
|
224
|
+
let convertToDecimal = function (value) {
|
|
225
|
+
if (value === null)
|
|
226
|
+
return null;
|
|
227
|
+
let valueType = toString.call(value);
|
|
228
|
+
if (valueType === '[object String]' && !isNaN(value))
|
|
229
|
+
return Number(value);
|
|
230
|
+
if (valueType === '[object Number]')
|
|
231
|
+
return value;
|
|
232
|
+
if (valueType === '[object Boolean]')
|
|
233
|
+
return value ? 1 : 0;
|
|
234
|
+
throw errorInvalidConversion(value, 'decimal');
|
|
235
|
+
};
|
|
236
|
+
let convertToBoolean = function (value) {
|
|
237
|
+
if (value === null)
|
|
238
|
+
return null;
|
|
239
|
+
let valueType = toString.call(value);
|
|
240
|
+
if (valueType === '[object String]') {
|
|
241
|
+
if (value === '1' || value.toUpperCase() === 'T' || value.toUpperCase() === 'TRUE' || value.toUpperCase() === 'Y' || value.toUpperCase() === 'YES')
|
|
242
|
+
return true;
|
|
243
|
+
if (value === '0' || value.toUpperCase() === 'F' || value.toUpperCase() === 'FALSE' || value.toUpperCase() === 'N' || value.toUpperCase() === 'NO')
|
|
244
|
+
return false;
|
|
245
|
+
}
|
|
246
|
+
if (valueType === '[object Number]') {
|
|
247
|
+
if (value === 1)
|
|
248
|
+
return true;
|
|
249
|
+
if (value === 0)
|
|
250
|
+
return false;
|
|
251
|
+
}
|
|
252
|
+
if (valueType === '[object Boolean]')
|
|
253
|
+
return value;
|
|
254
|
+
throw errorInvalidConversion(value, 'boolean');
|
|
255
|
+
};
|
|
256
|
+
let convertToDatetime = function (value) {
|
|
257
|
+
if (value === null)
|
|
258
|
+
return null;
|
|
259
|
+
let valueType = toString.call(value);
|
|
260
|
+
if (valueType === '[object String]') {
|
|
261
|
+
let matchDatetime = /^(\d{4})-(\d{1,2})-(\d{1,2})[T,\s](\d{1,2})\:(\d{1,2})\:(\d{1,2})\.?(\d+)?Z?$/.exec(value);
|
|
262
|
+
if (matchDatetime)
|
|
263
|
+
return new Date(Date.UTC(Number(matchDatetime[1]), Number(matchDatetime[2]) - 1, Number(matchDatetime[3]), Number(matchDatetime[4]), Number(matchDatetime[5]), Number(matchDatetime[6] || 0), convertMilliseconds(matchDatetime[7])));
|
|
264
|
+
else {
|
|
265
|
+
const probableDate = new Date(value);
|
|
266
|
+
if (probableDate.toString() !== 'Invalid Date') {
|
|
267
|
+
return probableDate;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
if (valueType === '[object Date]') {
|
|
272
|
+
return value;
|
|
273
|
+
}
|
|
274
|
+
if (valueType === "[object Number]") {
|
|
275
|
+
return new Date(value);
|
|
276
|
+
}
|
|
277
|
+
throw errorInvalidConversion(value, 'datetime');
|
|
278
|
+
};
|
|
279
|
+
let convertToDate = function (value) {
|
|
280
|
+
if (value === null)
|
|
281
|
+
return null;
|
|
282
|
+
let valueType = toString.call(value);
|
|
283
|
+
if (valueType === '[object String]') {
|
|
284
|
+
let matchDate = /^(\d{4})-(\d{1,2})-(\d{1,2})$/.exec(value);
|
|
285
|
+
if (matchDate)
|
|
286
|
+
//TODO: revisar por qu esta asumiendo que es una fecha UTC cuando deberia ser local
|
|
287
|
+
return new Date(Date.UTC(Number(matchDate[1]), Number(matchDate[2]) - 1, Number(matchDate[3]), 0, 0, 0, 0));
|
|
288
|
+
let matchDatetime = /^(\d{4})-(\d{1,2})-(\d{1,2})[T,\s](\d{1,2})\:(\d{1,2})\:(\d{1,2})\.?(\d+)?Z?$/.exec(value);
|
|
289
|
+
if (matchDatetime)
|
|
290
|
+
return new Date(Date.UTC(Number(matchDatetime[1]), Number(matchDatetime[2]) - 1, Number(matchDatetime[3]), 0, 0, 0, 0));
|
|
291
|
+
else {
|
|
292
|
+
const probableDate = new Date(value);
|
|
293
|
+
if (probableDate.toString() !== 'Invalid Date') {
|
|
294
|
+
//TODO: revisar por qu esta asumiendo que es una fecha UTC cuando deberia ser local
|
|
295
|
+
return new Date(Date.UTC(probableDate.getUTCFullYear(), probableDate.getUTCMonth(), probableDate.getUTCDate(), 0, 0, 0, 0));
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
if (valueType === "[object Number]") {
|
|
300
|
+
value = new Date(value);
|
|
301
|
+
}
|
|
302
|
+
if (valueType === '[object Date]') {
|
|
303
|
+
return new Date(Date.UTC(value.getUTCFullYear(), value.getUTCMonth(), value.getUTCDate(), 0, 0, 0, 0));
|
|
304
|
+
}
|
|
305
|
+
throw errorInvalidConversion(value, 'date');
|
|
306
|
+
};
|
|
307
|
+
let convertToTime = function (value) {
|
|
308
|
+
if (value === null)
|
|
309
|
+
return null;
|
|
310
|
+
let valueType = toString.call(value);
|
|
311
|
+
if (valueType === '[object String]') {
|
|
312
|
+
let matchTime = /^\+?(\d{1,2})\:(\d{1,2})\:(\d{1,2})\.?(\d+)?$/.exec(value);
|
|
313
|
+
if (matchTime) {
|
|
314
|
+
return new Date(Date.UTC(1970, 0, 1, Number(matchTime[1]), Number(matchTime[2]), Number(matchTime[3]), convertMilliseconds(matchTime[4])));
|
|
315
|
+
}
|
|
316
|
+
let matchDatetime = /^(\d{4})-(\d{1,2})-(\d{1,2})[T,\s](\d{1,2})\:(\d{1,2})\:(\d{1,2})\.?(\d+)?Z?$/.exec(value);
|
|
317
|
+
if (matchDatetime) {
|
|
318
|
+
return new Date(Date.UTC(1970, 0, 1, Number(matchDatetime[4]), Number(matchDatetime[5]), Number(matchDatetime[6] || 0), convertMilliseconds(matchDatetime[7])));
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
if (valueType === '[object Date]') {
|
|
322
|
+
return new Date(Date.UTC(1970, 0, 1, value.getUTCHours(), value.getUTCMinutes(), value.getUTCSeconds(), value.getUTCMilliseconds()));
|
|
323
|
+
}
|
|
324
|
+
throw errorInvalidConversion(value, 'time');
|
|
325
|
+
};
|
|
326
|
+
let convertToBinary = function (value) {
|
|
327
|
+
if (value == null)
|
|
328
|
+
return null;
|
|
329
|
+
if (value && value.type === 'Buffer')
|
|
330
|
+
return Buffer.from(value);
|
|
331
|
+
if (Buffer.isBuffer(value))
|
|
332
|
+
return value;
|
|
333
|
+
if (Array.isArray(value))
|
|
334
|
+
return Buffer.from(value);
|
|
335
|
+
throw errorInvalidConversion(value, 'binary');
|
|
336
|
+
};
|
|
337
|
+
let convertMilliseconds = function (strMilliseconds) {
|
|
338
|
+
if (strMilliseconds) {
|
|
339
|
+
if (strMilliseconds.length < 3)
|
|
340
|
+
strMilliseconds = strMilliseconds.padEnd(3, '0');
|
|
341
|
+
if (strMilliseconds.length > 3)
|
|
342
|
+
strMilliseconds = strMilliseconds.substr(0, 3);
|
|
343
|
+
return Number(strMilliseconds);
|
|
344
|
+
}
|
|
345
|
+
else
|
|
346
|
+
return 0;
|
|
347
|
+
};
|
|
348
|
+
let errorInvalidConversion = function (value, targetType) {
|
|
349
|
+
let err = new Error();
|
|
350
|
+
err.code = 'InvalidConversion';
|
|
351
|
+
err.data = { value: value, targetType: targetType };
|
|
352
|
+
return err;
|
|
353
|
+
};
|
|
354
|
+
|
|
355
|
+
function getTransactionsContext(callContext) {
|
|
356
|
+
if (!callContext.rdsTransactionContext) {
|
|
357
|
+
callContext.rdsTransactionContext = [];
|
|
358
|
+
}
|
|
359
|
+
return callContext.rdsTransactionContext;
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* @param {*} callContext
|
|
363
|
+
* @param {*} connection
|
|
364
|
+
* @return { rdsConnection: RdsConnection, mustBeClosed: boolean }
|
|
365
|
+
*/
|
|
366
|
+
let getRdsConnection = async function (callContext, connection) {
|
|
367
|
+
/**
|
|
368
|
+
* 1-. Debido a que cada petición tiene su propia pila de conexiones para la
|
|
369
|
+
* transacción, la obtenemos para ver cúal es la conexión que debe devolver.
|
|
370
|
+
*/
|
|
371
|
+
let transactionsStack = getTransactionsContext(callContext);
|
|
372
|
+
/**
|
|
373
|
+
* 2-. Si la pila se encuentra vacía, indica que no estamos en un entorno de
|
|
374
|
+
* transacción, por lo tanto, devolvemos una conexión nueva.
|
|
375
|
+
*/
|
|
376
|
+
if (transactionsStack.length === 0) {
|
|
377
|
+
let rdsConnection = new RdsConnection(await connection.provider.createRdsConnection(connection), connection.provider);
|
|
378
|
+
return { rdsConnection, mustBeClosed: true };
|
|
379
|
+
} else {
|
|
380
|
+
/**
|
|
381
|
+
* 3-. Si la pila no se encuentra vacía, significa que estamos en un contexto en donde
|
|
382
|
+
* se manejan transacciones, la transaccion que debe utilizarla conexion es la última
|
|
383
|
+
*
|
|
384
|
+
* De esta transaccion, debemos obtener la conexion asociada al nombre de conexión. Si
|
|
385
|
+
* esta no existe, debemos generar una conexion nueva.
|
|
386
|
+
*/
|
|
387
|
+
let connectionName = connection.name;
|
|
388
|
+
var transactionBrick = transactionsStack[transactionsStack.length - 1];
|
|
389
|
+
|
|
390
|
+
if (!transactionBrick.connection) {
|
|
391
|
+
let rdsConnection = new RdsConnection(await connection.provider.createRdsConnection(connection), connection.provider);
|
|
392
|
+
return { rdsConnection, mustBeClosed: true };
|
|
393
|
+
}
|
|
394
|
+
let rdsConnection = transactionBrick.connection[connectionName];
|
|
395
|
+
if (!rdsConnection) {
|
|
396
|
+
/**
|
|
397
|
+
* Sino, tenemos que crear una nueva conexión y asociarla con el bloque de transacción para poder
|
|
398
|
+
* registrarla y devolverla de ahora en mas. Además, se inicializa la conexión para indicar el tipo
|
|
399
|
+
* de propagación que va a tener la transacción
|
|
400
|
+
*/
|
|
401
|
+
rdsConnection = new RdsConnection(await connection.provider.createRdsConnection(connection), connection.provider);
|
|
402
|
+
transactionBrick.connection[connectionName] = rdsConnection;
|
|
403
|
+
await rdsConnection.beginTransaction();
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* Si el bloque de transacción tiene asociada una conexión, devolvemos la misma, acompañada con
|
|
407
|
+
* el tipo de transacción que estamos llevando adelante.
|
|
408
|
+
*/
|
|
409
|
+
return { rdsConnection, mustBeClosed: false };
|
|
410
|
+
}
|
|
411
|
+
};
|
|
412
|
+
/**
|
|
413
|
+
* @param {*} nativeConnection
|
|
414
|
+
* @param {*} provider
|
|
415
|
+
* @constructor
|
|
416
|
+
*/
|
|
417
|
+
function RdsConnection(nativeConnection, provider) {
|
|
418
|
+
let transactionRequest = false;
|
|
419
|
+
return {
|
|
420
|
+
async beginTransaction() {
|
|
421
|
+
transactionRequest = true;
|
|
422
|
+
return await provider.beginTransaction(nativeConnection);
|
|
423
|
+
},
|
|
424
|
+
async close() {
|
|
425
|
+
transactionRequest = false;
|
|
426
|
+
return await provider.close(nativeConnection);
|
|
427
|
+
},
|
|
428
|
+
async commitTransaction() {
|
|
429
|
+
transactionRequest = false;
|
|
430
|
+
return await provider.commitTransaction(nativeConnection);
|
|
431
|
+
},
|
|
432
|
+
get connection() {
|
|
433
|
+
return nativeConnection;
|
|
434
|
+
},
|
|
435
|
+
get isTransactionRequest() {
|
|
436
|
+
return transactionRequest;
|
|
437
|
+
},
|
|
438
|
+
async rollbackTransaction() {
|
|
439
|
+
transactionRequest = false;
|
|
440
|
+
return await provider.rollbackTransaction(nativeConnection);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
let _relationalDatabaseQueryId;
|
|
446
|
+
|
|
447
|
+
module.exports = {
|
|
448
|
+
execute: async function (callContext, connection, sql, parameters, options, types, fnSelection) {
|
|
449
|
+
let traceId = null;
|
|
450
|
+
let traceStartTime = null;
|
|
451
|
+
if (process.env.blz_traceAll === 'true' || process.env.blz_traceRelationalDatabaseQueries === 'true') {
|
|
452
|
+
if (typeof _relationalDatabaseQueryId === 'undefined')
|
|
453
|
+
_relationalDatabaseQueryId = 1;
|
|
454
|
+
else
|
|
455
|
+
_relationalDatabaseQueryId++;
|
|
456
|
+
traceId = _relationalDatabaseQueryId;
|
|
457
|
+
traceStartTime = Date.now();
|
|
458
|
+
console.log((callContext.devTime ? '' : new Date().toISOString() + ' | ') + 'RELATIONAL DATABASE QUERY (' + traceId + ') | ' + connection.name + ' | ' + sql + ' | PARAMETERS: ' + JSON.stringify(parameters));
|
|
459
|
+
}
|
|
460
|
+
let resultSet = null, rdsConnection = null, mustBeClosed = null;
|
|
461
|
+
try {
|
|
462
|
+
if (process.env.blz_securityApiSanitizeSqlInjection) {
|
|
463
|
+
sql = guard.validateRawSql(sql)
|
|
464
|
+
parameters = guard.validateParamList(parameters);
|
|
465
|
+
}
|
|
466
|
+
({ rdsConnection, mustBeClosed } = await getRdsConnection(callContext, connection));
|
|
467
|
+
if (options) {
|
|
468
|
+
options.isTransactionRequest = rdsConnection.isTransactionRequest;
|
|
469
|
+
} else {
|
|
470
|
+
options = {
|
|
471
|
+
isTransactionRequest: rdsConnection.isTransactionRequest
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
let preResult = await connection.provider.executeSql(rdsConnection.connection, sql, parameters, options);
|
|
475
|
+
if (process.env.blz_traceAll === 'true' || process.env.blz_traceRelationalDatabaseQueries === 'true')
|
|
476
|
+
console.log((callContext.devTime ? '' : new Date().toISOString() + ' | ') + 'RELATIONAL DATABASE QUERY (' + traceId + ') | ' + connection.name + ' | ' + (Date.now() - traceStartTime) + ' milliseconds');
|
|
477
|
+
let result = { data: null };
|
|
478
|
+
if (preResult.data) {
|
|
479
|
+
if (options.queryOne) {
|
|
480
|
+
let row = preResult.data.length > 0 ? preResult.data[0] : null;
|
|
481
|
+
if (row) {
|
|
482
|
+
adjustTypes(row, types);
|
|
483
|
+
if (process.env.blz_traceAll === 'true' || process.env.blz_traceRelationalDatabaseQueries === 'true')
|
|
484
|
+
console.log((callContext.devTime ? '' : new Date().toISOString() + ' | ') + 'RELATIONAL DATABASE QUERY (' + traceId + ') | ' + connection.name + ' | ' + JSON.stringify(row));
|
|
485
|
+
result.data = await fnSelection(row);
|
|
486
|
+
}
|
|
487
|
+
else {
|
|
488
|
+
if (process.env.blz_traceAll === 'true' || process.env.blz_traceRelationalDatabaseQueries === 'true')
|
|
489
|
+
console.log((callContext.devTime ? '' : new Date().toISOString() + ' | ') + 'RELATIONAL DATABASE QUERY (' + traceId + ') | ' + connection.name + ' | No records found');
|
|
490
|
+
result.data = null;
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
else {
|
|
494
|
+
result.data = [];
|
|
495
|
+
let rowIndex = 0;
|
|
496
|
+
for (let i = 0; i < preResult.data.length; i++) {
|
|
497
|
+
let row = preResult.data[i];
|
|
498
|
+
adjustTypes(row, types);
|
|
499
|
+
rowIndex++;
|
|
500
|
+
if (rowIndex <= 10 && (process.env.blz_traceAll === 'true' || process.env.blz_traceRelationalDatabaseQueries === 'true'))
|
|
501
|
+
console.log((callContext.devTime ? '' : new Date().toISOString() + ' | ') + 'RELATIONAL DATABASE QUERY (' + traceId + ') | ' + connection.name + ' | ' + JSON.stringify(row));
|
|
502
|
+
result.data.push(await fnSelection(row));
|
|
503
|
+
}
|
|
504
|
+
if (rowIndex === 0 && (process.env.blz_traceAll === 'true' || process.env.blz_traceRelationalDatabaseQueries === 'true'))
|
|
505
|
+
console.log((callContext.devTime ? '' : new Date().toISOString() + ' | ') + 'RELATIONAL DATABASE QUERY (' + traceId + ') | ' + connection.name + ' | No records found');
|
|
506
|
+
if (rowIndex > 10 && (process.env.blz_traceAll === 'true' || process.env.blz_traceRelationalDatabaseQueries === 'true'))
|
|
507
|
+
console.log((callContext.devTime ? '' : new Date().toISOString() + ' | ') + 'RELATIONAL DATABASE QUERY (' + traceId + ') | ' + connection.name + ' | More records found');
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
else if (preResult.resultSet) {
|
|
511
|
+
resultSet = preResult.resultSet;
|
|
512
|
+
if (options.queryOne) {
|
|
513
|
+
let row = await resultSet.getRow();
|
|
514
|
+
if (row) {
|
|
515
|
+
adjustTypes(row, types);
|
|
516
|
+
if (process.env.blz_traceAll === 'true' || process.env.blz_traceRelationalDatabaseQueries === 'true')
|
|
517
|
+
console.log((callContext.devTime ? '' : new Date().toISOString() + ' | ') + 'RELATIONAL DATABASE QUERY (' + traceId + ') | ' + connection.name + ' | ' + JSON.stringify(row));
|
|
518
|
+
result.data = await fnSelection(row);
|
|
519
|
+
}
|
|
520
|
+
else {
|
|
521
|
+
if (process.env.blz_traceAll === 'true' || process.env.blz_traceRelationalDatabaseQueries === 'true')
|
|
522
|
+
console.log((callContext.devTime ? '' : new Date().toISOString() + ' | ') + 'RELATIONAL DATABASE QUERY (' + traceId + ') | ' + connection.name + ' | No records found');
|
|
523
|
+
result.data = null;
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
else {
|
|
527
|
+
result.data = [];
|
|
528
|
+
let rowIndex = 0;
|
|
529
|
+
let row = await resultSet.getRow();
|
|
530
|
+
if (row)
|
|
531
|
+
adjustTypes(row, types);
|
|
532
|
+
while (row) {
|
|
533
|
+
rowIndex++;
|
|
534
|
+
if (rowIndex <= 10 && (process.env.blz_traceAll === 'true' || process.env.blz_traceRelationalDatabaseQueries === 'true'))
|
|
535
|
+
console.log((callContext.devTime ? '' : new Date().toISOString() + ' | ') + 'RELATIONAL DATABASE QUERY (' + traceId + ') | ' + connection.name + ' | ' + JSON.stringify(row));
|
|
536
|
+
result.data.push(await fnSelection(row));
|
|
537
|
+
row = await resultSet.getRow();
|
|
538
|
+
if (row)
|
|
539
|
+
adjustTypes(row, types);
|
|
540
|
+
}
|
|
541
|
+
if (rowIndex === 0 && (process.env.blz_traceAll === 'true' || process.env.blz_traceRelationalDatabaseQueries === 'true'))
|
|
542
|
+
console.log((callContext.devTime ? '' : new Date().toISOString() + ' | ') + 'RELATIONAL DATABASE QUERY (' + traceId + ') | ' + connection.name + ' | No records found');
|
|
543
|
+
if (rowIndex > 10 && (process.env.blz_traceAll === 'true' || process.env.blz_traceRelationalDatabaseQueries === 'true'))
|
|
544
|
+
console.log((callContext.devTime ? '' : new Date().toISOString() + ' | ') + 'RELATIONAL DATABASE QUERY (' + traceId + ') | ' + connection.name + ' | More records found');
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
if (preResult.rowsAffected)
|
|
548
|
+
result.rowsAffected = preResult.rowsAffected;
|
|
549
|
+
if (preResult.id)
|
|
550
|
+
result.id = preResult.id;
|
|
551
|
+
if (preResult.ids)
|
|
552
|
+
result.ids = preResult.ids;
|
|
553
|
+
if (preResult.outParameters)
|
|
554
|
+
result.outParameters = preResult.outParameters;
|
|
555
|
+
if (resultSet && resultSet.close)
|
|
556
|
+
await resultSet.close();
|
|
557
|
+
if (mustBeClosed)
|
|
558
|
+
await connection.provider.close(rdsConnection.connection);
|
|
559
|
+
return result;
|
|
560
|
+
}
|
|
561
|
+
catch (err) {
|
|
562
|
+
if (resultSet && resultSet.close)
|
|
563
|
+
await resultSet.close();
|
|
564
|
+
if (mustBeClosed)
|
|
565
|
+
await connection.provider.close(rdsConnection.connection);
|
|
566
|
+
let rdsError = new Error();
|
|
567
|
+
rdsError.code = 'RdsError';
|
|
568
|
+
rdsError.message = 'Error executing sql ' + sql;
|
|
569
|
+
rdsError.data = { connectionName: connection.name, sql: sql, parameters: parameters };
|
|
570
|
+
rdsError.innerError = err;
|
|
571
|
+
throw rdsError;
|
|
572
|
+
}
|
|
573
|
+
},
|
|
574
|
+
checkConnection: async function (connection) {
|
|
575
|
+
({ rdsConnection, mustBeClosed } = await getRdsConnection({}, connection));
|
|
576
|
+
let rdsConnection = new RdsConnection(await connection.provider.createRdsConnection(connection), connection.provider);
|
|
577
|
+
}
|
|
578
|
+
};
|