Files
novacpx/panel/api/endpoints/auth.php
T
myron 62707d62ce Fail2Ban whitelist management + auth failure logging
- firewall.php: auto-detect server IPs (loopback, all interface IPs,
  private /24 subnets) for Fail2Ban ignoreip; f2b-ignoreip-list/add/
  remove/reset actions; write to jail.local directly (www-data owns it);
  f2b_set_ignoreip() reloads fail2ban after every change
- auth.php: log failed logins to /var/log/novacpx/access.log in format
  fail2ban filters expect — "FAILED LOGIN from <IP> [portal]"
- deploy/fail2ban/: filter.d conf files for all 4 NovaCPX jails
- install.sh: auto-detect local IPs → ignoreip in jail.local; install
  filter files; create access.log (www-data:www-data 664)
- admin.js: Fail2Ban Whitelist section in firewall page — chip list with
  add/remove/reset; loopback shown with lock icon and non-removable

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 16:10:05 +00:00

58 lines
2.2 KiB
PHP

<?php
$method = $_SERVER['REQUEST_METHOD'];
$body = json_decode(file_get_contents('php://input'), true) ?? [];
match ($action) {
'login' => (function() use ($body) {
$username = trim($body['username'] ?? '');
$password = $body['password'] ?? '';
if (!$username || !$password) Response::error('Username and password required');
$auth = Auth::getInstance();
$token = $auth->attempt($username, $password);
if (!$token) {
// Log failure for Fail2Ban to detect
$ip = $_SERVER['REMOTE_ADDR'] ?? 'unknown';
$port = (int)($_SERVER['SERVER_PORT'] ?? 0);
$portal = $port === PORT_ADMIN ? 'admin' : ($port === PORT_RESELLER ? 'reseller' : ($port === PORT_WEBMAIL ? 'webmail' : 'user'));
$logLine = date('Y-m-d H:i:s') . " FAILED LOGIN from {$ip} [{$portal}] user:{$username}\n";
@file_put_contents('/var/log/novacpx/access.log', $logLine, FILE_APPEND | LOCK_EX);
novacpx_log('warn', "Failed login for '$username' from $ip");
Response::error('Invalid credentials', 401);
}
$user = $auth->user();
audit('login', 'auth');
Response::success([
'token' => $token,
'portal_url' => Auth::portalUrl($user['role']),
'user' => [
'id' => $user['id'],
'username' => $user['username'],
'email' => $user['email'],
'role' => $user['role'],
'theme' => $user['theme'],
],
], 'Login successful');
})(),
'logout' => (function() {
Auth::getInstance()->logout();
audit('logout', 'auth');
Response::success(null, 'Logged out');
})(),
'me' => (function() {
$auth = Auth::getInstance();
if (!$auth->check()) Response::error('Unauthorized', 401);
$u = $auth->user();
Response::success([
'id' => $u['uid'] ?? $u['id'],
'username' => $u['username'],
'email' => $u['email'],
'role' => $u['role'],
'theme' => $u['theme'],
]);
})(),
default => Response::error('Unknown auth action', 404),
};