Commit 2a0e463d authored by Vitaly Lipatov's avatar Vitaly Lipatov

web: require browser challenge for unban

parent eca023ed
<?php <?php
header('Content-Type: text/html; charset=utf-8'); header('Content-Type: text/html; charset=utf-8');
session_start();
$ip = $_SERVER['REMOTE_ADDR'] ?? ''; $ip = $_SERVER['REMOTE_ADDR'] ?? '';
$settings = parse_ini_file('/etc/eterban/settings.ini'); $settings = parse_ini_file('/etc/eterban/settings.ini');
...@@ -16,6 +17,47 @@ if (empty($hostname)) { ...@@ -16,6 +17,47 @@ if (empty($hostname)) {
$hostname = gethostname(); $hostname = gethostname();
} }
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
$nonce = bin2hex(random_bytes(16));
$_SESSION['eterban_unban_nonce'] = $nonce;
$_SESSION['eterban_unban_expires'] = time() + 300;
?>
<!doctype html>
<html><head><meta charset="utf-8"><title>Unban request</title></head>
<body><p>Preparing unban request…</p>
<noscript>JavaScript is required to submit an unban request.</noscript>
<form id="unban-form" method="post">
<input type="hidden" name="nonce" value="<?= htmlspecialchars($nonce, ENT_QUOTES, 'UTF-8') ?>">
<input type="hidden" id="proof" name="proof">
</form>
<script>
async function submitUnban() {
const nonce = document.querySelector('[name=nonce]').value;
const bytes = new TextEncoder().encode('eterban-unban-v1:' + nonce);
const digest = await crypto.subtle.digest('SHA-256', bytes);
document.getElementById('proof').value = [...new Uint8Array(digest)]
.map(value => value.toString(16).padStart(2, '0')).join('');
document.getElementById('unban-form').submit();
}
submitUnban();
</script></body></html>
<?php
exit;
}
$nonce = $_POST['nonce'] ?? '';
$proof = $_POST['proof'] ?? '';
$expires = $_SESSION['eterban_unban_expires'] ?? 0;
$session_nonce = $_SESSION['eterban_unban_nonce'] ?? '';
$expected = hash('sha256', 'eterban-unban-v1:' . $session_nonce);
unset($_SESSION['eterban_unban_nonce'], $_SESSION['eterban_unban_expires']);
if (!is_string($nonce) || !is_string($proof) || time() > $expires ||
!hash_equals($session_nonce, $nonce) ||
!hash_equals($expected, $proof)) {
http_response_code(400);
exit('Invalid or expired unban challenge.');
}
try { try {
$redis = new Redis(); $redis = new Redis();
if (!$redis->connect($host_redis, 6379, 2.5)) { if (!$redis->connect($host_redis, 6379, 2.5)) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment