lemon-core 4.1.15 → 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 +6 -6
- package/dist/cores/lambda/lambda-web-handler.js +387 -412
- 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 +5 -5
- package/dist/engine/utilities.js +301 -293
- 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 -28
- package/dist/tools/shared.js +0 -143
- package/dist/tools/shared.js.map +0 -1
|
@@ -1,13 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
2
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
4
|
};
|
|
@@ -65,9 +56,9 @@ const $kmsPool = {};
|
|
|
65
56
|
* @returns http response body
|
|
66
57
|
*/
|
|
67
58
|
const buildResponse = (statusCode, body, options) => {
|
|
68
|
-
const contentType = options
|
|
69
|
-
const origin =
|
|
70
|
-
const credentials =
|
|
59
|
+
const contentType = options?.contentType;
|
|
60
|
+
const origin = options?.origin === undefined ? '*' : options?.origin;
|
|
61
|
+
const credentials = options?.credentials === undefined ? true : options?.credentials;
|
|
71
62
|
const isBase64Encoded = contentType && !contentType.startsWith('text/') ? true : false;
|
|
72
63
|
const _isXml = (body) => body.startsWith('<?xml ') && body.trim().endsWith('>');
|
|
73
64
|
const _isHtml = (body) => body.startsWith('<!DOCTYPE html>') || (body.startsWith('<') && body.endsWith('>'));
|
|
@@ -122,28 +113,28 @@ exports.redirect = redirect;
|
|
|
122
113
|
* @param event event
|
|
123
114
|
* @param $ctx context
|
|
124
115
|
*/
|
|
125
|
-
const promised = (event, $ctx) =>
|
|
116
|
+
const promised = async (event, $ctx) => {
|
|
126
117
|
// TO SERVE BINARY. `$ npm i -S serverless-apigw-binary serverless-apigwy-binary`. refer 'https://read.acloud.guru/serverless-image-optimization-and-delivery-510b6c311fe5'
|
|
127
118
|
if (event && event.httpMethod == 'GET' && event.path == '/favicon.ico') {
|
|
128
119
|
return () => (0, exports.success)(FAVICON_ICO, 'image/x-icon');
|
|
129
120
|
}
|
|
130
121
|
//* transform to protocol-context.
|
|
131
122
|
const param = protocol_1.default.service.asTransformer('web').transformToParam(event, $ctx);
|
|
132
|
-
(0, engine_1._log)(NS, '! protocol-param =', engine_1.$U.json(
|
|
123
|
+
(0, engine_1._log)(NS, '! protocol-param =', engine_1.$U.json({ ...param, body: undefined })); // hide `.body` in log.
|
|
133
124
|
//* returns object..
|
|
134
125
|
return { event, param, $ctx };
|
|
135
|
-
}
|
|
126
|
+
};
|
|
136
127
|
exports.promised = promised;
|
|
137
128
|
/**
|
|
138
129
|
* builder for default handler
|
|
139
130
|
*/
|
|
140
|
-
const mxNextHandler = (thiz) => (params) =>
|
|
131
|
+
const mxNextHandler = (thiz) => async (params) => {
|
|
141
132
|
//* determine if param or func.
|
|
142
133
|
const fx = typeof params == 'function' ? params : null;
|
|
143
134
|
const $param = params && typeof params == 'object' ? params : null;
|
|
144
135
|
const { param, event } = $param || {};
|
|
145
136
|
//* call the main handler()
|
|
146
|
-
const R = $param ?
|
|
137
|
+
const R = $param ? await thiz.handleProtocol(param, event) : fx;
|
|
147
138
|
//* - if like to override the full response, then return function.
|
|
148
139
|
if (R && typeof R == 'function')
|
|
149
140
|
return R();
|
|
@@ -155,7 +146,7 @@ const mxNextHandler = (thiz) => (params) => __awaiter(void 0, void 0, void 0, fu
|
|
|
155
146
|
}
|
|
156
147
|
//* returns response..
|
|
157
148
|
return (0, exports.success)(R);
|
|
158
|
-
}
|
|
149
|
+
};
|
|
159
150
|
exports.mxNextHandler = mxNextHandler;
|
|
160
151
|
/**
|
|
161
152
|
* builder for failure promised.
|
|
@@ -215,32 +206,15 @@ exports.mxNextFailure = mxNextFailure;
|
|
|
215
206
|
* - default WEB Handler w/ event-listeners.
|
|
216
207
|
*/
|
|
217
208
|
class LambdaWEBHandler extends lambda_handler_1.LambdaSubHandler {
|
|
209
|
+
//* shared config.
|
|
210
|
+
static REPORT_ERROR = lambda_handler_1.LambdaHandler.REPORT_ERROR;
|
|
211
|
+
//* handlers map.
|
|
212
|
+
_handlers = {};
|
|
218
213
|
/**
|
|
219
214
|
* default constructor w/ registering self.
|
|
220
215
|
*/
|
|
221
216
|
constructor(lambda, register) {
|
|
222
217
|
super(lambda, register ? 'web' : undefined);
|
|
223
|
-
//* handlers map.
|
|
224
|
-
this._handlers = {};
|
|
225
|
-
/**
|
|
226
|
-
* Default WEB Handler.
|
|
227
|
-
*/
|
|
228
|
-
this.handle = (event, $ctx) => __awaiter(this, void 0, void 0, function* () {
|
|
229
|
-
//* inspect API parameters.
|
|
230
|
-
(0, engine_1._log)(NS, `handle()....`);
|
|
231
|
-
const $path = event.pathParameters || {};
|
|
232
|
-
const $param = event.queryStringParameters || {};
|
|
233
|
-
(0, engine_1._log)(NS, '! path =', event.path);
|
|
234
|
-
(0, engine_1._log)(NS, '! $path =', engine_1.$U.json($path));
|
|
235
|
-
(0, engine_1._log)(NS, '! $param =', engine_1.$U.json($param));
|
|
236
|
-
//* start promised..
|
|
237
|
-
return (0, exports.promised)(event, $ctx).then((0, exports.mxNextHandler)(this)).catch((0, exports.mxNextFailure)(event, $ctx));
|
|
238
|
-
});
|
|
239
|
-
/**
|
|
240
|
-
* builder of tools for http-headers
|
|
241
|
-
* - extracting header content, and parse.
|
|
242
|
-
*/
|
|
243
|
-
this.tools = (headers) => new MyHttpHeaderTool(headers);
|
|
244
218
|
// _log(NS, `LambdaWEBHandler()..`);
|
|
245
219
|
}
|
|
246
220
|
/**
|
|
@@ -285,196 +259,202 @@ class LambdaWEBHandler extends lambda_handler_1.LambdaSubHandler {
|
|
|
285
259
|
return M;
|
|
286
260
|
}, {});
|
|
287
261
|
}
|
|
262
|
+
/**
|
|
263
|
+
* Default WEB Handler.
|
|
264
|
+
*/
|
|
265
|
+
handle = async (event, $ctx) => {
|
|
266
|
+
//* inspect API parameters.
|
|
267
|
+
(0, engine_1._log)(NS, `handle()....`);
|
|
268
|
+
const $path = event.pathParameters || {};
|
|
269
|
+
const $param = event.queryStringParameters || {};
|
|
270
|
+
(0, engine_1._log)(NS, '! path =', event.path);
|
|
271
|
+
(0, engine_1._log)(NS, '! $path =', engine_1.$U.json($path));
|
|
272
|
+
(0, engine_1._log)(NS, '! $param =', engine_1.$U.json($param));
|
|
273
|
+
//* start promised..
|
|
274
|
+
return (0, exports.promised)(event, $ctx).then((0, exports.mxNextHandler)(this)).catch((0, exports.mxNextFailure)(event, $ctx));
|
|
275
|
+
};
|
|
288
276
|
/**
|
|
289
277
|
* handle param via protocol-service.
|
|
290
278
|
*
|
|
291
279
|
* @param param protocol parameters
|
|
292
280
|
* @param event (optional) origin event object.
|
|
293
281
|
*/
|
|
294
|
-
handleProtocol(param, event) {
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
282
|
+
async handleProtocol(param, event) {
|
|
283
|
+
if (!param)
|
|
284
|
+
throw new Error(`@param (protocol-param) is required!`);
|
|
285
|
+
//TODO [Steve] id, cmd can (or should) be null or empty! (support for `/{cmd+}` pattern) @251212
|
|
286
|
+
const TYPE = `${param.type || ''}`;
|
|
287
|
+
const MODE = `${param.mode || 'GET'}`;
|
|
288
|
+
const ID = `${param.id || ''}`;
|
|
289
|
+
const CMD = `${param.cmd || ''}`;
|
|
290
|
+
const PATH = `${(event && event.path) || ''}`;
|
|
291
|
+
const $param = param.param;
|
|
292
|
+
const $body = param.body;
|
|
293
|
+
const context = param.context;
|
|
294
|
+
//* debug print body.
|
|
295
|
+
if (!$body) {
|
|
296
|
+
(0, engine_1._log)(NS, `#${MODE}:${CMD} (${TYPE}/${ID})....`);
|
|
297
|
+
}
|
|
298
|
+
else {
|
|
299
|
+
(0, engine_1._log)(NS, `#${MODE}:${CMD} (${TYPE}/${ID}).... body.len=`, $body ? engine_1.$U.json($body).length : -1);
|
|
300
|
+
}
|
|
301
|
+
//* find target next function
|
|
302
|
+
// const decoder: NextDecoder | CoreWEBController = this._handlers[TYPE];
|
|
303
|
+
const next = ((decoder) => {
|
|
304
|
+
//* as default handler '/', say the current version.
|
|
305
|
+
if (MODE === 'LIST' && TYPE === '' && ID === '' && CMD === '') {
|
|
306
|
+
return async () => {
|
|
307
|
+
const $pack = (0, tools_1.loadJsonSync)('package.json');
|
|
308
|
+
const name = ($pack && $pack.name) || 'LEMON API';
|
|
309
|
+
const version = ($pack && $pack.version) || '0.0.0';
|
|
310
|
+
const modules = [`${name}/${version}`];
|
|
311
|
+
//* shows version of `lemon-core` via `dependencies`.
|
|
312
|
+
const coreVer = $pack && $pack.dependencies && $pack.dependencies['lemon-core'];
|
|
313
|
+
if (coreVer)
|
|
314
|
+
modules.push(`lemon-core/${coreVer.startsWith('^') ? coreVer.substring(1) : coreVer}`);
|
|
315
|
+
return modules.join('\n');
|
|
316
|
+
};
|
|
313
317
|
}
|
|
314
|
-
//*
|
|
315
|
-
|
|
316
|
-
const next = ((decoder) => {
|
|
317
|
-
//* as default handler '/', say the current version.
|
|
318
|
-
if (MODE === 'LIST' && TYPE === '' && ID === '' && CMD === '') {
|
|
319
|
-
return () => __awaiter(this, void 0, void 0, function* () {
|
|
320
|
-
const $pack = (0, tools_1.loadJsonSync)('package.json');
|
|
321
|
-
const name = ($pack && $pack.name) || 'LEMON API';
|
|
322
|
-
const version = ($pack && $pack.version) || '0.0.0';
|
|
323
|
-
const modules = [`${name}/${version}`];
|
|
324
|
-
//* shows version of `lemon-core` via `dependencies`.
|
|
325
|
-
const coreVer = $pack && $pack.dependencies && $pack.dependencies['lemon-core'];
|
|
326
|
-
if (coreVer)
|
|
327
|
-
modules.push(`lemon-core/${coreVer.startsWith('^') ? coreVer.substring(1) : coreVer}`);
|
|
328
|
-
return modules.join('\n');
|
|
329
|
-
});
|
|
330
|
-
}
|
|
331
|
-
//* error if no decoder.
|
|
332
|
-
if (!decoder)
|
|
333
|
-
return null;
|
|
334
|
-
//* use decoder() to find target.
|
|
335
|
-
if (typeof decoder == 'function')
|
|
336
|
-
return decoder(MODE, ID, CMD, PATH);
|
|
337
|
-
else if (typeof decoder == 'object') {
|
|
338
|
-
const func = decoder.decode(MODE, ID, CMD, PATH);
|
|
339
|
-
if (!func)
|
|
340
|
-
return null; // avoid 'null' error.
|
|
341
|
-
const next = (i, p, b, c) => func.call(decoder, i, p, b, c);
|
|
342
|
-
return next;
|
|
343
|
-
}
|
|
318
|
+
//* error if no decoder.
|
|
319
|
+
if (!decoder)
|
|
344
320
|
return null;
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
321
|
+
//* use decoder() to find target.
|
|
322
|
+
if (typeof decoder == 'function')
|
|
323
|
+
return decoder(MODE, ID, CMD, PATH);
|
|
324
|
+
else if (typeof decoder == 'object') {
|
|
325
|
+
const func = decoder.decode(MODE, ID, CMD, PATH);
|
|
326
|
+
if (!func)
|
|
327
|
+
return null; // avoid 'null' error.
|
|
328
|
+
const next = (i, p, b, c) => func.call(decoder, i, p, b, c);
|
|
329
|
+
return next;
|
|
350
330
|
}
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
331
|
+
return null;
|
|
332
|
+
})(this._handlers[TYPE]);
|
|
333
|
+
//* if no next, then report error.
|
|
334
|
+
if (!next || typeof next != 'function') {
|
|
335
|
+
(0, engine_1._err)(NS, `! WARN ! MISSING NEXT-HANDLER. event=`, engine_1.$U.json(event));
|
|
336
|
+
throw new Error(`404 NOT FOUND - ${MODE} /${TYPE}/${ID}${CMD ? `/${CMD}` : ''}`);
|
|
337
|
+
}
|
|
338
|
+
//* call next.. (it will return result or promised)
|
|
339
|
+
return (() => {
|
|
340
|
+
try {
|
|
341
|
+
const R = next(ID, $param, $body, context);
|
|
342
|
+
return R instanceof Promise ? R : Promise.resolve(R);
|
|
343
|
+
}
|
|
344
|
+
catch (e) {
|
|
345
|
+
return Promise.reject(e);
|
|
346
|
+
}
|
|
347
|
+
})();
|
|
362
348
|
}
|
|
349
|
+
/**
|
|
350
|
+
* builder of tools for http-headers
|
|
351
|
+
* - extracting header content, and parse.
|
|
352
|
+
*/
|
|
353
|
+
tools = (headers) => new MyHttpHeaderTool(headers);
|
|
363
354
|
/**
|
|
364
355
|
* pack the request context for Http request.
|
|
365
356
|
*
|
|
366
357
|
* @param event origin Event.
|
|
367
358
|
* @param orgContext (optional) original lambda.Context
|
|
368
359
|
*/
|
|
369
|
-
packContext(event, orgContext) {
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
if
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
const
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
return $ctx;
|
|
402
|
-
});
|
|
360
|
+
async packContext(event, orgContext) {
|
|
361
|
+
(0, engine_1._log)(NS, `packContext(${event ? '' : 'null'})..`);
|
|
362
|
+
if (!event)
|
|
363
|
+
return null;
|
|
364
|
+
//* prepare chain object.
|
|
365
|
+
const reqContext = event?.requestContext;
|
|
366
|
+
orgContext && (0, engine_1._log)(NS, `> orgContext =`, engine_1.$U.S(orgContext, 256, 32));
|
|
367
|
+
reqContext && (0, engine_1._log)(NS, `> reqContext =`, engine_1.$U.S(reqContext, 256, 32));
|
|
368
|
+
// STEP.1 support lambda call JWT Token authentication.
|
|
369
|
+
const headers = event.headers;
|
|
370
|
+
if (headers && headers[protocol_service_1.HEADER_PROTOCOL_CONTEXT]) {
|
|
371
|
+
//* if it is protocol request via lambda, then returns valid context.
|
|
372
|
+
const $param = protocol_1.default.service.asTransformer('web').transformToParam(event);
|
|
373
|
+
return $param?.context;
|
|
374
|
+
}
|
|
375
|
+
// STEP.2 use internal identity json data via python lambda call.
|
|
376
|
+
const $tool = this.tools(headers);
|
|
377
|
+
const identity = await $tool.parseIdentityHeader();
|
|
378
|
+
const _prepare = () => {
|
|
379
|
+
const cookie = $tool.parseCookiesHeader();
|
|
380
|
+
const domain = $tool.getHeader('host');
|
|
381
|
+
const referer = $tool.getHeader('referer');
|
|
382
|
+
const origin = $tool.getHeader('origin');
|
|
383
|
+
const userAgent = $tool.getHeader('user-agent');
|
|
384
|
+
const authorization = $tool.getHeader('authorization');
|
|
385
|
+
return { identity, cookie, domain, referer, origin, userAgent, authorization };
|
|
386
|
+
};
|
|
387
|
+
// STEP.3. prepare the final `next-context`.
|
|
388
|
+
const $ctx = await $tool.prepareContext(_prepare(), reqContext);
|
|
389
|
+
$ctx.source = protocol_1.default.service.myProtocolURI($ctx); // self service-uri as source
|
|
390
|
+
// FINIAL. returns
|
|
391
|
+
return $ctx;
|
|
403
392
|
}
|
|
404
393
|
}
|
|
405
394
|
exports.LambdaWEBHandler = LambdaWEBHandler;
|
|
406
|
-
//* shared config.
|
|
407
|
-
LambdaWEBHandler.REPORT_ERROR = lambda_handler_1.LambdaHandler.REPORT_ERROR;
|
|
408
395
|
/**
|
|
409
396
|
* class: `MyHttpHeaderTool`
|
|
410
397
|
* - basic implementation of HttpHeaderTool
|
|
411
398
|
*/
|
|
412
399
|
class MyHttpHeaderTool {
|
|
400
|
+
headers;
|
|
401
|
+
static _accountId;
|
|
402
|
+
static _accountIdPromise;
|
|
413
403
|
/**
|
|
414
404
|
* default constructor.
|
|
415
405
|
* @param headers
|
|
416
406
|
*/
|
|
417
407
|
constructor(headers, options) {
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
this.onlyDefined = test_helper_1.onlyDefined;
|
|
421
|
-
/**
|
|
422
|
-
* build default JWT secret from AWS account id + magic key.
|
|
423
|
-
*/
|
|
424
|
-
this.buildJwtSecret = () => __awaiter(this, void 0, void 0, function* () {
|
|
425
|
-
const accountId = yield this.getAccountId();
|
|
426
|
-
const secret = JWT_MAGIC_KEY; // 유출되면 피곤함.
|
|
427
|
-
const _hmac = (msg, key = secret) => engine_1.$U.hmac(msg, key, 'sha256', 'base64'); // 기본 로직
|
|
428
|
-
return _hmac(_hmac(accountId, _hmac(JWT_SIGN_KEY)), JWT_SIGN_KEY);
|
|
429
|
-
});
|
|
430
|
-
/**
|
|
431
|
-
* get current aws account-id via STS. (once)
|
|
432
|
-
*/
|
|
433
|
-
this.getAccountId = () => __awaiter(this, void 0, void 0, function* () {
|
|
434
|
-
if (MyHttpHeaderTool._accountId)
|
|
435
|
-
return MyHttpHeaderTool._accountId;
|
|
436
|
-
if (!MyHttpHeaderTool._accountIdPromise) {
|
|
437
|
-
MyHttpHeaderTool._accountIdPromise = (() => __awaiter(this, void 0, void 0, function* () {
|
|
438
|
-
// 1. getHelloArn()에서 ARN을 통해 accountId 추출 시도
|
|
439
|
-
try {
|
|
440
|
-
const arn = (0, engine_1.getHelloArn)(null, NS);
|
|
441
|
-
if (arn && arn.startsWith('arn:aws:')) {
|
|
442
|
-
const accountId = arn.split(':')[4];
|
|
443
|
-
if (accountId)
|
|
444
|
-
return accountId;
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
catch (e) {
|
|
448
|
-
(0, engine_1._log)(NS, '! getHelloArn failed, fallback to STS');
|
|
449
|
-
}
|
|
450
|
-
// 2. fallback: STS 호출 (awsConfig 사용)
|
|
451
|
-
const cfg = (0, tools_1.awsConfig)(engine_1.$engine);
|
|
452
|
-
const sts = new client_sts_1.STSClient(cfg);
|
|
453
|
-
const data = yield sts.send(new client_sts_1.GetCallerIdentityCommand({}));
|
|
454
|
-
return (data === null || data === void 0 ? void 0 : data.Account) || '000000000000';
|
|
455
|
-
}))().catch(err => {
|
|
456
|
-
(0, engine_1._err)(NS, '! err@jwt.accountId =', err);
|
|
457
|
-
return '000000000000';
|
|
458
|
-
});
|
|
459
|
-
}
|
|
460
|
-
MyHttpHeaderTool._accountId = yield MyHttpHeaderTool._accountIdPromise;
|
|
461
|
-
return MyHttpHeaderTool._accountId;
|
|
462
|
-
});
|
|
463
|
-
/**
|
|
464
|
-
* check if this request is from externals (like API-GW)
|
|
465
|
-
* @returns true if in external
|
|
466
|
-
*/
|
|
467
|
-
this.isExternal = () => {
|
|
468
|
-
const host = this.getHeader('host');
|
|
469
|
-
const isExternal = host ? true : false;
|
|
470
|
-
return !!isExternal;
|
|
471
|
-
};
|
|
472
|
-
const isClone = (_a = options === null || options === void 0 ? void 0 : options.isClone) !== null && _a !== void 0 ? _a : true;
|
|
473
|
-
this.headers = isClone ? Object.assign({}, headers) : headers;
|
|
408
|
+
const isClone = options?.isClone ?? true;
|
|
409
|
+
this.headers = isClone ? { ...headers } : headers;
|
|
474
410
|
}
|
|
475
411
|
hello() {
|
|
476
412
|
return 'header-tool-by-default';
|
|
477
413
|
}
|
|
414
|
+
/** expose `onlyDefined` */
|
|
415
|
+
onlyDefined = test_helper_1.onlyDefined;
|
|
416
|
+
/**
|
|
417
|
+
* build default JWT secret from AWS account id + magic key.
|
|
418
|
+
*/
|
|
419
|
+
buildJwtSecret = async () => {
|
|
420
|
+
const accountId = await this.getAccountId();
|
|
421
|
+
const secret = JWT_MAGIC_KEY; // 유출되면 피곤함.
|
|
422
|
+
const _hmac = (msg, key = secret) => engine_1.$U.hmac(msg, key, 'sha256', 'base64'); // 기본 로직
|
|
423
|
+
return _hmac(_hmac(accountId, _hmac(JWT_SIGN_KEY)), JWT_SIGN_KEY);
|
|
424
|
+
};
|
|
425
|
+
/**
|
|
426
|
+
* get current aws account-id via STS. (once)
|
|
427
|
+
*/
|
|
428
|
+
getAccountId = async () => {
|
|
429
|
+
if (MyHttpHeaderTool._accountId)
|
|
430
|
+
return MyHttpHeaderTool._accountId;
|
|
431
|
+
if (!MyHttpHeaderTool._accountIdPromise) {
|
|
432
|
+
MyHttpHeaderTool._accountIdPromise = (async () => {
|
|
433
|
+
// 1. getHelloArn()에서 ARN을 통해 accountId 추출 시도
|
|
434
|
+
try {
|
|
435
|
+
const arn = (0, engine_1.getHelloArn)(null, NS);
|
|
436
|
+
if (arn && arn.startsWith('arn:aws:')) {
|
|
437
|
+
const accountId = arn.split(':')[4];
|
|
438
|
+
if (accountId)
|
|
439
|
+
return accountId;
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
catch (e) {
|
|
443
|
+
(0, engine_1._log)(NS, '! getHelloArn failed, fallback to STS');
|
|
444
|
+
}
|
|
445
|
+
// 2. fallback: STS 호출 (awsConfig 사용)
|
|
446
|
+
const cfg = (0, tools_1.awsConfig)(engine_1.$engine);
|
|
447
|
+
const sts = new client_sts_1.STSClient(cfg);
|
|
448
|
+
const data = await sts.send(new client_sts_1.GetCallerIdentityCommand({}));
|
|
449
|
+
return data?.Account || '000000000000';
|
|
450
|
+
})().catch(err => {
|
|
451
|
+
(0, engine_1._err)(NS, '! err@jwt.accountId =', err);
|
|
452
|
+
return '000000000000';
|
|
453
|
+
});
|
|
454
|
+
}
|
|
455
|
+
MyHttpHeaderTool._accountId = await MyHttpHeaderTool._accountIdPromise;
|
|
456
|
+
return MyHttpHeaderTool._accountId;
|
|
457
|
+
};
|
|
478
458
|
/**
|
|
479
459
|
* get values by name
|
|
480
460
|
* @param name case-insentive name of field
|
|
@@ -509,6 +489,15 @@ class MyHttpHeaderTool {
|
|
|
509
489
|
const vals = this.getHeaders(name);
|
|
510
490
|
return vals.length < 1 ? undefined : vals[vals.length - 1];
|
|
511
491
|
}
|
|
492
|
+
/**
|
|
493
|
+
* check if this request is from externals (like API-GW)
|
|
494
|
+
* @returns true if in external
|
|
495
|
+
*/
|
|
496
|
+
isExternal = () => {
|
|
497
|
+
const host = this.getHeader('host');
|
|
498
|
+
const isExternal = host ? true : false;
|
|
499
|
+
return !!isExternal;
|
|
500
|
+
};
|
|
512
501
|
/**
|
|
513
502
|
* parse of header[`x-lemon-identity`] to get the instance of `NextIdentity`
|
|
514
503
|
* - lambda 호출의 2가지 방법이 있음 (interval vs external)
|
|
@@ -523,48 +512,43 @@ class MyHttpHeaderTool {
|
|
|
523
512
|
* - support ONLY JWT Token authentication (verification).
|
|
524
513
|
* - iat
|
|
525
514
|
*/
|
|
526
|
-
parseIdentityHeader(name = HEADER_LEMON_IDENTITY) {
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
if (!val) {
|
|
535
|
-
//NOP
|
|
536
|
-
}
|
|
537
|
-
else if (isInternal && val.startsWith('{') && val.endsWith('}')) {
|
|
538
|
-
result = yield this.parseIdentityJson(val);
|
|
539
|
-
}
|
|
540
|
-
else if (typeof val === 'string' && val.split('.').length === 3) {
|
|
541
|
-
result = yield this.parseIdentityJWT(val);
|
|
542
|
-
}
|
|
515
|
+
async parseIdentityHeader(name = HEADER_LEMON_IDENTITY) {
|
|
516
|
+
//* internal means `request from internal services`
|
|
517
|
+
const isInternal = !this.isExternal();
|
|
518
|
+
const val = this.getHeader(name);
|
|
519
|
+
let result = val ? { meta: val } : {};
|
|
520
|
+
try {
|
|
521
|
+
if (!val) {
|
|
522
|
+
//NOP
|
|
543
523
|
}
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
(0, engine_1._err)(NS, '!WARN! identity =', val);
|
|
547
|
-
result.error = (0, test_helper_1.GETERR)(e);
|
|
524
|
+
else if (isInternal && val.startsWith('{') && val.endsWith('}')) {
|
|
525
|
+
result = await this.parseIdentityJson(val);
|
|
548
526
|
}
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
}
|
|
527
|
+
else if (typeof val === 'string' && val.split('.').length === 3) {
|
|
528
|
+
result = await this.parseIdentityJWT(val);
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
catch (e) {
|
|
532
|
+
(0, engine_1._err)(NS, '!WARN! parse.err =', e);
|
|
533
|
+
(0, engine_1._err)(NS, '!WARN! identity =', val);
|
|
534
|
+
result.error = (0, test_helper_1.GETERR)(e);
|
|
535
|
+
}
|
|
536
|
+
//* overwrite finally language selection.
|
|
537
|
+
const lang = this.parseLanguageHeader() ?? result?.lang;
|
|
538
|
+
return { ...result, lang };
|
|
553
539
|
}
|
|
554
540
|
/**
|
|
555
541
|
* parse as identity from json encoded text.
|
|
556
542
|
*/
|
|
557
|
-
parseIdentityJson(val) {
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
return data;
|
|
567
|
-
});
|
|
543
|
+
async parseIdentityJson(val) {
|
|
544
|
+
if (typeof val !== 'string')
|
|
545
|
+
throw new Error(`@val[${val}] is invalid - not string!`);
|
|
546
|
+
//* (ONLY for internal) parse payload as `json`
|
|
547
|
+
const data = JSON.parse(val);
|
|
548
|
+
// if (typeof data?.ns !== 'string') throw new Error(`.ns[${data?.ns}] is required - IdentityHeader`);
|
|
549
|
+
if (typeof data?.sid !== 'string' || !data?.sid)
|
|
550
|
+
throw new Error(`.sid[${data?.sid}] is required - IdentityHeader`);
|
|
551
|
+
return data;
|
|
568
552
|
}
|
|
569
553
|
/**
|
|
570
554
|
* find(or make) the proper KMSService per key
|
|
@@ -581,86 +565,85 @@ class MyHttpHeaderTool {
|
|
|
581
565
|
/**
|
|
582
566
|
* encode as JWT string.
|
|
583
567
|
*/
|
|
584
|
-
encodeIdentityJWT(identity, params) {
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
568
|
+
async encodeIdentityJWT(identity, params) {
|
|
569
|
+
// STEP.0 validate paramters.
|
|
570
|
+
if (!identity || typeof identity !== 'object')
|
|
571
|
+
throw new Error(`@identity (object) is required - but ${typeof identity}`);
|
|
572
|
+
// STEP.1 prepare payload data
|
|
573
|
+
const current = params?.current ?? engine_1.$U.current_time_ms();
|
|
574
|
+
const alias = params?.alias;
|
|
575
|
+
const useHs256 = params?.useHs256 ?? false;
|
|
576
|
+
const service = config_1.default?.config?.getService?.();
|
|
577
|
+
// service 검증 (useHs256 + alias 없을 때만)
|
|
578
|
+
if (useHs256 && !alias && service && !/^[a-z][a-zA-Z0-9-]*$/.test(service)) {
|
|
579
|
+
throw new Error(`@service[${service}] is invalid - encodeIdentityJWT()`);
|
|
580
|
+
}
|
|
581
|
+
// issuer 결정
|
|
582
|
+
const iss = alias ? `kms/${alias}` : useHs256 ? `api/${service}` : null;
|
|
583
|
+
// alg 헤더 결정
|
|
584
|
+
const alg = alias ? 'RS256' : useHs256 ? 'HS256' : 'RS256';
|
|
585
|
+
const payload = {
|
|
586
|
+
...identity,
|
|
587
|
+
iss, //* issuer name.
|
|
588
|
+
iat: Math.floor(current / 1000), //* issued at
|
|
589
|
+
exp: params?.exp ?? Math.floor(current / 1000) + 24 * 60 * 60, //* max 1 day.
|
|
590
|
+
};
|
|
591
|
+
const base64url = (t) => (0, aws_kms_service_1.fromBase64)(Buffer.from(t).toString('base64'));
|
|
592
|
+
const data = {
|
|
593
|
+
header: base64url(JSON.stringify({ alg, typ: 'JWT' })),
|
|
594
|
+
payload: base64url(JSON.stringify(payload)),
|
|
595
|
+
};
|
|
596
|
+
// STEP.2 encode and calc signature.
|
|
597
|
+
const message = [data.header, data.payload].join('.');
|
|
598
|
+
const signature = alias || useHs256 ? await this.signToken(alias, message) : '';
|
|
599
|
+
const token = [message, signature].join('.');
|
|
600
|
+
return { signature, message, token };
|
|
615
601
|
}
|
|
616
602
|
/**
|
|
617
603
|
* parse as jwt-token, and validate the signature.
|
|
618
604
|
* - supports both `kms/*` and `api/*` issuers via verifyToken()
|
|
619
605
|
*/
|
|
620
|
-
parseIdentityJWT(token, params) {
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
//* skip verification if not required
|
|
647
|
-
if (!isVerify)
|
|
648
|
-
return data;
|
|
649
|
-
// STEP.2 verify signature by iss (supports kms/* and api/*)
|
|
650
|
-
const verified = yield this.verifyToken(iss, message, signature, { token }).catch(e => {
|
|
651
|
-
throw new Error(`@signature[] is invalid (${(0, test_helper_1.GETERR)(e)}) - ${errScope}`);
|
|
652
|
-
});
|
|
653
|
-
if (!(verified === null || verified === void 0 ? void 0 : verified.valid)) {
|
|
654
|
-
const errMsg = (verified === null || verified === void 0 ? void 0 : verified.error) || `failed to verify by ${iss}`;
|
|
655
|
-
throw new Error(`@signature[] is invalid (${errMsg}) - ${errScope}`);
|
|
656
|
-
}
|
|
657
|
-
// STEP.3 validate expiration
|
|
658
|
-
if (!exp)
|
|
659
|
-
throw new Error(`.exp[${exp}] is invalid (empty) - ${errScope}`);
|
|
660
|
-
if (exp * 1000 < current)
|
|
661
|
-
throw new Error(`.exp[${engine_1.$U.ts(exp * 1000)}] is invalid (expired) - ${errScope}`);
|
|
606
|
+
async parseIdentityJWT(token, params) {
|
|
607
|
+
const isVerify = params?.verify ?? true;
|
|
608
|
+
const errScope = `verifyJWT(http)`;
|
|
609
|
+
//* it must be JWT Token. verify signature, and load.
|
|
610
|
+
if (typeof token !== 'string' || !token)
|
|
611
|
+
throw new Error(`@token (string) is required (but ${typeof token}) - ${errScope}`);
|
|
612
|
+
const sections = token.split('.');
|
|
613
|
+
if (sections.length !== 3)
|
|
614
|
+
throw new Error(`@token[${token}] is invalid (format) - ${errScope}`);
|
|
615
|
+
// STEP.1 decode jwt, and extract { iss, iat, exp }
|
|
616
|
+
const current = params?.current ?? engine_1.$U.current_time_ms();
|
|
617
|
+
const [header, payload, signature] = sections;
|
|
618
|
+
const message = [header, payload].join('.');
|
|
619
|
+
const data = engine_1.$U.jwt().decode(token, { complete: false, json: true });
|
|
620
|
+
if (!data)
|
|
621
|
+
throw new Error(`@token[${token}] is invalid (failed to decode) - ${errScope}`);
|
|
622
|
+
const { iss, iat, exp } = data;
|
|
623
|
+
// STEP.1-1 validate parameters.
|
|
624
|
+
if (typeof iss !== 'string' && iss !== null)
|
|
625
|
+
throw new Error(`.iss (string) is required - ${errScope}`);
|
|
626
|
+
if (typeof iat !== 'number' && iat !== null)
|
|
627
|
+
throw new Error(`.iat (number) is required - ${errScope}`);
|
|
628
|
+
if (typeof exp !== 'number' && exp !== null)
|
|
629
|
+
throw new Error(`.exp (number) is required - ${errScope}`);
|
|
630
|
+
//* skip verification if not required
|
|
631
|
+
if (!isVerify)
|
|
662
632
|
return data;
|
|
633
|
+
// STEP.2 verify signature by iss (supports kms/* and api/*)
|
|
634
|
+
const verified = await this.verifyToken(iss, message, signature, { token }).catch(e => {
|
|
635
|
+
throw new Error(`@signature[] is invalid (${(0, test_helper_1.GETERR)(e)}) - ${errScope}`);
|
|
663
636
|
});
|
|
637
|
+
if (!verified?.valid) {
|
|
638
|
+
const errMsg = verified?.error || `failed to verify by ${iss}`;
|
|
639
|
+
throw new Error(`@signature[] is invalid (${errMsg}) - ${errScope}`);
|
|
640
|
+
}
|
|
641
|
+
// STEP.3 validate expiration
|
|
642
|
+
if (!exp)
|
|
643
|
+
throw new Error(`.exp[${exp}] is invalid (empty) - ${errScope}`);
|
|
644
|
+
if (exp * 1000 < current)
|
|
645
|
+
throw new Error(`.exp[${engine_1.$U.ts(exp * 1000)}] is invalid (expired) - ${errScope}`);
|
|
646
|
+
return data;
|
|
664
647
|
}
|
|
665
648
|
/**
|
|
666
649
|
* parse of header[HEADER_LEMON_LANGUAGE] to get language-type.
|
|
@@ -688,99 +671,93 @@ class MyHttpHeaderTool {
|
|
|
688
671
|
/**
|
|
689
672
|
* override with AWS request-context
|
|
690
673
|
*/
|
|
691
|
-
prepareContext($org, reqContext) {
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
if (
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
$idt.
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
const context = Object.assign(Object.assign({}, $org), { userAgent, clientIp, requestId, accountId, domain });
|
|
723
|
-
return context;
|
|
724
|
-
});
|
|
674
|
+
async prepareContext($org, reqContext) {
|
|
675
|
+
const errScope = `web.prepareContext(${$org?.requestId ?? ''})`;
|
|
676
|
+
// STEP.4 override w/ cognito authentication to NextIdentity.
|
|
677
|
+
if (reqContext?.identity?.cognitoIdentityPoolId !== undefined) {
|
|
678
|
+
const $idt = $org?.identity;
|
|
679
|
+
if (!$idt)
|
|
680
|
+
throw new Error(`.identity (NextIdentity) is required - ${errScope}`);
|
|
681
|
+
const $req = reqContext.identity;
|
|
682
|
+
(0, engine_1._inf)(NS, '! identity(req) :=', engine_1.$U.json($req));
|
|
683
|
+
$idt.identityProvider = $req.cognitoAuthenticationProvider; // provider string.
|
|
684
|
+
$idt.identityPoolId = $req.cognitoIdentityPoolId; // identity-pool-id like 'ap-northeast-2:618ce9d2-3ad6-49df-b3b3-e248ea51425e'
|
|
685
|
+
$idt.identityId = $req.cognitoIdentityId; // identity-id like 'ap-northeast-2:dbd95fb4-7423-48b8-8a04-56e5bc95e444'
|
|
686
|
+
$idt.accountId = $req.accountId; // account-id should be same as context.accountId
|
|
687
|
+
$idt.userAgent = $req.userAgent; // user-agent string.
|
|
688
|
+
if (typeof $req.caller == 'string')
|
|
689
|
+
$idt.caller = $req.caller;
|
|
690
|
+
if (typeof $req.accessKey == 'string')
|
|
691
|
+
$idt.accessKey = $req.accessKey;
|
|
692
|
+
if (typeof $req.apiKey == 'string')
|
|
693
|
+
$idt.apiKey = $req.apiKey;
|
|
694
|
+
(0, engine_1._inf)(NS, '! identity(new) :=', engine_1.$U.json({ ...$idt }));
|
|
695
|
+
}
|
|
696
|
+
// STEP.5 extract additional request infor from req-context.
|
|
697
|
+
const clientIp = `${reqContext?.identity?.sourceIp || $org?.clientIp || ''}`;
|
|
698
|
+
const userAgent = `${reqContext?.identity?.userAgent || $org?.userAgent || ''}`;
|
|
699
|
+
const requestId = `${reqContext?.requestId || $org?.requestId || ''}`;
|
|
700
|
+
const accountId = `${reqContext?.accountId || $org?.accountId || ''}`;
|
|
701
|
+
const domain = `${reqContext?.domainName || $org?.domain || ''}`; //* chore avoid null of headers
|
|
702
|
+
//* save into headers and returns.
|
|
703
|
+
const context = { ...$org, userAgent, clientIp, requestId, accountId, domain };
|
|
704
|
+
return context;
|
|
725
705
|
}
|
|
726
706
|
/**
|
|
727
707
|
* verify token signature by iss.
|
|
728
708
|
* - `kms/*`: verify by KMS (RS256)
|
|
729
709
|
* - `api/*`: verify by HS256 (local) or protocol (remote)
|
|
730
710
|
*/
|
|
731
|
-
verifyToken(iss, message, signature, options) {
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
const
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
if (
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
711
|
+
async verifyToken(iss, message, signature, options) {
|
|
712
|
+
const errScope = `verifyToken(${iss ?? ''})`;
|
|
713
|
+
const _alias = (iss, prefix) => {
|
|
714
|
+
const value = iss.substring(prefix.length);
|
|
715
|
+
return value.includes(',') ? value.substring(0, value.indexOf(',')) : value;
|
|
716
|
+
};
|
|
717
|
+
try {
|
|
718
|
+
// KMS verification (RS256) - iss starts with 'kms/'
|
|
719
|
+
if (typeof iss === 'string' && iss.startsWith('kms/')) {
|
|
720
|
+
const alias = _alias(iss, 'kms/');
|
|
721
|
+
if (!alias)
|
|
722
|
+
throw new Error(`@alias (string) is required - ${errScope}`);
|
|
723
|
+
const $kms = this.findKMSService(`alias/${alias}`);
|
|
724
|
+
const valid = await $kms.verify(message, signature, { throwable: true });
|
|
725
|
+
return { valid };
|
|
726
|
+
}
|
|
727
|
+
// API verification - iss starts with 'api/'
|
|
728
|
+
if (typeof iss === 'string' && iss.startsWith('api/')) {
|
|
729
|
+
const issuer = iss.substring(4);
|
|
730
|
+
// validate issuer format
|
|
731
|
+
if (!/^[a-z][a-zA-Z0-9-]*$/.test(issuer)) {
|
|
732
|
+
throw new Error(`@issuer[${issuer}] is invalid - ${errScope}`);
|
|
748
733
|
}
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
}
|
|
756
|
-
const currentService = (_b = (_a = config_1.default === null || config_1.default === void 0 ? void 0 : config_1.default.config) === null || _a === void 0 ? void 0 : _a.getService) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
757
|
-
// verify if issued by current service
|
|
758
|
-
if (issuer === currentService) {
|
|
759
|
-
const secret = yield this.buildJwtSecret();
|
|
760
|
-
const expected = (0, aws_kms_service_1.fromBase64)(engine_1.$U.hmac(message, secret, 'sha256', 'base64'));
|
|
761
|
-
const valid = expected === signature;
|
|
762
|
-
return { valid };
|
|
763
|
-
}
|
|
764
|
-
// verify via protocol
|
|
765
|
-
const token = (_c = options === null || options === void 0 ? void 0 : options.token) !== null && _c !== void 0 ? _c : `${message}.${signature}`;
|
|
766
|
-
const body = { token };
|
|
767
|
-
const payload = {
|
|
768
|
-
service: issuer,
|
|
769
|
-
type: 'oauth',
|
|
770
|
-
mode: 'POST',
|
|
771
|
-
id: 'verify-token',
|
|
772
|
-
body,
|
|
773
|
-
context: {},
|
|
774
|
-
};
|
|
775
|
-
const res = yield protocol_1.default.service.execute(payload);
|
|
776
|
-
return res;
|
|
734
|
+
const currentService = config_1.default?.config?.getService?.();
|
|
735
|
+
// verify if issued by current service
|
|
736
|
+
if (issuer === currentService) {
|
|
737
|
+
const secret = await this.buildJwtSecret();
|
|
738
|
+
const expected = (0, aws_kms_service_1.fromBase64)(engine_1.$U.hmac(message, secret, 'sha256', 'base64'));
|
|
739
|
+
const valid = expected === signature;
|
|
740
|
+
return { valid };
|
|
777
741
|
}
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
742
|
+
// verify via protocol
|
|
743
|
+
const token = options?.token ?? `${message}.${signature}`;
|
|
744
|
+
const body = { token };
|
|
745
|
+
const payload = {
|
|
746
|
+
service: issuer,
|
|
747
|
+
type: 'oauth',
|
|
748
|
+
mode: 'POST',
|
|
749
|
+
id: 'verify-token',
|
|
750
|
+
body,
|
|
751
|
+
context: {},
|
|
752
|
+
};
|
|
753
|
+
const res = await protocol_1.default.service.execute(payload);
|
|
754
|
+
return res;
|
|
782
755
|
}
|
|
783
|
-
|
|
756
|
+
throw new Error(`@iss[${iss}] is invalid (unsupportable issuer) - ${errScope}`);
|
|
757
|
+
}
|
|
758
|
+
catch (e) {
|
|
759
|
+
return { valid: false, error: (0, test_helper_1.GETERR)(e) };
|
|
760
|
+
}
|
|
784
761
|
}
|
|
785
762
|
/**
|
|
786
763
|
* sign the message w/ alias
|
|
@@ -789,29 +766,27 @@ class MyHttpHeaderTool {
|
|
|
789
766
|
* @param alias kms key alias
|
|
790
767
|
* @param message the jwt message string
|
|
791
768
|
*/
|
|
792
|
-
signToken(alias, message) {
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
}
|
|
814
|
-
});
|
|
769
|
+
async signToken(alias, message) {
|
|
770
|
+
const errScope = `signToken(${alias ?? ''})`;
|
|
771
|
+
if (!message)
|
|
772
|
+
throw new Error(`@message (string) is required - ${errScope}`);
|
|
773
|
+
const useKms = !!alias;
|
|
774
|
+
if (useKms) {
|
|
775
|
+
// KMS verification (RS256)
|
|
776
|
+
if (!alias)
|
|
777
|
+
return '';
|
|
778
|
+
const $kms = new aws_kms_service_1.AWSKMSService(`alias/${alias}`);
|
|
779
|
+
const signature = await $kms.sign(message, true);
|
|
780
|
+
(0, engine_1._inf)(NS, `> signature[${alias}] with KMS =`, signature);
|
|
781
|
+
return signature;
|
|
782
|
+
}
|
|
783
|
+
else {
|
|
784
|
+
// HS256: sign directly with secret
|
|
785
|
+
const secret = await this.buildJwtSecret();
|
|
786
|
+
const signature = (0, aws_kms_service_1.fromBase64)(engine_1.$U.hmac(message, secret, 'sha256', 'base64'));
|
|
787
|
+
(0, engine_1._inf)(NS, `> signature[${alias}] with HS256 =`, signature);
|
|
788
|
+
return signature;
|
|
789
|
+
}
|
|
815
790
|
}
|
|
816
791
|
}
|
|
817
792
|
exports.MyHttpHeaderTool = MyHttpHeaderTool;
|