The verification tables (token_verification*, phone_verification*) use the phone number as a lookup key: written when the code is sent, read when it is checked. Storing it encrypted worked only because encryptData() is deterministic — under AES-GCM the two sides would produce different ciphertexts and no code would ever verify, locking every user out of registration and OTP sign-in. otpPhoneKey() stores a keyed HMAC of the normalised number instead. No schema change is needed since the column is textual, local and international formats now resolve to the same key, and the value cannot be reversed without the pepper. It falls back to the previous behaviour when no pepper is configured. Applied to both sides of every affected flow — request/verify, and the driver and passenger send/verify pairs — including the OTP value itself where it is compared by equality rather than decrypted. auth/otp/verify.php already decrypts the token before comparing, so it needed no change there. Also adds ENCRYPTION_MODE to EncryptionHelper: encryptData() writes GCM when set to 'gcm', CBC otherwise. Verified in both directions — rows written under CBC stay readable after switching, and rows written under GCM stay readable after rolling back — so the switch is reversible by an environment variable. The admin console's own OTP is unaffected: it keys the table by the stored ciphertext read from adminUser, identical on both sides. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
81 lines
3.0 KiB
PHP
81 lines
3.0 KiB
PHP
<?php
|
|
// File: verify_otp.php (with enhanced logging)
|
|
// siro_v1/auth/token_passenger
|
|
require_once __DIR__ . '/../../connect.php';
|
|
|
|
// --- Start of Script Execution ---
|
|
error_log("--- [verify_otp.php] Script execution started. ---");
|
|
|
|
$phoneNumber = filterRequest("phone_number");
|
|
$otp = filterRequest("otp");
|
|
|
|
// Log received data for debugging. Be mindful of logging sensitive data in production.
|
|
error_log("[verify_otp.php] Received phone_number: $phoneNumber | Received otp: $otp");
|
|
|
|
if (empty($phoneNumber) || empty($otp)) {
|
|
error_log("[verify_otp.php] Error: Phone number or OTP is empty.");
|
|
jsonError("Phone number and OTP are required.");
|
|
exit();
|
|
}
|
|
|
|
$phoneNumber_encrypted = otpPhoneKey($phoneNumber);
|
|
// الرمز يُقارن بالتساوي أيضاً، فيحتاج نفس الصيغة الثابتة
|
|
$otp_encrypted = otpPhoneKey($otp);
|
|
|
|
try {
|
|
// 1. التحقق من Redis بدلاً من MySQL
|
|
if (!$redis) {
|
|
jsonError("Security service unavailable");
|
|
exit;
|
|
}
|
|
|
|
$cachedOtp = $redis->get("otp:passenger:$phoneNumber");
|
|
|
|
if ($cachedOtp && $cachedOtp === $otp) {
|
|
// ننجح في التحقق ونحذف المفتاح من Redis لمنع استخدامه مرة أخرى (One-time use)
|
|
$redis->del("otp:passenger:$phoneNumber");
|
|
|
|
error_log("[verify_otp.php] OTP verified via Redis for phone: $phoneNumber");
|
|
|
|
// 2. التحقق من وجود الراكب في قاعدة البيانات
|
|
$passengerStmt = $con->prepare("SELECT id FROM passengers WHERE phone = ?");
|
|
$passengerStmt->execute([$phoneNumber_encrypted]);
|
|
$passenger = $passengerStmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
if ($passenger) {
|
|
$passengerID = $passenger['id'];
|
|
|
|
// تحديث التوكن والبصمة إن وجدا
|
|
$newToken = filterRequest("token");
|
|
$fingerPrint = filterRequest("fingerPrint");
|
|
|
|
if ($newToken && $fingerPrint) {
|
|
$tokenEncrypted = $encryptionHelper->encryptData($newToken);
|
|
$updateTokenStmt = $con->prepare("UPDATE tokens SET token = ?, fingerPrint = ? WHERE passengerID = ?");
|
|
$updateTokenStmt->execute([$tokenEncrypted, $fingerPrint, $passengerID]);
|
|
}
|
|
|
|
printSuccess([
|
|
"message" => "Token verified and updated.",
|
|
"isRegistered" => true,
|
|
"passengerID" => $passengerID
|
|
]);
|
|
|
|
} else {
|
|
printSuccess([
|
|
"message" => "Phone verified, passenger not found.",
|
|
"isRegistered" => false
|
|
]);
|
|
}
|
|
|
|
} else {
|
|
error_log("[verify_otp.php] Invalid or expired OTP for phone: $phoneNumber");
|
|
jsonError("Invalid or expired OTP.");
|
|
}
|
|
|
|
} catch (Exception $e) {
|
|
// Log the detailed database error message for debugging.
|
|
error_log("[verify_otp.php] FATAL DATABASE ERROR: " . $e->getMessage());
|
|
jsonError("Database error");
|
|
}
|
|
?>
|