lemon-core 4.1.14 → 4.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (154) hide show
  1. package/dist/common/test-helper.d.ts +2 -2
  2. package/dist/common/test-helper.js +24 -26
  3. package/dist/common/test-helper.js.map +1 -1
  4. package/dist/controllers/dummy-controller.js +39 -46
  5. package/dist/controllers/dummy-controller.js.map +1 -1
  6. package/dist/controllers/general-api-controller.js +95 -100
  7. package/dist/controllers/general-api-controller.js.map +1 -1
  8. package/dist/controllers/general-controller.js +81 -82
  9. package/dist/controllers/general-controller.js.map +1 -1
  10. package/dist/cores/api/api-service.d.ts +1 -1
  11. package/dist/cores/api/api-service.js +228 -269
  12. package/dist/cores/api/api-service.js.map +1 -1
  13. package/dist/cores/aws/aws-kms-service.d.ts +1 -2
  14. package/dist/cores/aws/aws-kms-service.js +143 -153
  15. package/dist/cores/aws/aws-kms-service.js.map +1 -1
  16. package/dist/cores/aws/aws-s3-service.d.ts +2 -4
  17. package/dist/cores/aws/aws-s3-service.js +306 -330
  18. package/dist/cores/aws/aws-s3-service.js.map +1 -1
  19. package/dist/cores/aws/aws-sns-service.js +147 -153
  20. package/dist/cores/aws/aws-sns-service.js.map +1 -1
  21. package/dist/cores/aws/aws-sqs-service.js +149 -170
  22. package/dist/cores/aws/aws-sqs-service.js.map +1 -1
  23. package/dist/cores/aws/index.js +10 -20
  24. package/dist/cores/aws/index.js.map +1 -1
  25. package/dist/cores/cache/cache-service.d.ts +2 -2
  26. package/dist/cores/cache/cache-service.js +435 -499
  27. package/dist/cores/cache/cache-service.js.map +1 -1
  28. package/dist/cores/config/config-service.d.ts +1 -1
  29. package/dist/cores/config/config-service.js +56 -63
  30. package/dist/cores/config/config-service.js.map +1 -1
  31. package/dist/cores/config/index.js +14 -24
  32. package/dist/cores/config/index.js.map +1 -1
  33. package/dist/cores/core-services.d.ts +1 -1
  34. package/dist/cores/dynamo/dynamo-query-service.js +37 -51
  35. package/dist/cores/dynamo/dynamo-query-service.js.map +1 -1
  36. package/dist/cores/dynamo/dynamo-scan-service.d.ts +2 -2
  37. package/dist/cores/dynamo/dynamo-scan-service.js +29 -40
  38. package/dist/cores/dynamo/dynamo-scan-service.js.map +1 -1
  39. package/dist/cores/dynamo/dynamo-service.d.ts +2 -2
  40. package/dist/cores/dynamo/dynamo-service.js +528 -601
  41. package/dist/cores/dynamo/dynamo-service.js.map +1 -1
  42. package/dist/cores/dynamo/tools/expressions.js +17 -7
  43. package/dist/cores/dynamo/tools/expressions.js.map +1 -1
  44. package/dist/cores/dynamo/tools/query.js +142 -127
  45. package/dist/cores/dynamo/tools/query.js.map +1 -1
  46. package/dist/cores/dynamo/tools/scan.js +111 -97
  47. package/dist/cores/dynamo/tools/scan.js.map +1 -1
  48. package/dist/cores/dynamo/tools/serializer.js +17 -7
  49. package/dist/cores/dynamo/tools/serializer.js.map +1 -1
  50. package/dist/cores/dynamo/tools/utils.d.ts +0 -2
  51. package/dist/cores/dynamo/tools/utils.js.map +1 -1
  52. package/dist/cores/elastic/elastic6-query-service.js +307 -324
  53. package/dist/cores/elastic/elastic6-query-service.js.map +1 -1
  54. package/dist/cores/elastic/elastic6-service.d.ts +3 -3
  55. package/dist/cores/elastic/elastic6-service.js +568 -647
  56. package/dist/cores/elastic/elastic6-service.js.map +1 -1
  57. package/dist/cores/elastic/hangul-service.js +52 -54
  58. package/dist/cores/elastic/hangul-service.js.map +1 -1
  59. package/dist/cores/lambda/index.js +42 -36
  60. package/dist/cores/lambda/index.js.map +1 -1
  61. package/dist/cores/lambda/lambda-alb-handler.d.ts +2 -2
  62. package/dist/cores/lambda/lambda-alb-handler.js +59 -72
  63. package/dist/cores/lambda/lambda-alb-handler.js.map +1 -1
  64. package/dist/cores/lambda/lambda-cognito-handler.js +10 -19
  65. package/dist/cores/lambda/lambda-cognito-handler.js.map +1 -1
  66. package/dist/cores/lambda/lambda-cron-handler.d.ts +1 -1
  67. package/dist/cores/lambda/lambda-cron-handler.js +14 -23
  68. package/dist/cores/lambda/lambda-cron-handler.js.map +1 -1
  69. package/dist/cores/lambda/lambda-dynamo-stream-handler.d.ts +2 -2
  70. package/dist/cores/lambda/lambda-dynamo-stream-handler.js +57 -67
  71. package/dist/cores/lambda/lambda-dynamo-stream-handler.js.map +1 -1
  72. package/dist/cores/lambda/lambda-handler.d.ts +22 -22
  73. package/dist/cores/lambda/lambda-handler.js +93 -106
  74. package/dist/cores/lambda/lambda-handler.js.map +1 -1
  75. package/dist/cores/lambda/lambda-notification-handler.d.ts +1 -1
  76. package/dist/cores/lambda/lambda-notification-handler.js +39 -50
  77. package/dist/cores/lambda/lambda-notification-handler.js.map +1 -1
  78. package/dist/cores/lambda/lambda-sns-handler.js +79 -88
  79. package/dist/cores/lambda/lambda-sns-handler.js.map +1 -1
  80. package/dist/cores/lambda/lambda-sqs-handler.js +79 -88
  81. package/dist/cores/lambda/lambda-sqs-handler.js.map +1 -1
  82. package/dist/cores/lambda/lambda-web-handler.d.ts +21 -43
  83. package/dist/cores/lambda/lambda-web-handler.js +392 -482
  84. package/dist/cores/lambda/lambda-web-handler.js.map +1 -1
  85. package/dist/cores/lambda/lambda-wss-handler.js +23 -32
  86. package/dist/cores/lambda/lambda-wss-handler.js.map +1 -1
  87. package/dist/cores/protocol/index.js +10 -20
  88. package/dist/cores/protocol/index.js.map +1 -1
  89. package/dist/cores/protocol/protocol-service.d.ts +3 -3
  90. package/dist/cores/protocol/protocol-service.js +235 -227
  91. package/dist/cores/protocol/protocol-service.js.map +1 -1
  92. package/dist/cores/storage/http-storage-service.js +65 -85
  93. package/dist/cores/storage/http-storage-service.js.map +1 -1
  94. package/dist/cores/storage/model-manager.js +66 -85
  95. package/dist/cores/storage/model-manager.js.map +1 -1
  96. package/dist/cores/storage/proxy-storage-service.d.ts +2 -2
  97. package/dist/cores/storage/proxy-storage-service.js +562 -599
  98. package/dist/cores/storage/proxy-storage-service.js.map +1 -1
  99. package/dist/cores/storage/redis-storage-service.js +163 -177
  100. package/dist/cores/storage/redis-storage-service.js.map +1 -1
  101. package/dist/cores/storage/storage-service.js +281 -322
  102. package/dist/cores/storage/storage-service.js.map +1 -1
  103. package/dist/engine/builder.d.ts +1 -1
  104. package/dist/engine/builder.js +59 -63
  105. package/dist/engine/builder.js.map +1 -1
  106. package/dist/engine/engine.d.ts +4 -4
  107. package/dist/engine/engine.js +9 -18
  108. package/dist/engine/engine.js.map +1 -1
  109. package/dist/engine/types.d.ts +1 -1
  110. package/dist/engine/utilities.d.ts +14 -10
  111. package/dist/engine/utilities.js +301 -280
  112. package/dist/engine/utilities.js.map +1 -1
  113. package/dist/environ.js +4 -6
  114. package/dist/environ.js.map +1 -1
  115. package/dist/extended/abstract-service.js +595 -645
  116. package/dist/extended/abstract-service.js.map +1 -1
  117. package/dist/extended/libs/sig-v4.js.map +1 -1
  118. package/dist/generated/field-registry.d.ts +10 -0
  119. package/dist/generated/field-registry.js +17 -0
  120. package/dist/generated/field-registry.js.map +1 -0
  121. package/dist/helpers/helpers.d.ts +17 -9
  122. package/dist/helpers/helpers.js +88 -78
  123. package/dist/helpers/helpers.js.map +1 -1
  124. package/dist/index.js +17 -7
  125. package/dist/index.js.map +1 -1
  126. package/dist/lib/dynamodb-value.js +2 -3
  127. package/dist/lib/dynamodb-value.js.map +1 -1
  128. package/dist/tools/express.js +4 -5
  129. package/dist/tools/express.js.map +1 -1
  130. package/dist/tools/tools.d.ts +3 -1
  131. package/dist/tools/tools.js +14 -21
  132. package/dist/tools/tools.js.map +1 -1
  133. package/package.json +19 -18
  134. package/dist/exec-cli.d.ts +0 -2
  135. package/dist/exec-cli.js +0 -211
  136. package/dist/exec-cli.js.map +0 -1
  137. package/dist/lib/dynamo/expressions.d.ts +0 -14
  138. package/dist/lib/dynamo/expressions.js +0 -212
  139. package/dist/lib/dynamo/expressions.js.map +0 -1
  140. package/dist/lib/dynamo/query.d.ts +0 -43
  141. package/dist/lib/dynamo/query.js +0 -246
  142. package/dist/lib/dynamo/query.js.map +0 -1
  143. package/dist/lib/dynamo/scan.d.ts +0 -33
  144. package/dist/lib/dynamo/scan.js +0 -172
  145. package/dist/lib/dynamo/scan.js.map +0 -1
  146. package/dist/lib/dynamo/serializer.d.ts +0 -12
  147. package/dist/lib/dynamo/serializer.js +0 -243
  148. package/dist/lib/dynamo/serializer.js.map +0 -1
  149. package/dist/lib/dynamo/utils.d.ts +0 -15
  150. package/dist/lib/dynamo/utils.js +0 -129
  151. package/dist/lib/dynamo/utils.js.map +0 -1
  152. package/dist/tools/shared.d.ts +0 -37
  153. package/dist/tools/shared.js +0 -130
  154. package/dist/tools/shared.js.map +0 -1
