"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.HandlerBarHelper = void 0;
const handlebars_1 = __importDefault(require("handlebars"));
const moment_1 = __importDefault(require("moment"));
// @ts-ignore
const uuid_1 = require("uuid");
// @ts-ignore
const jsonpath_1 = __importDefault(require("jsonpath"));
const logger_1 = __importDefault(require("../logger"));
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
/**
* Defines and registers custom handlebar helpers now, randomValue, capture and num_between
*/
class HandlerBarHelper {
constructor() {
/**
* Registers now helper
* - If now helper is called without a format, set a default format as YYYY-MM-DD hh:mm:ss else use the format provided
* - Set default offset to be used if offset is not specified. Default offset is 0s i.e. no offset
* - If offset is defined the value will be stored in context.hash.offset, eg X days.
* - Split value by a space, first element will be the amount of offset i.e. X, second element will be unit of offset, i.e. days
* - Return a value with specified format and added offset
* @returns {void}
*/
this.nowHelper = () => {
handlebars_1.default.registerHelper("now", (context) => {
const format = typeof context.hash.format === "undefined" ? "YYYY-MM-DD hh:mm:ss" : context.hash.format;
let offsetUnit = "s";
let offsetAmount = 0;
if (typeof context.hash.offset !== "undefined") {
let offset = context.hash.offset.split(" ");
offsetAmount = offset[0];
offsetUnit = offset[1];
}
switch (format) {
case "epoch":
return moment_1.default().add(offsetAmount, offsetUnit).format("x");
case "unix":
return moment_1.default().add(offsetAmount, offsetUnit).format("X");
default:
return moment_1.default().add(offsetAmount, offsetUnit).format(format);
}
});
};
/**
* Registers randomValue helper
* - If length of randomValue is not specified, set default length to 16
* - If type of randomValue is not specified, set default type to ALPHANUMERIC
* - If uppercase is specified, and is of ALPHABETICAL or ALPHANUMERIC type, add _UPPER to the type
* - If type is UUID, return UUID, else generate a random value with specified type and length
* @returns {void}
*/
this.randomValueHelper = () => {
handlebars_1.default.registerHelper("randomValue", (context) => {
let length = typeof context.hash.length === "undefined" ? 16 : context.hash.length;
let type = typeof context.hash.type === "undefined" ? "ALPHANUMERIC" : context.hash.type;
if (context.hash.uppercase && type.includes("ALPHA")) {
type = type + "_UPPER";
}
if (type === "UUID") {
return uuid_1.v4();
}
else {
return this.randomString(length, this.genCharArray(type));
}
});
};
/**
* Registers capture helper
* - Get the request object passed in from the context by calling template({request: req})
* - Get the from value passed in while calling {{capture from=}}, accepted values query, headers, path, body
* - For query and headers, key is required, else if not found a null/undefined value will be automatically returned.
* - For path additional input regex is mandatory, if not passed return error
* - For body additional inputs using and selector are mandatory, if not passed return error
* @returns {void}
*/
this.requestHelper = () => {
handlebars_1.default.registerHelper("capture", (context) => {
const request = context.data.root.request;
const from = context.hash.from;
switch (from) {
case "query":
return request.query[context.hash.key];
case "headers":
return request.headers[context.hash.key];
case "path":
if (typeof context.hash.regex === "undefined") {
logger_1.default.debug("ERROR: No regex specified");
return "Please specify a regex with path";
}
else {
let regex = new RegExp(context.hash.regex);
if (regex.test(request.path)) {
return regex.exec(request.path)[1];
}
else {
logger_1.default.debug(`ERROR: No match found for specified regex ${context.hash.regex}`);
return "No match found.";
}
}
case "body":
if (typeof context.hash.using === "undefined" || typeof context.hash.selector == "undefined") {
logger_1.default.debug("ERROR: No selector or using values specified");
return "Please specify using and selector fields.";
}
else {
switch (context.hash.using) {
case "regex": {
let regex = new RegExp(context.hash.selector);
let body = JSON.stringify(request.body, null, 2);
if (regex.test(body)) {
return regex.exec(body)[1];
}
else {
logger_1.default.debug(`ERROR: No match found for specified regex ${context.hash.selector}`);
return "No match found.";
}
}
case "jsonpath": {
try {
return jsonpath_1.default.query(request.body, context.hash.selector);
}
catch (err) {
logger_1.default.debug(`ERROR: No match found for specified jsonpath ${context.hash.selector}`);
logger_1.default.error(`ERROR: ${err}`);
return "some error occuered";
}
}
default:
return null;
}
}
default:
return null;
}
});
};
/**
* Registers num_between helper
* - If lower or upper value is not passed, return 0
* - If lower value is greater than upper value, log error and return 0
* @returns {void}
*/
this.numBetweenHelper = () => {
handlebars_1.default.registerHelper("num_between", (context) => {
if (typeof context.hash.lower === "undefined" || typeof context.hash.upper === "undefined") {
logger_1.default.error("lower or upper value not specified.");
return 0;
}
else {
const lower = parseInt(context.hash.lower);
const upper = parseInt(context.hash.upper);
if (lower > upper) {
logger_1.default.error("lower value cannot be greater than upper value.");
return 0;
}
const num = Math.floor(Math.random() * (upper - lower + 1) + lower);
return num;
}
});
};
/**
* Registers file helper
* - If file path is not included in the defined handlebar, log an error.
* - If file path is passed, check if file exists and send the return value to HttpParser to process
* @returns {void}
*/
this.fileHelper = () => {
handlebars_1.default.registerHelper("file", (context) => {
if (typeof context.hash.path === "undefined") {
logger_1.default.error("File path not specified.");
}
else {
if (fs_1.default.existsSync(path_1.default.resolve(context.hash.path))) {
return `camouflage_file_helper=${path_1.default.resolve(context.hash.path)}`;
}
}
});
};
/**
* Registers code helper
* - Define request and logger in the scope of the code helper context, allowing user to use request, logger in their mock files
* - If file path is passed, check if file exists and send the return value to HttpParser to process
* - Evaluate the response of the function passed in and return the resulting response object to HttpParser
* @returns {void}
*/
this.codeHelper = () => {
handlebars_1.default.registerHelper("code", (context) => {
/* eslint-disable no-unused-vars */
const request = context.data.root.request;
const logger = context.data.root.logger;
/* eslint-disable no-unused-vars */
const code = eval(context.fn(this));
code["CamouflageResponseType"] = "code";
return JSON.stringify(code);
});
};
/**
* Registers inject helper
* - Define request and logger in the scope of the code helper context
* - Evaluate the response of the function passed in and return the resulting response object to HttpParser
* @returns {void}
*/
this.injectHelper = () => {
handlebars_1.default.registerHelper("inject", (context) => {
const request = context.data.root.request;
const logger = context.data.root.logger;
const result = eval(context.fn(this));
return result;
});
};
/**
* Generates an random sequence of characters
* @param {number} length - length of generated string
* @param {string} chars - A sequence of valid characters for a specified type returned by genCharArray
* @returns {string} A random sequence of characters of specified length
*/
this.randomString = (length, chars) => {
var result = "";
if (typeof chars === "undefined") {
this.randomFixedInteger(length);
}
else {
for (var i = length; i > 0; --i)
result += chars[Math.floor(Math.random() * chars.length)];
}
return result;
};
/**
* Generates an random number of given length
* @param {number} length - length of number of be generated
* @returns {number} A number of specified length. i.e. 10 digit number: 2341912498
*/
this.randomFixedInteger = (length) => {
return Math.floor(Math.pow(10, length - 1) + Math.random() * (Math.pow(10, length) - Math.pow(10, length - 1) - 1));
};
/**
* Generates an string of characters to be used by randomString function for randomizing.
* @param {string} type - Type of random value to be generated
* @returns {string} A string of squence of valid characters according to type
*/
this.genCharArray = (type) => {
let alphabet;
/**
* Create a numbers array of [0...9]
*/
let numbers = [...Array(10)].map((x, i) => i);
switch (type) {
case "ALPHANUMERIC":
/**
* If type is ALPHANUMERIC, return a string with characters [a-z][A-Z][0-9]
* */
alphabet = [...Array(26)].map((x, i) => String.fromCharCode(i + 97) + String.fromCharCode(i + 65));
return alphabet.join("") + numbers.join("");
case "ALPHANUMERIC_UPPER":
/**
* If type is ALPHANUMERIC_UPPER, return a string with characters [A-Z][0-9]
*/
alphabet = [...Array(26)].map((x, i) => String.fromCharCode(i + 65));
return alphabet.join("") + numbers.join("");
case "ALPHABETIC":
/**
* If type is ALPHABETIC, return a string with characters [a-z][A-Z]
*/
alphabet = [...Array(26)].map((x, i) => String.fromCharCode(i + 97) + String.fromCharCode(i + 65));
return alphabet.join("");
case "ALPHABETIC_UPPER":
/**
* If type is ALPHABETIC_UPPER, return a string with characters [A-Z]
*/
alphabet = [...Array(26)].map((x, i) => String.fromCharCode(i + 65));
return alphabet.join("");
case "NUMERIC":
/**
* If type is NUMERIC, return a string with characters [0-9]
*/
return numbers.join("");
default:
break;
}
};
}
}
exports.HandlerBarHelper = HandlerBarHelper;
//# sourceMappingURL=handleBarDefinition.js.map