-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.js
More file actions
122 lines (110 loc) · 4.72 KB
/
index.js
File metadata and controls
122 lines (110 loc) · 4.72 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
require("dotenv").config({ path: ["chall.env", ".env"] });
const express = require("express");
const axios = require("axios");
const fs = require("fs");
const path = require("path");
const puppeteer = require("puppeteer");
const app = express();
const port = Number(process.env.PORT) || 8080;
const submitPage = fs.readFileSync(path.join(__dirname, "submit.html"), "utf8");
function replace(str, old, rep) {
return str.replaceAll(old, rep.replaceAll("$", "$$$$"));
}
const opts = {
pipe: true,
args: ["--js-flags=--jitless"],
};
if (process.env.PUPPETEER_OPTIONS) {
Object.assign(opts, JSON.parse(process.env.PUPPETEER_OPTIONS));
}
try {
const status = fs.readFileSync("/proc/1/status", "utf8");
const capBnd = parseInt(status.match(/^CapBnd:\s+([0-9a-f]+)$/m)[1], 16);
if ((capBnd & (1 << 21)) === 0) {
console.error("WARNING: Missing CAP_SYS_ADMIN. Adding --no-sandbox to Chrome launch options.");
opts.args.push("--no-sandbox");
}
} catch (err) {}
let browser = puppeteer.launch(opts);
app.use(express.urlencoded({ extended: false }));
const handlers = new Map();
for (const f of fs.readdirSync(path.join(__dirname, "handlers"))) {
if (f.endsWith(".js")) {
const handler = require("./" + path.join("handlers", f));
let page = replace(submitPage, "$NAME", handler.name);
page = replace(page, "$RECAPTCHA_SITE", process.env.RECAPTCHA_SITE || "");
page = replace(page, "$RECAPTCHA_SECRET", process.env.RECAPTCHA_SECRET || "");
app.get("/" + handler.name, (req, res) => {
res.type("text/html").send(page);
});
app.post("/" + handler.name, async (req, res) => {
if (!req.body || typeof req.body !== "object") {
return res.redirect(`/${handler.name}?e=${encodeURIComponent("Invalid request")}`);
}
const url = req.body.url;
if (typeof url !== "string" || !(handler.urlRegex || /^https?:\/\//).test(url)) {
return res.redirect(`/${handler.name}?e=${encodeURIComponent("Invalid URL")}`);
}
if (process.env.RECAPTCHA_SITE && process.env.RECAPTCHA_SECRET) {
try {
const body = new URLSearchParams({
secret: process.env.RECAPTCHA_SECRET,
response: req.body["g-recaptcha-response"],
});
const resp = await axios.post("https://www.google.com/recaptcha/api/siteverify", body);
if (!resp.data.success) {
return res.redirect(`/${handler.name}?e=${encodeURIComponent("Invalid captcha")}`);
}
} catch (err) {
console.error("Captcha verification failure", err);
return res.redirect(`/${handler.name}?e=${encodeURIComponent("Error verifying captcha")}`);
}
}
console.log(`Handler ${handler.name}: Visiting URL ${url}`);
let ctx = null;
let ret = undefined;
try {
if (handler.noContext) {
ret = await handler.execute(await browser, url);
} else {
try {
ctx = await (await browser).createBrowserContext();
} catch (err) {
if (err instanceof puppeteer.ConnectionClosedError) {
browser = puppeteer.launch(opts);
ctx = await (await browser).createBrowserContext();
} else {
throw err;
}
}
ret = await handler.execute(ctx, url);
}
} catch (err) {
console.error("Handler error", err);
return res.redirect(`/${handler.name}?e=${encodeURIComponent("Error visiting page")}`);
} finally {
if (ctx) {
try {
await ctx.close();
} catch (e) {}
}
}
if (typeof ret === "object" && ret !== null && "error" in ret) {
return res.redirect(`/${handler.name}?e=${encodeURIComponent(ret.error)}`);
}
return res.redirect(`/${handler.name}?m=${encodeURIComponent("Visit successful")}`);
});
handlers.set(handler.name, handler);
console.log(`Registered handler for ${handler.name}.`);
}
}
app.get("/", (req, res) => {
if (handlers.size === 1) {
res.redirect("/" + [...handlers.keys()][0]);
} else {
res.send("Admin bot is running.");
}
});
app.listen(port, () => {
console.log(`App listening on port ${port}.`);
});