zcatalyst-cli
Version:
Command Line Tool for CATALYST
377 lines (376 loc) • 20.2 kB
JavaScript
;
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);
})
};