Compare commits

...

5 Commits

8 changed files with 257 additions and 13 deletions

2
.gitignore vendored
View File

@ -130,3 +130,5 @@ dist
.yarn/install-state.gz
.pnp.*
# Routemap ignore
routemap.txt

View File

@ -235,6 +235,17 @@ module.exports = class HTTPServer extends Component {
});
});
this.app.use((req, res, next) => {
req.realip = req.ip;
if (req.headers["cf-connecting-ip"])
req.realip = req.headers["cf-connecting-ip"];
req.st403 = "<h1>403: Permission denied</h1><hr/><p>Permission denied.</p>";
req.st404 = "<h1>404: Page not finded</h1><hr/><p>Please, recheck the URL address and try again.</p>";
req.st500 = "<head><title>500: Internal Server Error</title></head><body><h1>Error:</h1><hr/><p>Error catched. Check logs</p></body>";
next();
});
this.app.use((req, res, next) => {
const currentDomain = req.hostname;
const isNotDomained = !this.syntax.domains[currentDomain];
@ -246,13 +257,6 @@ module.exports = class HTTPServer extends Component {
authPage(this, req, res, next)
});
this.app.use((req, res, next) => {
req.st403 = "<h1>403: Permission denied</h1><hr/><p>Permission denied.</p>";
req.st404 = "<h1>404: Page not finded</h1><hr/><p>Please, recheck the URL address and try again.</p>";
req.st500 = "<head><title>500: Internal Server Error</title></head><body><h1>Error:</h1><hr/><p>Error catched. Check logs</p></body>";
next();
});
this.app.use(cookieParser());
this.routelist.forEach(route => {

109
modules/antiddos.js Normal file
View File

@ -0,0 +1,109 @@
const { NetHelperModule } = global.moduleApi;
const express = require("express");
const captcha = require("draw-captcha");
const HTTPServer = require("../components/_http");
const captchaPage = `<!DOCTYPE html><html><head><title>Captcha handling required</title><meta name="viewport" content="width=device-width, initial-scale=1"><meta charset="utf-8"></head><body>
<center>
<h1>Enter captcha</h1>
<p><img src=:captchaImg:></img></p>
<form action="/captcha-solve/:sid:/:from:" method="get">
<p><input type="label" name="solve"> <input type="submit" id="solve-captcha"></p>
</form>
</center>
</body></html>`;
function randint (min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
async function getCaptchaPage (fromUrl) {
const sidDict = "1234567890abcdef";
let sid = "";
for (let i = 0; i < 32; i++) {
sid += sidDict[randint(0, 15)];
}
const captchaObject = new captcha.MasterCaptcha();
getCaptchaPage.sids[sid] = await captchaObject.setupRandomCaptcha();
return captchaPage
.replace(new RegExp(":captchaImg:"), `/captcha/${sid}`)
.replace(new RegExp(":from:"), Buffer.from(fromUrl).toString("hex"))
.replace(new RegExp(":sid:"), sid);
}
getCaptchaPage.sids = new Object();
module.exports = class ExampleMdoule extends NetHelperModule {
constructor () {
super();
this.router = express.Router();
this.lastUptime = new Date(new Date().getTime() + 3600000);
this.queryCount = 0;
this.ipWhiteListed = new Object();
this.querylimit = new this.statics.Operator("querylimit", (argv) => {
if (argv.length !== 1) return false;
return !Number.isNaN(+argv[0]);
}, (argv, self, syntaxTree) => {
if (!(syntaxTree.Type.prototype instanceof HTTPServer)) {
throw new SyntaxError("Unsupported type of server");
}
let [ queriesLimit ] = argv;
queriesLimit = +queriesLimit;
const router = this.router;
router.use(async (req, res, next) => {
req.adsEx = req.adsEx ?? {};
if (this.lastUptime <= new Date()) {
this.lastUptime = new Date(this.lastUptime.getTime() + 3600000);
this.queryCount = 1;
this.ipWhiteListed = new Object();
} else
this.queryCount++;
if (this.queryCount > queriesLimit) {
//this.lastUptime = new Date(new Date().getTime() + 3600000);
req.adsEx.needsCaptcha = this.ipWhiteListed[req.realip] !== true;
}
return next();
});
router.get("/captcha/:sid", async (req, res, next) => {
if (!req.adsEx.needsCaptcha)
return next();
const sid = req.params.sid;
const content = getCaptchaPage.sids[sid];
if (content === undefined) {
res.set("Content-Type", "text/plain");
return res.status(400).send("Invalid SID. Captcha was solved or not found");
}
res.set("Content-Type", "image/jpeg");
res.send(content.buffer);
});
router.get("/captcha-solve/:sid/:redirectTo", async (req, res) => {
const sid = req.params.sid;
const content = getCaptchaPage.sids[sid];
const redirectTo = Buffer.from(req.params.redirectTo, "hex").toString("utf8");
const isSolved = req.query.solve?.toLowerCase() === content?.code;
this.ipWhiteListed[req.realip] = isSolved;
req.adsEx.needsCaptcha = !isSolved;
res.redirect(redirectTo);
});
router.use(async (req, res, next) => {
if (!req.adsEx.needsCaptcha)
return next();
res.send(await getCaptchaPage(req.originalUrl));
});
});
this.operators.push(this.querylimit);
}
bind (type) {
super.bind(type);
this.serverType.routelist.push(this.router);
}
};

View File

@ -1,7 +1,7 @@
const express = require("express");
const { NetHelperModule } = global.moduleApi;
const HTTPReverse = require("../components/http-reverse");
const HTTPServer = require("../components/_http");
module.exports = class CustomAuthPage extends NetHelperModule {
constructor () {
@ -11,7 +11,7 @@ module.exports = class CustomAuthPage extends NetHelperModule {
this.cauth = new this.statics.Operator("cauth", (argv) => {
return argv.length === 2;
}, (argv, self, syntaxTree) => {
if (![HTTPReverse].includes(syntaxTree.Type)) {
if (!(syntaxTree.Type.prototype instanceof HTTPServer)) {
throw new SyntaxError("Unsupported type of server");
}
const [ login, password ] = argv;

91
package-lock.json generated
View File

@ -12,6 +12,7 @@
"body": "^5.1.0",
"body-parser": "^1.20.3",
"cookie-parser": "^1.4.7",
"draw-captcha": "^0.0.2",
"express": "^4.21.2",
"mime": "^3.0.0",
"node-fetch": "^2.6.7",
@ -51,6 +52,16 @@
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
"integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
},
"node_modules/array-parallel": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/array-parallel/-/array-parallel-0.1.3.tgz",
"integrity": "sha512-TDPTwSWW5E4oiFiKmz6RGJ/a80Y91GuLgUYuLd49+XBS75tYo8PNgaT2K/OxuQYqkoI852MDGBorg9OcUSTQ8w=="
},
"node_modules/array-series": {
"version": "0.1.5",
"resolved": "https://registry.npmjs.org/array-series/-/array-series-0.1.5.tgz",
"integrity": "sha512-L0XlBwfx9QetHOsbLDrE/vh2t018w9462HM3iaFfxRiK83aJjAt/Ja3NMkOW7FICwWTlQBa3ZbL5FKhuQWkDrg=="
},
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@ -264,6 +275,15 @@
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
"integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
},
"node_modules/cross-spawn": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz",
"integrity": "sha512-yAXz/pA1tD8Gtg2S98Ekf/sewp3Lcp3YoFKJ4Hkp5h5yLWnKVTDU0kwjKJ8NDCYcfTLfyGkzTikst+jWypT1iA==",
"dependencies": {
"lru-cache": "^4.0.1",
"which": "^1.2.9"
}
},
"node_modules/debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
@ -289,6 +309,15 @@
"npm": "1.2.8000 || >= 1.4.16"
}
},
"node_modules/draw-captcha": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/draw-captcha/-/draw-captcha-0.0.2.tgz",
"integrity": "sha512-rXFp1AvzjzznpNSBnhcOo5/UaX98VQa3ZCr225OA1dNwtlE4zz1L5490xWIAFctTGEyZvJ9tcLIRFnM947FVnA==",
"dependencies": {
"express": "^4.21.2",
"gm": "^1.25.0"
}
},
"node_modules/dunder-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
@ -522,6 +551,33 @@
"node": ">= 6"
}
},
"node_modules/gm": {
"version": "1.25.0",
"resolved": "https://registry.npmjs.org/gm/-/gm-1.25.0.tgz",
"integrity": "sha512-4kKdWXTtgQ4biIo7hZA396HT062nDVVHPjQcurNZ3o/voYN+o5FUC5kOwuORbpExp3XbTJ3SU7iRipiIhQtovw==",
"dependencies": {
"array-parallel": "~0.1.3",
"array-series": "~0.1.5",
"cross-spawn": "^4.0.0",
"debug": "^3.1.0"
},
"engines": {
"node": ">=14"
}
},
"node_modules/gm/node_modules/debug": {
"version": "3.2.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
"integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
"dependencies": {
"ms": "^2.1.1"
}
},
"node_modules/gm/node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
},
"node_modules/gopd": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
@ -651,6 +707,20 @@
"node": ">=0.12.0"
}
},
"node_modules/isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="
},
"node_modules/lru-cache": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
"integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==",
"dependencies": {
"pseudomap": "^1.0.2",
"yallist": "^2.1.2"
}
},
"node_modules/math-intrinsics": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
@ -884,6 +954,11 @@
"node": ">= 0.10"
}
},
"node_modules/pseudomap": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
"integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ=="
},
"node_modules/pstree.remy": {
"version": "1.1.8",
"resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz",
@ -1255,6 +1330,22 @@
"tr46": "~0.0.3",
"webidl-conversions": "^3.0.0"
}
},
"node_modules/which": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
"integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
"dependencies": {
"isexe": "^2.0.0"
},
"bin": {
"which": "bin/which"
}
},
"node_modules/yallist": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
"integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A=="
}
}
}

