From 061431f36ac1023ce3d420b792d137e7362d63d1 Mon Sep 17 00:00:00 2001 From: Hamza-Ayed Date: Sun, 3 May 2026 15:16:36 +0300 Subject: [PATCH] =?UTF-8?q?=F0=9F=9A=80=20=D9=85=D9=8F=D8=B5=D8=A7=D8=AF?= =?UTF-8?q?=D9=8E=D9=82:=20=D8=AA=D8=AD=D8=AF=D9=8A=D8=AB=20=D8=A8=D8=B1?= =?UTF-8?q?=D9=85=D8=AC=D9=8A=20=D8=AC=D8=AF=D9=8A=D8=AF=202026-05-03=2015?= =?UTF-8?q?:16?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Core/Application.php | 2 +- app/Modules/Auth/AuthController.php | 31 ++++++++++++++++ public/index.php | 9 +++-- public/shell.php | 56 ++++++++++++++++++++++++++++- 4 files changed, 94 insertions(+), 4 deletions(-) diff --git a/app/Core/Application.php b/app/Core/Application.php index c6f7ace..f2e516a 100644 --- a/app/Core/Application.php +++ b/app/Core/Application.php @@ -64,7 +64,7 @@ final class Application header('Strict-Transport-Security: max-age=31536000; includeSubDomains; preload'); header('Referrer-Policy: strict-origin-when-cross-origin'); header('Permissions-Policy: camera=(), microphone=(), geolocation=()'); - header('Content-Security-Policy: default-src \'self\'; script-src \'self\' cdn.tailwindcss.com unpkg.com; style-src \'self\' \'unsafe-inline\' fonts.googleapis.com; font-src fonts.gstatic.com'); + header('Content-Security-Policy: default-src \'self\'; script-src \'self\' \'unsafe-inline\' cdn.tailwindcss.com unpkg.com cdn.jsdelivr.net; style-src \'self\' \'unsafe-inline\' fonts.googleapis.com; font-src fonts.gstatic.com; img-src \'self\' data: blob:;'); header_remove('X-Powered-By'); try { diff --git a/app/Modules/Auth/AuthController.php b/app/Modules/Auth/AuthController.php index 533fba6..bfd7fc8 100644 --- a/app/Modules/Auth/AuthController.php +++ b/app/Modules/Auth/AuthController.php @@ -178,6 +178,37 @@ final class AuthController } } + public function login2FAVerify(Request $request): void + { + $data = $request->getBody(); + $code = $data['code'] ?? ''; + $userId = $request->user->user_id; + + $db = \App\Core\Database::getInstance(); + $stmt = $db->prepare("SELECT totp_secret FROM users WHERE id = ?"); + $stmt->execute([$userId]); + $secret = $stmt->fetchColumn(); + + $totpService = new \App\Services\TotpService(); + if ($secret && $totpService->verify($secret, $code)) { + // Re-fetch user for full data + $stmt = $db->prepare("SELECT * FROM users WHERE id = ?"); + $stmt->execute([$userId]); + $user = $stmt->fetch(); + + $authService = new AuthService(); + $tokens = $authService->generateTokens($user); + + Response::json([ + 'success' => true, + 'data' => $tokens, + 'message' => 'تم التحقق بنجاح' + ]); + } else { + Response::error('رمز التحقق غير صحيح', 'INVALID_CODE', 401); + } + } + public function disable2FA(Request $request): void { $db = \App\Core\Database::getInstance(); diff --git a/public/index.php b/public/index.php index 03a75c1..146ceae 100644 --- a/public/index.php +++ b/public/index.php @@ -31,6 +31,10 @@ $router->addRoute('POST', '/api/v1/auth/2fa/verify', [ 'middleware' => [\App\Middleware\AuthMiddleware::class], 'handler' => [AuthController::class, 'verify2FA'] ]); +$router->addRoute('POST', '/api/v1/auth/2fa/verify_login', [ + 'middleware' => [\App\Middleware\AuthMiddleware::class], + 'handler' => [AuthController::class, 'login2FAVerify'] +]); $router->addRoute('POST', '/api/v1/auth/2fa/disable', [ 'middleware' => [\App\Middleware\AuthMiddleware::class], 'handler' => [AuthController::class, 'disable2FA'] @@ -139,9 +143,10 @@ $router->addRoute('GET', '/api/v1/health', function($request) { }); // ══ Determine if this is an API request ═════════════════════════════ -$apiRoute = $_GET['route'] ?? null; +$requestPath = $_GET['route'] ?? parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH); +$isApi = str_starts_with($requestPath, '/api/v1'); -if (!$apiRoute) { +if (!$isApi) { // Not an API call — serve the SPA shell include __DIR__ . '/shell.php'; exit; diff --git a/public/shell.php b/public/shell.php index d76aea5..477971a 100644 --- a/public/shell.php +++ b/public/shell.php @@ -147,7 +147,7 @@