Merge pull request #41 from GeoffMoore1979/feature/media-users-pages
fix: suppress verbose PHP errors and bound login/audit housekeeping cost
This commit was merged in pull request #41.
This commit is contained in:
@@ -1,6 +1,12 @@
|
|||||||
<?php
|
<?php
|
||||||
/** Shared entry-point setup: loads configuration into $config and registers the NeoCMS class autoloader. */
|
/** Shared entry-point setup: loads configuration into $config and registers the NeoCMS class autoloader. */
|
||||||
|
|
||||||
|
// Keep stack traces and filesystem paths out of responses; every engine warning still reaches PHP's own error log.
|
||||||
|
error_reporting(E_ALL);
|
||||||
|
ini_set('display_errors', '0');
|
||||||
|
ini_set('display_startup_errors', '0');
|
||||||
|
ini_set('log_errors', '1');
|
||||||
|
|
||||||
require_once __DIR__ . '/config.php';
|
require_once __DIR__ . '/config.php';
|
||||||
|
|
||||||
// URL prefix of the site root: "/neocms" for http://localhost/neocms/, "" for a site at the domain root.
|
// URL prefix of the site root: "/neocms" for http://localhost/neocms/, "" for a site at the domain root.
|
||||||
|
|||||||
@@ -42,7 +42,9 @@ class Logger
|
|||||||
}
|
}
|
||||||
@chmod($this->logsDir, 0700);
|
@chmod($this->logsDir, 0700);
|
||||||
|
|
||||||
if ($this->auditEnabled) {
|
// Pruning scans every rotated log file; a Logger is built on every request, so do this
|
||||||
|
// occasionally rather than on each one (the same probabilistic approach as PHP's own session GC).
|
||||||
|
if ($this->auditEnabled && random_int(1, 100) === 1) {
|
||||||
$this->pruneExpiredLogs();
|
$this->pruneExpiredLogs();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,9 @@ final class LoginRateLimiter
|
|||||||
private int $maxIdentityAttempts;
|
private int $maxIdentityAttempts;
|
||||||
private int $maxAddressAttempts;
|
private int $maxAddressAttempts;
|
||||||
|
|
||||||
|
/** Hard ceiling on tracked buckets, so a distributed flood of distinct addresses or login names cannot grow the state file without bound. */
|
||||||
|
private const MAX_TRACKED_KEYS = 20000;
|
||||||
|
|
||||||
/** Configure the protected state file and throttling thresholds. */
|
/** Configure the protected state file and throttling thresholds. */
|
||||||
public function __construct(string $dataDirectory, array $options = [])
|
public function __construct(string $dataDirectory, array $options = [])
|
||||||
{
|
{
|
||||||
@@ -93,6 +96,16 @@ final class LoginRateLimiter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
unset($record);
|
unset($record);
|
||||||
|
|
||||||
|
if (count($state) > self::MAX_TRACKED_KEYS) {
|
||||||
|
// Evict the least recently active buckets first; an evicted bucket simply restarts its count.
|
||||||
|
uasort($state, static function (array $a, array $b): int {
|
||||||
|
$lastA = max((int) ($a['locked_until'] ?? 0), $a['attempts'] ? (int) end($a['attempts']) : 0);
|
||||||
|
$lastB = max((int) ($b['locked_until'] ?? 0), $b['attempts'] ? (int) end($b['attempts']) : 0);
|
||||||
|
return $lastA <=> $lastB;
|
||||||
|
});
|
||||||
|
$state = array_slice($state, -self::MAX_TRACKED_KEYS, null, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Serialise state updates beneath an exclusive lock to avoid concurrent lost updates. */
|
/** Serialise state updates beneath an exclusive lock to avoid concurrent lost updates. */
|
||||||
|
|||||||
Reference in New Issue
Block a user