1
0
mirror of git://f0xx.org/ac/ac-deploy synced 2026-07-29 07:17:38 +03:00

fix(cluster0): wire 2FA redirects, heartbeat session touch, TOTP reset script

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Anton Afanasyeu
2026-07-11 14:48:27 +02:00
parent a411dc5405
commit 54174e7497
4 changed files with 77 additions and 9 deletions

View File

@@ -62,4 +62,8 @@ if ($type === 'ra') {
$resp['heartbeat'] = array_merge($resp['heartbeat'], $ra);
}
if (Auth::user()) {
Auth::touchSession();
}
echo json_encode($resp, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);

View File

@@ -132,6 +132,11 @@ if ($route === '/api/rbac.php' || str_ends_with($route, '/api/rbac.php')) {
exit;
}
if ($route === '/api/media_pipelines.php' || str_ends_with($route, '/api/media_pipelines.php')) {
require __DIR__ . '/api/media_pipelines.php';
exit;
}
if ($route === '/api/ticket_attachment.php' || str_ends_with($route, '/api/ticket_attachment.php')) {
require __DIR__ . '/api/ticket_attachment.php';
exit;
@@ -159,11 +164,12 @@ if ($route === '/logout') {
}
if ($route === '/login' && $_SERVER['REQUEST_METHOD'] === 'POST') {
Auth::captureRedirectFromRequest();
$user = trim($_POST['username'] ?? '');
$pass = $_POST['password'] ?? '';
$result = Auth::login($user, $pass);
if ($result === true) {
header('Location: ' . $base . '/');
header('Location: ' . Auth::postLoginRedirect($base . '/'));
exit;
}
if ($result === 'pending_2fa') {
@@ -184,10 +190,12 @@ if ($route === '/login' && $_SERVER['REQUEST_METHOD'] === 'POST') {
}
if ($route === '/login') {
Auth::captureRedirectFromRequest();
if (Auth::pending2faUserId() > 0) {
header('Location: ' . Auth::authUrl('/two-factor'));
exit;
}
$loginRedirect = Auth::peekPostLoginRedirect('');
require __DIR__ . '/../views/login.php';
exit;
}
@@ -242,7 +250,7 @@ if ($route === '/two-factor' && $_SERVER['REQUEST_METHOD'] === 'POST') {
}
$code = trim($_POST['code'] ?? '');
if (Auth::completeTotpLogin($code)) {
header('Location: ' . $base . '/');
header('Location: ' . Auth::postLoginRedirect($base . '/'));
exit;
}
$twofaError = 'Invalid code';
@@ -278,9 +286,11 @@ if (
$_SESSION['pending_2fa_exp'] = time() + 300;
$status = AuthApproval::pollStatus($rawToken);
if ($status === 'approved') {
// Attempt to complete the login server-side within this same request
if (Auth::completeTotpLoginByApproval($rawToken)) {
echo json_encode(['status' => 'approved', 'redirect' => $base . '/']);
echo json_encode([
'status' => 'approved',
'redirect' => Auth::postLoginRedirect($base . '/'),
]);
} else {
echo json_encode(['status' => 'expired']);
}
@@ -292,13 +302,19 @@ if (
// Approval confirmation page shown to the already-logged-in mobile user.
if ($route === '/two-factor/approve' && $_SERVER['REQUEST_METHOD'] === 'POST') {
$rawToken = trim($_POST['token'] ?? '');
$totpCode = trim($_POST['code'] ?? '');
$mobileUser = Auth::user();
if (!$mobileUser) {
header('Location: ' . Auth::authUrl('/login') . '?redirect=' . urlencode(Auth::authUrl('/two-factor/approve') . '?token=' . urlencode($_POST['token'] ?? '')));
$approved = false;
if ($mobileUser && $rawToken !== '') {
$approved = AuthApproval::approve($rawToken, (int) ($mobileUser['id'] ?? 0), Auth::clientIp());
} elseif ($rawToken !== '' && $totpCode !== '') {
$approved = AuthApproval::approveWithTotp($rawToken, $totpCode, Auth::clientIp());
} else {
$returnUrl = Auth::authUrl('/two-factor/approve') . '?token=' . urlencode($rawToken);
header('Location: ' . Auth::authUrl('/login') . '?redirect=' . urlencode($returnUrl));
exit;
}
$rawToken = trim($_POST['token'] ?? '');
$approved = $rawToken !== '' && AuthApproval::approve($rawToken, (int) ($mobileUser['id'] ?? 0), Auth::clientIp());
$approveResult = $approved ? 'ok' : 'error';
require __DIR__ . '/../views/two_factor_approve.php';
exit;
@@ -398,6 +414,15 @@ if ($view === 'short_links' && !Rbac::can('short_links_view')) {
exit;
}
if ($view === 'media_pipelines') {
require_once __DIR__ . '/../src/MediaPipelinesRepository.php';
if (!MediaPipelinesRepository::gateAllowed()) {
http_response_code(403);
echo 'Forbidden';
exit;
}
}
if ($view === 'report' && isset($_GET['id'])) {
try {
$report = ReportRepository::getById((int) $_GET['id']);
@@ -455,6 +480,7 @@ $pageTitle = match ($view) {
'live_sessions' => 'Live sessions',
'remote_access' => 'Remote access',
'short_links' => 'Short links',
'media_pipelines' => 'Media pipelines',
'rbac' => 'Access control',
'reports', 'report' => 'Issues',
default => 'Console',