Initial V2 commit

This commit is contained in:
Hamza-Ayed
2026-04-22 21:59:56 +03:00
commit 4706404488
53 changed files with 4392 additions and 0 deletions

View File

@@ -0,0 +1,153 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Str;
/**
* OTP Controller
* Replaces: auth/otpmessage.php, verifyOtpMessage.php, sendVerifyEmail.php, etc.
*/
class OtpController extends Controller
{
/** POST /v2/otp/send */
public function send(Request $request): JsonResponse
{
$request->validate(['phone' => 'required|string']);
$phone = $request->input('phone');
// Rate limit: 3 OTP per phone per 5 minutes
$key = "otp_limit:{$phone}";
if (Cache::get($key, 0) >= 3) {
return response()->json(['status' => 'failure', 'message' => 'Too many OTP requests'], 429);
}
Cache::increment($key);
Cache::put($key, Cache::get($key), 300);
// Generate 6-digit OTP
$otp = str_pad(random_int(0, 999999), 6, '0', STR_PAD_LEFT);
$expiration = now()->addMinutes(5);
// Store OTP
DB::connection('primary')->table('phone_verification')->updateOrInsert(
['phone_number' => $phone],
[
'token_code' => password_hash($otp, PASSWORD_BCRYPT),
'expiration_time' => $expiration,
'is_verified' => 0,
'created_at' => now(),
]
);
// TODO: Send SMS via external provider
// For now, return success (SMS sending is provider-specific)
return response()->json([
'status' => 'success',
'message' => 'OTP sent',
'expires_at' => $expiration->toIso8601String(),
]);
}
/** POST /v2/otp/verify */
public function verify(Request $request): JsonResponse
{
$request->validate([
'phone' => 'required|string',
'otp' => 'required|string|size:6',
]);
$phone = $request->input('phone');
$otp = $request->input('otp');
$record = DB::connection('primary')->table('phone_verification')
->where('phone_number', $phone)
->where('is_verified', 0)
->where('expiration_time', '>', now())
->first();
if (!$record) {
return response()->json(['status' => 'failure', 'message' => 'OTP expired or not found'], 400);
}
// Verify OTP hash
if (!password_verify($otp, $record->token_code)) {
return response()->json(['status' => 'failure', 'message' => 'Invalid OTP'], 400);
}
// Mark as verified
DB::connection('primary')->table('phone_verification')
->where('phone_number', $phone)
->update(['is_verified' => 1]);
return response()->json(['status' => 'success', 'message' => 'Phone verified']);
}
/** POST /v2/otp/email/send */
public function sendEmail(Request $request): JsonResponse
{
$request->validate(['email' => 'required|email']);
$email = $request->input('email');
$token = Str::random(32);
DB::connection('primary')->table('email_verifications')->updateOrInsert(
['email' => $email],
[
'token' => password_hash($token, PASSWORD_BCRYPT),
'verified' => 0,
'created_at' => now(),
'updated_at' => now(),
]
);
// TODO: Send email with token link
return response()->json(['status' => 'success', 'message' => 'Verification email sent']);
}
/** POST /v2/otp/email/verify */
public function verifyEmail(Request $request): JsonResponse
{
$request->validate([
'email' => 'required|email',
'token' => 'required|string',
]);
$record = DB::connection('primary')->table('email_verifications')
->where('email', $request->input('email'))
->where('verified', 0)
->first();
if (!$record || !password_verify($request->input('token'), $record->token)) {
return response()->json(['status' => 'failure', 'message' => 'Invalid verification'], 400);
}
DB::connection('primary')->table('email_verifications')
->where('email', $request->input('email'))
->update(['verified' => 1, 'updated_at' => now()]);
return response()->json(['status' => 'success', 'message' => 'Email verified']);
}
/** GET /v2/otp/check-phone?phone=XXX */
public function checkPhone(Request $request): JsonResponse
{
$request->validate(['phone' => 'required|string']);
$verified = DB::connection('primary')->table('phone_verification')
->where('phone_number', $request->input('phone'))
->where('is_verified', 1)
->exists();
return response()->json([
'status' => 'success',
'data' => ['verified' => $verified],
]);
}
}