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.
- package/dist/common/test-helper.d.ts +2 -2
- package/dist/common/test-helper.js +24 -26
- package/dist/common/test-helper.js.map +1 -1
- package/dist/controllers/dummy-controller.js +39 -46
- package/dist/controllers/dummy-controller.js.map +1 -1
- package/dist/controllers/general-api-controller.js +95 -100
- package/dist/controllers/general-api-controller.js.map +1 -1
- package/dist/controllers/general-controller.js +81 -82
- package/dist/controllers/general-controller.js.map +1 -1
- package/dist/cores/api/api-service.d.ts +1 -1
- package/dist/cores/api/api-service.js +228 -269
- package/dist/cores/api/api-service.js.map +1 -1
- package/dist/cores/aws/aws-kms-service.d.ts +1 -2
- package/dist/cores/aws/aws-kms-service.js +143 -153
- package/dist/cores/aws/aws-kms-service.js.map +1 -1
- package/dist/cores/aws/aws-s3-service.d.ts +2 -4
- package/dist/cores/aws/aws-s3-service.js +306 -330
- package/dist/cores/aws/aws-s3-service.js.map +1 -1
- package/dist/cores/aws/aws-sns-service.js +147 -153
- package/dist/cores/aws/aws-sns-service.js.map +1 -1
- package/dist/cores/aws/aws-sqs-service.js +149 -170
- package/dist/cores/aws/aws-sqs-service.js.map +1 -1
- package/dist/cores/aws/index.js +10 -20
- package/dist/cores/aws/index.js.map +1 -1
- package/dist/cores/cache/cache-service.d.ts +2 -2
- package/dist/cores/cache/cache-service.js +435 -499
- package/dist/cores/cache/cache-service.js.map +1 -1
- package/dist/cores/config/config-service.d.ts +1 -1
- package/dist/cores/config/config-service.js +56 -63
- package/dist/cores/config/config-service.js.map +1 -1
- package/dist/cores/config/index.js +14 -24
- package/dist/cores/config/index.js.map +1 -1
- package/dist/cores/core-services.d.ts +1 -1
- package/dist/cores/dynamo/dynamo-query-service.js +37 -51
- package/dist/cores/dynamo/dynamo-query-service.js.map +1 -1
- package/dist/cores/dynamo/dynamo-scan-service.d.ts +2 -2
- package/dist/cores/dynamo/dynamo-scan-service.js +29 -40
- package/dist/cores/dynamo/dynamo-scan-service.js.map +1 -1
- package/dist/cores/dynamo/dynamo-service.d.ts +2 -2
- package/dist/cores/dynamo/dynamo-service.js +528 -601
- package/dist/cores/dynamo/dynamo-service.js.map +1 -1
- package/dist/cores/dynamo/tools/expressions.js +17 -7
- package/dist/cores/dynamo/tools/expressions.js.map +1 -1
- package/dist/cores/dynamo/tools/query.js +142 -127
- package/dist/cores/dynamo/tools/query.js.map +1 -1
- package/dist/cores/dynamo/tools/scan.js +111 -97
- package/dist/cores/dynamo/tools/scan.js.map +1 -1
- package/dist/cores/dynamo/tools/serializer.js +17 -7
- package/dist/cores/dynamo/tools/serializer.js.map +1 -1
- package/dist/cores/dynamo/tools/utils.d.ts +0 -2
- package/dist/cores/dynamo/tools/utils.js.map +1 -1
- package/dist/cores/elastic/elastic6-query-service.js +307 -324
- package/dist/cores/elastic/elastic6-query-service.js.map +1 -1
- package/dist/cores/elastic/elastic6-service.d.ts +3 -3
- package/dist/cores/elastic/elastic6-service.js +568 -647
- package/dist/cores/elastic/elastic6-service.js.map +1 -1
- package/dist/cores/elastic/hangul-service.js +52 -54
- package/dist/cores/elastic/hangul-service.js.map +1 -1
- package/dist/cores/lambda/index.js +42 -36
- package/dist/cores/lambda/index.js.map +1 -1
- package/dist/cores/lambda/lambda-alb-handler.d.ts +2 -2
- package/dist/cores/lambda/lambda-alb-handler.js +59 -72
- package/dist/cores/lambda/lambda-alb-handler.js.map +1 -1
- package/dist/cores/lambda/lambda-cognito-handler.js +10 -19
- package/dist/cores/lambda/lambda-cognito-handler.js.map +1 -1
- package/dist/cores/lambda/lambda-cron-handler.d.ts +1 -1
- package/dist/cores/lambda/lambda-cron-handler.js +14 -23
- package/dist/cores/lambda/lambda-cron-handler.js.map +1 -1
- package/dist/cores/lambda/lambda-dynamo-stream-handler.d.ts +2 -2
- package/dist/cores/lambda/lambda-dynamo-stream-handler.js +57 -67
- package/dist/cores/lambda/lambda-dynamo-stream-handler.js.map +1 -1
- package/dist/cores/lambda/lambda-handler.d.ts +22 -22
- package/dist/cores/lambda/lambda-handler.js +93 -106
- package/dist/cores/lambda/lambda-handler.js.map +1 -1
- package/dist/cores/lambda/lambda-notification-handler.d.ts +1 -1
- package/dist/cores/lambda/lambda-notification-handler.js +39 -50
- package/dist/cores/lambda/lambda-notification-handler.js.map +1 -1
- package/dist/cores/lambda/lambda-sns-handler.js +79 -88
- package/dist/cores/lambda/lambda-sns-handler.js.map +1 -1
- package/dist/cores/lambda/lambda-sqs-handler.js +79 -88
- package/dist/cores/lambda/lambda-sqs-handler.js.map +1 -1
- package/dist/cores/lambda/lambda-web-handler.d.ts +21 -43
- package/dist/cores/lambda/lambda-web-handler.js +392 -482
- package/dist/cores/lambda/lambda-web-handler.js.map +1 -1
- package/dist/cores/lambda/lambda-wss-handler.js +23 -32
- package/dist/cores/lambda/lambda-wss-handler.js.map +1 -1
- package/dist/cores/protocol/index.js +10 -20
- package/dist/cores/protocol/index.js.map +1 -1
- package/dist/cores/protocol/protocol-service.d.ts +3 -3
- package/dist/cores/protocol/protocol-service.js +235 -227
- package/dist/cores/protocol/protocol-service.js.map +1 -1
- package/dist/cores/storage/http-storage-service.js +65 -85
- package/dist/cores/storage/http-storage-service.js.map +1 -1
- package/dist/cores/storage/model-manager.js +66 -85
- package/dist/cores/storage/model-manager.js.map +1 -1
- package/dist/cores/storage/proxy-storage-service.d.ts +2 -2
- package/dist/cores/storage/proxy-storage-service.js +562 -599
- package/dist/cores/storage/proxy-storage-service.js.map +1 -1
- package/dist/cores/storage/redis-storage-service.js +163 -177
- package/dist/cores/storage/redis-storage-service.js.map +1 -1
- package/dist/cores/storage/storage-service.js +281 -322
- package/dist/cores/storage/storage-service.js.map +1 -1
- package/dist/engine/builder.d.ts +1 -1
- package/dist/engine/builder.js +59 -63
- package/dist/engine/builder.js.map +1 -1
- package/dist/engine/engine.d.ts +4 -4
- package/dist/engine/engine.js +9 -18
- package/dist/engine/engine.js.map +1 -1
- package/dist/engine/types.d.ts +1 -1
- package/dist/engine/utilities.d.ts +14 -10
- package/dist/engine/utilities.js +301 -280
- package/dist/engine/utilities.js.map +1 -1
- package/dist/environ.js +4 -6
- package/dist/environ.js.map +1 -1
- package/dist/extended/abstract-service.js +595 -645
- package/dist/extended/abstract-service.js.map +1 -1
- package/dist/extended/libs/sig-v4.js.map +1 -1
- package/dist/generated/field-registry.d.ts +10 -0
- package/dist/generated/field-registry.js +17 -0
- package/dist/generated/field-registry.js.map +1 -0
- package/dist/helpers/helpers.d.ts +17 -9
- package/dist/helpers/helpers.js +88 -78
- package/dist/helpers/helpers.js.map +1 -1
- package/dist/index.js +17 -7
- package/dist/index.js.map +1 -1
- package/dist/lib/dynamodb-value.js +2 -3
- package/dist/lib/dynamodb-value.js.map +1 -1
- package/dist/tools/express.js +4 -5
- package/dist/tools/express.js.map +1 -1
- package/dist/tools/tools.d.ts +3 -1
- package/dist/tools/tools.js +14 -21
- package/dist/tools/tools.js.map +1 -1
- package/package.json +19 -18
- package/dist/exec-cli.d.ts +0 -2
- package/dist/exec-cli.js +0 -211
- package/dist/exec-cli.js.map +0 -1
- package/dist/lib/dynamo/expressions.d.ts +0 -14
- package/dist/lib/dynamo/expressions.js +0 -212
- package/dist/lib/dynamo/expressions.js.map +0 -1
- package/dist/lib/dynamo/query.d.ts +0 -43
- package/dist/lib/dynamo/query.js +0 -246
- package/dist/lib/dynamo/query.js.map +0 -1
- package/dist/lib/dynamo/scan.d.ts +0 -33
- package/dist/lib/dynamo/scan.js +0 -172
- package/dist/lib/dynamo/scan.js.map +0 -1
- package/dist/lib/dynamo/serializer.d.ts +0 -12
- package/dist/lib/dynamo/serializer.js +0 -243
- package/dist/lib/dynamo/serializer.js.map +0 -1
- package/dist/lib/dynamo/utils.d.ts +0 -15
- package/dist/lib/dynamo/utils.js +0 -129
- package/dist/lib/dynamo/utils.js.map +0 -1
- package/dist/tools/shared.d.ts +0 -37
- package/dist/tools/shared.js +0 -130
- package/dist/tools/shared.js.map +0 -1
package/dist/engine/utilities.js
CHANGED
|
@@ -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 (
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
*/
|