feat: implement mail-login directadmin plugin

This commit is contained in:
Marek Miklewicz
2026-06-30 11:31:19 +02:00
parent f6506e3293
commit 77c5431db0
34 changed files with 1620 additions and 0 deletions
+76
View File
@@ -0,0 +1,76 @@
<?php
declare(strict_types=1);
final class ClientIp
{
/**
* @param array<string,mixed> $server
*/
public static function resolve(array $server, Settings $settings): string
{
$remote = self::validIp((string)($server['REMOTE_ADDR'] ?? ''));
if ($settings->clientIpMode() === 'direct') {
return $remote;
}
if (!self::ipInList($remote, $settings->trustedProxies())) {
throw new RuntimeException('REMOTE_ADDR is not a trusted proxy');
}
$xff = (string)($server['HTTP_X_FORWARDED_FOR'] ?? '');
foreach (explode(',', $xff) as $candidate) {
$candidate = trim($candidate);
if (filter_var($candidate, FILTER_VALIDATE_IP)) {
return $candidate;
}
}
throw new RuntimeException('Missing valid forwarded client IP');
}
private static function validIp(string $ip): string
{
$ip = trim($ip);
if (!filter_var($ip, FILTER_VALIDATE_IP)) {
throw new InvalidArgumentException('Invalid client IP');
}
return $ip;
}
/**
* @param list<string> $allowed
*/
private static function ipInList(string $ip, array $allowed): bool
{
foreach ($allowed as $entry) {
if ($entry === $ip) {
return true;
}
if (str_contains($entry, '/') && self::cidrContains($entry, $ip)) {
return true;
}
}
return false;
}
private static function cidrContains(string $cidr, string $ip): bool
{
[$network, $prefix] = array_pad(explode('/', $cidr, 2), 2, '');
if (!filter_var($network, FILTER_VALIDATE_IP) || !preg_match('/^[0-9]+$/', $prefix)) {
return false;
}
$networkBin = inet_pton($network);
$ipBin = inet_pton($ip);
if ($networkBin === false || $ipBin === false || strlen($networkBin) !== strlen($ipBin)) {
return false;
}
$bits = (int)$prefix;
$bytes = intdiv($bits, 8);
$remainder = $bits % 8;
if ($bytes > 0 && substr($networkBin, 0, $bytes) !== substr($ipBin, 0, $bytes)) {
return false;
}
if ($remainder === 0) {
return true;
}
$mask = chr((0xff << (8 - $remainder)) & 0xff);
return (ord($networkBin[$bytes]) & ord($mask)) === (ord($ipBin[$bytes]) & ord($mask));
}
}