ts-comply
Version:
TypeTools is a Typescript library for providing extensible tooling runtime validations and type helpers.
1,894 lines • 96.4 kB
JavaScript
"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 __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
var useValue = arguments.length > 2;
for (var i = 0; i < initializers.length; i++) {
value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
}
return useValue ? value : void 0;
};
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
var _, done = false;
for (var i = decorators.length - 1; i >= 0; i--) {
var context = {};
for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
for (var p in contextIn.access) context.access[p] = contextIn.access[p];
context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
if (kind === "accessor") {
if (result === void 0) continue;
if (result === null || typeof result !== "object") throw new TypeError("Object expected");
if (_ = accept(result.get)) descriptor.get = _;
if (_ = accept(result.set)) descriptor.set = _;
if (_ = accept(result.init)) initializers.push(_);
}
else if (_ = accept(result)) {
if (kind === "field") initializers.push(_);
else descriptor[key] = _;
}
}
if (target) Object.defineProperty(target, contextIn.name, descriptor);
done = true;
};
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 __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));
};
var _this = this;
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["CACHE_DATA_FETCH_FAILED"] = 0] = "CACHE_DATA_FETCH_FAILED";
HttpShimCodeEnum[HttpShimCodeEnum["ACCESSOR_HEADER_NOT_FOUND"] = 1] = "ACCESSOR_HEADER_NOT_FOUND";
HttpShimCodeEnum[HttpShimCodeEnum["ACCESSOR_BAD_FORMAT"] = 2] = "ACCESSOR_BAD_FORMAT";
HttpShimCodeEnum[HttpShimCodeEnum["NO_ACCESSOR"] = 3] = "NO_ACCESSOR";
HttpShimCodeEnum[HttpShimCodeEnum["ENCRYPTED_OP_NO_SECURE_PAYLOAD"] = 4] = "ENCRYPTED_OP_NO_SECURE_PAYLOAD";
HttpShimCodeEnum[HttpShimCodeEnum["ENCRYPTED_OP_PATH_NOT_FOUND"] = 5] = "ENCRYPTED_OP_PATH_NOT_FOUND";
HttpShimCodeEnum[HttpShimCodeEnum["ENCRYPTED_OP_METHOD_NOT_FOUND"] = 6] = "ENCRYPTED_OP_METHOD_NOT_FOUND";
HttpShimCodeEnum[HttpShimCodeEnum["ENCRYPTED_OP_NON_JSON_PAYLOAD"] = 7] = "ENCRYPTED_OP_NON_JSON_PAYLOAD";
HttpShimCodeEnum[HttpShimCodeEnum["SECURE_CHANNEL_NOT_FOUND"] = 8] = "SECURE_CHANNEL_NOT_FOUND";
HttpShimCodeEnum[HttpShimCodeEnum["AUTH_HEADER_NOT_FOUND"] = 9] = "AUTH_HEADER_NOT_FOUND";
HttpShimCodeEnum[HttpShimCodeEnum["AUTH_HEADER_NOT_VALID"] = 10] = "AUTH_HEADER_NOT_VALID";
HttpShimCodeEnum[HttpShimCodeEnum["AUTH_HEADER_SIGNED_BUT_PUBLIC_KEY_NOT_FOUND"] = 11] = "AUTH_HEADER_SIGNED_BUT_PUBLIC_KEY_NOT_FOUND";
HttpShimCodeEnum[HttpShimCodeEnum["AUTH_HEADER_SIGNED_NO_ROLES_MAP"] = 12] = "AUTH_HEADER_SIGNED_NO_ROLES_MAP";
HttpShimCodeEnum[HttpShimCodeEnum["AUTH_HEADER_SIGNED_ROLE_UNAUTHORZIED_FOR_API"] = 13] = "AUTH_HEADER_SIGNED_ROLE_UNAUTHORZIED_FOR_API";
HttpShimCodeEnum[HttpShimCodeEnum["AUTH_HEADER_SIGNED_BUT_API_DENIES_ALL"] = 14] = "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 (method, deco) {
deco.addInitializer(function () {
var target = this;
var sourceClass = this.constructor;
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: sourceClass,
className: sourceClass.name,
method: httpMethod,
path: path,
handlerName: deco.name,
};
if (apiOptions) {
Object.assign(methodApi, apiOptions);
}
if (!target.apiMap) {
target.apiMap = {};
}
target.apiMap[apiKey] = methodApi;
if (!target.apiRegistrations) {
target.apiRegistrations = [];
}
target.addRegistration(methodApi);
}
});
return method;
};
}
var HTTP = exports.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 (method, deco) {
deco.addInitializer(function () {
var target = this;
if (typeof access === 'string') {
var strAccess = access;
access = {};
Object.defineProperty(access, strAccess, { value: true });
}
if (!access.class) {
Object.defineProperty(access, 'class', { value: target.constructor });
}
target.addAccessRule(deco.name, access);
});
return method;
};
};
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;
}());
;
var HttpServerShim = exports.HttpServerShim = function () {
var _b;
var _instanceExtraInitializers = [];
var _getRoles_decorators;
var _getServerPublicInfo_decorators;
var _newSecureChannel_decorators;
var _encryptedOperation_decorators;
var _proxyRequestOperation_decorators;
return _b = (function () {
function HttpServerShim(config, globalConf, beforeSuper) {
var _this = this;
this.config = (__runInitializers(this, _instanceExtraInitializers), void 0);
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, _a, _b, channelKey, i;
return __generator(this, function (_c) {
switch (_c.label) {
case 0:
if (!!this.config.skipConfigSecretResolution) return [3, 4];
return [4, this.getDestorClient()];
case 1:
destor = _c.sent();
_a = this;
return [4, secret_resolver_1.SecretManager.resolve(this.config, destor)];
case 2:
_a.config = _c.sent();
if (!!this.config.skipAuthServerResolution) return [3, 4];
_b = this;
return [4, secret_resolver_1.SecretManager.resolve('<config.authServers>', destor)];
case 3:
_b.authServers = (_c.sent());
_c.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, _a = this.apiRegistrations; _i < _a.length; _i++) {
var api = _a[_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 _a = 0, processors_1 = processors; _a < processors_1.length; _a++) {
var proc = processors_1[_a];
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 _a;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
if (this.destor) {
return [2, this.destor];
}
if (!this.destorPromise) return [3, 2];
return [4, this.destorPromise];
case 1: return [2, _b.sent()];
case 2:
this.destorPromise = (0, destor_client_1.getDestorClient)();
_a = this;
return [4, this.destorPromise];
case 3:
_a.destor = _b.sent();
return [2];
}
});
});
};
HttpServerShim.prototype.getRoles = function (op) {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
return [2, op.res.returnJsonPreserialized('')];
});
});
};
HttpServerShim.prototype.getServerPublicInfo = function (op) {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
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 (_a) {
switch (_a.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 = _a.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 (_a) {
switch (_a.label) {
case 0:
api = op.req.decryptedApiTarget;
if (!!skipRunning) return [3, 2];
return [4, this[api.handlerName](op)];
case 1:
_a.sent();
_a.label = 2;
case 2: return [2];
}
});
});
};
HttpServerShim.prototype.proxyRequestOperation = function (op) {
var _a;
return __awaiter(this, void 0, void 0, function () {
var _i, _b, checker, allowed, message, paramsCopy, url, method, timeout, headers, newHeaders, _c, _d, headerName, headerValue, reqOpts, proxyRequestFunction;
var _e;
return __generator(this, function (_f) {
switch (_f.label) {
case 0:
if (this.proxyRequest.enabled) {
return [2, op.res.returnNotOk(500, "Proxy request not enabled")];
}
if (!((_a = this.proxyRequest.requestCheckers) === null || _a === void 0 ? void 0 : _a.length)) return [3, 4];
_i = 0, _b = this.proxyRequest.requestCheckers;
_f.label = 1;
case 1:
if (!(_i < _b.length)) return [3, 4];
checker = _b[_i];
return [4, checker(op.req.params)];
case 2:
allowed = (_e = _f.sent(), _e.allowed), message = _e.message;
if (!allowed) {
return [2, op.res.returnNotOk(500, "Proxy request not allowed: ".concat(message))];
}
_f.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 (_c = 0, _d = headers.split(','); _c < _d.length; _c++) {
headerName = _d[_c];
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 (_a) {
switch (_a.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:
_a.sent();
_a.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;
var _a, _b, _c;
return __generator(this, function (_d) {
switch (_d.label) {
case 0:
proms = [];
try {
this.beforeStop();
}
catch (e) {
console.error(e);
}
try {
(_c = (_b = (_a = this.baseLibData) === null || _a === void 0 ? void 0 : _a.express) === null || _b === void 0 ? void 0 : _b.server) === null || _c === void 0 ? void 0 : _c.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:
_d.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 (_a) {
switch (_a.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 = _a.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, _a, preType, preFunc, passed;
var _b;
return __generator(this, function (_c) {
switch (_c.label) {
case 0:
allPassed = true;
if (!(((_b = op.api.pre) === null || _b === void 0 ? void 0 : _b.length) > 0)) return [3, 4];
_i = 0, _a = op.api.pre;
_c.label = 1;
case 1:
if (!(_i < _a.length)) return [3, 4];
preType = _a[_i];
preFunc = this.preHandler.byType[preType];
if (!preFunc) {
return [3, 3];
}
return [4, preFunc.apply(this.preHandler, [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.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, _a, postType, postFunc, passed;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
allPassed = true;
if (!op.api.post) return [3, 4];
_i = 0, _a = op.api.post;
_b.label = 1;
case 1:
if (!(_i < _a.length)) return [3, 4];
postType = _a[_i];
postFunc = this.postHandler.byType[postType];
if (!postFunc) {
return [3, 3];
}
return [4, postFunc.apply(this.postHandler, [op])];
case 2:
passed = _b.sent();
if (!passed) {
allPassed = false;
return [3, 4];
}
_b.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 = {};
if (isParam) {
node['?param-name?'] = { nextNode: nextNode, slot: slot, name: slot.substr(1), registeredPath: path };
}
node[slot] = nextNode;
node = node[slot];
}
else {
return null;
}
}
if (!node) {
return null;
}
if (newApi) {
if (node.__apidef__ && node.__apidef__.methods[newApi.method]) {
throw new Error("Cannot register api at ".concat(newApi.method, " ").concat(path, ", another api is already registered"));
}
if (!node.__apidef__) {
node.__apidef__ = {
type: 'api',
path: path,
registeredPath: path,
methods: {},
params: {},
};
}
node.__apidef__.methods[newApi.method] = newApi;
return node.__apidef__;
}
var registeredDef = node.__apidef__;
if (!registeredDef) {
return null;
}
return {
type: 'api',
path: path,
methods: registeredDef.methods,
registeredPath: registeredDef.registeredPath,
params: paramCollector,
};
};
HttpServerShim.prototype.destroyAllWorkers = function () {
var proms = [];
for (var _i = 0, _a = Object.keys(this.workerFleet); _i < _a.length; _i++) {
var workerClass = _a[_i];
var fleet = this.workerFleet[workerClass];
for (var _b = 0, _c = fleet.workers; _b < _c.length; _b++) {
var worker = _c[_b];
var terminationProm = worker.terminate();
proms.push(terminationProm);
process_exit_handler_1.ProcessExit.gracefulExitPromises.push(terminationProm);
}
}
this.workerFleet = {};
return globals_ix_1.PromUtil.allSettled(proms);
};
return HttpServerShim;
}()),
(function () {
_getRoles_decorators = [HTTP.GET('/test-roles-api', { rootMount: true }), HTTP.ACCESS({ ADMIN: true, NO_AUTH: true })];
_getServerPublicInfo_decorators = [HTTP.GET(HTTP.SHIM.ROOT_API_PUBLIC_INFO, { rootMount: true })];
_newSecureChannel_decorators = [HTTP.GET(HTTP.SHIM.ROOT_API_NEW_CHANNEL, { rootMount: true })];
_encryptedOperation_decorators = [HTTP.METHODS(http_models_1.httpRest, HTTP.SHIM.ROOT_API_SECURE_API, { rootMount: true })];
_proxyRequestOperation_decorators = [HTTP.GET(HTTP.SHIM.ROOT_API_PROXY_REQUEST, { rootMount: true })];
__esDecorate(_b, null, _getRoles_decorators, { kind: "method", name: "getRoles", static: false, private: false, access: { has: function (obj) { return "getRoles" in obj; }, get: function (obj) { return obj.getRoles; } } }, null, _instanceExtraInitializers);
__esDecorate(_b, null, _getServerPublicInfo_decorators, { kind: "method", name: "getServerPublicInfo", static: false, private: false, access: { has: function (obj) { return "getServerPublicInfo" in obj; }, get: function (obj) { return obj.getServerPublicInfo; } } }, null, _instanceExtraInitializers);
__esDecorate(_b, null, _newSecureChannel_decorators, { kind: "method", name: "newSecureChannel", static: false, private: false, access: { has: function (obj) { return "newSecureChannel" in obj; }, get: function (obj) { return obj.newSecureChannel; } } }, null, _instanceExtraInitializers);
__esDecorate(_b, null, _encryptedOperation_decorators, { kind: "method", name: "encryptedOperation", static: false, private: false, access: { has: function (obj) { return "encryptedOperation" in obj; }, get: function (obj) { return obj.encryptedOperation; } } }, null, _instanceExtraInitializers);
__esDecorate(_b, null, _proxyRequestOperation_decorators, { kind: "method", name: "proxyRequestOperation", static: false, private: false, access: { has: function (obj) { return "proxyRequestOperation" in obj; }, get: function (obj) { return obj.proxyRequestOperation; } } }, null, _instanceExtraInitializers);
})(),
_b;
}();
var HttpRequest = (function () {
function HttpRequest(op) {
this.body = null;
this.bodyRaw = null;
this.headers = {};
this.t = Date.now();
this.op = op;
}
HttpRequest.prototype.getHeader = function (headerName) {
switch (this.op.server.config.type) {
case HttpBaseLib.EXPRESS:
return this.op.oriReq.header(headerName);
default:
return null;
}
};
return HttpRequest;
}());
exports.HttpRequest = HttpRequest;
var HttpResponse = (function () {
function HttpResponse(op) {
this.headers = {};
this.t = -1;
this.dt = -1;
this.ended = false;
this.output = [];
this.endingPayload = '';
this.endingPayloadRaw = '';
this.statusCode = 200;
this.appErrorCode = 'GENERIC_ERROR';
this.onends = [];
this.op = op;
}
Object.defineProperty(HttpResponse.prototype, "onend", {
get: function () { return this.onends; },
enumerable: false,
configurable: true
});
HttpResponse.prototype.send = function (payload) {
if (this.ended) {
return;
}
this.op.oriRes.send(payload);
this.output.push(payload);
return this;
};
HttpResponse.prototype.end = function (payload, returnValue) {
if (this.ended) {
return;
}
this.ended = true;
this.t = Date.now();
this.dt = this.t - this.req.t;
for (var _i = 0, _b = this.onends; _i < _b.length; _i++) {
var onend = _b[_i];
try {
if (onend) {
onend();
}
}
catch (e) { }
}
this.endingPayload = payload;
this.output.push(payload);
if (returnValue !== undefined) {
this.returnValue = returnValue;
}
return this;
};
HttpResponse.prototype.status = function (num) {
this.statusCode = num;
return this;
};
HttpResponse.prototype.returnCached = function (code, cached) {
this.statusCode = code;
return this.end(cached);
};
HttpResponse.prototype.returnNotOk = function (code, message) {
if (message === void 0) { message = ''; }
var statusName = 'unclassified_server_error';
switch (code) {
case 400:
statusName = 'bad_request';
break;
case 401:
statusName = 'unauthorized';
break;
case 404:
statusName = 'not_found';
break;
case 500:
statusName = 'internal_server_error';
break;
}
var resObj = { status: statusName, message: message };
if (!message && this.op.errors.length > 0) {
var e = this.op.errors[0].e;
message = e.message;
if (this.op.server.config.debug.showErrorStack) {
resObj.stackTrace = e.stack;
}
}
this.statusCode = code;
return this.end(JSON.stringify(resObj));
};
HttpResponse.prototype.okJsonPreserialized = function (serial) { return "{\"status\":\"ok\",\"result\":".concat(serial, "}"); };
HttpResponse.prototype.okJsonString = function (obj) { return JSON.stringify({ status: 'ok', result: obj }); };
HttpResponse.prototype.returnJsonPreserialized = function (serialized, original) {
this.end("{\"status\":\"ok\",\"result\":".concat(serialized, "}"));
return original;
};
HttpResponse.prototype.returnJson = function (obj) {
this.end(JSON.stringify({ status: 'ok', result: obj }), obj);
return obj;
};
return HttpResponse;
}());
exports.HttpResponse = HttpResponse;
var HttpPathResolution = (function () {
function HttpPathResolution() {
}
return HttpPathResolution;
}());
exports.HttpPathResolution = HttpPathResolution;
var HttpOp = (function () {
function HttpOp(server, api, oriReq, oriRes) {
if (oriReq === void 0) { oriReq = null; }
if (oriRes === void 0) { oriRes = null; }
this.server = server;
this.api = api;
this.oriReq = oriReq;
this.oriRes = oriRes;
this.error = null;
this.errors = [];
this.pendingSequential = [];
this.pendingParallel = [];
this.params = {};
this.req = new HttpRequest(this);
this.req.params = this.params;
this.res = new HttpResponse(this);
this.res.req = this.req;
this.req.res = this.res;
this.cache = new HttpCacheOp(this);
}
HttpOp.prototype.raise = function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
if (typeof args[0] === 'number') {
var _b = args, statusCode = _b[0], errorCode = _b[1], message = _b[2];
if (!this.res.ended) {
this.res.returnNotOk(statusCode, message);
}
return exports.HttpShimCode.error(errorCode, message, { statusCode: statusCode });
}
else {
if (args[0] instanceof Error) {
args[0] = (0, globals_ix_1.errorResult)(args[0]);
}
var _c = args, result = _c[0], statusCode = _c[1];
if (result.ok) {
if (!statusCode) {
statusCode = result.statusCode ? result.statusCode : 200;
}
if (!this.res.ended) {
this.res.status(statusCode).returnJson(result.data);
}
}
else {
if (!statusCode) {
statusCode = result.statusCode ? result.statusCode : 500;
}
if (!this.res.ended) {
this.res.returnNotOk(statusCode, result.message);
}
}
return result;
}
};
HttpOp.prototype.returnJson = function (obj) {
var status = 'ok';
var result = obj;
if (obj && obj.isResultKind) {
var res = obj;
if (res.bad) {
status = 'error';
result = res.message;
}
else {
result = res.data;
}
if (res.statusCode) {
this.res.status(res.statusCode);
}
}
if (status === 'error') {
return this.res.end(JSON.stringify({ status: status, message: result, server: this.server.config.name }), obj);
}
else {
return this.res.end(JSON.stringify({ status: status, result: result, server: this.server.config.name }), obj);
}
};
HttpOp.prototype.setResponse = function (endingPayload) {
if (endingPayload) {
this.res.endingPayload = endingPayload;
}
};
HttpOp.prototype.addSequentialProcess = function (proc) {
this.pendingSequential.push(proc);
return proc;
};
HttpOp.prototype.waitFor = function (resolver) {
var proc = new Promise(resolver);
this.pendingSequential.push(proc);
return proc;
};
HttpOp.prototype.run = function (fromInternal) {
if (fromInternal === void 0) { fromInternal = false; }
return __awaiter(this, void 0, void 0, function () {
var preRes, _i, _b, prom;
return __generator(this, function (_c) {
switch (_c.label) {
case 0:
this.fromInternal = fromInternal;
return [4, this.server.handlePre(this)];
case 1:
preRes = _c.sent();
if (!preRes) return [3, 6];
return [4, this.server[this.api.handlerName](this)];
case 2:
_c.sent();
_i = 0, _b = this.pendingSequential;
_c.label = 3;
case 3:
if (!(_i < _b.length)) return [3, 6];
prom = _b[_i];
return [4, Promise.resolve(prom)];
case 4:
_c.sent();
_c.label = 5;
case 5:
_i++;
return [3, 3];
case 6: return [4, this.server.handlePost(this)];
case 7:
_c.sent();
if (this.secureChannel) {
this.res.endingPayloadRaw = this.res.endingPayload;
this.res.endingPayload = JSON.stringify({
status: 'ok',
format: 'json',
encrypted: true,
payload: this.secureChannel.createWrappedPayload(this.res.endingPayload),
});
}
this.finish();
return [2];
}
});
});
};
HttpOp.prototype.finish = function () {
switch (this.server.config.type) {
case HttpBaseLib.EXPRESS:
this.oriRes.status(this.res.statusCode).end(this.res.endingPayload);
return null;
default:
throw new Error("Unknown base http library type: ".concat(this.server.config.type));
}
};
return HttpOp;
}());
exports.HttpOp = HttpOp;
var PreHandler = (function () {
function PreHandler() {
var _b;
this.byType = {};
this.byType = (_b = {},
_b[ReqProcessor.DECRYPT] = this.optionalDecrypt,
_b[ReqProcessor.AUTH] = this.auth,
_b[ReqProcessor.BASIC] = this.basic,
_b);
}
PreHandler.prototype.auth = function (op) {
return __awaiter(this, void 0, void 0, function () {
var _this = this;
return __generator(this, function (_b) {
return [2, (0, globals_ix_1.promise)(function (resolve) { return __awaiter(_this, void 0, void 0, function () {
var srvConfig, authData, apiRoleBook, headerText, _b, signedType, scheme, payloadBase64, sigBase64, publicKey, found, _i, _c, authServerKey, verifyResult, roleData, targetRoleKey, rolesApplicable, _d, _e, role;
var _f;
return __generator(this, function (_g) {
srvConfig = op.server.config;
if (srvConfig.security.noauth) {
return [2, resolve(true)];
}
switch (srvConfig.type) {
case HttpBaseLib.EXPRESS:
authData = op.oriReq.headers.authorization;
apiRoleBook = op.server.apiAccess[op.api.handlerName];
if (!op.fromInternal && (apiRoleBook === null || apiRoleBook === void 0 ? void 0 : apiRoleBook['deny-all'])) {
op.returnJson(exports.HttpShimCode.error('AUTH_HEADER_SIGNED_BUT_API_DENIES_ALL', "API '".concat(op.api.method, " ").concat(op.api.fullpath, "' is set to deny-all")));
}
if (authData) {
if (authData.startsWith('Bearer ')) {
headerText = authData.split('Bearer ')[1];
if (headerText.startsWith('SIGNED.')) {
_b = headerText.split('.'), signedType = _b[0], scheme = _b[1], payloadBase64 = _b[2], sigBase64 = _b[3], publicKey = _b[4];
if (scheme === 'ECC_4Q') {
found = false;
for (_i = 0, _c = Object.keys(op.server.authServers); _i < _c.length; _i++) {
authServerKey = _c[_i];
if (op.server.authServers[authServerKey].publicKey === publicKey) {
found = true;
break;
}
}
if (!found) {
op.returnJson(exports.HttpShimCode.error('AUTH_HEADER_SIGNED_BUT_PUBLIC_KEY_NOT_FOUND'));
return [2, resolve(false)];
}
verifyResult = secure_channel_1.SecureHandshake.verifyStamp({ payload: payloadBase64, sig: sigBase64 }, publicKey);
if (verifyResult.bad) {
op.returnJson(verifyResult);
return [2, resolve(false)];
}
try {
roleData = JSON.parse(Buffer.from(payloadBase64, 'base64').toString('utf8'));
op.user = {
username: roleData.name,
publicKeys: roleData.publicKey,
roles: roleData.server[op.server.config.name],
rolesApplicable: null,
};
targetRoleKey = void 0;
if (apiRoleBook && !apiRoleBook['allow-all']) {
targetRoleKey = Object.keys(apiRoleBook);
rolesApplicable = [];
for (_d = 0, _e = op.user.roles; _d < _e.length; _d++) {
role = _e[_d];
if (apiRoleBook[role]) {
rolesApplicable.push(role);
}
}
op.user.rolesApplicable = rolesApplicable;
if (!((_f = op.user.rolesApplicable) === null || _f === void 0 ? void 0 : _f.length)) {
op.returnJson(exports.HttpShimCode.error('AUTH_HEADER_SIGNED_ROLE_UNAUTHORZIED_FOR_API', "API '".concat(op.api.method, " ").concat(op.api.fullpath, "' as user '").concat(op.user.username, "' with roles [").concat(op.user.roles.join(', '), "] ") +
"has no authorizable match for the API requiring [".concat(targetRoleKey.join(', '), "]")));
return [2, resolve(false)];
}
}
}
catch (e) {
op.returnJson(exports.HttpShimCode.error('AUTH_HEADER_SIGNED_NO_ROLES_MAP'));
return [2, resolve(false)];
}
return [2, resolve(true)];
}
}
else if (headerText.startsWith('SYMNT_HASH.')) {
}
}
op.returnJson(exports.HttpShimCode.error('AUTH_HEADER_NOT_VALID'));
return [2, resolve(false)];
}
else {
op.returnJson(exports.HttpShimCode.error('AUTH_HEADER_NOT_FOUND'));
return [2, resolve(false)];
}
break;
}
return [2];
});
}); })];
});
});
};
PreHandler.prototype.basic = function (op) {
return __awaiter(this, void 0, void 0, function () {
var _this = this;
return __generator(this, function (_b) {
return [2, (0, globals_ix_1.promise)(function (resolve) { return __awaiter(_this, void 0, void 0, function () {
var errored_1, chunks_1;
return __generator(this, function (_b) {
switch (op.server.config.type) {
case HttpBaseLib.EXPRESS:
op.oriRes.header('Content-Type', 'application/json');
errored_1 = false;
chunks_1 = [];
op.oriReq.on('data', function (chunk) {
chunks_1.push(chunk);
});
op.oriReq.on('end', function () {
try {
op.req.params = op.oriReq.params ? op.oriReq.params : {};
var queryParamNames = void 0;
if (op.oriReq.query && (queryParamNames = Object.keys(op.oriReq.query)).length > 0) {
for (var _i = 0, queryParamNames_1 = queryParamNames; _i < queryParamNames_1.length; _i++) {
var queryParamName = queryParamNames_1[_i];
op.req.params[queryParamName] = op.oriReq.query[queryParamName];
}
}
op.req.bodyRaw = Buffer.concat(chunks_1);
var bod = op.req.body = op.req.bodyRaw.toString();
if (op.oriReq.headers['encrypted-api']) {
op.req.encryptedPayload = bod;
var prepareResult = op.server.prepareEncryptedOperation(op);
if (prepareResult.bad) {
op.raise(prepareResult);
return resolve(false);
}
}
else {
op.params = op.req.params;
op.req.body = op.req.bodyRaw.toString();
if (isJsonString(op.req.body)) {
try {
op.req.data = JSON.parse(op.req.body);
if (typeof op.req.data === 'object' && !Array.isArray(op.req.data)) {
Object.assign(op.req.params, op.req.data);
}
}
catch (e) {
console.error('BAD_JSON', e);
}
}
}
resolve(true);
}
catch (e) {
console.error(e);
}
});
op.oriReq.on('error', function (e) {
console.error(e);
errored_1 = true;
resolve(false);
});
break;
}
return [2];
});
}); })];
});
});
};
PreHandler.prototype.optionalDecrypt = function (op) {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_b) {
return [2, new Promise(function (resolve) {
})];
});
});
};
return PreHandler;
}());
exports.PreHandler = PreHandler;
var PostHandler = (function () {
function PostHandler() {
var _b;
this.byType = {};
this.byType = (_b = {},
_b[ReqProcessor.BASIC] = this.basic,
_b[ReqProcessor.ENCRYPT] = this.optionalEncrypt,
_b);
}
PostHandler.prototype.basic = function (op) {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_b) {
return [2, new Promise(function (resolve) {
switch (op.server.config.type) {
case HttpBaseLib.EXPRESS:
resolve(true);
break;
}
})];
});
});
};
PostHandler.prototype.optionalEncrypt = function (op) {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_b) {
return [2, new Promise(function (resolve) {
switch (op.server.config.type) {
case HttpBaseLib.EXPRESS:
resolve(true);
break;
}
})];
});
});
};
return PostHandler;
}());
exports.PostHandler = PostHandler;
var CacheParser;
(function (CacheParser) {
CacheParser["JSON"] = "JSON";
})(CacheParser = exports.CacheParser || (exports.CacheParser = {}));
var CacheDef = (function () {
function CacheDef(init) {
this.keys = null;
this.keysExceptLast = null;
this.lastKey = null;
this.maxOld = 0;
this.matchExactly = false;
this.defStack = '';
if (init) {
Object.assign(this, init);
}
if (this.path.indexOf('/') >= 0) {
this.keys = [];
var keys = this.path.split('/').slice(1);
for (var _i = 0, keys_1 = keys; _i < keys_1.length; _i++) {
var keyname = keys_1[_i];
if (keyname.startsWith(':')) {
this.keys.push({ name: keyname.split(':')[1], type: 'param' });
}
else {
this.keys.push({ name: keyname, type: 'fixed' });
}
}
this.lastKey = this.keys[this.keys.length - 1];
this.keysExceptLast = this.keys.slice(0, -1);
}
if (!this.serializer) {
this.serializer = CacheParser.JSON;
}
}
return CacheDef;
}());
exports.CacheDef = CacheDef;
var CacheEntry = (function () {
function CacheEntry(init) {
if (init) {
Object.assign(this, init);
}
}
CacheEntry.prototype.asResponse = function () {
if (this.serializedResponse) {
return this.serializedResponse;
}
};
CacheEntry.prototype.asSerialized = function () { return this.serialized; };
CacheEntry.prototype.getData = function (option) {
var nav = this.keyNavigate(option);
return nav.target[nav.key];
};
CacheEntry.prototype.keyNavigate = function (option) {
if (this.def.keys) {
if (!this.rootNode) {
this.rootNode = {};
}
var node = this.rootNode;
for (var _i = 0, _b = this.def.keysExceptLast; _i < _b.length; _i++) {
var keyInfo = _b[_i];
var key = this.resolvePathKey(keyInfo, option);
if (!node[key]) {
node[key.name] = {};
}
node = node[key];
}
var lastKeyStr = this.resolvePathKey(this.def.lastKey, option);
return { key: lastKeyStr, target: node };
}
else {
return { key: 'value', target: this };
}
};
CacheEntry.prototype.resolvePathKey = function (keyInfo, opt) {
var _b;
var key;
if (keyInfo.type === 'fixed') {
key = keyInfo.name;
}
else {
if (!(opt === null || opt === void 0 ? void 0 : opt.pathParams)) {
throw new Error("Cannot naviagate cache path '".concat(this.def.path, "'. param not given"));
}
var paramValue = (_b = opt === null || opt === void 0 ? void 0 : opt.pathParams) === null || _b === void 0 ? void 0 : _b[keyInfo.name];
if (!paramValue) {
throw new Error("Cannot naviagate cache path '".concat(this.def.path, "'. param '").concat(keyInfo.name, "' not found"));
}
key = paramValue;
}
if (!key) {
throw new Error("Cannot naviagate cache path '".concat(this.def.path, "; Params = ").concat(opt.pathParams));
}
return key;
};
return CacheEntry;
}());
exports.CacheEntry = CacheEntry;
var HttpCacheOp = (function () {
function HttpCacheOp(op) {
this.op = op;
}
HttpCacheOp.prototype.handler = function (cacheDef, option, dataResolver) {
return __awaiter(this, void 0, void 0, function () {
var entry, matched;
var _this = this;
return __generator(this, function (_b) {
if (!option) {
option = {};
}
if (!option.pathParams) {
option.pathParams = {};
}
if (this.op.req.params) {
Object.assign(option.pathParams, this.op.req.params);
}
entry = this.cacheEntryGet(cacheDef, option);
matched = entry ? true : false;
return [2, this.op.addSequentialProcess(new Promise(function (procResolve) {
var resolve = function (data, cacheEntry) {
if (matched && (cacheEntry === null || cacheEntry === void 0 ? void 0 : cacheEntry.serializedResponse)) {
_this.op.setResponse(cacheEntry.serializedResponse);
return procResolve();
}
var dataString;
var responseString;
switch (cacheDef.serializer) {
case CacheParser.JSON:
dataString = option.serialized = JSON.stringify(data);
responseString = option.serializedResponse = _this.op.res.okJsonPreserialized(dataString);
break;
}
_this.cacheSet(cacheDef, data, option);
_this.op.setResponse(responseString);
return procResolve();
};
var reject = function (result) {
_this.op.raise(result);
return procResolve();
};
if (matched) {
resolve(entry.getData(option), entry);
}
else {
try {
dataResolver(resolve, reject);
}
catch (e) {
_this.op.raise(exports.HttpShimCode.error('CACHE_DATA_FETCH_FAILED'), http_models_1.HttpCode.INTERNAL_SERVER_ERROR);
return procResolve();
}
}
}))];
});
});
};
HttpCacheOp.prototype.cacheEntryGet = function (cacheDef, option) {
var cacheData = this.op.server.cacheData[cacheDef.path];
if (!cacheData || !cacheData.hasValue) {
return null;
}
var matchExactly = cacheDef.matchExactly ? true : (option.matchExactly ? true : false);
if (matchExactly) {
if (option && option.version && option.version !== cacheData.version) {
return null;
}
}
else {
if (cacheData.def.maxOld !== 0 &&
Date.now() - cacheData.version > cacheData.def.maxOld) {
return null;
}
}
++cacheData.hits;
return cacheData;
};
HttpCacheOp.prototype.cacheSet = function (cacheDef, value, option) {
if (!this.op.server.cacheData[cacheDef.path]) {
throw new Error("Cache key '".concat(cacheDef.path, "' is not defined ahead-of-time for this server."));
}
var cacheData = this.op.server.cacheData[cacheDef.path];
var setter = cacheData.keyNavigate(option);
setter.target[setter.key] = value;
if (option === null || option === void 0 ? void 0 : option.version) {
cacheData.version = option.version;
}
else {
cacheData.version = Date.now();
}
if (option === null || option === void 0 ? void 0 : option.serialized) {
cacheData.serialized = option.serialized;
}
if (option === null || option === void 0 ? void 0 : option.serializedResponse) {
cacheData.serializedResponse = option.serializedResponse;
}
cacheData.hasValue = true;
return cacheData;
};
HttpCacheOp.prototype.cacheUnset = function (cacheDef) {
var cacheData = this.op.server.cacheData[cacheDef.path];
if (cacheData) {
cacheData.hasValue = false;
}
return cacheData;
};
return HttpCacheOp;
}());
exports.HttpCacheOp = HttpCacheOp;
function expressHandler(server, api) {
var _this = this;
return function (oriReq, oriRes) { return __awaiter(_this, void 0, void 0, function () {
var op;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
op = new HttpOp(server, api, oriReq, oriRes);
op.method = oriReq.method;
return [4, op.run()];
case 1:
_b.sent();
return [2];
}
});
}); };
}
function isJsonString(str) {
return (str.startsWith('{') && str.endsWith('}')) || (str.startsWith('[') && str.endsWith(']'));
}
//# sourceMappingURL=http.shim.js.map