UNPKG

ts-comply

Version:

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

153 lines (140 loc) 6.25 kB
/* * Copyright 2014-2021 Firestack, all rights reserved. */ import { passthru, passthruError, ReturnCodeFamily } from '../../../src/common/globals.ix'; import { HttpServerShim, HTTP, HttpBaseLib, HttpOp, ReqProcessor, ParamDef, HttpOpType } from '../http.shim'; import * as fs from 'fs'; import { HttpCode } from '../http.models'; import { envVar } from '../../../src/common/env/env.profile'; import { as, required } from '../../../src/type-transform'; import { parseProperties } from '../../../src/common/util/convenience/properties.parse'; import { pathNavigate } from '../../util/node-util'; import { SecureChannelTypes } from '../../../src/common/security/security.common'; const scopeName = `destor;pid=${process.pid}`; enum DestorCodeEnum { DESTOR_RESOLVE_CONFIG_APP_PROFILE_NOT_FOUND, DESTOR_AUTH_SERVER_APP_PROFILE_NOT_FOUND, DESTOR_SECRET_NOT_FOUND, } export const DestorCode = ReturnCodeFamily('DestorCode', DestorCodeEnum); let localData; let destorData; function getConf() { localData = parseProperties(fs.readFileSync(process.env.DESTOR_SERVER_CONFIG_FILE, 'utf8')); destorData = localData.destor; return localData; } export class DestorServer extends HttpServerShim { dataResolution: 'local-file' | 'remote' = envVar('DESTOR_SERVER_DATA_RESOLUTION', 'local-file'); constructor() { super({ name: 'destor', type: HttpBaseLib.EXPRESS, scopeName, security: { accessor: { required: true, baseToken: process.env.DESTOR_SERVER_BASE_TOKEN }, secureChannel: { enabled: true, required: true, encryption: SecureChannelTypes.ECC_4Q, signingKey: process.env.DESTOR_SERVER_SIGNING_KEY }, }, startOptions: { port: process.env.DESTOR_SERVER_PORT ? parseInt(process.env.DESTOR_SERVER_PORT, 10) : 17070 }, skipConfigSecretResolution: true, }); this.apiVersion = 'v1'; this.apiPath = this.configGlobal.destor.basePath; this.addDefaultProcessor(ReqProcessor.BASIC); getConf(); if (this.dataResolution === 'local-file') { setInterval(() => { try { getConf() } catch (e) { console.error(e); } }, 30000); } } @HTTP.GET(`/`, { rootMount: true }) async rootProofOfAuthenticity(op: HttpOp) { const accessorResult = this.checkAccessor(op); if (accessorResult.bad) { return passthruError(accessorResult); } const stamp = await this.stamp(); return op.res.returnJson({ ...stamp }); } getResolvConfig_iface = { path: `/resolve-config/:env`, description: ``, params: { env: { required, type: `string`, default: as<string>(), description: `` }, targets: { required, type: `string`, default: as<string>(), description: `` }, }, returns: { type: `{[key: string]: {value: any, error?: string}}`, default: as<{[key: string]: {value: any, error?: string}}>() }, }; @HTTP.GET(`/resolve-config/:env`, { rootMount: true }) async getResolveConfig(op: HttpOpType<typeof this.getResolvConfig_iface>) { const targets = op.params.targets.split('|').map(target => { target = target.trim(); while (target.startsWith('<') && target.endsWith('>')) { target = target.slice(1, -1); } return target; }); if (this.dataResolution === 'local-file') { if (!localData?.profiles?.[op.params.env]) { return op.raise(DestorCode.error('DESTOR_RESOLVE_CONFIG_APP_PROFILE_NOT_FOUND', `application profile env '${op.params.env}' not found on destor config`)); } const result: {[key: string]: {value: any, error?: string}} = {}; for (const targetStr of targets) { const lit = targetStr.split('?:'); const targetPathStr = lit[0]?.trim(); const defaultValueDef = lit[1]?.trimStart(); let defaultValue: any; if (defaultValueDef) { if (defaultValueDef.indexOf(':') >= 0) { const dfLit = defaultValueDef.split(':'); const dfType = dfLit[0]; const dfValueStr = dfLit.slice(1).join(':'); if (dfType === 'number') { defaultValue = +dfValueStr; } else if (dfType === 'boolean') { defaultValue = dfValueStr.toLowerCase() === 'true' ? true : false; } else if (dfType === 'string') { defaultValue = dfValueStr; } } else { defaultValue = defaultValueDef; } } const targetPath = targetPathStr.split('.'); if (targetPath[0] !== 'config' && targetPath[0] !== 'secret') { result[targetStr] = { value: null, error: `resolvable path must start with 'config' or 'secret', got '${targetPath[0]}'` }; continue; } let resolved = pathNavigate(targetPath, localData?.profiles?.[op.params.env]); if (resolved === null) { resolved = pathNavigate(targetPath, localData?.global); } const resObj: {value: any, error?: string} = { value: resolved }; if (resolved === null) { if (defaultValueDef) { resObj.value = defaultValue; } else { resObj.error = `not_found`; } } result[targetStr] = resObj; } op.returnJson(result); } } getAuthServer_iface = { path: `/auth-servers/:env`, description: ``, params: { env: { required, type: `string`, default: as<string>(), description: `` }, }, returns: { type: `{[name: string]: { url: string, type: string, publicKey: string }}`, default: as<{[name: string]: { url: string, type: string, publicKey: string }}>() }, }; @HTTP.GET(`/auth-servers/:env`, { rootMount: true }) async getAuthServer(op: HttpOpType<typeof this.getAuthServer_iface>) { if (this.dataResolution === 'local-file') { if (!localData?.profiles?.[op.params.env]) { return op.raise(DestorCode.error('DESTOR_AUTH_SERVER_APP_PROFILE_NOT_FOUND', `application profile env '${op.params.env}' not found on destor config`)); } let data = pathNavigate(['config', 'authServers'], localData?.profiles?.[op.params.env]); if (data === null) { data = pathNavigate(['config', 'authServers'], localData?.global); } return op.returnJson(data); } } }