diff options
| author | Gab <24553253+gabrix73@users.noreply.github.com> | 2026-08-14 20:39:22 +0200 |
|---|---|---|
| committer | Gab <24553253+gabrix73@users.noreply.github.com> | 2026-08-14 20:39:22 +0200 |
| commit | 43fbddf016f94f4ba006d82c9a67dca61b5852a1 (patch) | |
| tree | 70054d5fa8a34bb094b8c3ef8ddc9c1fcea3b3d5 /download_remailers.php | |
| parent | 994071243fc80990cf09e820b671006e9bd31c76 (diff) | |
| download | yamnweb-43fbddf016f94f4ba006d82c9a67dca61b5852a1.tar.gz yamnweb-43fbddf016f94f4ba006d82c9a67dca61b5852a1.tar.xz yamnweb-43fbddf016f94f4ba006d82c9a67dca61b5852a1.zip | |
Complete Nym and YAMN transport integration
Diffstat (limited to 'download_remailers.php')
| -rw-r--r-- | download_remailers.php | 104 |
1 files changed, 91 insertions, 13 deletions
diff --git a/download_remailers.php b/download_remailers.php index d601ac6..babfcbe 100644 --- a/download_remailers.php +++ b/download_remailers.php @@ -26,16 +26,23 @@ class SecureRemailerDownloader { private $storageDir = '/opt/yamn-data/cache'; private $remailersFile = '/opt/yamn-data/cache/remailers.txt'; private $pubringFile = '/opt/yamn-master/pubring.mix'; // Yamn expects it here + private $statsAttemptFile = '/opt/yamn-data/cache/remailers.last-attempt'; + private $keyringAttemptFile = '/opt/yamn-data/cache/pubring.last-attempt'; private $backupDir = '/opt/yamn-data/backups'; private $logFile = '/var/log/yamn_download.log'; - // Update interval with jitter (20-28 hours instead of exactly 24) - private $minUpdateInterval = 72000; // 20 hours - private $maxUpdateInterval = 100800; // 28 hours + // Reuse local data for a full day before contacting a pinger again. + private $updateInterval = 86400; // GPG verification (if available) private $verifyGPG = false; private $gpgKeyId = null; + + // Result of the most recent refresh attempt for each data set. + private $lastUpdateStatus = [ + 'stats' => 'not-run', + 'keyring' => 'not-run' + ]; public function __construct() { // Create directories if they don't exist @@ -51,6 +58,8 @@ class SecureRemailerDownloader { * Main download function with all security checks */ public function downloadRemailers() { + $this->resetUpdateStatus(); + // Download both stats and keyring $statsResult = $this->downloadStats(); $keyringResult = $this->downloadKeyring(); @@ -62,11 +71,20 @@ class SecureRemailerDownloader { * Download remailer stats (mlist.txt) */ private function downloadStats(bool $force = false) { - // Check if update is needed (with randomized interval) + // Check whether local data is older than one day. if (!$force && !$this->needsUpdate($this->remailersFile)) { $this->log("Stats update not needed yet"); + $this->lastUpdateStatus['stats'] = 'fresh'; + return true; + } + + if (!$force && $this->attemptIsRecent($this->statsAttemptFile)) { + $this->log("Stats refresh already attempted within the last day"); + $this->lastUpdateStatus['stats'] = 'deferred'; return true; } + + $this->markAttempt($this->statsAttemptFile); // Add random delay to prevent timing correlation $this->randomDelay(5, 60); @@ -74,6 +92,7 @@ class SecureRemailerDownloader { // Verify Tor is working if (!$this->checkTorConnection()) { $this->log("ERROR: Tor connection not available", 'ERROR'); + $this->lastUpdateStatus['stats'] = 'failed'; return false; } @@ -97,11 +116,13 @@ class SecureRemailerDownloader { if (!$success) { $this->log("ERROR: Failed to download stats from all sources", 'ERROR'); $this->restoreBackup($this->remailersFile, 'remailers'); + $this->lastUpdateStatus['stats'] = 'failed'; return false; } - + $this->log("Remailer stats updated successfully"); $this->cleanOldBackups('remailers'); + $this->lastUpdateStatus['stats'] = 'updated'; return true; } @@ -110,11 +131,20 @@ class SecureRemailerDownloader { * Download public keyring (pubring.mix) */ private function downloadKeyring(bool $force = false) { - // Check if update is needed (with randomized interval) + // Check whether local data is older than one day. if (!$force && !$this->needsUpdate($this->pubringFile)) { $this->log("Keyring update not needed yet"); + $this->lastUpdateStatus['keyring'] = 'fresh'; return true; } + + if (!$force && $this->attemptIsRecent($this->keyringAttemptFile)) { + $this->log("Keyring refresh already attempted within the last day"); + $this->lastUpdateStatus['keyring'] = 'deferred'; + return true; + } + + $this->markAttempt($this->keyringAttemptFile); // Add random delay to prevent timing correlation $this->randomDelay(5, 60); @@ -122,6 +152,7 @@ class SecureRemailerDownloader { // Verify Tor is working if (!$this->checkTorConnection()) { $this->log("ERROR: Tor connection not available", 'ERROR'); + $this->lastUpdateStatus['keyring'] = 'failed'; return false; } @@ -153,17 +184,19 @@ class SecureRemailerDownloader { if (!$success) { $this->log("ERROR: Failed to download keyring from all sources", 'ERROR'); $this->restoreBackup($this->pubringFile, 'pubring'); + $this->lastUpdateStatus['keyring'] = 'failed'; return false; } - + $this->log("Public keyring updated successfully"); $this->cleanOldBackups('pubring'); + $this->lastUpdateStatus['keyring'] = 'updated'; return true; } /** - * Check if update is needed with randomized interval + * Check if a local data file is older than one day. */ private function needsUpdate($filepath) { if (!file_exists($filepath)) { @@ -172,10 +205,27 @@ class SecureRemailerDownloader { $fileAge = time() - filemtime($filepath); - // Random threshold between 20-28 hours - $threshold = mt_rand($this->minUpdateInterval, $this->maxUpdateInterval); - - return $fileAge > $threshold; + return $fileAge > $this->updateInterval; + } + + /** + * Avoid retrying an unavailable source on every browser reload. + */ + private function attemptIsRecent($filepath) { + return file_exists($filepath) + && (time() - filemtime($filepath)) <= $this->updateInterval; + } + + /** + * Record an update attempt before opening any network connection. + */ + private function markAttempt($filepath) { + if (file_put_contents($filepath, (string) time(), LOCK_EX) === false) { + $this->log("Unable to record refresh attempt", 'WARNING'); + return; + } + + chmod($filepath, 0600); } /** @@ -538,11 +588,39 @@ class SecureRemailerDownloader { * Force update of both stats and keyring */ public function forceUpdate() { + $this->resetUpdateStatus(); + $statsResult = $this->downloadStats(true); $keyringResult = $this->downloadKeyring(true); - + return $statsResult && $keyringResult; } + + /** + * Return the result of the latest refresh attempt. + * + * Values are: fresh, updated, deferred, failed, or not-run. + */ + public function getLastUpdateStatus() { + return $this->lastUpdateStatus; + } + + /** + * Whether the existing statistics and keyring can still be used. + */ + public function hasUsableData() { + return file_exists($this->remailersFile) + && filesize($this->remailersFile) > 0 + && file_exists($this->pubringFile) + && filesize($this->pubringFile) > 0; + } + + private function resetUpdateStatus() { + $this->lastUpdateStatus = [ + 'stats' => 'not-run', + 'keyring' => 'not-run' + ]; + } /** * Get status of downloaded files |
