UNPKG

@jovian/type-tools

Version:

TypeTools is a Typescript library for providing extensible tooling runtime validations and type helpers.

1,051 lines (1,050 loc) 85.9 kB
"use strict"; var __extends = (this && this.__extends) || (function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; return extendStatics(d, b); }; return function (d, b) { if (typeof b !== "function" && b !== null) throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { if (ar || !(i in from)) { if (!ar) ar = Array.prototype.slice.call(from, 0, i); ar[i] = from[i]; } } return to.concat(ar || Array.prototype.slice.call(from)); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.HttpCacheOp = exports.CacheEntry = exports.CacheDef = exports.CacheParser = exports.PostHandler = exports.PreHandler = exports.HttpOp = exports.HttpPathResolution = exports.HttpResponse = exports.HttpRequest = exports.HttpServerShim = exports.HTTP = exports.isClass = exports.HttpBaseLib = exports.HttpServerShimApi = exports.HttpApiOptions = exports.ReqProcessor = exports.HttpShimCode = void 0; var express = __importStar(require("express")); var config_util_1 = require("../../src/common/util/config.util"); var dev_null_proxy_1 = require("../../src/common/util/convenience/dev.null.proxy"); var secure_channel_1 = require("../secure-channel/secure-channel"); var http_models_1 = require("./http.models"); var http_shim_worker_security_1 = require("./http.shim.worker.security"); var defaultConfig = __importStar(require("./http.shim.default.config.json")); var defaultGlobalConfig = __importStar(require("./http.shim.global.conf.json")); var axios = __importStar(require("axios")); var globals_ix_1 = require("../../src/common/globals.ix"); var secret_resolver_1 = require("../secret-resoluton/secret-resolver"); var destor_client_1 = require("./destor/destor.client"); var url = __importStar(require("url")); var process_exit_handler_1 = require("../proc/process.exit.handler"); var HttpShimCodeEnum; (function (HttpShimCodeEnum) { HttpShimCodeEnum[HttpShimCodeEnum["ACCESSOR_HEADER_NOT_FOUND"] = 0] = "ACCESSOR_HEADER_NOT_FOUND"; HttpShimCodeEnum[HttpShimCodeEnum["ACCESSOR_BAD_FORMAT"] = 1] = "ACCESSOR_BAD_FORMAT"; HttpShimCodeEnum[HttpShimCodeEnum["NO_ACCESSOR"] = 2] = "NO_ACCESSOR"; HttpShimCodeEnum[HttpShimCodeEnum["ENCRYPTED_OP_NO_SECURE_PAYLOAD"] = 3] = "ENCRYPTED_OP_NO_SECURE_PAYLOAD"; HttpShimCodeEnum[HttpShimCodeEnum["ENCRYPTED_OP_PATH_NOT_FOUND"] = 4] = "ENCRYPTED_OP_PATH_NOT_FOUND"; HttpShimCodeEnum[HttpShimCodeEnum["ENCRYPTED_OP_METHOD_NOT_FOUND"] = 5] = "ENCRYPTED_OP_METHOD_NOT_FOUND"; HttpShimCodeEnum[HttpShimCodeEnum["ENCRYPTED_OP_NON_JSON_PAYLOAD"] = 6] = "ENCRYPTED_OP_NON_JSON_PAYLOAD"; HttpShimCodeEnum[HttpShimCodeEnum["SECURE_CHANNEL_NOT_FOUND"] = 7] = "SECURE_CHANNEL_NOT_FOUND"; HttpShimCodeEnum[HttpShimCodeEnum["AUTH_HEADER_NOT_FOUND"] = 8] = "AUTH_HEADER_NOT_FOUND"; HttpShimCodeEnum[HttpShimCodeEnum["AUTH_HEADER_NOT_VALID"] = 9] = "AUTH_HEADER_NOT_VALID"; HttpShimCodeEnum[HttpShimCodeEnum["AUTH_HEADER_SIGNED_BUT_PUBLIC_KEY_NOT_FOUND"] = 10] = "AUTH_HEADER_SIGNED_BUT_PUBLIC_KEY_NOT_FOUND"; HttpShimCodeEnum[HttpShimCodeEnum["AUTH_HEADER_SIGNED_NO_ROLES_MAP"] = 11] = "AUTH_HEADER_SIGNED_NO_ROLES_MAP"; HttpShimCodeEnum[HttpShimCodeEnum["AUTH_HEADER_SIGNED_ROLE_UNAUTHORZIED_FOR_API"] = 12] = "AUTH_HEADER_SIGNED_ROLE_UNAUTHORZIED_FOR_API"; HttpShimCodeEnum[HttpShimCodeEnum["AUTH_HEADER_SIGNED_BUT_API_DENIES_ALL"] = 13] = "AUTH_HEADER_SIGNED_BUT_API_DENIES_ALL"; })(HttpShimCodeEnum || (HttpShimCodeEnum = {})); exports.HttpShimCode = (0, globals_ix_1.ReturnCodeFamily)('HttpShimCode', HttpShimCodeEnum); var ReqProcessor; (function (ReqProcessor) { ReqProcessor["AUTH"] = "AUTH"; ReqProcessor["BASIC"] = "BASIC"; ReqProcessor["DECRYPT"] = "DECRYPT"; ReqProcessor["ENCRYPT"] = "ENCRYPT"; })(ReqProcessor = exports.ReqProcessor || (exports.ReqProcessor = {})); var HttpApiOptions = (function () { function HttpApiOptions() { } return HttpApiOptions; }()); exports.HttpApiOptions = HttpApiOptions; var HttpServerShimApi = (function (_super) { __extends(HttpServerShimApi, _super); function HttpServerShimApi() { var _this = _super !== null && _super.apply(this, arguments) || this; _this.path = ''; _this.fullpath = ''; _this.method = http_models_1.HttpMethod.GET; return _this; } return HttpServerShimApi; }(HttpApiOptions)); exports.HttpServerShimApi = HttpServerShimApi; var HttpBaseLib; (function (HttpBaseLib) { HttpBaseLib["EXPRESS"] = "EXPRESS"; })(HttpBaseLib = exports.HttpBaseLib || (exports.HttpBaseLib = {})); function isClass(target) { return !!target.prototype && !!target.constructor.name; } exports.isClass = isClass; function methodsRegister(httpMethods, path, apiOptions) { path = path.replace(/\/\//g, '/'); return function (target, propertyKey, descriptor) { for (var _i = 0, httpMethods_1 = httpMethods; _i < httpMethods_1.length; _i++) { var httpMethod = httpMethods_1[_i]; var apiKey = "".concat(httpMethod, " ").concat(path); var methodApi = { class: target.constructor, className: target.constructor.name, method: httpMethod, path: path, handlerName: propertyKey }; if (apiOptions) { Object.assign(methodApi, apiOptions); } if (!target.apiMap) { target.apiMap = {}; } target.apiMap[apiKey] = methodApi; if (!target.apiRegistrations) { target.apiRegistrations = []; } target.addRegistration(methodApi); } }; } var HTTP = (function () { function HTTP() { } var _a; _a = HTTP; HTTP.GET = (function (path, apiOptions) { return methodsRegister([http_models_1.HttpMethod.GET], path, apiOptions); }); HTTP.POST = (function (path, apiOptions) { return methodsRegister([http_models_1.HttpMethod.POST], path, apiOptions); }); HTTP.PATCH = (function (path, apiOptions) { return methodsRegister([http_models_1.HttpMethod.PATCH], path, apiOptions); }); HTTP.DELETE = (function (path, apiOptions) { return methodsRegister([http_models_1.HttpMethod.DELETE], path, apiOptions); }); HTTP.METHODS = (function (methods, path, apiOptions) { return methodsRegister(methods, path, apiOptions); }); HTTP.ACCESS = function (access) { return function (target, propertyKey, descriptor) { if (typeof access === 'string') { var strAccess = access; access = {}; Object.defineProperty(access, strAccess, { value: true }); } Object.defineProperty(access, 'class', { value: target.constructor }); target.addAccessRule(propertyKey, access); }; }; HTTP.ACL = _a.ACCESS; HTTP.SHIM = { ROOT_API_PROXY_REQUEST: '/proxy-request', ROOT_API_PUBLIC_INFO: '/public-info', ROOT_API_NEW_CHANNEL: '/secure-channel', ROOT_API_SECURE_API: '/secure-api', }; HTTP.STATUS = http_models_1.HttpCode; return HTTP; }()); exports.HTTP = HTTP; ; var HttpServerShim = (function () { function HttpServerShim(config, globalConf, beforeSuper) { var _this = this; this.publicInfo = {}; this.publicInfoString = ''; this.authServers = {}; this.apiPath = 'api'; this.apiVersion = 'v1'; this.apiPathList = []; this.apiPathIface = {}; this.pathTree = {}; this.defaultProcessors = []; this.proxyRequest = { enabled: false, requestCheckers: [], }; this.secureChannels = {}; this.workerFleet = {}; this.cacheData = {}; this.state = { activePort: 0, closed: false, started: false, apiRegistered: false, apiRegisterStack: null, closingPromise: null, }; this.baseLibData = { express: { server: null, }, }; if (beforeSuper) { beforeSuper(); } this.configGlobal = (0, config_util_1.completeConfig)(globalConf ? globalConf : {}, defaultGlobalConfig); this.config = this.normalizeServerConfig(config); this.preHandler = new PreHandler(); this.postHandler = new PostHandler(); this.configResolutionPromise = this.configResolution(); this.setBaseLayer(); if (!this.config.name) { this.config.name = 'unnamed-server'; } if (!this.config.env) { this.config.env = 'test'; } process_exit_handler_1.ProcessExit.addHandler(function (e) { _this.close(); }); } HttpServerShim.prototype.configResolution = function () { return __awaiter(this, void 0, void 0, function () { var destor, _b, _c, channelKey, i; return __generator(this, function (_d) { switch (_d.label) { case 0: if (!!this.config.skipConfigSecretResolution) return [3, 4]; return [4, this.getDestorClient()]; case 1: destor = _d.sent(); _b = this; return [4, secret_resolver_1.SecretManager.resolve(this.config, destor)]; case 2: _b.config = _d.sent(); if (!!this.config.skipAuthServerResolution) return [3, 4]; _c = this; return [4, secret_resolver_1.SecretManager.resolve('<config.authServers>', destor)]; case 3: _c.authServers = (_d.sent()); _d.label = 4; case 4: if (this.config.security.secureChannel.enabled && this.config.security.secureChannel.signingKey) { channelKey = this.config.security.secureChannel.signingKey; if (!this.config.security.secureChannel.publicKey && channelKey && !channelKey.startsWith('<')) { this.config.security.secureChannel.publicKey = secure_channel_1.SecureHandshake.getPublicKeyFrom(channelKey); } for (i = 0; i < this.config.workers.secureChannelWorkers.initialCount; ++i) { this.addWorker(http_shim_worker_security_1.SecureChannelWorkerClient, { workerId: i, scopeName: this.config.scopeName, signingKey: channelKey, }); } } this.configResolutionPromise = null; this.afterConfigResolution(); return [2]; } }); }); }; HttpServerShim.prototype.registerApis = function () { if (this.state.apiRegistered) { throw new Error("Cannot register apis twice; already registered from ".concat(this.state.apiRegisterStack)); } this.state.apiRegistered = true; this.state.apiRegisterStack = new Error().stack; for (var _i = 0, _b = this.apiRegistrations; _i < _b.length; _i++) { var api = _b[_i]; if (this instanceof api.class) { this.register(api); } } }; HttpServerShim.prototype.normalizeServerConfig = function (config) { if (!config.scopeName) { config.scopeName = "httpshim;pid=".concat(process.pid); } var newConfig = (0, config_util_1.completeConfig)(config, defaultConfig); newConfig.debug.showErrorStack = true; return newConfig; }; HttpServerShim.prototype.addDefaultProcessor = function () { var processors = []; for (var _i = 0; _i < arguments.length; _i++) { processors[_i] = arguments[_i]; } if (this.state.apiRegistered) { throw new Error("addDefaultProcessor must be called before api registration"); } for (var _b = 0, processors_1 = processors; _b < processors_1.length; _b++) { var proc = processors_1[_b]; this.defaultProcessors.push(proc); } }; HttpServerShim.prototype.cacheDefine = function (init) { if (this.cacheData[init.path]) { throw new Error("Cache path '".concat(init.path, "' is already defined.")); } var def = new CacheDef(init); this.cacheData[def.path] = new CacheEntry({ value: null, hits: 0, version: 0, def: def, }); return def; }; HttpServerShim.prototype.addWorker = function (workerClass, workerData) { if (!workerData) { workerData = {}; } if (!this.workerFleet[workerClass.name]) { this.workerFleet[workerClass.name] = { workers: [] }; } var workersReg = this.workerFleet[workerClass.name]; var worker = new workerClass(workerData); workersReg.workers.push(worker); return worker; }; HttpServerShim.prototype.pickWorker = function (workerClass) { if (!this.workerFleet[workerClass.name]) { return dev_null_proxy_1.proxyParameterFunctionToNull; } var workers = this.workerFleet[workerClass.name].workers; if (workers.length === 0) { return dev_null_proxy_1.proxyParameterFunctionToNull; } return this.workerFleet[workerClass.name].workers[0]; }; HttpServerShim.prototype.setBaseLayer = function () { switch (this.config.type) { case HttpBaseLib.EXPRESS: this.baseApp = express.default(); var secOptions_1 = this.configGlobal.http.securityHeaders; if (secOptions_1.profile === 'allow-all') { this.baseApp.use(function (req, res, next) { if (secOptions_1.allowRequestOrigin) { res.header('Access-Control-Allow-Origin', secOptions_1.allowRequestOrigin); } if (secOptions_1.allowRequestHeaders) { res.header('Access-Control-Allow-Headers', secOptions_1.allowRequestOrigin); } if (req.method === 'OPTIONS') { res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH, DELETE, OPTIONS'); return res.end(); } next(); }); } break; } }; HttpServerShim.prototype.setFinalLayer = function () { switch (this.config.type) { case HttpBaseLib.EXPRESS: break; } }; HttpServerShim.prototype.getDestorClient = function () { return __awaiter(this, void 0, void 0, function () { var _b; return __generator(this, function (_c) { switch (_c.label) { case 0: if (this.destor) { return [2, this.destor]; } if (!this.destorPromise) return [3, 2]; return [4, this.destorPromise]; case 1: return [2, _c.sent()]; case 2: this.destorPromise = (0, destor_client_1.getDestorClient)(); _b = this; return [4, this.destorPromise]; case 3: _b.destor = _c.sent(); return [2]; } }); }); }; HttpServerShim.prototype.getRoles = function (op) { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_b) { return [2, op.res.returnJsonPreserialized('')]; }); }); }; HttpServerShim.prototype.getServerPublicInfo = function (op) { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_b) { return [2, op.res.returnJsonPreserialized(this.publicInfoString)]; }); }); }; HttpServerShim.prototype.newSecureChannel = function (op) { return __awaiter(this, void 0, void 0, function () { var accessInfoResult, accessInfo, peerInfo, channel, secureChannelResponseResult; return __generator(this, function (_b) { switch (_b.label) { case 0: accessInfoResult = this.checkAccessor(op, true); if (accessInfoResult.bad) { return [2, op.raise(accessInfoResult, HTTP.STATUS.BAD_REQUEST)]; } accessInfo = accessInfoResult.data; peerInfo = { ecdhPublicKey: Buffer.from(accessInfo.channelPublicKey, 'base64'), iden: null, data: null, }; return [4, this.pickWorker(http_shim_worker_security_1.SecureChannelWorkerClient).newChannel(peerInfo)]; case 1: channel = _b.sent(); channel.signing = { type: '4Q', public: this.config.security.secureChannel.publicKey, private: this.config.security.secureChannel.signingKey, }; this.secureChannels[channel.peerInfo.ecdhPublicKey.toString('base64')] = channel; secureChannelResponseResult = channel.getSecureChannelResponse(); if (secureChannelResponseResult.bad) { return [2, op.raise(secureChannelResponseResult, HTTP.STATUS.UNAUTHORIZED)]; } return [2, op.res.returnJson(secureChannelResponseResult.data)]; } }); }); }; HttpServerShim.prototype.encryptedOperation = function (op, skipRunning) { if (skipRunning === void 0) { skipRunning = false; } return __awaiter(this, void 0, void 0, function () { var api; return __generator(this, function (_b) { switch (_b.label) { case 0: api = op.req.decryptedApiTarget; if (!!skipRunning) return [3, 2]; return [4, this[api.handlerName](op)]; case 1: _b.sent(); _b.label = 2; case 2: return [2]; } }); }); }; HttpServerShim.prototype.proxyRequestOperation = function (op) { var _b; return __awaiter(this, void 0, void 0, function () { var _i, _c, checker, _d, allowed, message, paramsCopy, url, method, timeout, headers, newHeaders, _e, _f, headerName, headerValue, reqOpts, proxyRequestFunction; return __generator(this, function (_g) { switch (_g.label) { case 0: if (this.proxyRequest.enabled) { return [2, op.res.returnNotOk(500, "Proxy request not enabled")]; } if (!((_b = this.proxyRequest.requestCheckers) === null || _b === void 0 ? void 0 : _b.length)) return [3, 4]; _i = 0, _c = this.proxyRequest.requestCheckers; _g.label = 1; case 1: if (!(_i < _c.length)) return [3, 4]; checker = _c[_i]; return [4, checker(op.req.params)]; case 2: _d = _g.sent(), allowed = _d.allowed, message = _d.message; if (!allowed) { return [2, op.res.returnNotOk(500, "Proxy request not allowed: ".concat(message))]; } _g.label = 3; case 3: _i++; return [3, 1]; case 4: paramsCopy = JSON.parse(JSON.stringify(op.req.params)); url = paramsCopy.__url; method = paramsCopy.__method ? paramsCopy.__method : http_models_1.HttpMethod.GET; timeout = paramsCopy.__timeout ? paramsCopy.__timeout : 7000; headers = paramsCopy.__headers ? paramsCopy.__headers : ''; if (paramsCopy.__url) { delete paramsCopy.__url; } if (paramsCopy.__method) { delete paramsCopy.__method; } if (paramsCopy.__headers) { delete paramsCopy.__headers; } if (paramsCopy.__timeout) { delete paramsCopy.__timeout; } if (paramsCopy.__enc) { delete paramsCopy.__enc; } newHeaders = {}; for (_e = 0, _f = headers.split(','); _e < _f.length; _e++) { headerName = _f[_e]; headerValue = op.req.getHeader(headerName); if (headerValue) { newHeaders[headerName] = headerValue; } } reqOpts = { timeout: timeout, headers: newHeaders, params: paramsCopy, }; switch (method) { case 'GET': { proxyRequestFunction = axios.default.get; break; } case 'PUT': { proxyRequestFunction = axios.default.put; break; } case 'POST': { proxyRequestFunction = axios.default.post; break; } case 'PATCH': { proxyRequestFunction = axios.default.patch; break; } case 'DELETE': { proxyRequestFunction = axios.default.delete; break; } } op.waitFor(function (resolve) { proxyRequestFunction.apply(axios.default, [url, reqOpts]).then(function (res) { if (typeof res.data === 'string') { op.res.returnJson({ message: res.data }); } else { op.res.returnJson(res.data); } resolve(); }).catch(function (e) { var res = e.response; if (res) { op.res.returnNotOk(res.status, "Proxy request failed: ".concat(res.data)); } else { op.res.returnNotOk(500, "Proxy request failed: ".concat(e.message)); } resolve(); }); }); return [2]; } }); }); }; HttpServerShim.prototype.addAccessRule = function (memberMethodName, access) { if (!this.apiAccess) { this.apiAccess = {}; } var memberMethodName2 = memberMethodName; if (!this[memberMethodName2]) { throw new Error("Cannot defined roles for non-existing class method '".concat(memberMethodName2, "'")); } this.apiAccess[memberMethodName2] = access; }; HttpServerShim.prototype.addRegistration = function (api) { if (!this.apiRegistrations) { this.apiRegistrations = []; } this.apiRegistrations.push(api); }; HttpServerShim.prototype.register = function (api) { var _this = this; var apiVersion = api.apiVersion ? api.apiVersion : this.apiVersion; var apiPath = api.apiPath ? api.apiPath : this.apiPath; var finalMountPath = api.rootMount ? '' : "/".concat(apiPath, "/").concat(apiVersion); var fullpath = "".concat(finalMountPath, "/").concat(api.path).replace(/\/\//g, '/'); api.fullpath = fullpath; this.pathResolve(fullpath, api); var apiKey = "".concat(api.method, " ").concat(api.fullpath); this.apiPathList.push(apiKey); var iface = this[api.handlerName + '_iface']; if (iface) { iface.consumed = 1; this.apiPathIface[apiKey] = { method: api.method, path: api.path, handlerName: api.handlerName, description: iface.description ? iface.description : '', params: Object.keys(iface.params).map(function (paramName) { var paramInfo = iface.params[paramName]; return { required: paramInfo.required ? true : false, type: paramInfo.type }; }), returns: iface.returns.type, acl: null, }; setImmediate(function () { _this.apiPathIface[apiKey].acl = _this.apiAccess[api.handlerName] ? _this.apiAccess[api.handlerName] : null; }); } if (!api.pre) { api.pre = []; } if (!api.preDefaultProcesserAdded) { api.pre = __spreadArray(__spreadArray([], this.defaultProcessors, true), api.pre, true); api.pre = api.pre.filter(function (a, i) { return api.pre.indexOf(a) === i; }); api.preDefaultProcesserAdded = true; } switch (this.config.type) { case HttpBaseLib.EXPRESS: switch (api.method) { case http_models_1.HttpMethod.GET: return this.baseApp.get(fullpath, expressHandler(this, api)); case http_models_1.HttpMethod.POST: return this.baseApp.post(fullpath, expressHandler(this, api)); case http_models_1.HttpMethod.PUT: return this.baseApp.put(fullpath, expressHandler(this, api)); case http_models_1.HttpMethod.PATCH: return this.baseApp.patch(fullpath, expressHandler(this, api)); case http_models_1.HttpMethod.DELETE: return this.baseApp.delete(fullpath, expressHandler(this, api)); } break; } console.error("unmatched api", api); }; HttpServerShim.prototype.beforeStart = function () { }; HttpServerShim.prototype.afterStart = function () { }; HttpServerShim.prototype.afterConfigResolution = function () { }; HttpServerShim.prototype.beforeStop = function () { }; HttpServerShim.prototype.afterStop = function () { }; HttpServerShim.prototype.addPublicInfo = function (info) { Object.assign(this.publicInfo, info); }; HttpServerShim.prototype.start = function (options) { var _this = this; return (0, globals_ix_1.promise)(function (resolve, reject) { return __awaiter(_this, void 0, void 0, function () { var newAccess, app; var _this = this; return __generator(this, function (_b) { switch (_b.label) { case 0: if (this.state.started) { return [2, resolve()]; } this.state.started = true; if (!this.configResolutionPromise) return [3, 2]; return [4, this.configResolutionPromise]; case 1: _b.sent(); _b.label = 2; case 2: if (!options) { options = this.config.startOptions; } if (!options) { return [2, reject(new Error("Cannot start server without start options."))]; } this.addPublicInfo({ tokenRequired: this.config.security.token.required, accessorRequired: this.config.security.accessor.required, secureChannelScheme: this.config.security.secureChannel.encryption, secureChannelPublicKey: this.config.security.secureChannel.publicKey, secureChannelStrict: this.config.security.secureChannel.strict, secureChannelRequired: this.config.security.secureChannel.required, apiPathList: this.apiPathList, apiInterface: this.apiPathIface }); this.apiRegistrations = this.apiRegistrations.filter(function (api) { return _this instanceof api.class; }); newAccess = {}; Object.keys(this.apiAccess).forEach(function (handlerName) { if (_this instanceof _this.apiAccess[handlerName]['class']) { newAccess[handlerName] = _this.apiAccess[handlerName]; } }); this.apiAccess = newAccess; this.registerApis(); this.publicInfoString = JSON.stringify(this.publicInfo, null, 4); switch (this.config.type) { case HttpBaseLib.EXPRESS: try { this.beforeStart(); } catch (e) { console.error(e); } try { app = this.baseApp; this.baseLibData.express.server = app.listen(options.port, function () { _this.state.activePort = options.port; resolve(); try { _this.afterStart(); } catch (e) { console.error(e); } }); } catch (e) { return [2, reject(e)]; } break; } return [2]; } }); }); }); }; HttpServerShim.prototype.close = function () { var _this = this; if (this.state.closingPromise) { return this.state.closingPromise; } this.state.closed = true; switch (this.config.type) { case HttpBaseLib.EXPRESS: this.state.closingPromise = (0, globals_ix_1.promise)(function (resolve) { return __awaiter(_this, void 0, void 0, function () { var proms; return __generator(this, function (_b) { switch (_b.label) { case 0: proms = []; try { this.beforeStop(); } catch (e) { console.error(e); } try { this.baseLibData.express.server.close(); } catch (e) { console.error(e); } try { proms.push(this.destroyAllWorkers()); } catch (e) { console.error(e); } try { this.afterStop(); } catch (e) { console.error(e); } return [4, globals_ix_1.PromUtil.allSettled(proms)]; case 1: _b.sent(); resolve(); return [2]; } }); }); }); break; } return this.state.closingPromise; }; HttpServerShim.prototype.stamp = function (payload, encoding) { if (encoding === void 0) { encoding = 'ascii'; } return __awaiter(this, void 0, void 0, function () { var payloadB64, sig; return __generator(this, function (_b) { switch (_b.label) { case 0: if (!payload) { payload = secure_channel_1.SecureHandshake.timeAuth(); } if (typeof payload === 'string') { payloadB64 = Buffer.from(payload, encoding).toString('base64'); } else { payloadB64 = payload.toString('base64'); } return [4, this.pickWorker(http_shim_worker_security_1.SecureChannelWorkerClient).signMessage(payloadB64)]; case 1: sig = _b.sent(); return [2, { payload: payloadB64, sig: sig }]; } }); }); }; HttpServerShim.prototype.prepareEncryptedOperation = function (op) { if (op.req.decryptedApiTarget) { return (0, globals_ix_1.ok)(op.req.decryptedApiTarget); } var decryptResult = this.getDecryptedPayload(op); if (decryptResult.bad) { return op.raise(decryptResult, HTTP.STATUS.UNAUTHORIZED); } if (!op.req.decryptedPayloadObject) { return op.raise(http_models_1.HttpCode.BAD_REQUEST, "ENCRYPTED_OP_NON_JSON_PAYLOAD", "Supplied secure payload is not JSON format"); } var args = op.req.decryptedPayloadObject; var resolved = this.pathResolve(args.path); if (!resolved) { return op.raise(http_models_1.HttpCode.NOT_FOUND, "ENCRYPTED_OP_PATH_NOT_FOUND", "Encrypted access to unknown path: '".concat(args.path, "'")); } var api = resolved.methods[op.method]; if (!api) { return op.raise(http_models_1.HttpCode.NOT_FOUND, "ENCRYPTED_OP_METHOD_NOT_FOUND", "Method ".concat(op.method, " not found for '").concat(api.fullpath, "'")); } if (args.headers) { Object.assign(op.req.headers, args); } op.params = op.req.params; var pathQueryParams = url.parse(args.path, true).query; if (Object.keys(resolved.params).length > 0) { Object.assign(op.req.params, resolved.params); } if (Object.keys(pathQueryParams).length > 0) { Object.assign(op.req.params, pathQueryParams); } if (args.body) { try { var data = JSON.parse(args.body); op.req.data = data; if (data && typeof data === 'object' && !Array.isArray(data)) { Object.assign(op.req.params, data); } } catch (e) { } } op.req.decryptedApiTarget = api; return (0, globals_ix_1.ok)(api); }; HttpServerShim.prototype.checkAccessor = function (op, forceVerify) { if (forceVerify === void 0) { forceVerify = false; } var authorizationHeader = op.req.getHeader('Accessor'); var accessorConf = this.config.security.accessor; if (accessorConf.required || forceVerify) { if (!authorizationHeader) { return op.raise(http_models_1.HttpCode.UNAUTHORIZED, "ACCESSOR_HEADER_NOT_FOUND", "Accessor header does not exist"); } } else { return (0, globals_ix_1.ok)({ accessor: null, t: 0, channelPublicKey: '' }); } var authInfo = secure_channel_1.SecureHandshake.parseAuthHeader(authorizationHeader); var accessorExpression = authInfo.accessorExpression; var timeWindow = this.config.security.accessor.timeWindow; if (!accessorConf.baseTokenBuffer) { accessorConf.baseTokenBuffer = Buffer.from(accessorConf.baseToken, 'ascii'); } var accessDataResult = secure_channel_1.SecureHandshake.verifyAccessor(accessorExpression, accessorConf.baseTokenBuffer, timeWindow); if (accessDataResult.bad) { return op.raise(accessDataResult, http_models_1.HttpCode.UNAUTHORIZED); } return (0, globals_ix_1.ok)(__assign(__assign({}, accessDataResult.data), { channelPublicKey: authInfo.peerEcdhPublicKey })); }; HttpServerShim.prototype.getSecureChannel = function (op) { var accessInfoResult = this.checkAccessor(op, true); if (accessInfoResult.bad) { return op.raise(accessInfoResult, HTTP.STATUS.BAD_REQUEST); } var channelId = accessInfoResult.data.channelPublicKey; var channel = this.secureChannels[channelId]; if (!channel) { return op.raise(http_models_1.HttpCode.UNAUTHORIZED, "SECURE_CHANNEL_NOT_FOUND", "secure channel not found: ".concat(channelId)); } op.secureChannel = channel; return (0, globals_ix_1.ok)(channel); }; HttpServerShim.prototype.getDecryptedPayload = function (op) { if (op.req.decryptedPayload) { return (0, globals_ix_1.ok)(op.req.decryptedPayload); } var channelResult = this.getSecureChannel(op); if (channelResult.bad) { return op.raise(channelResult, HTTP.STATUS.UNAUTHORIZED); } var channel = channelResult.data; var payload = channel.parseWrappedPayloadBase64(op.req.encryptedPayload); if (!payload || !payload.__scp) { return op.raise(http_models_1.HttpCode.BAD_REQUEST, 'ENCRYPTED_OP_NO_SECURE_PAYLOAD', 'Secure payload not found'); } op.req.decryptedPayload = channel.decryptSecureChannelPayloadIntoString(payload); if (isJsonString(op.req.decryptedPayload)) { op.req.decryptedPayloadObject = JSON.parse(op.req.decryptedPayload); } return (0, globals_ix_1.ok)(op.req.decryptedPayload); }; HttpServerShim.prototype.handlePre = function (op) { var _this = this; return (0, globals_ix_1.promise)(function (resolve) { return __awaiter(_this, void 0, void 0, function () { var allPassed, _i, _b, preType, preFunc, passed; var _c; return __generator(this, function (_d) { switch (_d.label) { case 0: allPassed = true; if (!(((_c = op.api.pre) === null || _c === void 0 ? void 0 : _c.length) > 0)) return [3, 4]; _i = 0, _b = op.api.pre; _d.label = 1; case 1: if (!(_i < _b.length)) return [3, 4]; preType = _b[_i]; preFunc = this.preHandler.byType[preType]; if (!preFunc) { return [3, 3]; } return [4, preFunc.apply(this.preHandler, [op])]; case 2: passed = _d.sent(); if (!passed) { allPassed = false; return [3, 4]; } _d.label = 3; case 3: _i++; return [3, 1]; case 4: resolve(allPassed); return [2]; } }); }); }); }; HttpServerShim.prototype.handlePost = function (op) { var _this = this; return (0, globals_ix_1.promise)(function (resolve) { return __awaiter(_this, void 0, void 0, function () { var allPassed, _i, _b, postType, postFunc, passed; return __generator(this, function (_c) { switch (_c.label) { case 0: allPassed = true; if (!op.api.post) return [3, 4]; _i = 0, _b = op.api.post; _c.label = 1; case 1: if (!(_i < _b.length)) return [3, 4]; postType = _b[_i]; postFunc = this.postHandler.byType[postType]; if (!postFunc) { return [3, 3]; } return [4, postFunc.apply(this.postHandler, [op])]; case 2: passed = _c.sent(); if (!passed) { allPassed = false; return [3, 4]; } _c.label = 3; case 3: _i++; return [3, 1]; case 4: resolve(allPassed); return [2]; } }); }); }); }; HttpServerShim.prototype.pathResolve = function (path, newApi) { if (newApi === void 0) { newApi = null; } var paths = path.split('/'); if (paths[0] === '') { paths.shift(); } var paramCollector = {}; var node = this.pathTree; for (var _i = 0, paths_1 = paths; _i < paths_1.length; _i++) { var pathSlot = paths_1[_i]; var slot = decodeURIComponent(pathSlot.split('?')[0].split('#')[0]); if (slot === '__apidef__') { return null; } var isParam = slot.startsWith(':'); if (node[slot]) { node = node[slot]; continue; } var paramDef = node['?param-name?']; if (paramDef) { if (newApi && isParam && paramDef.slot !== slot) { throw new Error("Cannot register a parameter slot ".concat(slot, ", ") + "parameter ".concat(paramDef.slot, " has been registered by ").concat(paramDef.registeredPath)); } paramCollector[paramDef.name] = slot; node = paramDef.nextNode; continue; } if (newApi) { var nextNode = {};