UNPKG

zcatalyst-cli

Version:

Command Line Tool for CATALYST

377 lines (376 loc) 20.2 kB
'use strict'; 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 __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.apigUtils = void 0; const ansi_colors_1 = require("ansi-colors"); const util_1 = require("util"); const client_utils_1 = require("./client-utils"); const index_js_1 = __importDefault(require("./error/index.js")); const execute_script_1 = __importDefault(require("./execute-script")); const fn_utils_1 = require("./fn-utils"); const runtime_store_1 = __importDefault(require("./runtime-store")); const config_1 = require("./util_modules/config"); const constants_1 = require("./util_modules/constants"); const fs_1 = require("./util_modules/fs"); const js_1 = require("./util_modules/js"); const index_1 = require("./util_modules/logger/index"); const option_1 = require("./util_modules/option"); const project_1 = require("./util_modules/project"); exports.apigUtils = { validate: () => __awaiter(void 0, void 0, void 0, function* () { const ruleFile = (0, project_1.resolveProjectPath)(config_1.apigConfig.rules()); const ruleArr = (yield fs_1.ASYNC.readJSONFile(ruleFile, { checkpath: true, throws: true }).catch((err) => { throw new index_js_1.default('Unable to read ' + ruleFile + ' file.', { exit: 1, errorId: 'APIG-UTILS-1', arg: [(0, ansi_colors_1.bold)(ruleFile), ansi_colors_1.italic.red(err)], original: err }); })); if (ruleArr === undefined) { throw new index_js_1.default(ruleFile + ' file not found' + constants_1.FILENAME.config, { exit: 1, errorId: 'APIG-UTILS-2', arg: [ansi_colors_1.bold.red(ruleFile), (0, ansi_colors_1.bold)(constants_1.FILENAME.config)] }); } let localRuleArr = []; let redirectPath; try { yield client_utils_1.clientUtils.validate({ skipPluginValidation: true }); const homepage = runtime_store_1.default.get('context.client.homepage', 'index.html'); const loginRedirect = runtime_store_1.default.get('context.client.login_redirect', homepage); if (typeof loginRedirect === 'string') { redirectPath = loginRedirect.startsWith('/') ? loginRedirect : '/app/' + loginRedirect; } } catch (e) { (0, index_1.debug)(index_js_1.default.getErrorInstance(e).message); } let redirectIdx = -1; const namesArr = []; const sourceUrlByConfig = {}; localRuleArr = ruleArr.map((rule, index) => { var _a, _b; if (rule.name === undefined || rule.name === null) { throw new index_js_1.default('Name for an APIG rule is missing', { exit: 1, errorId: 'APIG-UTILS-3', arg: [ansi_colors_1.italic.red(JSON.stringify(rule, null, ' '))] }); } if (namesArr.includes(rule.name)) { throw new index_js_1.default('Duplicate APIG rule detected', { exit: 1, errorId: 'APIG-UTILS-4', arg: [ansi_colors_1.bold.red(rule.name)] }); } namesArr.push(rule.name); if (rule.source_endpoint === undefined || rule.source_endpoint === null) { throw new index_js_1.default('source_endpoint missing for rule ' + rule.name, { exit: 1, errorId: 'APIG-UTILS-5', arg: [ansi_colors_1.bold.red(rule.name), (0, ansi_colors_1.bold)('source_endpoint')] }); } if (rule.method === undefined || rule.method === null) { throw new index_js_1.default('method missing for rule ' + rule.name, { exit: 1, errorId: 'APIG-UTILS-5', arg: [ansi_colors_1.bold.red(rule.name), (0, ansi_colors_1.bold)('method')] }); } if (sourceUrlByConfig[rule.source_endpoint] !== undefined && sourceUrlByConfig[rule.source_endpoint][rule.method] !== undefined) { const duplicateRuleName = sourceUrlByConfig[rule.source_endpoint][rule.method] || ''; throw new index_js_1.default(rule.name + 'has duplicate "source_endpoint" as ' + duplicateRuleName, { exit: 1, errorId: 'APIG-UTILS-6', arg: [ (0, ansi_colors_1.bold)(rule.name), (0, ansi_colors_1.bold)('source_endpoint'), ansi_colors_1.italic.red(rule.source_endpoint), (0, ansi_colors_1.bold)(duplicateRuleName) ] }); } if (sourceUrlByConfig[rule.source_endpoint] === undefined) { sourceUrlByConfig[rule.source_endpoint] = {}; } sourceUrlByConfig[rule.source_endpoint][rule.method] = rule.name; if (rule.name === 'Login Redirect') { const homepage = runtime_store_1.default.get('context.client.homepage'); const clientValidity = runtime_store_1.default.get('context.client.valid', false); if (!clientValidity || (redirectPath === undefined && homepage === undefined)) { throw new index_js_1.default('Login Redirect rule cannot be verified since client package is not valid', { exit: 1, errorId: 'APIG-UTILS-7', arg: [(0, ansi_colors_1.bold)(rule.name)] }); } else if (!redirectPath) { redirectPath = '/app/' + homepage; } redirectIdx = index; runtime_store_1.default.set('context.client.login_redirect', rule.source_endpoint); if (rule.target_endpoint && rule.target_endpoint !== redirectPath) { (0, index_1.debug)('Login redirect - target_endpoint is modified to match the local client'); } rule.target_endpoint = redirectPath; if (rule.method && rule.method !== 'GET') { (0, index_1.debug)('Login redirect - method is modified to match the local client'); } rule.method = 'GET'; rule.system = true; } if ((_a = rule.target_endpoint) === null || _a === void 0 ? void 0 : _a.match('/baas/v1/project/([0-9]+)/function/([0-9A-Za-z_]+)/execute')) { const identifier = rule.target_endpoint.split('/')[6]; rule.target_endpoint = '/server/' + identifier + '/execute'; } if (rule.target === 'client' || ((_b = rule.target_endpoint) === null || _b === void 0 ? void 0 : _b.startsWith('/app/'))) { if (rule.authentication !== undefined && rule.authentication !== null) { throw new index_js_1.default('client target cannot have authentication, for rule name : ' + rule.name, { exit: 1, errorId: 'APIG-UTILS-8', arg: [(0, ansi_colors_1.bold)(rule.name), ansi_colors_1.italic.red('"authentication"')] }); } } const { created_by, created_time, modified_by, modified_time, api_id } = rule, remaining = __rest(rule, ["created_by", "created_time", "modified_by", "modified_time", "api_id"]); if (remaining.target === 'client') { delete remaining.target_id; } return js_1.JS.removeNullAndUndefined(remaining); }); if (redirectIdx === -1 && redirectPath !== undefined) { localRuleArr.push({ name: 'Login Redirect', source_endpoint: redirectPath, target_endpoint: redirectPath, target: 'client', method: 'GET', throttling: { overall: {}, ip: {} }, system: true }); } const content = JSON.stringify(localRuleArr, null, 2) + '\n'; yield fs_1.ASYNC.writeFile(ruleFile, content, 'utf8'); runtime_store_1.default.set('context.apig.source', ruleFile); return [...localRuleArr, ...constants_1.APIG_RULES]; }), compile: (ruleArr) => { const localConfig = {}; ruleArr.forEach((rule) => { const { source_endpoint, method } = rule, otherProps = __rest(rule, ["source_endpoint", "method"]); const sourceUrl = source_endpoint .split('/') .map((part, currentIdx, allParts) => { if (part.startsWith('{')) { const regexParts = part.slice(1, -1).split(':'); if (regexParts.length !== 2) { throw new index_js_1.default('Invalid regex format', { errorId: 'APIG-UTILS-15', exit: 1, arg: [ (0, ansi_colors_1.red)(rule.name), ansi_colors_1.italic.green(`"{var:regex}"`), (0, ansi_colors_1.bold)('var'), (0, ansi_colors_1.bold)('regex') ] }); } try { rule.name, new RegExp(regexParts[1]); } catch (regexError) { const err = index_js_1.default.getErrorInstance(regexError, { message: 'source_endpoint provided for apig rule "' + rule.name + '" is not valid', skipHelp: false }); err.errorId = 'APIG-UTILS-9'; err.arg = [ (0, ansi_colors_1.bold)('source_endpoint'), (0, ansi_colors_1.bold)(rule.name), (0, ansi_colors_1.italic)(source_endpoint.replace(part, (0, ansi_colors_1.red)(part))), (0, ansi_colors_1.bold)('Error: ') + ansi_colors_1.italic.red((0, util_1.inspect)(regexError)) ]; throw err; } if (regexParts[1].includes('^') || regexParts[1].includes('$')) { throw new index_js_1.default('source_endpoint provided for apig rule "' + rule.name + '" is not valid. ' + 'Url should not contain ^ or $ symbols', { exit: 1, errorId: 'APIG-UTILS-10', arg: [ (0, ansi_colors_1.bold)('source_endpoint'), (0, ansi_colors_1.bold)(rule.name), (0, ansi_colors_1.italic)(source_endpoint.replace(part, (0, ansi_colors_1.red)(part))), (0, ansi_colors_1.bold)('Error: ') + ansi_colors_1.italic.red('Regular Expression(s) in the source_endpoint should not contain ^ or $ symbols') ] }); } if (regexParts[1].includes('.*') && currentIdx !== allParts.length - 1) { throw new index_js_1.default('source url provided for apig rule "' + rule.name + '" is not valid. ' + 'Url should not contain wildcard character in the mid of path', { exit: 1, errorId: 'APIG-UTILS-10', arg: [ (0, ansi_colors_1.bold)('source_endpoint'), (0, ansi_colors_1.bold)(rule.name), (0, ansi_colors_1.italic)(source_endpoint.replace(part, (0, ansi_colors_1.red)(part))), (0, ansi_colors_1.bold)('Error: ') + ansi_colors_1.italic.red('Regular Expression(s) in the source_endpoint with the wildcard character(.*)' + ' is only allowed to be present at the last section of the endpoint') ] }); } let actualRegex = regexParts[1]; actualRegex = actualRegex.replace('(.*)', '*'); actualRegex = actualRegex.replace('.', '[\\s\\S]'); if (actualRegex.startsWith('(') && actualRegex.endsWith(')')) { actualRegex = actualRegex.slice(1, -1); } return `:${regexParts[0]}(${actualRegex})`; } return part; }) .join('/'); if (!otherProps.system && otherProps.name === 'Login Redirect') { throw new index_js_1.default('Login Redirect is a system reserved name. Please define it as system value', { exit: 2 }); } if (otherProps.target_endpoint === undefined) { switch (otherProps.target) { case 'client': case 'advancedio': throw new index_js_1.default('"target_endpoint"(mandatory) is missing, for rule name : ' + otherProps.name, { exit: 1, errorId: 'APIG-UTILS-11', arg: [(0, ansi_colors_1.bold)(otherProps.name), (0, ansi_colors_1.bold)('target_endpoint')] }); case 'basicio': if (otherProps.target_id === undefined) { throw new index_js_1.default('If target is function "target_id" is mandatory, for rule name : ' + otherProps.name, { exit: 1, errorId: 'APIG-UTILS-11', arg: [(0, ansi_colors_1.bold)(otherProps.name), (0, ansi_colors_1.bold)('target_id')] }); } const generatedUrl = fn_utils_1.fnUtils.common.generateUrlForTarget({ name: otherProps.target_id, type: constants_1.REFERENCE.functions.type[otherProps.target], source: '', build: '', valid: true }); if (generatedUrl === undefined) { throw new index_js_1.default('"target" provided for function is not a valid one. Please specify if basicio or advancedio, for rule name : ' + otherProps.name, { exit: 2 }); } otherProps.target_endpoint = '/' + generatedUrl.replace('https://', '').split('/').slice(1).join('/'); break; default: if (otherProps.target === undefined) { throw new index_js_1.default('target_endpoint and target both are undefined for rule name : ' + otherProps.name, { exit: 1, errorId: 'APIG-UTILS-12', arg: [ (0, ansi_colors_1.bold)(otherProps.name), (0, ansi_colors_1.bold)('target_endpoint'), (0, ansi_colors_1.bold)('target') ] }); } throw new index_js_1.default('invalid target in APIG rule: ' + otherProps.name, { exit: 1, errorId: 'APIG-UTILS-13', arg: [ (0, ansi_colors_1.bold)('target'), ansi_colors_1.italic.red(otherProps.target), (0, ansi_colors_1.bold)(otherProps.name), (0, ansi_colors_1.bold)(['* client', '* advancedio', '* basicio'].join('\n')) ] }); } } if (!otherProps.target_endpoint.startsWith('/baas/') && !otherProps.target_endpoint.startsWith('/app/') && !otherProps.target_endpoint.startsWith('/server/') && !otherProps.target_endpoint.startsWith('/oauthorize') && !otherProps.target_endpoint.startsWith('/__catalyst/')) { throw new index_js_1.default('target_endpoint is not recognized for rule name : ' + otherProps.name, { exit: 1, errorId: 'APIG-UTILS-14', arg: [ (0, ansi_colors_1.bold)('target_endpoint'), ansi_colors_1.italic.red(otherProps.target_endpoint), (0, ansi_colors_1.bold)(otherProps.name) ] }); } if (method === 'ANY') { js_1.JS.set(localConfig, [sourceUrl, 'all'], otherProps); } else { js_1.JS.set(localConfig, [sourceUrl, method.toLowerCase()], otherProps); } }); if (Object.keys(localConfig).length > 0) { runtime_store_1.default.set('context.apig.local.config', localConfig); } return localConfig; }, executeHook: ({ prefix, command }) => __awaiter(void 0, void 0, void 0, function* () { if ((0, option_1.getOptionValue)('ignoreScripts', false)) { (0, index_1.debug)(`skipping ${prefix + command} hook`); return; } const exeCommand = config_1.apigConfig.script(prefix + command, null); if (exeCommand === null) { return; } return (0, execute_script_1.default)('apig:' + prefix + command); }), pack: () => __awaiter(void 0, void 0, void 0, function* () { const file = (0, project_1.resolveProjectPath)(config_1.apigConfig.rules()); return fs_1.SYNC.getReadStream(file); }) };