110 lines
4.3 KiB
JavaScript
110 lines
4.3 KiB
JavaScript
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);
|
|
}
|
|
};
|