Stop exposing captcha passphrase
This commit is contained in:
@@ -11,6 +11,46 @@ const rooms = new Map();
|
||||
const watchStates = new Map();
|
||||
const presentationStates = new Map();
|
||||
const defaultRoomId = "main";
|
||||
const captchaGlyphs = {
|
||||
a: ["01110", "10001", "10001", "11111", "10001", "10001", "10001"],
|
||||
b: ["11110", "10001", "10001", "11110", "10001", "10001", "11110"],
|
||||
c: ["01111", "10000", "10000", "10000", "10000", "10000", "01111"],
|
||||
d: ["11110", "10001", "10001", "10001", "10001", "10001", "11110"],
|
||||
e: ["11111", "10000", "10000", "11110", "10000", "10000", "11111"],
|
||||
f: ["11111", "10000", "10000", "11110", "10000", "10000", "10000"],
|
||||
g: ["01111", "10000", "10000", "10111", "10001", "10001", "01111"],
|
||||
h: ["10001", "10001", "10001", "11111", "10001", "10001", "10001"],
|
||||
i: ["11111", "00100", "00100", "00100", "00100", "00100", "11111"],
|
||||
j: ["00111", "00010", "00010", "00010", "10010", "10010", "01100"],
|
||||
k: ["10001", "10010", "10100", "11000", "10100", "10010", "10001"],
|
||||
l: ["10000", "10000", "10000", "10000", "10000", "10000", "11111"],
|
||||
m: ["10001", "11011", "10101", "10101", "10001", "10001", "10001"],
|
||||
n: ["10001", "11001", "10101", "10011", "10001", "10001", "10001"],
|
||||
o: ["01110", "10001", "10001", "10001", "10001", "10001", "01110"],
|
||||
p: ["11110", "10001", "10001", "11110", "10000", "10000", "10000"],
|
||||
q: ["01110", "10001", "10001", "10001", "10101", "10010", "01101"],
|
||||
r: ["11110", "10001", "10001", "11110", "10100", "10010", "10001"],
|
||||
s: ["01111", "10000", "10000", "01110", "00001", "00001", "11110"],
|
||||
t: ["11111", "00100", "00100", "00100", "00100", "00100", "00100"],
|
||||
u: ["10001", "10001", "10001", "10001", "10001", "10001", "01110"],
|
||||
v: ["10001", "10001", "10001", "10001", "10001", "01010", "00100"],
|
||||
w: ["10001", "10001", "10001", "10101", "10101", "10101", "01010"],
|
||||
x: ["10001", "10001", "01010", "00100", "01010", "10001", "10001"],
|
||||
y: ["10001", "10001", "01010", "00100", "00100", "00100", "00100"],
|
||||
z: ["11111", "00001", "00010", "00100", "01000", "10000", "11111"],
|
||||
0: ["01110", "10001", "10011", "10101", "11001", "10001", "01110"],
|
||||
1: ["00100", "01100", "00100", "00100", "00100", "00100", "01110"],
|
||||
2: ["01110", "10001", "00001", "00010", "00100", "01000", "11111"],
|
||||
3: ["11110", "00001", "00001", "01110", "00001", "00001", "11110"],
|
||||
4: ["10010", "10010", "10010", "11111", "00010", "00010", "00010"],
|
||||
5: ["11111", "10000", "10000", "11110", "00001", "00001", "11110"],
|
||||
6: ["01111", "10000", "10000", "11110", "10001", "10001", "01110"],
|
||||
7: ["11111", "00001", "00010", "00100", "01000", "01000", "01000"],
|
||||
8: ["01110", "10001", "10001", "01110", "10001", "10001", "01110"],
|
||||
9: ["01110", "10001", "10001", "01111", "00001", "00001", "11110"],
|
||||
"-": ["00000", "00000", "00000", "11111", "00000", "00000", "00000"],
|
||||
_: ["00000", "00000", "00000", "00000", "00000", "00000", "11111"]
|
||||
};
|
||||
|
||||
const mimeTypes = {
|
||||
".html": "text/html; charset=utf-8",
|
||||
@@ -53,6 +93,35 @@ function captchaAccepted(value) {
|
||||
return String(value || "") === captchaPassphrase;
|
||||
}
|
||||
|
||||
function captchaSvg() {
|
||||
const cell = 4;
|
||||
const gap = 4;
|
||||
const padding = 10;
|
||||
const chars = [...captchaPassphrase.toLowerCase()];
|
||||
const width = Math.max(160, padding * 2 + chars.length * (5 * cell + gap) - gap);
|
||||
const height = 42;
|
||||
const rects = [];
|
||||
|
||||
chars.forEach((char, index) => {
|
||||
const glyph = captchaGlyphs[char] || captchaGlyphs._;
|
||||
const xOffset = padding + index * (5 * cell + gap);
|
||||
glyph.forEach((row, y) => {
|
||||
[...row].forEach((pixel, x) => {
|
||||
if (pixel === "1") {
|
||||
rects.push(`<rect x="${xOffset + x * cell}" y="${7 + y * cell}" width="${cell - 1}" height="${cell - 1}" rx="1"/>`);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}">
|
||||
<rect width="100%" height="100%" fill="#eef2f6"/>
|
||||
<path d="M0 34 C35 2 78 44 ${width} 12" stroke="rgba(24,32,42,0.22)" stroke-width="1.5" fill="none"/>
|
||||
<g fill="#18202a" transform="skewX(-4)">${rects.join("")}</g>
|
||||
</svg>`;
|
||||
}
|
||||
|
||||
function normalizePlaylist(playlist) {
|
||||
if (!Array.isArray(playlist)) return [];
|
||||
|
||||
@@ -190,13 +259,17 @@ const server = http.createServer(async (req, res) => {
|
||||
return;
|
||||
}
|
||||
|
||||
if (req.method === "GET" && url.pathname === "/config") {
|
||||
sendJson(res, 200, {
|
||||
captcha: {
|
||||
enabled: true,
|
||||
passphrase: captchaPassphrase
|
||||
}
|
||||
if ((req.method === "GET" || req.method === "HEAD") && url.pathname === "/captcha.svg") {
|
||||
res.writeHead(200, {
|
||||
"content-type": "image/svg+xml; charset=utf-8",
|
||||
"cache-control": "no-store"
|
||||
});
|
||||
res.end(req.method === "HEAD" ? undefined : captchaSvg());
|
||||
return;
|
||||
}
|
||||
|
||||
if (req.method === "GET" && url.pathname === "/captcha/verify") {
|
||||
sendJson(res, 200, { ok: captchaAccepted(url.searchParams.get("answer")) });
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user