From cee6265930155d99ea41cb573fb4b7e79fb237f9 Mon Sep 17 00:00:00 2001 From: Hamza-Ayed Date: Wed, 26 Aug 2026 23:01:25 +0300 Subject: [PATCH] fix: Accurate Nabeh OTP response parsing and live gateway error reporting --- backend/app/Controllers/AuthController.php | 36 ++++++++++--- backend/app/Services/NabehService.php | 59 ++++++++++++++++------ 2 files changed, 72 insertions(+), 23 deletions(-) diff --git a/backend/app/Controllers/AuthController.php b/backend/app/Controllers/AuthController.php index fa7d6c8..0c29a27 100644 --- a/backend/app/Controllers/AuthController.php +++ b/backend/app/Controllers/AuthController.php @@ -90,9 +90,35 @@ class AuthController // 4. Send OTP via Nabeh Service $nabeh = new NabehService(); - $sent = $nabeh->sendOtp($cleanPhone, $otp, 'image', $appName); + $sendResult = $nabeh->sendOtp($cleanPhone, $otp, 'image', $appName); - $isDebug = filter_var(getenv('APP_DEBUG') ?: true, FILTER_VALIDATE_BOOLEAN); + $isDebug = filter_var(getenv('APP_DEBUG'), FILTER_VALIDATE_BOOLEAN); + + if (!$sendResult['success']) { + $errorMsg = $sendResult['error'] ?? 'تعذر إرسال رمز التحقق عبر الواتساب من منصة نبيه'; + + if ($isDebug) { + // In debug mode, allow progression with debug OTP + $response->json([ + 'status' => 'success', + 'message' => 'وضع التطوير نشط (تعذر الإرسال الفعلي) — الرمز: ' . $otp, + 'debug_otp' => $otp, + 'data' => [ + 'phone_masked' => substr($cleanPhone, 0, 3) . '****' . substr($cleanPhone, -3), + 'expires_in' => 300, + 'gateway_error' => $sendResult + ] + ]); + return; + } + + $response->status(502)->json([ + 'status' => 'error', + 'message' => $errorMsg, + 'gateway_error' => $sendResult + ]); + return; + } $resData = [ 'status' => 'success', @@ -103,12 +129,8 @@ class AuthController ] ]; - // Expose OTP only in debug mode for seamless local testing - if ($isDebug || !$sent) { + if ($isDebug) { $resData['debug_otp'] = $otp; - if (!$sent) { - $resData['message'] = 'تم توليد رمز التحقق (بيئة التطوير / محاكاة الإرسال)'; - } } $response->json($resData); diff --git a/backend/app/Services/NabehService.php b/backend/app/Services/NabehService.php index 454444e..0bd95f0 100644 --- a/backend/app/Services/NabehService.php +++ b/backend/app/Services/NabehService.php @@ -18,7 +18,6 @@ class NabehService $this->email = (string)getenv('NABEH_EMAIL'); $this->password = (string)getenv('NABEH_PASSWORD'); - // Strict validation: NO fallback defaults allowed $missing = []; if (empty($this->authUrl)) $missing[] = 'NABEH_AUTH_URL'; if (empty($this->sendUrl)) $missing[] = 'NABEH_SEND_URL'; @@ -39,7 +38,7 @@ class NabehService try { $redis = RedisClient::getInstance(); $cachedToken = $redis->get('nabeh_bearer_token'); - if ($cachedToken) { + if ($cachedToken && strlen((string)$cachedToken) > 20) { return (string)$cachedToken; } } catch (\Exception $e) { @@ -57,8 +56,10 @@ class NabehService CURLOPT_POST => true, CURLOPT_POSTFIELDS => $payload, CURLOPT_RETURNTRANSFER => true, - CURLOPT_TIMEOUT => 15, + CURLOPT_TIMEOUT => 30, + CURLOPT_CONNECTTIMEOUT => 10, CURLOPT_HTTPHEADER => ['Content-Type: application/json'], + CURLOPT_SSL_VERIFYPEER => false, ]); $response = curl_exec($ch); @@ -101,11 +102,18 @@ class NabehService if (!$bearerToken) { return [ 'success' => false, - 'error' => 'فشل الحصول على توكن المصادقة من منصة نبيه. تأكد من صحة NABEH_EMAIL و NABEH_PASSWORD.' + 'error' => 'فشل الحصول على توكن المصادقة من منصة نبيه. تأكد من صحة NABEH_EMAIL و NABEH_PASSWORD في .env.' ]; } + // Clean phone format: ensure Jordan numbers are standardized (9627XXXXXXXX) $phoneRaw = preg_replace('/\D+/', '', $receiver); + if (str_starts_with($phoneRaw, '07')) { + $phoneRaw = '962' . substr($phoneRaw, 1); + } elseif (str_starts_with($phoneRaw, '7') && strlen($phoneRaw) === 9) { + $phoneRaw = '962' . $phoneRaw; + } + $type = in_array($method, ['text', 'voice', 'image'], true) ? $method : 'image'; // 1. First attempt with image @@ -116,8 +124,13 @@ class NabehService // 2. Fallback to text if image fails if ($type === 'image') { - error_log("ℹ️ [Nabeh OTP Fallback] Image failed, retrying with text type..."); - return $this->attemptSend($phoneRaw, 'text', $otp, $appName, $bearerToken); + error_log("ℹ️ [Nabeh OTP Fallback] Image failed, retrying with text type for phone {$phoneRaw}..."); + $textResult = $this->attemptSend($phoneRaw, 'text', $otp, $appName, $bearerToken); + if ($textResult['success']) { + return $textResult; + } + // Return text attempt with details + return $textResult; } return $result; @@ -137,7 +150,9 @@ class NabehService CURLOPT_POST => true, CURLOPT_POSTFIELDS => $payload, CURLOPT_RETURNTRANSFER => true, - CURLOPT_TIMEOUT => 15, + CURLOPT_TIMEOUT => 35, + CURLOPT_CONNECTTIMEOUT => 10, + CURLOPT_SSL_VERIFYPEER => false, CURLOPT_HTTPHEADER => [ 'Content-Type: application/json', "Authorization: Bearer {$bearerToken}", @@ -150,30 +165,42 @@ class NabehService curl_close($ch); if ($curlError) { + error_log("❌ [Nabeh OTP cURL Error] " . $curlError); return [ - 'success' => false, - 'error' => 'cURL Connection Error: ' . $curlError, - 'response' => null + 'success' => false, + 'http_code' => $httpCode, + 'error' => 'cURL Connection Error: ' . $curlError, + 'response' => null ]; } + error_log("ℹ️ [Nabeh OTP Response (HTTP {$httpCode})] " . $response); + if ($httpCode === 200 && $response) { $decoded = json_decode($response, true); if ($decoded) { $statusStr = strtolower((string)($decoded['status'] ?? '')); - $msgStr = strtolower((string)($decoded['message'] ?? '')); + $msgStr = strtolower((string)($decoded['message'] ?? '')); + $errStr = strtolower((string)($decoded['error'] ?? '')); + if ( !empty($decoded['success']) || in_array($statusStr, ['success', 'ok', 'true', '200', 'sent', 'queued', '1'], true) || ($decoded['status'] ?? false) === true || + ($decoded['code'] ?? 0) === 200 || + !empty($decoded['message_id']) || + !empty($decoded['id']) || + !empty($decoded['token']) || str_contains($msgStr, 'success') || str_contains($msgStr, 'sent') || - str_contains($msgStr, 'تم') + str_contains($msgStr, 'تم') || + str_contains($errStr, 'via gateway') ) { return [ - 'success' => true, - 'message' => 'تم إرسال رمز التحقق بنجاح عبر الواتساب', - 'raw' => $decoded + 'success' => true, + 'http_code' => 200, + 'message' => 'تم إرسال رمز التحقق بنجاح عبر الواتساب', + 'raw' => $decoded ]; } } @@ -182,7 +209,7 @@ class NabehService return [ 'success' => false, 'http_code' => $httpCode, - 'error' => 'Nabeh Gateway rejected OTP request', + 'error' => 'Nabeh Gateway rejected request (HTTP ' . $httpCode . ')', 'response' => $response ]; }