@@ -15,13 +15,23 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
15
15
  }) : function(o, v) {
16
16
  o["default"] = v;
17
17
  });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
25
35
  var __importDefault = (this && this.__importDefault) || function (mod) {
26
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
27
37
  };
@@ -49,278 +59,11 @@ const COLORS = {
49
59
  * - various functions
50
60
  */
51
61
  class Utilities {
62
+ _$;
63
+ log;
64
+ err;
65
+ name;
52
66
  constructor(_$) {
53
- /**
54
- * parse float by decimal point 2
55
- */
56
- this.F2 = (x, mode = 'round') => this.FN(x, 2, mode);
57
- /**
58
- * parse float by decimal point 3
59
- */
60
- this.F3 = (x, mode = 'round') => this.FN(x, 3, mode);
61
- /**
62
- * convert and cut string like `abcd....z`
63
- */
64
- this.S = (_, h, t = 32, delim = '...') => [typeof _ == 'string' ? _ : `${this.json(_) || ''}`]
65
- .map(s => h && s.length > h + t
66
- ? s.substring(0, h) + delim + (s.length > h + t ? s.substring(s.length - t) : '')
67
- : s)
68
- .join('');
69
- /**
70
- * group as qs
71
- */
72
- this.qs = {
73
- /**
74
- * parse qs string
75
- */
76
- parse: (q) => this.qs_parse(q),
77
- /**
78
- * stringify qs object
79
- */
80
- stringify: (q) => this.qs_stringify(q),
81
- };
82
- /**
83
- * get crypto object.
84
- *
85
- * @deprecated since nodejs22, use `crypto2` instead.
86
- */
87
- this.crypto = (passwd, algorithm) => {
88
- algorithm = algorithm || 'aes-256-ctr';
89
- const MAGIC = 'LM!#';
90
- /**
91
- * Simulate OpenSSL's EVP_BytesToKey method
92
- */
93
- const evpBytesToKey = (password, keyLen, ivLen) => {
94
- let data = Buffer.alloc(0);
95
- let prev = Buffer.alloc(0);
96
- while (data.length < keyLen + ivLen) {
97
- const hash = crypto_1.default.createHash('md5');
98
- hash.update(Buffer.concat([prev, password]));
99
- prev = hash.digest();
100
- data = Buffer.concat([data, prev]);
101
- }
102
- return {
103
- key: data.slice(0, keyLen),
104
- iv: data.slice(keyLen, keyLen + ivLen),
105
- };
106
- };
107
- const getKeyIV = () => {
108
- const passwordBuf = Buffer.from(passwd, 'binary');
109
- const keyLen = 32; // for aes-256
110
- const ivLen = 16; // AES block size
111
- return evpBytesToKey(passwordBuf, keyLen, ivLen);
112
- };
113
- return new (class {
114
- constructor() {
115
- /** @deprecated since nodejs22 */
116
- this.encrypt = (val) => {
117
- val = val === undefined ? null : val;
118
- // msg = msg && typeof msg == 'object' ? JSON_TAG+JSON.stringify(msg) : msg;
119
- //* 어느 데이터 타입이든 저장하기 위해서, object로 만든다음, 암호화 시킨다.
120
- const msg = JSON.stringify({ alg: algorithm, val: val });
121
- const buffer = Buffer.from(`${MAGIC}${msg || ''}`, 'utf8');
122
- const { key, iv } = getKeyIV();
123
- const cipher = crypto_1.default.createCipheriv(algorithm, key, iv);
124
- const crypted = Buffer.concat([cipher.update(buffer), cipher.final()]);
125
- return crypted.toString(1 ? 'base64' : 'utf8');
126
- };
127
- /** @deprecated since nodejs22 */
128
- this.decrypt = (msg) => {
129
- const buffer = Buffer.from(`${msg || ''}`, 'base64');
130
- const { key, iv } = getKeyIV();
131
- const decipher = crypto_1.default.createDecipheriv(algorithm, key, iv);
132
- const decrypted = Buffer.concat([decipher.update(buffer), decipher.final()]);
133
- const dec = decrypted.toString('utf8');
134
- if (!dec.startsWith(MAGIC))
135
- throw new Error('400 INVALID PASSWD - invalid magic string!');
136
- const data = dec.slice(MAGIC.length);
137
- if (data && !data.startsWith('{') && !data.endsWith('}'))
138
- throw new Error('400 INVALID PASSWD - invalid json string!');
139
- const $msg = JSON.parse(data) || {};
140
- return $msg.val;
141
- };
142
- }
143
- })();
144
- };
145
- /**
146
- * get crypto2 object (w/ Cipheriv).
147
- * - to avoid `(node:66818) Warning: Use Cipheriv for counter mode of aes-256-ctr`
148
- *
149
- * @param passwd password to crypt
150
- * @param algorithm (default as `aes-256-ctr`)
151
- * @param ivNumb iv number to populate. (default as 0, or -1 use random)
152
- * @param magic magic string to verify (default `LM!#`)
153
- */
154
- this.crypto2 = (passwd, algorithm, ivNumb, magic) => {
155
- algorithm = algorithm || 'aes-256-ctr';
156
- const MAGIC = magic === undefined ? 'LM!#' : `${magic || ''}`;
157
- const iv = Buffer.from(Array.prototype.map.call(Buffer.alloc(16), () => {
158
- return ivNumb === undefined ? 0 : ivNumb === -1 ? Math.floor(Math.random() * 256) : ivNumb;
159
- }));
160
- return new (class {
161
- constructor() {
162
- this.encrypt = (val) => {
163
- val = val === undefined ? null : val;
164
- //* use json string to support all data-type
165
- const msg = JSON.stringify({ alg: algorithm, val: val });
166
- const buffer = Buffer.from(`${MAGIC}${msg || ''}`, 'utf8');
167
- const key = Buffer.concat([Buffer.from(passwd)], Buffer.alloc(32).length);
168
- const cipher = crypto_1.default.createCipheriv(algorithm, key, iv);
169
- const crypted = Buffer.concat([cipher.update(buffer), cipher.final()]);
170
- return crypted.toString('base64');
171
- };
172
- this.decrypt = (msg) => {
173
- const buffer = Buffer.from(`${msg || ''}`, 'base64');
174
- const key = Buffer.concat([Buffer.from(passwd)], Buffer.alloc(32).length);
175
- const decipher = crypto_1.default.createDecipheriv(algorithm, key, iv);
176
- const dec = Buffer.concat([decipher.update(buffer), decipher.final()]).toString('utf8');
177
- if (!dec.startsWith(MAGIC))
178
- throw new Error(`400 INVALID PASSWD - invalid magic string!`);
179
- const data = dec.substr(MAGIC.length);
180
- if (data && !data.startsWith('{') && !data.endsWith('}'))
181
- throw new Error('400 INVALID PASSWD - invalid json string!');
182
- const $msg = JSON.parse(data) || {};
183
- return $msg.val;
184
- };
185
- }
186
- })();
187
- };
188
- /**
189
- * get crypto3 object (with nonce + timestamp based IV).
190
- * - version header (16 bytes, plaintext)
191
- * - format: {versionHeader:16}{nonce:8}{timestamp:13}{encryptedBase64}
192
- *
193
- * @param passwd password to crypt
194
- * @param algorithm (default as `aes-256-ctr`)
195
- */
196
- this.crypto3 = (passwd, algorithm) => {
197
- algorithm = algorithm || 'aes-256-ctr';
198
- const VERSION = 'V003';
199
- const VERSION_HEADER = `LM!#${VERSION}`.padEnd(16, '0'); // "LM!#V00300000000" (16 bytes, plaintext)
200
- const key = Buffer.concat([Buffer.from(passwd)], Buffer.alloc(32).length);
201
- const hmac = (data, sig) => this.hmac(data, sig, 'sha256', 'hex');
202
- const currentMs = () => this.current_time_ms();
203
- const makeNonce = () => this.uuid().replace(/-/g, '').substring(0, 8);
204
- return new (class {
205
- constructor() {
206
- this.encrypt = (val, options) => {
207
- var _a, _b;
208
- val = val === undefined ? null : val;
209
- const nonce = (_a = options === null || options === void 0 ? void 0 : options.nonce) !== null && _a !== void 0 ? _a : makeNonce();
210
- const timestamp = String((_b = options === null || options === void 0 ? void 0 : options.current) !== null && _b !== void 0 ? _b : currentMs()).padStart(13, '0');
211
- const iv = Buffer.from(hmac(`${nonce}:${timestamp}`, passwd).substring(0, 32), 'hex');
212
- const buffer = Buffer.from(JSON.stringify({ d: val }), 'utf8');
213
- const cipher = crypto_1.default.createCipheriv(algorithm, key, iv);
214
- const crypted = Buffer.concat([cipher.update(buffer), cipher.final()]);
215
- return `${VERSION_HEADER}${nonce}${timestamp}${crypted.toString('base64')}`;
216
- };
217
- this.decrypt = (msg, options) => {
218
- var _a;
219
- if (!msg)
220
- throw new Error('@msg (string) is required!');
221
- if (msg.length < 37)
222
- throw new Error('400 INVALID DATA - data too short!');
223
- // 1. read version header
224
- const versionHeader = msg.substring(0, 16);
225
- if (!versionHeader.startsWith('LM!#'))
226
- throw new Error('400 INVALID MAGIC - invalid magic string!');
227
- const version = versionHeader.substring(4, 8);
228
- if (version !== VERSION)
229
- throw new Error(`400 INVALID VERSION - expected ${VERSION}, got ${version}!`);
230
- // 2. parse nonce, timestamp, encrypted data
231
- const nonce = msg.substring(16, 24);
232
- const timestamp = msg.substring(24, 37);
233
- const encryptedBase64 = msg.substring(37);
234
- if (!/^\d+$/.test(timestamp))
235
- throw new Error('400 INVALID DATA - invalid timestamp!');
236
- if ((options === null || options === void 0 ? void 0 : options.maxAge) !== undefined) {
237
- const current = (_a = options === null || options === void 0 ? void 0 : options.current) !== null && _a !== void 0 ? _a : currentMs();
238
- if (current - parseInt(timestamp, 10) > options.maxAge)
239
- throw new Error('400 INVALID DATA - expired timestamp!');
240
- }
241
- // 3. decrypt
242
- const iv = Buffer.from(hmac(`${nonce}:${timestamp}`, passwd).substring(0, 32), 'hex');
243
- const decipher = crypto_1.default.createDecipheriv(algorithm, key, iv);
244
- const dec = Buffer.concat([
245
- decipher.update(Buffer.from(encryptedBase64, 'base64')),
246
- decipher.final(),
247
- ]).toString('utf8');
248
- if (!dec.startsWith('{') || !dec.endsWith('}'))
249
- throw new Error('400 INVALID PASSWD - invalid json string!');
250
- const $msg = JSON.parse(dec) || {};
251
- return $msg.d;
252
- };
253
- }
254
- })();
255
- };
256
- /**
257
- * encrypt shorthand using crypto3
258
- */
259
- this.encrypt = (data, secret, options) => {
260
- return this.crypto3(secret).encrypt(data, options);
261
- };
262
- /**
263
- * decrypt shorthand using crypto3
264
- */
265
- this.decrypt = (data, secret, options) => {
266
- return this.crypto3(secret).decrypt(data, options);
267
- };
268
- /**
269
- * builder for `JWTHelper`
270
- * @param passcode string for verification.
271
- * @param current_ms (optional) current time in millisecond (required to verify `exp`)
272
- */
273
- this.jwt = (passcode, current_ms) => {
274
- const $U = this;
275
- /**
276
- * main class.
277
- */
278
- return new (class JWTHelper {
279
- constructor() {
280
- /**
281
- * use `jsonwebtoken` directly.
282
- */
283
- this.$ = jsonwebtoken_1.default;
284
- /**
285
- * encode object to token string
286
- * - Synchronous Sign with default (HS256: HMAC SHA256)
287
- *
288
- * @param data object
289
- * @param algorithm algorithm to use
290
- */
291
- this.encode = (data, algorithm = 'HS256') => {
292
- data = current_ms ? Object.assign(Object.assign({}, data), { iat: Math.floor(current_ms / 1000) }) : data;
293
- const token = jsonwebtoken_1.default.sign(data, passcode, { algorithm });
294
- return token;
295
- };
296
- /**
297
- * decode token string
298
- *
299
- * @param token string
300
- */
301
- this.decode = (token, options) => {
302
- const N = jsonwebtoken_1.default.decode(token, options);
303
- return N;
304
- };
305
- /**
306
- * verify token
307
- * - Synchronous Verify with default (HS256: HMAC SHA256)
308
- *
309
- * @param token
310
- * @param algorithm
311
- * @throws `jwt expired` if exp has expired!.
312
- */
313
- this.verify = (token, algorithm = 'HS256') => {
314
- const verified = jsonwebtoken_1.default.verify(token, passcode, { algorithms: [algorithm] });
315
- const cur = $U.N(current_ms, 0);
316
- const exp = $U.N(verified === null || verified === void 0 ? void 0 : verified.exp, 0) * 1000;
317
- if (cur > 0 && exp > 0 && exp < current_ms)
318
- throw new Error(`jwt expired at ${$U.ts(exp)}`);
319
- return verified;
320
- };
321
- }
322
- })();
323
- };
324
67
  this._$ = _$;
325
68
  this.log = _$.log;
326
69
  this.err = _$.err;
@@ -638,6 +381,22 @@ class Utilities {
638
381
  const val3 = val2 / div;
639
382
  return val3;
640
383
  }
384
+ /**
385
+ * parse float by decimal point 2
386
+ */
387
+ F2 = (x, mode = 'round') => this.FN(x, 2, mode);
388
+ /**
389
+ * parse float by decimal point 3
390
+ */
391
+ F3 = (x, mode = 'round') => this.FN(x, 3, mode);
392
+ /**
393
+ * convert and cut string like `abcd....z`
394
+ */
395
+ S = (_, h, t = 32, delim = '...') => [typeof _ == 'string' ? _ : `${this.json(_) || ''}`]
396
+ .map(s => h && s.length > h + t
397
+ ? s.substring(0, h) + delim + (s.length > h + t ? s.substring(s.length - t) : '')
398
+ : s)
399
+ .join('');
641
400
  /**
642
401
  * remove internal properties which starts with _ or $
643
402
  */
@@ -714,6 +473,7 @@ class Utilities {
714
473
  */
715
474
  isEqual(obj1, obj2) {
716
475
  const keys = Object.keys;
476
+ const toString = Object.prototype.toString;
717
477
  function tagTester(name) {
718
478
  return function (obj) {
719
479
  return toString.call(obj) === '[object ' + name + ']';
@@ -906,7 +666,8 @@ class Utilities {
906
666
  */
907
667
  md5(data, digest) {
908
668
  digest = digest === undefined ? 'hex' : digest;
909
- return crypto_1.default.createHash('md5').update(data).digest(digest);
669
+ const _digest = digest === 'latin1' ? 'binary' : digest;
670
+ return crypto_1.default.createHash('md5').update(data).digest(_digest);
910
671
  }
911
672
  /**
912
673
  * get hmac hash
@@ -915,7 +676,8 @@ class Utilities {
915
676
  KEY = KEY || 'XENI';
916
677
  encoding = encoding || 'base64';
917
678
  algorithm = algorithm || 'sha256';
918
- return crypto_1.default.createHmac(algorithm, KEY).update(data).digest(encoding);
679
+ const _encoding = encoding === 'latin1' ? 'binary' : encoding;
680
+ return crypto_1.default.createHmac(algorithm, KEY).update(data).digest(_encoding);
919
681
  }
920
682
  /**
921
683
  * parse query-string.
@@ -946,6 +708,265 @@ class Utilities {
946
708
  const param = query_string_1.default.stringify(query);
947
709
  return param;
948
710
  }
711
+ /**
712
+ * group as qs
713
+ */
714
+ qs = {
715
+ /**
716
+ * parse qs string
717
+ */
718
+ parse: (q) => this.qs_parse(q),
719
+ /**
720
+ * stringify qs object
721
+ */
722
+ stringify: (q) => this.qs_stringify(q),
723
+ };
724
+ /**
725
+ * get crypto object.
726
+ *
727
+ * @deprecated since nodejs22, use `crypto2` instead.
728
+ */
729
+ crypto = (passwd, algorithm) => {
730
+ algorithm = algorithm || 'aes-256-ctr';
731
+ const MAGIC = 'LM!#';
732
+ /**
733
+ * Simulate OpenSSL's EVP_BytesToKey method
734
+ */
735
+ const evpBytesToKey = (password, keyLen, ivLen) => {
736
+ let data = Buffer.alloc(0);
737
+ let prev = Buffer.alloc(0);
738
+ while (data.length < keyLen + ivLen) {
739
+ const hash = crypto_1.default.createHash('md5');
740
+ hash.update(Buffer.concat([prev, password]));
741
+ prev = hash.digest();
742
+ data = Buffer.concat([data, prev]);
743
+ }
744
+ return {
745
+ key: data.slice(0, keyLen),
746
+ iv: data.slice(keyLen, keyLen + ivLen),
747
+ };
748
+ };
749
+ const getKeyIV = () => {
750
+ const passwordBuf = Buffer.from(passwd, 'binary');
751
+ const keyLen = 32; // for aes-256
752
+ const ivLen = 16; // AES block size
753
+ return evpBytesToKey(passwordBuf, keyLen, ivLen);
754
+ };
755
+ return new (class {
756
+ /** @deprecated since nodejs22 */
757
+ encrypt = (val) => {
758
+ val = val === undefined ? null : val;
759
+ // msg = msg && typeof msg == 'object' ? JSON_TAG+JSON.stringify(msg) : msg;
760
+ //* 어느 데이터 타입이든 저장하기 위해서, object로 만든다음, 암호화 시킨다.
761
+ const msg = JSON.stringify({ alg: algorithm, val: val });
762
+ const buffer = Buffer.from(`${MAGIC}${msg || ''}`, 'utf8');
763
+ const { key, iv } = getKeyIV();
764
+ const cipher = crypto_1.default.createCipheriv(algorithm, key, iv);
765
+ const crypted = Buffer.concat([cipher.update(buffer), cipher.final()]);
766
+ return crypted.toString(1 ? 'base64' : 'utf8');
767
+ };
768
+ /** @deprecated since nodejs22 */
769
+ decrypt = (msg) => {
770
+ const buffer = Buffer.from(`${msg || ''}`, 'base64');
771
+ const { key, iv } = getKeyIV();
772
+ const decipher = crypto_1.default.createDecipheriv(algorithm, key, iv);
773
+ const decrypted = Buffer.concat([decipher.update(buffer), decipher.final()]);
774
+ const dec = decrypted.toString('utf8');
775
+ if (!dec.startsWith(MAGIC))
776
+ throw new Error('400 INVALID PASSWD - invalid magic string!');
777
+ const data = dec.slice(MAGIC.length);
778
+ if (data && !data.startsWith('{') && !data.endsWith('}'))
779
+ throw new Error('400 INVALID PASSWD - invalid json string!');
780
+ const $msg = JSON.parse(data) || {};
781
+ return $msg.val;
782
+ };
783
+ })();
784
+ };
785
+ /**
786
+ * get crypto2 object (w/ Cipheriv).
787
+ * - to avoid `(node:66818) Warning: Use Cipheriv for counter mode of aes-256-ctr`
788
+ *
789
+ * @param passwd password to crypt
790
+ * @param algorithm (default as `aes-256-ctr`)
791
+ * @param ivNumb iv number to populate. (default as 0, or -1 use random)
792
+ * @param magic magic string to verify (default `LM!#`)
793
+ */
794
+ crypto2 = (passwd, algorithm, ivNumb, magic) => {
795
+ algorithm = algorithm || 'aes-256-ctr';
796
+ const MAGIC = magic === undefined ? 'LM!#' : `${magic || ''}`;
797
+ const iv = Buffer.from(Array.prototype.map.call(Buffer.alloc(16), () => {
798
+ return ivNumb === undefined ? 0 : ivNumb === -1 ? Math.floor(Math.random() * 256) : ivNumb;
799
+ }));
800
+ return new (class {
801
+ encrypt = (val) => {
802
+ val = val === undefined ? null : val;
803
+ //* use json string to support all data-type
804
+ const msg = JSON.stringify({ alg: algorithm, val: val });
805
+ const buffer = Buffer.from(`${MAGIC}${msg || ''}`, 'utf8');
806
+ const key = Buffer.concat([Buffer.from(passwd)], Buffer.alloc(32).length);
807
+ const cipher = crypto_1.default.createCipheriv(algorithm, key, iv);
808
+ const crypted = Buffer.concat([cipher.update(buffer), cipher.final()]);
809
+ return crypted.toString('base64');
810
+ };
811
+ decrypt = (msg) => {
812
+ const buffer = Buffer.from(`${msg || ''}`, 'base64');
813
+ const key = Buffer.concat([Buffer.from(passwd)], Buffer.alloc(32).length);
814
+ const decipher = crypto_1.default.createDecipheriv(algorithm, key, iv);
815
+ const dec = Buffer.concat([decipher.update(buffer), decipher.final()]).toString('utf8');
816
+ if (!dec.startsWith(MAGIC))
817
+ throw new Error(`400 INVALID PASSWD - invalid magic string!`);
818
+ const data = dec.substr(MAGIC.length);
819
+ if (data && !data.startsWith('{') && !data.endsWith('}'))
820
+ throw new Error('400 INVALID PASSWD - invalid json string!');
821
+ const $msg = JSON.parse(data) || {};
822
+ return $msg.val;
823
+ };
824
+ })();
825
+ };
826
+ /**
827
+ * get crypto3 object (with nonce + timestamp based IV).
828
+ *
829
+ * format details, see `crypto3` tests.
830
+ * 1. nonce = random hex string with length 13 (like `a1b2c3d4e5f67`)
831
+ * 2. head = `LM!#${VERSION}:${nonce}:${timestamp}` -> base64 encode with constant length 48 (no padding)
832
+ * 3. body = JSON({d: data}) -> encrypted by AES-256-CTR with key = passwd
833
+ * 4. final = [head, body].join('')
834
+ *
835
+ * @param passwd password to crypt
836
+ * @param algorithm (default as `aes-256-ctr`)
837
+ */
838
+ crypto3 = (passwd, algorithm) => {
839
+ algorithm = algorithm || 'aes-256-ctr';
840
+ const MAGIC = 'LM!#';
841
+ const VERSION = 'V003';
842
+ const HEAD_B64_LEN = 48; // 36 bytes -> 48 base64 (no padding)
843
+ const errScope = `crypto3(${algorithm}#${VERSION})`;
844
+ const key = Buffer.concat([Buffer.from(passwd)], Buffer.alloc(32).length);
845
+ const hmac = (data, sig) => this.hmac(data, sig, 'sha256', 'hex');
846
+ const currentMs = () => this.current_time_ms(); // 13 digits timestamp
847
+ const makeNonce = () => this.uuid().replace(/-/g, '').substring(0, 13); // 13 chars (52-bit entropy)
848
+ return new (class {
849
+ encrypt = (val, options) => {
850
+ val = val === undefined ? null : val;
851
+ const nonce = options?.nonce ?? makeNonce();
852
+ const timestamp = String(options?.current ?? currentMs()).padStart(13, '0');
853
+ const iv = Buffer.from(hmac(`${nonce}:${timestamp}`, passwd).substring(0, 32), 'hex'); // AES IV must be 16 bytes.
854
+ const buffer = Buffer.from(JSON.stringify({ d: val }), 'utf8');
855
+ const cipher = crypto_1.default.createCipheriv(algorithm, key, iv);
856
+ const crypted = Buffer.concat([cipher.update(buffer), cipher.final()]);
857
+ const headRaw = `${MAGIC}${VERSION}:${nonce}:${timestamp}`;
858
+ const head = Buffer.from(headRaw).toString('base64');
859
+ const body = crypted.toString('base64');
860
+ return [head, body].join('');
861
+ };
862
+ decrypt = (msg, options) => {
863
+ if (!msg)
864
+ throw new Error(`@msg (string) is required - ${errScope}`);
865
+ if (msg.length < HEAD_B64_LEN)
866
+ throw new Error(`400 INVALID DATA - data too short! @${errScope}`);
867
+ // 1. decode base64 header (48 chars -> 36 bytes)
868
+ const headBase64 = msg.substring(0, HEAD_B64_LEN);
869
+ const head = Buffer.from(headBase64, 'base64').toString('utf8');
870
+ if (head.length !== 36)
871
+ throw new Error(`400 INVALID DATA - invalid header! @${errScope}`);
872
+ // 2. validate magic and version
873
+ if (!head.startsWith(MAGIC))
874
+ throw new Error(`400 INVALID MAGIC - invalid magic! @${errScope}`);
875
+ const version = head.substring(4, 8);
876
+ if (version !== VERSION)
877
+ throw new Error(`400 INVALID VERSION - expected ${VERSION}, got ${version}! @${errScope}`);
878
+ // 3. parse nonce, timestamp (format: LM!#V003:nonce:timestamp)
879
+ const [, nonce, timestamp] = head.substring(8).split(':');
880
+ if (!nonce || nonce.length !== 13)
881
+ throw new Error(`400 INVALID DATA - invalid nonce! @${errScope}`);
882
+ if (!timestamp || !/^\d+$/.test(timestamp))
883
+ throw new Error(`400 INVALID DATA - invalid timestamp! @${errScope}`);
884
+ if (options?.maxAge !== undefined) {
885
+ const current = options?.current ?? currentMs();
886
+ if (current - parseInt(timestamp, 10) > options.maxAge)
887
+ throw new Error(`400 INVALID DATA - expired timestamp! @${errScope}`);
888
+ }
889
+ // 4. decrypt
890
+ const iv = Buffer.from(hmac(`${nonce}:${timestamp}`, passwd).substring(0, 32), 'hex');
891
+ const decipher = crypto_1.default.createDecipheriv(algorithm, key, iv);
892
+ const dec = Buffer.concat([
893
+ decipher.update(Buffer.from(msg.substring(HEAD_B64_LEN), 'base64')),
894
+ decipher.final(),
895
+ ]).toString('utf8');
896
+ if (!dec.startsWith('{') || !dec.endsWith('}'))
897
+ throw new Error(`400 INVALID PASSWD - invalid json string @${errScope}`);
898
+ const $msg = JSON.parse(dec) || {};
899
+ return $msg?.d;
900
+ };
901
+ })();
902
+ };
903
+ /**
904
+ * encrypt shorthand using crypto3
905
+ */
906
+ encrypt = (data, secret, options) => {
907
+ return this.crypto3(secret).encrypt(data, options);
908
+ };
909
+ /**
910
+ * decrypt shorthand using crypto3
911
+ */
912
+ decrypt = (data, secret, options) => {
913
+ return this.crypto3(secret).decrypt(data, options);
914
+ };
915
+ /**
916
+ * builder for `JWTHelper`
917
+ * @param passcode string for verification.
918
+ * @param current_ms (optional) current time in millisecond (required to verify `exp`)
919
+ */
920
+ jwt = (passcode, current_ms) => {
921
+ const $U = this;
922
+ /**
923
+ * main class.
924
+ */
925
+ return new (class JWTHelper {
926
+ constructor() { }
927
+ /**
928
+ * use `jsonwebtoken` directly.
929
+ */
930
+ $ = jsonwebtoken_1.default;
931
+ /**
932
+ * encode object to token string
933
+ * - Synchronous Sign with default (HS256: HMAC SHA256)
934
+ *
935
+ * @param data object
936
+ * @param algorithm algorithm to use
937
+ */
938
+ encode = (data, algorithm = 'HS256') => {
939
+ data = current_ms ? { ...data, iat: Math.floor(current_ms / 1000) } : data;
940
+ const token = jsonwebtoken_1.default.sign(data, passcode, { algorithm });
941
+ return token;
942
+ };
943
+ /**
944
+ * decode token string
945
+ *
946
+ * @param token string
947
+ */
948
+ decode = (token, options) => {
949
+ const N = jsonwebtoken_1.default.decode(token, options);
950
+ return N;
951
+ };
952
+ /**
953
+ * verify token
954
+ * - Synchronous Verify with default (HS256: HMAC SHA256)
955
+ *
956
+ * @param token
957
+ * @param algorithm
958
+ * @throws `jwt expired` if exp has expired!.
959
+ */
960
+ verify = (token, algorithm = 'HS256') => {
961
+ const verified = jsonwebtoken_1.default.verify(token, passcode, { algorithms: [algorithm] });
962
+ const cur = $U.N(current_ms, 0);
963
+ const exp = $U.N(verified?.exp, 0) * 1000;
964
+ if (cur > 0 && exp > 0 && exp < current_ms)
965
+ throw new Error(`jwt expired at ${$U.ts(exp)}`);
966
+ return verified;
967
+ };
968
+ })();
969
+ };
949
970
  /**
950
971
  * get UUID as `uuid.v4()`
951
972
  */