From 56e296e5875b10ed053cbdedbab08957fce2a461 Mon Sep 17 00:00:00 2001 From: Gab <24553253+gabrix73@users.noreply.github.com> Date: Sun, 16 Aug 2026 19:24:16 +0200 Subject: Harden Usenet threading and ingress delivery --- index.php | 52 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 3 deletions(-) (limited to 'index.php') diff --git a/index.php b/index.php index af646a6..bbab642 100644 --- a/index.php +++ b/index.php @@ -85,6 +85,43 @@ if (empty($_SESSION['csrf_token'])) { // Store current token for validation BEFORE any regeneration $currentCsrfToken = $_SESSION['csrf_token']; +/** + * Return remailer names whose public keys are valid today. + * + * @return array Name lookup table. + */ +function getUsableRemailerKeyNames(): array { + static $usableNames = null; + if (is_array($usableNames)) { + return $usableNames; + } + + $usableNames = []; + $keyring = yamnConfig('YAMN_PUBRING', '/opt/yamn-master/pubring.mix'); + if (!is_readable($keyring)) { + return $usableNames; + } + + $today = gmdate('Y-m-d'); + foreach (file($keyring, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) ?: [] as $line) { + $parts = preg_split('/\s+/', trim($line)); + if (count($parts) !== 7) { + continue; + } + [$name, , , , , $validFrom, $validUntil] = $parts; + if (!preg_match('/^[a-z0-9_-]+$/', $name) + || !preg_match('/^\d{4}-\d{2}-\d{2}$/', $validFrom) + || !preg_match('/^\d{4}-\d{2}-\d{2}$/', $validUntil)) { + continue; + } + if ($validFrom <= $today && $today <= $validUntil) { + $usableNames[$name] = true; + } + } + + return $usableNames; +} + /** * Parse remailers from file and return array by type * Entry and Exit can use ANY remailer @@ -95,6 +132,7 @@ $currentCsrfToken = $_SESSION['csrf_token']; */ function getRemailers($type) { $remailers = ['*']; // Always include Random option + $usableKeyNames = getUsableRemailerKeyNames(); // Try multiple file locations $files = [ @@ -140,6 +178,7 @@ function getRemailers($type) { // Validate name: lowercase letters, numbers, hyphens only if (!preg_match('/^[a-z0-9-]+$/', $remailerName)) continue; + if (!isset($usableKeyNames[$remailerName])) continue; // Check if last field is 'D' (middle capability flag) $lastField = end($parts); @@ -185,6 +224,9 @@ function resolveRemailer($remailer, $availableRemailers) { $randomIndex = array_rand($candidates); return $candidates[$randomIndex]; } + if (!in_array($remailer, $availableRemailers, true)) { + throw new Exception("Selected remailer is no longer available. Reload the page and choose again."); + } return $remailer; } @@ -246,11 +288,15 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { $middleRemailer = isset($_POST['middle_remailer']) ? filter_var($_POST['middle_remailer'], FILTER_SANITIZE_STRING) : ''; $exitRemailer = isset($_POST['exit_remailer']) ? filter_var($_POST['exit_remailer'], FILTER_SANITIZE_STRING) : ''; $from = isset($_POST['from']) ? filter_var($_POST['from'], FILTER_SANITIZE_STRING) : ''; - $replyTo = isset($_POST['reply_to']) ? filter_var($_POST['reply_to'], FILTER_SANITIZE_STRING) : ''; + $replyTo = isset($_POST['reply_to']) && is_string($_POST['reply_to']) + ? trim($_POST['reply_to']) + : ''; $to = isset($_POST['to']) ? filter_var($_POST['to'], FILTER_SANITIZE_EMAIL) : ''; $subject = isset($_POST['subject']) ? filter_var($_POST['subject'], FILTER_SANITIZE_STRING) : ''; $newsgroups = isset($_POST['newsgroups']) ? filter_var($_POST['newsgroups'], FILTER_SANITIZE_STRING) : ''; - $references = isset($_POST['references']) ? filter_var($_POST['references'], FILTER_SANITIZE_STRING) : ''; + $references = isset($_POST['references']) && is_string($_POST['references']) + ? trim($_POST['references']) + : ''; $data = isset($_POST['data']) ? $_POST['data'] : ''; // Keep original formatting $copies = isset($_POST['copies']) ? intval($_POST['copies']) : 1; @@ -766,7 +812,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
Required for email delivery. Leave empty when publishing to a newsgroup.
Optional. When set, the message is routed through the configured Mail-to-News gateway. Leave empty for email.
-
Optional. Links the article to an existing thread.
+
Optional. Enter one or more space-separated Message-IDs, without the References: label. The last ID becomes In-Reply-To.
The server creates the encrypted YAMN envelope in memory and sends only that packet through Nym. Remailer queues may take several hours.
-- cgit v1.2.3