diff --git a/components/_component.js b/components/_component.js index 768794b..8475a92 100644 --- a/components/_component.js +++ b/components/_component.js @@ -1,3 +1,8 @@ module.exports = class Component { - constructor () {} + constructor (address, syntaxTree) { + this.adr = address; + this.syntax = syntaxTree; + } + + run () {} }; diff --git a/components/http-reverse.js b/components/http-reverse.js index b2fd0fe..113312d 100644 --- a/components/http-reverse.js +++ b/components/http-reverse.js @@ -1,5 +1,78 @@ const Component = require("./_component"); +const express = require("express"); +const bodyParser = require("body-parser"); +const bodyHand = require('body'); +const url = require('url'); +const path = require('path'); +const fetch = require('node-fetch'); + +function logger (...p) { + return; + console.log("[DEBUG.main]:", ...p); +} + module.exports = class HTTPReverse extends Component { - constructor () { super(); } + constructor (adr, syntaxTree) { + super(adr, syntaxTree); + } + + run () { + this.app = express(); + + const address = this.adr.address ?? "127.0.0.1"; + const reverseTo = this.syntax.target ?? "https://example.org"; + + this.app.use('/*', async (req, res, next) => { // Myself body parser :) + bodyHand(req, res, { + limit: 9999999999, + cache: false, + encoding: 'base64' + }, (err, body) => { + if (!err) { + req.body = Buffer.from(body, 'base64'); + } else { + req.body = undefined; + } + next(); + }); + }); + + this.app.use("*", async (req, res) => { + logger("REQ HEADERS:>", req.headers); + logger("originalUrl:>", req.originalUrl); + const currentDomain = req.hostname; + const params = { method: req.method.toUpperCase(), headers: Object.assign({}, req.headers), redirect: "follow", follow: 20 }; + delete params.headers.host; + delete params.headers.referer; + if (!["GET", "HEAD"].includes(params.method)) + params.body = req.body; + logger("hostname:", currentDomain); + const reverseToLoc = !this.syntax.domains[currentDomain] ? reverseTo : this.syntax.domains[currentDomain].target; + const reqAddress = url.resolve(reverseToLoc, path.join("/", req.originalUrl)); + fetch(reqAddress, params) + .then(async result => { + const content = await result.text(); + logger("result:", result); + logger("result.text():", content); + Object.entries(result?.headers ? result.headers : new Object()).forEach(([header, value]) => { + res.set(header, value); + }); + res.status(result.status).send(content); + }) + .catch(err => { + console.error(err); + res.status(500).send("Error

Error:


Error catched. Check logs

"); + }); + }); + + this.app.listen(this.adr.port, address, (err) => { + if (err) { + throw err; + } + console.log(`Koboldcpp reverse proxy server listened at ${ + address + }:${this.adr.port}`); + }) + } }; diff --git a/routemap-parser.js b/routemap-parser.js index abdc78d..bda0569 100644 --- a/routemap-parser.js +++ b/routemap-parser.js @@ -5,17 +5,23 @@ const components = require("./components"); // General regexps // const FIND_ADDRESS_INSTR_REGEX = /([0-9]{1,3}\.){3}[0-9]{1,3}:[0-9]{1,5}\s{0,}\{[\s\n\r0-9a-z;:\/\."',]{0,}\}/gmi; const DOMAINER_REGEX = /domain\s{1,}[a-z0-9\.]{1,}\s{1,}\{[\s\n\r0-9a-z;:\/\."',]{0,}\}/gmi; +const DOMAINER_VALUE_FIND_REGEX = /domain\s{1,}[a-z0-9\.]{1,}\s{1,}\{/gmi; const ADDRESS_WITH_PORT_REGEX = /([0-9]{1,3}\.){3}[0-9]{1,3}:[0-9]{1,5}/gmi const FIND_ADDRESS_INSTR_REGEX = /([0-9]{1,3}\.){3}[0-9]{1,3}:[0-9]{1,5}\s{0,}\{([\s\n\r0-9a-z;:\/\."',]|domain\s{1,}[a-z0-9\.]{1,}\s{1,}\{[\s\n\r0-9a-z;:\/\."',]{0,}\}){0,}\}/gmi; const COMMENT_REGEX = /#.{0,}(\n|\r|$)/gmi; +const CONTENT_INTO_CURLY_BRACES = /\{[\s\n\r0-9a-z;:\/\."',]{0,}\}{0,}\}/gmi; // Instruction regexps -function readInstructions (instructions, fullCode) { - const syntaxTree = { domains: {}, firewall: false }; +function readInstructions (instructions, fullCode, forDomains=false) { + const syntaxTree = { firewall: false }; for (let instruction of instructions) { - if (!instruction) - break; + if (!instruction) { + if (instructions.indexOf(instruction) === instructions.length - 1) { + break; + } + throw new SyntaxError("Invalid syntax: `;;`"); + } const instructionParts = instruction.split(/\s{1,}/); const mainOperator = instructionParts[0]; switch (mainOperator) { @@ -32,13 +38,29 @@ function readInstructions (instructions, fullCode) { throw new SyntaxError("Invalid syntax of operator `target`: target "); syntaxTree.target = instructionParts[1]; break; + case "cert": + break; + case "firewall": + break; case "#instuction:domain": + if (forDomains) + throw new SyntaxError("Nested use of domains doesn't not supported"); break; default: throw new SyntaxError(`Unknown routemap's operator: ${mainOperator}`); } } + if (!forDomains) { + syntaxTree.domains = new Object(); + const allDomains = Object.fromEntries((fullCode.match(DOMAINER_REGEX) ?? []) + .map(x => [x.match(DOMAINER_VALUE_FIND_REGEX)[0].split(/\s{1,}/gmi)[1], x.match(CONTENT_INTO_CURLY_BRACES)[0].slice(1, -1).split(/\s{0,};\s{0,}/g).map(x => x.trim())])); + + for (let domain in allDomains) { + syntaxTree.domains[domain] = readInstructions(allDomains[domain], "", true); + } + } + return syntaxTree; } @@ -68,4 +90,5 @@ module.exports.parse = function () { syntaxTree[itemAdrInst.match(ADDRESS_WITH_PORT_REGEX)[0]] = localSyntaxTree; } logger("Full syntax tree:", syntaxTree); + return syntaxTree; } diff --git a/routemap.txt b/routemap.txt index cc60ed0..12b4a4a 100644 --- a/routemap.txt +++ b/routemap.txt @@ -1,11 +1,17 @@ 127.0.0.1:9889 { type revHTTP; + target https://example.org; # RRR domain localhost { firewall whitelist GLOBAL; type revHTTP; - target https://github.org; + target https://github.com; }; } -127.0.0.1:7889 {} +127.0.0.1:7889 { + type revHTTP; + target https://google.com; + cert public /path/to/cert.pub; + cert private /path/to/cert.priv; +} diff --git a/server.js b/server.js index acabd03..f2bdebe 100644 --- a/server.js +++ b/server.js @@ -1,72 +1,11 @@ 'use strict'; -const express = require("express"); -const bodyParser = require("body-parser"); -const bodyHand = require('body'); -const url = require('url'); -const path = require('path'); -const fetch = require('node-fetch'); -global.config = require("./config.json"); - const rtmap = require("./routemap-parser"); +const syntaxTree = rtmap.parse(); -const app = express(); - -const address = global.config.net.address ?? "127.0.0.1"; -const reverseTo = global.config.target ?? "https://example.org"; - -function logger (...p) { - return; - console.log("[DEBUG.main]:", ...p); +for (let faddress in syntaxTree) { + const [address, port] = faddress.split(/:/gmi); + const localSyntaxTree = syntaxTree[faddress]; + const instance = new localSyntaxTree.Type({ address, port }, localSyntaxTree); + instance.run(); } - -app.use('/*', async (req, res, next) => { // Myself body parser :) - bodyHand(req, res, { - limit: 9999999999, - cache: false, - encoding: 'base64' - }, (err, body) => { - if (!err) { - req.body = Buffer.from(body, 'base64'); - } else { - req.body = undefined; - } - next(); - }); -}); - -app.use("*", async (req, res) => { - logger("REQ HEADERS:>", req.headers); - logger("originalUrl:>", req.originalUrl); - const params = { method: req.method.toUpperCase(), headers: req.headers, redirect: "follow", follow: 20 }; - delete params.headers.host; - delete params.headers.referer; - if (!["GET", "HEAD"].includes(params.method)) - params.body = req.body; - const reqAddress = url.resolve(reverseTo, path.join("/", req.originalUrl)); - fetch(reverseTo, params) - .then(async result => { - const content = await result.text(); - logger("result:", result); - logger("result.text():", content); - Object.entries(result?.headers ? result.headers : new Object()).forEach(([header, value]) => { - res.set(header, value); - }); - res.status(result.status).send(content); - }) - .catch(err => { - console.error(err); - res.status(500).send("Error

Error:


Error catched. Check logs

"); - }); -}); - -rtmap.parse(); - -app.listen(global.config.net.port, address, (err) => { - if (err) { - throw err; - } - console.log(`Koboldcpp reverse proxy server listened at ${ - address - }:${global.config.net.port}`); -})