View File

@ -23,6 +23,7 @@
"body": "^5.1.0",
"body-parser": "^1.20.3",
"cookie-parser": "^1.4.7",
"draw-captcha": "^0.0.2",
"express": "^4.21.2",
"mime": "^3.0.0",
"node-fetch": "^2.6.7",

View File

@ -1,15 +1,14 @@
127.0.0.1:9889 {
import antiddos;
type revHTTP;
target https://example.org; # RRR
querylimit 0;
domain localhost {
firewall whitelist GLOBAL;
type revHTTP;
target https://github.com;
};
domain domain.loc {
import example;
testi;
};
}
127.0.0.1:7889 {

38
routemap.txt.custom Normal file
View File

@ -0,0 +1,38 @@
127.0.0.1:9889 {
type revHTTP;
target https://example.org; # RRR
domain localhost {
firewall whitelist GLOBAL;
type revHTTP;
target https://github.com;
};
domain domain.loc {
import example;
testi;
};
}
127.0.0.1:7889 {
import example, example_custom_auth;
type revHTTP;
target https://google.com;
auth loopback admin qwerty;
#cauth admin 123;
cert public ./tests/pub.crt;
cert private ./tests/priv.key;
}
127.0.0.1:9999 {
type redirectHTTP;
target https://duckduckgo.com;
domain localhost {
type revHTTP;
target https://google.com;
}
}
127.0.0.1:8081 {
type simpleHTTP;
target /;
#showdir;
}