mirror of
https://github.com/Wolvan/poll.horse.git
synced 2024-11-21 20:47:59 +01:00
Use CSRF token to discourage botting
A suggestion to avoid stupid bots to vote on polls was a token that gets checked to a session cookie on vote submission.
This commit is contained in:
parent
6a155f2eb4
commit
ab151cb732
3 changed files with 22 additions and 0 deletions
|
@ -36,6 +36,7 @@
|
|||
<section class="notepad">
|
||||
<div class="notepad-border"></div>
|
||||
<form action="{{ BACKEND_BASE_PATH }}/_backend/vote-form/{{ POLL_ID }}" method="POST">
|
||||
<input type="hidden" name="csrf_token" value="{{ CSRF_TOKEN }}">
|
||||
<section class="poll-title">
|
||||
{{ POLL_TITLE }}
|
||||
</section>
|
||||
|
|
|
@ -4,6 +4,7 @@ import { CookieOptions, Router } from "express";
|
|||
import { BackendPoll as Poll, DupeCheckMode } from "./Poll";
|
||||
import { MAX_POLL_OPTIONS, MAX_CHARACTER_LENGTH } from "./Config";
|
||||
import Storage from "./Storage";
|
||||
import crypto from "crypto";
|
||||
|
||||
function randomString(length = 10, charset = "abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789") {
|
||||
let result = "";
|
||||
|
@ -213,12 +214,25 @@ export default async function init(router: Router, polls: Storage): Promise<void
|
|||
const id = req.params.id;
|
||||
const votes = [].concat(req.body["poll-option"]);
|
||||
|
||||
const csrfTokenFromForm = req.body["csrf_token"];
|
||||
const csrfTokenFromCookie = req.cookies.csrftoken;
|
||||
|
||||
if (csrfTokenFromForm !== csrfTokenFromCookie) return res.redirect(`/${id}?error=${
|
||||
encodeURIComponent("Invalid CSRF token")
|
||||
}&options=${
|
||||
encodeURIComponent(votes.slice(0, MAX_POLL_OPTIONS).join("\uFFFE"))
|
||||
}`);
|
||||
|
||||
const error = await voteOnPoll(id, votes, {
|
||||
ip: req.headers["x-forwarded-for"] as string || req.socket.remoteAddress || "",
|
||||
setCookie: res.cookie.bind(res),
|
||||
cookies: req.cookies
|
||||
});
|
||||
|
||||
res.cookie("csrftoken", crypto.randomBytes(32).toString("base64"), {
|
||||
httpOnly: true,
|
||||
});
|
||||
|
||||
if (!error) return res.redirect("/" + id + "/r");
|
||||
if (error.statusCode === 404) return res.redirect("/");
|
||||
res.redirect(`/${id}?error=${
|
||||
|
|
|
@ -7,6 +7,7 @@ import fetch from 'node-fetch';
|
|||
import { program } from "commander";
|
||||
import { FrontendPoll as Poll, PollResult } from "./Poll";
|
||||
import { MAX_CHARACTER_LENGTH, MAX_POLL_OPTIONS } from "./Config";
|
||||
import crypto from "crypto";
|
||||
|
||||
const RenderBuffer = new WeakMap();
|
||||
const RenderReplacements = new WeakMap();
|
||||
|
@ -158,7 +159,13 @@ export default function init(router: Router): void {
|
|||
</div>`
|
||||
).join("");
|
||||
|
||||
const csrfToken = req.cookies.csrftoken || crypto.randomBytes(32).toString("base64");
|
||||
res.cookie("csrftoken", csrfToken, {
|
||||
httpOnly: true,
|
||||
});
|
||||
|
||||
await displayPage(req, res, "poll.html", {
|
||||
"CSRF_TOKEN": csrfToken,
|
||||
"POLL_ID": poll.id,
|
||||
"POLL_TITLE": xss(poll.title),
|
||||
"POLL_OPTION_DIVS": pollOptions,
|
||||
|
|
Loading…
Reference in a new issue