diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..b07b2dd --- /dev/null +++ b/.prettierrc @@ -0,0 +1,5 @@ +{ + "useTabs": false, + "tabWidth": 4, + "singleQuote": true +} diff --git a/app.js b/app.js index 329c48b..a6c012e 100644 --- a/app.js +++ b/app.js @@ -1,26 +1,21 @@ -require('dotenv').config() - +require('dotenv').config(); const figlet = require('figlet'); const chalk = require('chalk'); -console.log('-----------------------------------') -console.log( - figlet.textSync('HASH', { horizontalLayout: 'full' }) -); +console.log('-----------------------------------'); +console.log(figlet.textSync('HASH', { horizontalLayout: 'full' })); console.log(' HTTP Agnostic Software Honeypot '); console.log('-----------------------------------'); const logger = require('./libs/log'); - logger.info('App -> Starting HASH '); - -let appName = 'default'; //default app -//overwrite by environment variable or the cli -appName = process.env.HONEYPOT_PROFILE || process.argv.slice(2)[0]; +let appName = 'default'; //default app +//overwrite by environment variable or the cli +appName = process.env.HONEYPOT_PROFILE || process.argv.slice(2)[0]; -logger.info('App -> Loading Application: ' + appName) -const app = require('./libs/app')(__dirname, appName) +logger.info('App -> Loading Application: ' + appName); +const app = require('./libs/app')(__dirname, appName); app.logger = logger; const config = require('./libs/config')(app); @@ -31,35 +26,33 @@ const http = require('./libs/init')(app); const { Cache } = require('./libs/randomizer'); Cache.reset(); -//reset cache every 10 min (1000 * 60 * 10) +//reset cache every 10 min (1000 * 60 * 10) setInterval(() => { Cache.reset(); }, 600000); - //loading templates const Template = require('./libs/template'); const template = new Template(app); const { templates, dynamicTemplates } = template.load(); -//simulate +//simulate const Simulator = require('./libs/simulator'); const simulator = new Simulator(app, http, templates, dynamicTemplates); -simulator.apply() +simulator.apply(); //overwrite express error handler http.use((err, req, res, next) => { - logger.error('HTTP -> 500 error: ' + err.message, {stack: err.stack}); + logger.error('HTTP -> 500 error: ' + err.message, { stack: err.stack }); res.status(200).send('!!'); }); //default endpoint -http.get('/', (req,res) => { +http.get('/', (req, res) => { res.send('Hello, World'); -}) - +}); http.listen(config.port, () => { logger.info(`App -> ${app.name} listening on port ${config.port}`); -}) +}); diff --git a/libs/actor.js b/libs/actor.js index 0516be1..bed05d6 100644 --- a/libs/actor.js +++ b/libs/actor.js @@ -1,4 +1,3 @@ -// const mark +// const mark - -module.exports = {} \ No newline at end of file +module.exports = {}; diff --git a/libs/app.js b/libs/app.js index 910cd76..097374b 100644 --- a/libs/app.js +++ b/libs/app.js @@ -1,22 +1,34 @@ -const fs = require('fs') +const fs = require('fs'); module.exports = (basedir, name) => { const appDir = basedir + '/profiles/' + name; const initFile = appDir + '/init.yaml'; const templatesDir = appDir + '/templates'; const resourcesDir = templatesDir + '/resources'; - //check if the directory is available - if (!fs.existsSync(appDir)) { console.log("Error: Directory: `"+appDir+"` not exists"); process.exit(1); } - if (!fs.existsSync(initFile)) { console.log("Error: Init file: `"+initFile+"` not exists"); process.exit(1); } - if (!fs.existsSync(templatesDir)) { console.log("Error: Template directory: `"+appDir+"` not exists"); process.exit(1); } - if (!fs.existsSync(resourcesDir)) { console.log("Error: Template Resources directory: `"+appDir+"` not exists"); process.exit(1); } - + //check if the directory is available + if (!fs.existsSync(appDir)) { + console.log('Error: Directory: `' + appDir + '` not exists'); + process.exit(1); + } + if (!fs.existsSync(initFile)) { + console.log('Error: Init file: `' + initFile + '` not exists'); + process.exit(1); + } + if (!fs.existsSync(templatesDir)) { + console.log('Error: Template directory: `' + appDir + '` not exists'); + process.exit(1); + } + if (!fs.existsSync(resourcesDir)) { + console.log( + 'Error: Template Resources directory: `' + appDir + '` not exists' + ); + process.exit(1); + } + return { name, initFile, templatesDir, - resourcesDir - } -} - - + resourcesDir, + }; +}; diff --git a/libs/config.js b/libs/config.js index 8f89bc6..8282bf0 100644 --- a/libs/config.js +++ b/libs/config.js @@ -1,19 +1,21 @@ -const fs = require('fs') +const fs = require('fs'); const yaml = require('js-yaml'); const defaultConfig = { - port:3000, - headers: {} -} + port: 3000, + headers: {}, +}; module.exports = (app) => { try { let config = yaml.load(fs.readFileSync(app.initFile, 'utf8')); - app.logger.info('Config -> loading main config') + app.logger.info('Config -> loading main config'); return config; } catch (e) { - app.logger.error('Config -> loading main config failed, make sure init.yaml is exists and have correct values') - app.logger.error('Config -> Falling back to default config') + app.logger.error( + 'Config -> loading main config failed, make sure init.yaml is exists and have correct values' + ); + app.logger.error('Config -> Falling back to default config'); return defaultConfig; } -} \ No newline at end of file +}; diff --git a/libs/honeytraps/cookie.js b/libs/honeytraps/cookie.js index 16ea022..fd5d906 100644 --- a/libs/honeytraps/cookie.js +++ b/libs/honeytraps/cookie.js @@ -1,30 +1,29 @@ -const randomizer = require('../randomizer') - +const randomizer = require('../randomizer'); module.exports = (http) => { //add couple of fake cookies - //list of cookies to implement + //list of cookies to implement let cookie_set = { key: randomizer.faker.internet.domainWord(), - value: randomizer.faker.git.commitSha() - } + value: randomizer.faker.git.commitSha(), + }; - http.use(function(req, res, next) { + http.use(function (req, res, next) { //if not exists create it - if(!req.cookies || !req.cookies[cookie_set.key]){ + if (!req.cookies || !req.cookies[cookie_set.key]) { res.cookie(cookie_set.key, cookie_set.value, { - httpOnly: true - }) - next() - return + httpOnly: true, + }); + next(); + return; } - if(req.cookies && req.cookies[cookie_set.key] != cookie_set.value){ + if (req.cookies && req.cookies[cookie_set.key] != cookie_set.value) { //cookie manipulated - req.session.isMalicious = true + req.session.isMalicious = true; } //all good - next() + next(); }); -} \ No newline at end of file +}; diff --git a/libs/honeytraps/exposed-files.js b/libs/honeytraps/exposed-files.js index ab817de..0360220 100644 --- a/libs/honeytraps/exposed-files.js +++ b/libs/honeytraps/exposed-files.js @@ -1,24 +1,31 @@ -const fs = require('fs') -const randomizer = require('../randomizer') +const fs = require('fs'); +const randomizer = require('../randomizer'); module.exports = (http) => { - let files = { - ".env": randomizer.fakeIt(fs.readFileSync(__dirname + '/files/dotenv', {encoding: 'utf-8'})), - "readme.txt": randomizer.fakeIt(fs.readFileSync(__dirname + '/files/readme.txt', {encoding: 'utf-8'})), - "changelog.txt": randomizer.fakeIt(fs.readFileSync(__dirname + '/files/changelog.txt', {encoding: 'utf-8'})) + '.env': randomizer.fakeIt( + fs.readFileSync(__dirname + '/files/dotenv', { + encoding: 'utf-8', + }) + ), + 'readme.txt': randomizer.fakeIt( + fs.readFileSync(__dirname + '/files/readme.txt', { + encoding: 'utf-8', + }) + ), + 'changelog.txt': randomizer.fakeIt( + fs.readFileSync(__dirname + '/files/changelog.txt', { + encoding: 'utf-8', + }) + ), }; - - for (const route in files) { - const content = files[route]; - http.get("/"+route, (req,res) => { - req.session.isMalicious = true - res.set('Content-Type', 'text/plain') - res.status(500).send(content) + const content = files[route]; + http.get('/' + route, (req, res) => { + req.session.isMalicious = true; + res.set('Content-Type', 'text/plain'); + res.status(500).send(content); }); } - - -} \ No newline at end of file +}; diff --git a/libs/honeytraps/robots-txt.js b/libs/honeytraps/robots-txt.js index 75f2697..ee2e184 100644 --- a/libs/honeytraps/robots-txt.js +++ b/libs/honeytraps/robots-txt.js @@ -1,20 +1,21 @@ -const fs = require('fs') -const randomizer = require('../randomizer') +const fs = require('fs'); +const randomizer = require('../randomizer'); module.exports = (http) => { + let robotsTxt = fs.readFileSync(__dirname + '/files/robots.txt', { + encoding: 'utf-8', + }); + robotsTxt = randomizer.fakeIt(robotsTxt); - let robotsTxt = fs.readFileSync(__dirname + '/files/robots.txt', {encoding: 'utf-8'}); - robotsTxt = randomizer.fakeIt(robotsTxt) - - http.get('/robots.txt', (req,res) => { + http.get('/robots.txt', (req, res) => { let content = robotsTxt; - res.set('Content-Type', 'text/plain') + res.set('Content-Type', 'text/plain'); res.send(content); - }) + }); - http.get('/[cd]/*', (req,res) => { + http.get('/[cd]/*', (req, res) => { //if accessed, this request is malicious - req.session.isMalicious = true - res.status(500).send("Internal Server Error") - }) -} \ No newline at end of file + req.session.isMalicious = true; + res.status(500).send('Internal Server Error'); + }); +}; diff --git a/libs/init.js b/libs/init.js index 4cc03fd..d9b5213 100644 --- a/libs/init.js +++ b/libs/init.js @@ -1,93 +1,114 @@ -const express = require('express') -const mustacheExpress = require('mustache-express'); +const express = require('express'); +const mustacheExpress = require('mustache-express'); const crypto = require('crypto'); -const { faker } = require('./randomizer') +const { faker } = require('./randomizer'); module.exports = (app) => { - app.logger.info('Init -> Starting the server config') + app.logger.info('Init -> Starting the server config'); const exp = express(); //generate an app key //const randomAppKey = crypto.createHash('md5').update(text).digest('hex') - const randomAppKey = crypto.randomBytes(32).toString('hex') - - app.logger.info('Init -> Configuring required middlewares (sessions, bodyparser)') + const randomAppKey = crypto.randomBytes(32).toString('hex'); - if(app.config.disableBuiltIn && app.config.disableBuiltIn.includes('cookies')){ - app.logger.info('Init', 'Config: Disable cookies -> Skipping session & cookies management') + app.logger.info( + 'Init -> Configuring required middlewares (sessions, bodyparser)' + ); + + if ( + app.config.disableBuiltIn && + app.config.disableBuiltIn.includes('cookies') + ) { + app.logger.info( + 'Init', + 'Config: Disable cookies -> Skipping session & cookies management' + ); //simulating session for one request period - exp.use(function(req, res, next) { - req.session = {} - next() - }) - }else{ - const session = require('express-session') - const cookieParser = require('cookie-parser') - app.logger.info('Init -> Add session cookies') + exp.use(function (req, res, next) { + req.session = {}; + next(); + }); + } else { + const session = require('express-session'); + const cookieParser = require('cookie-parser'); + app.logger.info('Init -> Add session cookies'); //configure session - exp.set('trust proxy', 1) // trust first proxy - exp.use(session({ - secret: process.env.APP_KEY || crypto.randomUUID(), - resave: false, - saveUninitialized: true, - name: faker.internet.domainWord(), - //cookie: { secure: true } //production only ssl - })) - exp.use(cookieParser()) + exp.set('trust proxy', 1); // trust first proxy + exp.use( + session({ + secret: process.env.APP_KEY || crypto.randomUUID(), + resave: false, + saveUninitialized: true, + name: faker.internet.domainWord(), + //cookie: { secure: true } //production only ssl + }) + ); + exp.use(cookieParser()); } - exp.use(express.json()) // for parsing application/json - exp.use(express.urlencoded({ extended: true })) // for parsing application/x-www-form-urlencoded - - app.logger.info('Init -> Configure datadog logger') + exp.use(express.json()); // for parsing application/json + exp.use(express.urlencoded({ extended: true })); // for parsing application/x-www-form-urlencoded + + app.logger.info('Init -> Configure datadog logger'); const middlewareLogger = function (req, res, next) { exp.logger = (id, title, info) => { - app.logger.warn('HASH: ' + req.method + ' ' + req.originalUrl + ': ' + title,{ - type: "malicious", - templateId: id, - info, - http:{ - client_ip: req.ip, - host: req.headers.host, - method: req.method, - path: req.path, - }, - request:{ - query: req.query || {}, - params: req.params || {}, - body: req.body || {}, - headers: {...req.headers,...{"cookie_parsed":req.cookies}}, + app.logger.warn( + 'HASH: ' + req.method + ' ' + req.originalUrl + ': ' + title, + { + type: 'malicious', + templateId: id, + info, + http: { + client_ip: req.ip, + host: req.headers.host, + method: req.method, + path: req.path, + }, + request: { + query: req.query || {}, + params: req.params || {}, + body: req.body || {}, + headers: { + ...req.headers, + ...{ + cookie_parsed: req.cookies, + }, + }, + }, } - }); - } - next() - } - - exp.use(middlewareLogger); + ); + }; + next(); + }; + + exp.use(middlewareLogger); - app.logger.info('Init -> Configure template engine') + app.logger.info('Init -> Configure template engine'); exp.engine('mustache', mustacheExpress()); exp.set('view engine', 'mustache'); exp.set('views', __dirname + '/../views'); //remove signature - exp.disable('x-powered-by'); + exp.disable('x-powered-by'); exp.disable('etag'); - if(app.config.headers && Object.keys(app.config.headers).length > 0){ - app.logger.info('Init -> Expose global headers ' + JSON.stringify(app.config.headers)) + if (app.config.headers && Object.keys(app.config.headers).length > 0) { + app.logger.info( + 'Init -> Expose global headers ' + + JSON.stringify(app.config.headers) + ); //add global headers if any - exp.use(function(req, res, next) { + exp.use(function (req, res, next) { for (const header in app.config.headers) { - res.setHeader(header, app.config.headers[header]) + res.setHeader(header, app.config.headers[header]); } next(); }); } return exp; -} \ No newline at end of file +}; diff --git a/libs/log.js b/libs/log.js index 43b2940..f18a241 100644 --- a/libs/log.js +++ b/libs/log.js @@ -1,59 +1,68 @@ //const chalk = require('chalk'); -const winston = require('winston') +const winston = require('winston'); const availableTransports = { - "console": () => { + console: () => { return new winston.transports.Console({ format: winston.format.combine( winston.format.colorize(), winston.format.simple() - ) - }) + ), + }); }, - "file": () => { + file: () => { return new winston.transports.File({ filename: process.env.LOG_FILE, }); }, - "datadog" : () => { - const datadogServiceName = process.env.DD_SERVICE_NAME || process.env.HONEYPOT_PROFILE || 'default'; + datadog: () => { + const datadogServiceName = + process.env.DD_SERVICE_NAME || + process.env.HONEYPOT_PROFILE || + 'default'; const datadogApiKey = process.env.DD_API_KEY; if (!datadogApiKey) { - throw new Error("Missing Datadog API key - specify DD_API_KEY or disable the 'datadog' log transport.") + throw new Error( + "Missing Datadog API key - specify DD_API_KEY or disable the 'datadog' log transport." + ); } require('dd-trace').init({ appsec: true, logInjection: true, service: datadogServiceName, - }); + }); return new winston.transports.Http({ host: 'http-intake.logs.datadoghq.com', - path: '/api/v2/logs?dd-api-key='+process.env.DD_API_KEY+'&ddsource=nodejs&service='+encodeURIComponent(datadogServiceName), - ssl: true - }) + path: + '/api/v2/logs?dd-api-key=' + + process.env.DD_API_KEY + + '&ddsource=nodejs&service=' + + encodeURIComponent(datadogServiceName), + ssl: true, + }); }, -} +}; const logger = winston.createLogger({ level: 'info', exitOnError: false, - format: winston.format.json() + format: winston.format.json(), }); - //parse the logs transports -let transports = process.env.LOG_TRANSPORTS ? process.env.LOG_TRANSPORTS.split(',') : []; +let transports = process.env.LOG_TRANSPORTS + ? process.env.LOG_TRANSPORTS.split(',') + : []; for (const transport of transports) { - if(availableTransports[transport]){ + if (availableTransports[transport]) { logger.add(availableTransports[transport]()); logger.info('Log -> Enable log transport: ' + transport); - }else{ + } else { throw new Error('Log -> log transport "' + transport + '" not found.'); } } - -module.exports = logger; \ No newline at end of file +module.exports = logger; diff --git a/libs/randomizer.js b/libs/randomizer.js index 3eb403c..ab95b4f 100644 --- a/libs/randomizer.js +++ b/libs/randomizer.js @@ -1,95 +1,97 @@ -const { faker } = require('@faker-js/faker') +const { faker } = require('@faker-js/faker'); const Mustache = require('mustache'); const crypto = require('crypto'); const fs = require('fs'); -const path = require("path"); +const path = require('path'); -const fakeIt = (string) => { - let stringArr = string.split(/(\$]+>)/) +const fakeIt = (string) => { + let stringArr = string.split(/(\$]+>)/); for (let i = 0; i < stringArr.length; i++) { const chunk = stringArr[i]; - if(chunk.indexOf('$]+)>/g, "return this.faker.$1;"); - let res = new Function(fakerCall).apply({faker}); + let fakerCall = chunk.replace( + /\$]+)>/g, + 'return this.faker.$1;' + ); + let res = new Function(fakerCall).apply({ faker }); stringArr[i] = res; - } + } } return stringArr.join(''); -} - +}; const Cache = { - cacheDir: function(){ - return __dirname + '/../cache/'; + cacheDir: function () { + return __dirname + '/../cache/'; }, - key: function(text){ + key: function (text) { return crypto.createHash('md5').update(text).digest('hex'); }, - set: function(key, contents){ + set: function (key, contents) { return fs.writeFileSync(this.cacheDir() + key, contents); }, - get: function(key){ - try { //just in case of IO error - if(fs.existsSync(this.cacheDir() + key)){ - return fs.readFileSync(this.cacheDir() + key, {encoding:'utf-8'}) + get: function (key) { + try { + //just in case of IO error + if (fs.existsSync(this.cacheDir() + key)) { + return fs.readFileSync(this.cacheDir() + key, { + encoding: 'utf-8', + }); } return false; } catch (error) { return false; } }, - reset: function(){ + reset: function () { let directory = this.cacheDir(); fs.readdir(directory, (err, files) => { if (err) throw err; - + for (const file of files) { - if(file === '.gitignore') continue; + if (file === '.gitignore') continue; fs.unlink(path.join(directory, file), (err) => { if (err) throw err; }); } - }); - } -} - + }, +}; //considering non cachable variables const replaceUncachableVariables = (content) => { - content = content.replace("$", (new Date()).toISOString()) - content = content.replace("$", (new Date()).getUTCSeconds()) + content = content.replace('$', new Date().toISOString()); + content = content.replace('$', new Date().getUTCSeconds()); return content; -} - +}; const render = (httpRequest, contents, vars, enableCache) => { let renderedContents; //check cache first let cacheKey = Cache.key(httpRequest.path); - let res = Cache.get(cacheKey) - if(res){ + let res = Cache.get(cacheKey); + if (res) { return replaceUncachableVariables(res); } //cache not found, create it - renderedContents = fakeIt(contents) + renderedContents = fakeIt(contents); renderedContents = Mustache.render(renderedContents, vars); - if(enableCache){ + if (enableCache) { Cache.set(cacheKey, renderedContents); } - + return replaceUncachableVariables(renderedContents); -} +}; module.exports = { faker, fakeIt, render, - Cache -} \ No newline at end of file + Cache, +}; diff --git a/libs/simulator.js b/libs/simulator.js index a7eb93b..810de85 100644 --- a/libs/simulator.js +++ b/libs/simulator.js @@ -1,139 +1,175 @@ const { config } = require('dotenv'); -const fs = require('fs') +const fs = require('fs'); const path = require('path'); -const log = require('./log') -const randomizer = require('./randomizer') +const log = require('./log'); +const randomizer = require('./randomizer'); const honeytraps = { robots: require('./honeytraps/robots-txt'), exposedFiles: require('./honeytraps/exposed-files'), - cookies: require('./honeytraps/cookie') -} - - -class Simulator{ - constructor(app, http, templates, dynamicTemplates){ - this.app = app - this.http = http - this.templates = templates - this.dynamicTemplates = dynamicTemplates + cookies: require('./honeytraps/cookie'), +}; + +class Simulator { + constructor(app, http, templates, dynamicTemplates) { + this.app = app; + this.http = http; + this.templates = templates; + this.dynamicTemplates = dynamicTemplates; } - apply(){ + apply() { //built-in modules - this.builtinModules(this.app.config) + this.builtinModules(this.app.config); for (let index = 0; index < this.dynamicTemplates.length; index++) { this.mockDynamicRequest(this.dynamicTemplates[index]); } - - for (let index = 0; index < this.templates.length; index++) { + + for (let index = 0; index < this.templates.length; index++) { //check if its dynamic js file - this.mockTemplate(this.templates[index]) + this.mockTemplate(this.templates[index]); } } - builtinModules(config){ - - if(config.disableBuiltIn && config.disableBuiltIn.includes('traps')){ + builtinModules(config) { + if (config.disableBuiltIn && config.disableBuiltIn.includes('traps')) { return; } //load internal honeytraps honeytraps.robots(this.http); - honeytraps.exposedFiles(this.http) - honeytraps.cookies(this.http) + honeytraps.exposedFiles(this.http); + honeytraps.cookies(this.http); } - - mockDynamicRequest(template){ - this.app.logger.info('Simulator -> Mocking Dynamic request '+ template) + mockDynamicRequest(template) { + this.app.logger.info( + 'Simulator -> Mocking Dynamic request ' + template + ); require(template)(this.http); } - mockTemplate(template){ + mockTemplate(template) { for (const request of template.requests) { - this.mockRequest(request, template) + this.mockRequest(request, template); } } - - - mockRequest(request, template){ + mockRequest(request, template) { let expect = request.expect; - this.app.logger.info('Simulator -> Mocking request '+ template.id) - - //parse reply - if(request.reply.body.view){ - let viewContents = fs.readFileSync(this.app.resourcesDir + "/" +request.reply.body.view, {encoding:'utf8'}) - request.reply.body.contents = viewContents; + this.app.logger.info('Simulator -> Mocking request ' + template.id); + + //parse reply + if (request.reply.body.view) { + let viewContents = fs.readFileSync( + this.app.resourcesDir + '/' + request.reply.body.view, + { encoding: 'utf8' } + ); + request.reply.body.contents = viewContents; } - - switch (expect.method){ + switch (expect.method) { case 'ALL': - this.http.all(expect.path, this.handler(request, template, expect)) + this.http.all( + expect.path, + this.handler(request, template, expect) + ); break; case 'GET': - this.http.get(expect.path, this.handler(request, template, expect)) + this.http.get( + expect.path, + this.handler(request, template, expect) + ); break; case 'HEAD': - this.http.head(expect.path, this.handler(request, template, expect)) + this.http.head( + expect.path, + this.handler(request, template, expect) + ); break; case 'POST': - this.http.post(expect.path, this.handler(request, template, expect)) + this.http.post( + expect.path, + this.handler(request, template, expect) + ); break; case 'PUT': - this.http.put(expect.path, this.handler(request, template, expect)) + this.http.put( + expect.path, + this.handler(request, template, expect) + ); break; case 'DELETE': - this.http.delete(expect.path, this.handler(request, template, expect)) + this.http.delete( + expect.path, + this.handler(request, template, expect) + ); break; case 'patch': - this.http.delete(expect.path, this.handler(request, template, expect)) + this.http.delete( + expect.path, + this.handler(request, template, expect) + ); break; } } - handler(request, template){ + handler(request, template) { let reply = request.reply; - return (req,res) => { - - + return (req, res) => { //if this a trap mark the full session as malicious - if(request.isTrap){ + if (request.isTrap) { //TODO: mention trap name - this.app.logger.info('Simulator -> Trap hit, marking the session as malicious ') - req.session.isMalicious = true + this.app.logger.info( + 'Simulator -> Trap hit, marking the session as malicious ' + ); + req.session.isMalicious = true; } - + //report the malicious activities - if(req.session.isMalicious){ - this.http.logger(template.id, template.info.title, template.info) + if (req.session.isMalicious) { + this.http.logger( + template.id, + template.info.title, + template.info + ); } - res.set(reply.headers) - - if(reply.body.static){ - this.app.logger.info('Simulator -> Loading static file FROM ' + this.app.resourcesDir + "/" +request.reply.body.static) - let staticC = fs.readFileSync(this.app.resourcesDir + "/" +request.reply.body.static) - res.status(reply.status).send(staticC) - return; + res.set(reply.headers); + + if (reply.body.static) { + this.app.logger.info( + 'Simulator -> Loading static file FROM ' + + this.app.resourcesDir + + '/' + + request.reply.body.static + ); + let staticC = fs.readFileSync( + this.app.resourcesDir + '/' + request.reply.body.static + ); + res.status(reply.status).send(staticC); + return; } - let templateVars = Object.assign({ - params: req.params, - body: req.body, - query: req.query - }, reply.body.vars || {}) - - - let enableCache = reply.body.cache === false ? false : true; //default is true - let renderedContents = randomizer.render(req,reply.body.contents, templateVars, enableCache); - - res.status(reply.status).send(renderedContents) - } + let templateVars = Object.assign( + { + params: req.params, + body: req.body, + query: req.query, + }, + reply.body.vars || {} + ); + + let enableCache = reply.body.cache === false ? false : true; //default is true + let renderedContents = randomizer.render( + req, + reply.body.contents, + templateVars, + enableCache + ); + + res.status(reply.status).send(renderedContents); + }; } - } - -module.exports = Simulator \ No newline at end of file +module.exports = Simulator; diff --git a/libs/template.js b/libs/template.js index b63ae4e..d582ae0 100644 --- a/libs/template.js +++ b/libs/template.js @@ -1,56 +1,64 @@ -const fs = require('fs') +const fs = require('fs'); const path = require('path'); const yaml = require('js-yaml'); - -class Template{ - constructor(app){ - this.dir = app.templatesDir - this.logger = app.logger +class Template { + constructor(app) { + this.dir = app.templatesDir; + this.logger = app.logger; } - load(){ - this.logger.info('Template -> loading request templates from: '+this.dir); - const dirents = fs.readdirSync(this.dir, { withFileTypes: true }); + load() { + this.logger.info( + 'Template -> loading request templates from: ' + this.dir + ); + const dirents = fs.readdirSync(this.dir, { + withFileTypes: true, + }); const filesNames = dirents - .filter(dirent => dirent.isFile()) - .map(dirent => dirent.name); - + .filter((dirent) => dirent.isFile()) + .map((dirent) => dirent.name); + let templates = []; let dynamicTemplates = []; let specialTemplates = []; for (let index = 0; index < filesNames.length; index++) { const template = filesNames[index]; - + let ext = path.extname(template); - if(ext == '.js'){ + if (ext == '.js') { //dynamically loaded js - //add the filename to be required later + //add the filename to be required later dynamicTemplates.push(this.dir + '/' + template); continue; } - if(ext != '.yaml' && ext != '.yml') continue; //unsupported file format + if (ext != '.yaml' && ext != '.yml') continue; //unsupported file format try { - let doc = yaml.load(fs.readFileSync(this.dir + '/' + template, 'utf8')); - this.logger.info('Template -> loading template: '+template +' success ') + let doc = yaml.load( + fs.readFileSync(this.dir + '/' + template, 'utf8') + ); + this.logger.info( + 'Template -> loading template: ' + template + ' success ' + ); - if(template == '404.yaml' || template == '404.yml'){ - specialTemplates.push(doc) + if (template == '404.yaml' || template == '404.yml') { + specialTemplates.push(doc); continue; } - templates.push(doc) + templates.push(doc); } catch (e) { - throw new Error("Failed loading template: " + template + ": " + e) + throw new Error( + 'Failed loading template: ' + template + ': ' + e + ); } } - return { templates: [...templates, ...specialTemplates], - dynamicTemplates + dynamicTemplates, }; } } -module.exports = Template \ No newline at end of file +module.exports = Template; diff --git a/package-lock.json b/package-lock.json index 5ca73e7..52487df 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,6 +27,7 @@ "mustache": "^4.2.0", "mustache-express": "^1.3.2", "needle": "^3.2.0", + "prettier": "^2.8.6", "winston": "^3.8.2" } }, @@ -1932,6 +1933,20 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/prettier": { + "version": "2.8.6", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.6.tgz", + "integrity": "sha512-mtuzdiBbHwPEgl7NxWlqOkithPyp4VN93V7VeHVWBF+ad3I5avc0RVDT4oImXQy9H/AqxA2NSQH8pSxHW6FYbQ==", + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/protobufjs": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.1.2.tgz", @@ -4137,6 +4152,11 @@ "resolved": "https://registry.npmjs.org/pify/-/pify-5.0.0.tgz", "integrity": "sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==" }, + "prettier": { + "version": "2.8.6", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.6.tgz", + "integrity": "sha512-mtuzdiBbHwPEgl7NxWlqOkithPyp4VN93V7VeHVWBF+ad3I5avc0RVDT4oImXQy9H/AqxA2NSQH8pSxHW6FYbQ==" + }, "protobufjs": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.1.2.tgz", diff --git a/package.json b/package.json index 644266e..1380cda 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "main": "app.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", + "prettier": "./node_modules/prettier/bin-prettier.js --write \"./**/*.{js,jsx,ts,tsx}\"", "generate-third-party-licenses": "./node_modules/license-checker/bin/license-checker --csv > LICENSE-3rdparty.csv" }, "author": "", @@ -28,6 +29,7 @@ "mustache": "^4.2.0", "mustache-express": "^1.3.2", "needle": "^3.2.0", + "prettier": "^2.8.6", "winston": "^3.8.2" } }