diff --git a/exec/handlers/login.php b/exec/handlers/login.php index 33c47f2..c19c13b 100644 --- a/exec/handlers/login.php +++ b/exec/handlers/login.php @@ -26,7 +26,7 @@ return static function (): void { ]; $clientIp = ClientIp::resolve($_SERVER, $settings); - $auditBase['client_ip'] = $clientIp; + $auditBase['client_ip'] = $settings->auditClientIp($clientIp); $createdAt = time(); $correlation = KeyName::build($ctx->serverName(), $ctx->username(), $createdAt); $auditBase['correlation'] = $correlation; diff --git a/exec/lib/Settings.php b/exec/lib/Settings.php index f4cfe9c..5883473 100644 --- a/exec/lib/Settings.php +++ b/exec/lib/Settings.php @@ -64,6 +64,7 @@ final class Settings 'MAIL_LOGIN_REDIRECT_URL' => '/', 'LOGIN_KEY_TTL' => '30', 'USER_IP_BOUND' => '1', + 'IP_MASK' => '1', 'MAIL_LOGIN_SOURCE_SERVER_NAME' => '', 'MAIL_LOGIN_CLIENT_IP_MODE' => 'direct', 'MAIL_LOGIN_TRUSTED_PROXIES' => '', @@ -135,6 +136,16 @@ final class Settings return $this->getString('USER_IP_BOUND', '1') === '1'; } + public function ipMask(): bool + { + return $this->getString('IP_MASK', '1') === '1'; + } + + public function auditClientIp(string $clientIp): string + { + return $this->ipMask() ? 'MASLED' : $clientIp; + } + public function sourceServerName(): string { return $this->sanitizeServerName($this->getString('MAIL_LOGIN_SOURCE_SERVER_NAME', '')); @@ -247,6 +258,9 @@ final class Settings if (!in_array($this->getString('USER_IP_BOUND', ''), ['0', '1'], true)) { throw new InvalidArgumentException('USER_IP_BOUND must be 0 or 1'); } + if (!in_array($this->getString('IP_MASK', ''), ['0', '1'], true)) { + throw new InvalidArgumentException('IP_MASK must be 0 or 1'); + } if (!in_array(strtolower($this->getString('DEFAULT_ENABLE', 'true')), ['0', '1', 'true', 'false', 'yes', 'no', 'on', 'off'], true)) { throw new InvalidArgumentException('DEFAULT_ENABLE must be a boolean value'); } diff --git a/plugin-settings.conf b/plugin-settings.conf index 2a95388..ff2399c 100644 --- a/plugin-settings.conf +++ b/plugin-settings.conf @@ -24,6 +24,10 @@ LOGIN_KEY_TTL=30 # 1 = przypnij URL do IP przeglądarki użytkownika, 0 = nie przypinaj do IP. USER_IP_BOUND=1 +# 1 = maskuj IP użytkownika w audit.log jako MASLED, 0 = zapisuj rzeczywiste IP. +# To ustawienie nie zmienia IP przekazywanego do DirectAdmin przez --ip. +IP_MASK=1 + # Opcjonalna jawna nazwa źródłowego serwera. Puste = pierwsza etykieta SERVER_NAME. MAIL_LOGIN_SOURCE_SERVER_NAME= diff --git a/plugin.conf b/plugin.conf index c4a8f32..9e24192 100644 --- a/plugin.conf +++ b/plugin.conf @@ -2,7 +2,7 @@ name=mail-login id=mail-login type=user author=HITME.PL -version=1.0.7 +version=1.0.8 active=no installed=no user_run_as=root diff --git a/tests/package_contents_test.php b/tests/package_contents_test.php index 03a10c3..77daf14 100644 --- a/tests/package_contents_test.php +++ b/tests/package_contents_test.php @@ -8,7 +8,7 @@ test('plugin metadata and packaging docs match project rules', function (): void assert_contains('name=mail-login', $conf); assert_contains('id=mail-login', $conf); assert_contains('type=user', $conf); - assert_contains('version=1.0.7', $conf); + assert_contains('version=1.0.8', $conf); assert_contains('user_run_as=root', $conf); assert_contains('/Users/marek/GPT/ChatGPT/da_plugins/mail-login/src', $packing); assert_contains('/Users/marek/GPT/ChatGPT/da_plugins/mail-login/archives/X.Y.Z/mail-login.tar.gz', $packing); diff --git a/tests/settings_test.php b/tests/settings_test.php index 519109d..1b4b8ae 100644 --- a/tests/settings_test.php +++ b/tests/settings_test.php @@ -8,6 +8,8 @@ test('settings expose secure defaults from plugin-settings.conf', function (): v assert_same(30, $settings->loginKeyTtl()); assert_true($settings->userIpBound()); + assert_true($settings->ipMask()); + assert_same('MASLED', $settings->auditClientIp('198.51.100.10')); assert_true($settings->defaultEnable()); assert_same('login_url', $settings->method()); assert_same(1, $settings->mxLoginMode()); @@ -34,14 +36,28 @@ test('settings accept explicit ttl and user ip binding toggle', function (): voi $settings = Settings::fromArray([ 'LOGIN_KEY_TTL' => '5', 'USER_IP_BOUND' => '0', + 'IP_MASK' => '0', 'MX_LOGIN_MODE' => '2', ]); assert_same(5, $settings->loginKeyTtl()); assert_false($settings->userIpBound()); + assert_false($settings->ipMask()); + assert_same('198.51.100.10', $settings->auditClientIp('198.51.100.10')); assert_same(2, $settings->mxLoginMode()); }); +test('settings reject unsupported ip mask values', function (): void { + foreach (['yes', '2', ''] as $mask) { + try { + Settings::fromArray(['IP_MASK' => $mask]); + throw new RuntimeException('Expected invalid IP_MASK to fail: ' . $mask); + } catch (InvalidArgumentException $e) { + assert_contains('IP_MASK', $e->getMessage()); + } + } +}); + test('settings reject unsupported mx login mode values', function (): void { foreach (['0', '3', 'helper', ''] as $mode) { try {