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