@63klabs/cache-data 1.3.9 → 1.3.10

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.
@@ -1,141 +1,11 @@
1
- contentType = "application/json"
1
+ const { createGenericResponseModule } = require("./generic.response");
2
2
 
3
- headers = {
4
- "Content-Type": contentType
5
- };
3
+ const jsonBodyFormatter = (statusCode, message) => ({ message });
6
4
 
7
- json = function (data = null) {
5
+ const json = function (data = null) {
8
6
  return data ? data : {};
9
7
  };
10
8
 
11
- response200 = {
12
- statusCode: 200,
13
- headers: headers,
14
- body: {
15
- message: "Success"
16
- }
17
- };
18
-
19
- response400 = {
20
- statusCode: 400,
21
- headers: headers,
22
- body: {
23
- message: "Bad Request"
24
- }
25
- };
26
-
27
- response401 = {
28
- statusCode: 401,
29
- headers: headers,
30
- body: {
31
- message: "Unauthorized"
32
- }
33
- };
34
-
35
- response403 = {
36
- statusCode: 403,
37
- headers: headers,
38
- body: {
39
- message: "Forbidden"
40
- }
41
- };
42
-
43
- response404 = {
44
- statusCode: 404,
45
- headers: headers,
46
- body: {
47
- message: "Not Found"
48
- }
49
- };
50
-
51
- response405 = {
52
- statusCode: 405,
53
- headers: headers,
54
- body: {
55
- message: "Method Not Allowed"
56
- }
57
- };
58
-
59
- response408 = {
60
- statusCode: 408,
61
- headers: headers,
62
- body: {
63
- message: "Request Timeout"
64
- }
65
- };
66
-
67
- response418 = {
68
- statusCode: 418,
69
- headers: headers,
70
- body: {
71
- message: "I'm a teapot"
72
- }
73
- };
74
-
75
- response427 = {
76
- statusCode: 427,
77
- headers: headers,
78
- body: {
79
- message: "Too Many Requests"
80
- }
81
- };
82
-
83
- response500 = {
84
- statusCode: 500,
85
- headers: headers,
86
- body: {
87
- message: "Internal Server Error"
88
- }
89
- };
90
-
91
- /**
92
- *
93
- * @param {number|string} statusCode
94
- * @returns {{statusCode: number, headers: object, body: Array|Object|string}}
95
- */
96
- const response = function (statusCode) {
97
- // convert to int
98
- statusCode = parseInt(statusCode, 10);
99
-
100
- switch (statusCode) {
101
- case 200:
102
- return this.response200;
103
- case 400:
104
- return this.response400;
105
- case 401:
106
- return this.response401;
107
- case 403:
108
- return this.response403;
109
- case 404:
110
- return this.response404;
111
- case 405:
112
- return this.response405;
113
- case 408:
114
- return this.response408;
115
- case 418:
116
- return this.response418;
117
- case 427:
118
- return this.response427;
119
- case 500:
120
- return this.response500;
121
- default:
122
- return this.response500;
123
- }
124
- };
9
+ const mod = createGenericResponseModule("application/json", jsonBodyFormatter);
125
10
 
126
- module.exports = {
127
- contentType,
128
- headers,
129
- json,
130
- response200,
131
- response400,
132
- response401,
133
- response403,
134
- response404,
135
- response405,
136
- response408,
137
- response418,
138
- response427,
139
- response500,
140
- response
141
- }
11
+ module.exports = { ...mod, json };
@@ -1,121 +1,17 @@
1
- contentType = "application/rss+xml";
1
+ const { createGenericResponseModule } = require("./generic.response");
2
2
 
3
- headers = {
4
- "Content-Type": contentType
5
- };
6
-
7
- rss = (body) => {
3
+ const rss = (body) => {
8
4
  return `<?xml version="1.0" encoding="UTF-8" ?><rss version="2.0">${body}</rss>`;
9
- }
10
-
11
- response200 = {
12
- statusCode: 200,
13
- headers: headers,
14
- body: rss("<hello>Success</hello>")
15
- };
16
-
17
- response400 = {
18
- statusCode: 400,
19
- headers: headers,
20
- body: rss("<error>Bad Request</error>")
21
- };
22
-
23
- response401 = {
24
- statusCode: 401,
25
- headers: headers,
26
- body: rss("<error>Unauthorized</error>")
27
- };
28
-
29
- response403 = {
30
- statusCode: 403,
31
- headers: headers,
32
- body: rss("<error>Forbidden</error>")
33
5
  };
34
6
 
35
- response404 = {
36
- statusCode: 404,
37
- headers: headers,
38
- body: rss("<error>Not Found</error>")
39
- };
40
-
41
- response405 = {
42
- statusCode: 405,
43
- headers: headers,
44
- body: rss("<error>Method Not Allowed</error>")
45
- };
46
-
47
- response408 = {
48
- statusCode: 408,
49
- headers: headers,
50
- body: rss("<error>Request Timeout</error>")
51
- };
52
-
53
- response418 = {
54
- statusCode: 418,
55
- headers: headers,
56
- body: rss("<error>418 I'm a teapot</error>")
57
- };
58
-
59
- response427 = {
60
- statusCode: 427,
61
- headers: headers,
62
- body: rss("<error>Too Many Requests</error>")
63
- };
64
-
65
- response500 = {
66
- statusCode: 500,
67
- headers: headers,
68
- body: rss("<error>Internal Server Error</error>")
69
- };
70
-
71
- /**
72
- *
73
- * @param {number|string} statusCode
74
- * @returns {{statusCode: number, headers: object, body: Array|Object|string}}
75
- */
76
- response = function (statusCode) {
77
- // convert to int
78
- statusCode = parseInt(statusCode, 10);
79
-
80
- switch (statusCode) {
81
- case 200:
82
- return this.response200;
83
- case 400:
84
- return this.response400;
85
- case 401:
86
- return this.response401;
87
- case 403:
88
- return this.response403;
89
- case 404:
90
- return this.response404;
91
- case 405:
92
- return this.response405;
93
- case 408:
94
- return this.response408;
95
- case 418:
96
- return this.response418;
97
- case 427:
98
- return this.response427;
99
- case 500:
100
- return this.response500;
101
- default:
102
- return this.response500;
7
+ const rssBodyFormatter = (statusCode, message) => {
8
+ if (statusCode === 200) {
9
+ return rss("<hello>" + message + "</hello>");
103
10
  }
11
+ const msg = statusCode === 418 ? "418 " + message : message;
12
+ return rss("<error>" + msg + "</error>");
104
13
  };
105
14
 
106
- module.exports = {
107
- contentType,
108
- headers,
109
- rss,
110
- response200,
111
- response400,
112
- response401,
113
- response403,
114
- response404,
115
- response405,
116
- response408,
117
- response418,
118
- response427,
119
- response500,
120
- response
121
- }
15
+ const mod = createGenericResponseModule("application/rss+xml", rssBodyFormatter);
16
+
17
+ module.exports = { ...mod, rss };
@@ -1,119 +1,9 @@
1
- contentType = "text/plain";
1
+ const { createGenericResponseModule } = require("./generic.response");
2
2
 
3
- headers = {
4
- "Content-Type": contentType
5
- };
3
+ const textBodyFormatter = (statusCode, message) => message;
6
4
 
7
- text = (text) => { return text; }
5
+ const text = (text) => { return text; };
8
6
 
9
- response200 = {
10
- statusCode: 200,
11
- headers: headers,
12
- body: text("Success")
13
- };
7
+ const mod = createGenericResponseModule("text/plain", textBodyFormatter);
14
8
 
15
- response400 = {
16
- statusCode: 400,
17
- headers: headers,
18
- body: text("Bad Request")
19
- };
20
-
21
- response401 = {
22
- statusCode: 401,
23
- headers: headers,
24
- body: text("Unauthorized")
25
- };
26
-
27
- response403 = {
28
- statusCode: 403,
29
- headers: headers,
30
- body: text("Forbidden")
31
- };
32
-
33
- response404 = {
34
- statusCode: 404,
35
- headers: headers,
36
- body: text("Not Found")
37
- };
38
-
39
- response405 = {
40
- statusCode: 405,
41
- headers: headers,
42
- body: text("Method Not Allowed")
43
- };
44
-
45
- response408 = {
46
- statusCode: 408,
47
- headers: headers,
48
- body: text("Request Timeout")
49
- };
50
-
51
- response418 = {
52
- statusCode: 418,
53
- headers: headers,
54
- body: text("I'm a teapot")
55
- };
56
-
57
- response427 = {
58
- statusCode: 427,
59
- headers: headers,
60
- body: text("Too Many Requests")
61
- };
62
-
63
- response500 = {
64
- statusCode: 500,
65
- headers: headers,
66
- body: text("Internal Server Error")
67
- };
68
-
69
- /**
70
- *
71
- * @param {number|string} statusCode
72
- * @returns {{statusCode: number, headers: object, body: Array|Object|string}}
73
- */
74
- const response = function (statusCode) {
75
- // convert to int
76
- statusCode = parseInt(statusCode, 10);
77
-
78
- switch (statusCode) {
79
- case 200:
80
- return this.response200;
81
- case 400:
82
- return this.response400;
83
- case 401:
84
- return this.response401;
85
- case 403:
86
- return this.response403;
87
- case 404:
88
- return this.response404;
89
- case 405:
90
- return this.response405;
91
- case 408:
92
- return this.response408;
93
- case 418:
94
- return this.response418;
95
- case 427:
96
- return this.response427;
97
- case 500:
98
- return this.response500;
99
- default:
100
- return this.response500;
101
- }
102
- };
103
-
104
- module.exports = {
105
- contentType,
106
- headers,
107
- text,
108
- response200,
109
- response400,
110
- response401,
111
- response403,
112
- response404,
113
- response405,
114
- response408,
115
- response418,
116
- response427,
117
- response500,
118
- response
119
- }
9
+ module.exports = { ...mod, text };
@@ -1,121 +1,17 @@
1
- contentType = "application/xml";
1
+ const { createGenericResponseModule } = require("./generic.response");
2
2
 
3
- headers = {
4
- "Content-Type": contentType
5
- };
6
-
7
- xml = (body) => {
3
+ const xml = (body) => {
8
4
  return `<?xml version="1.0" encoding="UTF-8" ?>${body}`;
9
- }
10
-
11
- response200 = {
12
- statusCode: 200,
13
- headers: headers,
14
- body: xml("<hello>Success</hello>")
15
- };
16
-
17
- response400 = {
18
- statusCode: 400,
19
- headers: headers,
20
- body: xml("<error>Bad Request</error>")
21
- };
22
-
23
- response401 = {
24
- statusCode: 401,
25
- headers: headers,
26
- body: xml("<error>Unauthorized</error>")
27
- };
28
-
29
- response403 = {
30
- statusCode: 403,
31
- headers: headers,
32
- body: xml("<error>Forbidden</error>")
33
5
  };
34
6
 
35
- response404 = {
36
- statusCode: 404,
37
- headers: headers,
38
- body: xml("<error>Not Found</error>")
39
- };
40
-
41
- response405 = {
42
- statusCode: 405,
43
- headers: headers,
44
- body: xml("<error>Method Not Allowed</error>")
45
- };
46
-
47
- response408 = {
48
- statusCode: 408,
49
- headers: headers,
50
- body: xml("<error>Request Timeout</error>")
51
- };
52
-
53
- response418 = {
54
- statusCode: 418,
55
- headers: headers,
56
- body: xml("<error>418 I'm a teapot</error>")
57
- };
58
-
59
- response427 = {
60
- statusCode: 427,
61
- headers: headers,
62
- body: xml("<error>Too Many Requests</error>")
63
- };
64
-
65
- response500 = {
66
- statusCode: 500,
67
- headers: headers,
68
- body: xml("<error>Internal Server Error</error>")
69
- };
70
-
71
- /**
72
- *
73
- * @param {number|string} statusCode
74
- * @returns {{statusCode: number, headers: object, body: Array|Object|string}}
75
- */
76
- response = function (statusCode) {
77
- // convert to int
78
- statusCode = parseInt(statusCode, 10);
79
-
80
- switch (statusCode) {
81
- case 200:
82
- return this.response200;
83
- case 400:
84
- return this.response400;
85
- case 401:
86
- return this.response401;
87
- case 403:
88
- return this.response403;
89
- case 404:
90
- return this.response404;
91
- case 405:
92
- return this.response405;
93
- case 408:
94
- return this.response408;
95
- case 418:
96
- return this.response418;
97
- case 427:
98
- return this.response427;
99
- case 500:
100
- return this.response500;
101
- default:
102
- return this.response500;
7
+ const xmlBodyFormatter = (statusCode, message) => {
8
+ if (statusCode === 200) {
9
+ return xml("<hello>" + message + "</hello>");
103
10
  }
11
+ const msg = statusCode === 418 ? "418 " + message : message;
12
+ return xml("<error>" + msg + "</error>");
104
13
  };
105
14
 
106
- module.exports = {
107
- contentType,
108
- headers,
109
- xml,
110
- response200,
111
- response400,
112
- response401,
113
- response403,
114
- response404,
115
- response405,
116
- response408,
117
- response418,
118
- response427,
119
- response500,
120
- response
121
- }
15
+ const mod = createGenericResponseModule("application/xml", xmlBodyFormatter);
16
+
17
+ module.exports = { ...mod, xml };
@@ -20,7 +20,7 @@
20
20
 
21
21
  const { nodeVer, nodeVerMajor, nodeVerMinor, nodeVerMajorMinor } = require('./vars');
22
22
  const { AWS, AWSXRay } = require('./AWS.classes');
23
- const APIRequest = require("./APIRequest.class");
23
+ const ApiRequest = require("./ApiRequest.class");
24
24
  const RequestInfo = require("./RequestInfo.class");
25
25
  const ClientRequest = require("./ClientRequest.class");
26
26
  const ResponseDataModel = require("./ResponseDataModel.class");
@@ -34,7 +34,7 @@ const xmlGenericResponse = require('./generic.response.xml');
34
34
  const rssGenericResponse = require('./generic.response.rss');
35
35
  const textGenericResponse = require('./generic.response.text');
36
36
  const { printMsg, sanitize, obfuscate, hashThisData} = require('./utils');
37
- const { CachedParameterSecrets, CachedParameterSecret, CachedSSMParameter, CachedSecret } = require('./CachedParametersSecrets.classes')
37
+ const { CachedParameterSecrets, CachedParameterSecret, CachedSsmParameter, CachedSecret } = require('./CachedParametersSecrets.classes')
38
38
  const { Connections, Connection, ConnectionRequest, ConnectionAuthentication } = require('./Connections.classes')
39
39
 
40
40
  /*
@@ -295,7 +295,7 @@ class AppConfig {
295
295
  * const conn = Config.getConn('myConnection');
296
296
  * const cacheObj = await CacheableDataAccess.getData(
297
297
  * cacheProfile,
298
- * endpoint.get
298
+ * endpoint.send
299
299
  * conn
300
300
  * )
301
301
  * */
@@ -322,7 +322,7 @@ class AppConfig {
322
322
  * const { conn, cacheProfile } = Config.getConnCacheProfile('myConnection', 'myCacheProfile');
323
323
  * const cacheObj = await CacheableDataAccess.getData(
324
324
  * cacheProfile,
325
- * endpoint.get
325
+ * endpoint.send
326
326
  * conn
327
327
  * )
328
328
  */
@@ -463,6 +463,14 @@ class AppConfig {
463
463
  // put the parameter into its group
464
464
  const obj = parameters.find(o => o.path === groupPath);
465
465
  const group = obj.group;
466
+
467
+ // >! Guard against prototype pollution (CWE-471)
468
+ const DANGEROUS_KEYS = ['__proto__', 'constructor', 'prototype'];
469
+ if (DANGEROUS_KEYS.includes(group) || DANGEROUS_KEYS.includes(name)) {
470
+ DebugAndLog.warn(`Skipping dangerous parameter key: group="${group}", name="${name}"`);
471
+ return;
472
+ }
473
+
466
474
  if ( !(group in paramstore)) {
467
475
  paramstore[group] = {};
468
476
  }
@@ -534,8 +542,9 @@ module.exports = {
534
542
  Aws: AWS,
535
543
  AWSXRay,
536
544
  AwsXRay: AWSXRay, // Alias
537
- APIRequest,
538
- ApiRequest: APIRequest, // Alias
545
+ ApiRequest,
546
+ /** @deprecated Use ApiRequest instead */
547
+ APIRequest: ApiRequest, // Alias
539
548
  ImmutableObject,
540
549
  Timer,
541
550
  DebugAndLog,
@@ -548,9 +557,11 @@ module.exports = {
548
557
  ResponseDataModel,
549
558
  Response,
550
559
  AppConfig,
560
+ /** @deprecated Use AppConfig instead */
551
561
  _ConfigSuperClass: AppConfig, // Alias
552
- CachedSSMParameter,
553
- CachedSsmParameter: CachedSSMParameter, // Alias
562
+ CachedSsmParameter,
563
+ /** @deprecated Use CachedSsmParameter instead */
564
+ CachedSSMParameter: CachedSsmParameter, // Alias
554
565
  CachedSecret,
555
566
  CachedParameterSecret,
556
567
  CachedParameterSecrets,
@@ -5,6 +5,10 @@
5
5
  * single-parameter or multi-parameter interfaces. It handles errors gracefully and
6
6
  * logs validation failures.
7
7
  *
8
+ * The interface is determined by the params array length:
9
+ * - params.length === 1: Pass value directly (single-parameter interface)
10
+ * - params.length > 1: Pass object (multi-parameter interface)
11
+ *
8
12
  * @private
9
13
  * @class ValidationExecutor
10
14
  */
@@ -13,8 +17,8 @@ class ValidationExecutor {
13
17
  * Execute validation function with appropriate interface.
14
18
  *
15
19
  * Determines whether to pass a single value or an object based on the number
16
- * of parameters specified. Handles validation errors gracefully by catching
17
- * exceptions and logging them.
20
+ * of parameters in the params array. Handles validation errors gracefully by
21
+ * catching exceptions and logging them.
18
22
  *
19
23
  * @param {Function} validateFn - Validation function to execute
20
24
  * @param {Array<string>} paramNames - Parameter names to validate
@@ -22,7 +26,7 @@ class ValidationExecutor {
22
26
  * @returns {boolean} True if validation passes, false if fails or throws
23
27
  *
24
28
  * @example
25
- * // Single parameter validation
29
+ * // Single parameter validation (params.length === 1)
26
30
  * const isValid = ValidationExecutor.execute(
27
31
  * (value) => value.length > 0,
28
32
  * ['id'],
@@ -30,7 +34,7 @@ class ValidationExecutor {
30
34
  * );
31
35
  *
32
36
  * @example
33
- * // Multi-parameter validation
37
+ * // Multi-parameter validation (params.length > 1)
34
38
  * const isValid = ValidationExecutor.execute(
35
39
  * ({page, limit}) => page >= 1 && limit >= 1 && limit <= 100,
36
40
  * ['page', 'limit'],
@@ -316,7 +316,7 @@ class ValidationMatcher {
316
316
  * @returns {{validate: Function, params: Array<string>}|null} Validation rule or null
317
317
  */
318
318
  #findGlobalMatch(paramName) {
319
- // Check if parameter has a global validation function
319
+ // >! Try exact match first (for backwards compatibility)
320
320
  if (this.#paramValidations[paramName] && typeof this.#paramValidations[paramName] === 'function') {
321
321
  return {
322
322
  validate: this.#paramValidations[paramName],
@@ -324,6 +324,18 @@ class ValidationMatcher {
324
324
  };
325
325
  }
326
326
 
327
+ // >! Try case-insensitive match for query parameters
328
+ // >! Query parameters are lowercased in ClientRequest, but validation rules may use camelCase
329
+ const lowerParamName = paramName.toLowerCase();
330
+ for (const key in this.#paramValidations) {
331
+ if (key.toLowerCase() === lowerParamName && typeof this.#paramValidations[key] === 'function') {
332
+ return {
333
+ validate: this.#paramValidations[key],
334
+ params: [paramName] // Return the lowercased paramName that was passed in
335
+ };
336
+ }
337
+ }
338
+
327
339
  return null;
328
340
  }
329
341