Commit 25cefe7c authored by Mahmoud Aglan's avatar Mahmoud Aglan

OTP: switch to 4-digit codes, add 0000 universal bypass in demo mode

- Changed OTP from 6 digits to 4 digits
- Code 0000 always works in demo mode (no external SMS needed)
- Relaxed rate limit from 3 to 5 attempts, timeout 300s
- Validation accepts 4-6 digit codes for flexibility
Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
parent 391629ac
...@@ -23,7 +23,7 @@ public function requestOtp(Request $request): JsonResponse ...@@ -23,7 +23,7 @@ public function requestOtp(Request $request): JsonResponse
$phone = $this->normalizePhone($request->phone); $phone = $this->normalizePhone($request->phone);
$rateLimitKey = "otp_request:{$phone}"; $rateLimitKey = "otp_request:{$phone}";
if (RateLimiter::tooManyAttempts($rateLimitKey, 3)) { if (RateLimiter::tooManyAttempts($rateLimitKey, 5)) {
$seconds = RateLimiter::availableIn($rateLimitKey); $seconds = RateLimiter::availableIn($rateLimitKey);
return response()->json([ return response()->json([
'error' => 'too_many_attempts', 'error' => 'too_many_attempts',
...@@ -38,7 +38,7 @@ public function requestOtp(Request $request): JsonResponse ...@@ -38,7 +38,7 @@ public function requestOtp(Request $request): JsonResponse
->first(); ->first();
if (!$user) { if (!$user) {
RateLimiter::hit($rateLimitKey, 600); RateLimiter::hit($rateLimitKey, 300);
return response()->json([ return response()->json([
'error' => 'phone_not_found', 'error' => 'phone_not_found',
'message' => 'هذا الرقم غير مسجل في النظام', 'message' => 'هذا الرقم غير مسجل في النظام',
...@@ -48,14 +48,13 @@ public function requestOtp(Request $request): JsonResponse ...@@ -48,14 +48,13 @@ public function requestOtp(Request $request): JsonResponse
$mode = SystemSetting::get('auth_otp_mode', 'demo'); $mode = SystemSetting::get('auth_otp_mode', 'demo');
if ($mode === 'demo') { if ($mode === 'demo') {
Cache::put("otp:{$phone}", '123456', 300); Cache::put("otp:{$phone}", '1234', 300);
} else { } else {
$otp = str_pad(random_int(0, 999999), 6, '0', STR_PAD_LEFT); $otp = str_pad(random_int(0, 9999), 4, '0', STR_PAD_LEFT);
Cache::put("otp:{$phone}", $otp, 300); Cache::put("otp:{$phone}", $otp, 300);
// TODO: Send SMS via SmsService when SMS mode is enabled
} }
RateLimiter::hit($rateLimitKey, 600); RateLimiter::hit($rateLimitKey, 300);
return response()->json([ return response()->json([
'sent' => true, 'sent' => true,
...@@ -68,17 +67,23 @@ public function verify(Request $request): JsonResponse ...@@ -68,17 +67,23 @@ public function verify(Request $request): JsonResponse
{ {
$request->validate([ $request->validate([
'phone' => 'required|string|min:10|max:15', 'phone' => 'required|string|min:10|max:15',
'otp' => 'required|string|size:6', 'otp' => 'required|string|min:4|max:6',
]); ]);
$phone = $this->normalizePhone($request->phone); $phone = $this->normalizePhone($request->phone);
$cached = Cache::get("otp:{$phone}");
if (!$cached || $cached !== $request->otp) { // Universal bypass: 0000 always works in demo mode
return response()->json([ $mode = SystemSetting::get('auth_otp_mode', 'demo');
'error' => 'invalid_otp', $isBypass = $mode === 'demo' && $request->otp === '0000';
'message' => 'رمز التحقق غير صحيح',
], 401); if (!$isBypass) {
$cached = Cache::get("otp:{$phone}");
if (!$cached || $cached !== $request->otp) {
return response()->json([
'error' => 'invalid_otp',
'message' => 'رمز التحقق غير صحيح',
], 401);
}
} }
Cache::forget("otp:{$phone}"); Cache::forget("otp:{$phone}");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment