fix(security): wallet balance check with FOR UPDATE, remove user-supplied ID in signup, hardcoded IP to env
This commit is contained in:
@@ -11,7 +11,6 @@ $password = filterRequest("password");
|
|||||||
$gender = filterRequest("gender");
|
$gender = filterRequest("gender");
|
||||||
$birthdate = filterRequest("birthdate");
|
$birthdate = filterRequest("birthdate");
|
||||||
$site = filterRequest("site");
|
$site = filterRequest("site");
|
||||||
$id = filterRequest("id");
|
|
||||||
|
|
||||||
// تشفير البيانات الحساسة
|
// تشفير البيانات الحساسة
|
||||||
$phone = $encryptionHelper->encryptData($phone);
|
$phone = $encryptionHelper->encryptData($phone);
|
||||||
@@ -39,14 +38,13 @@ try {
|
|||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// إدخال البيانات الجديدة
|
// إدخال البيانات الجديدة (مع ID تلقائي)
|
||||||
$sql = "INSERT INTO passengers (
|
$sql = "INSERT INTO passengers (
|
||||||
id, phone, email, password, gender, birthdate, site, first_name, last_name
|
id, phone, email, password, gender, birthdate, site, first_name, last_name
|
||||||
) VALUES (
|
) VALUES (
|
||||||
:id, :phone, :email, :password, :gender, :birthdate, :site, :first_name, :last_name
|
UUID_SHORT(), :phone, :email, :password, :gender, :birthdate, :site, :first_name, :last_name
|
||||||
)";
|
)";
|
||||||
$stmt = $con->prepare($sql);
|
$stmt = $con->prepare($sql);
|
||||||
$stmt->bindParam(":id", $id);
|
|
||||||
$stmt->bindParam(":phone", $phone);
|
$stmt->bindParam(":phone", $phone);
|
||||||
$stmt->bindParam(":email", $email);
|
$stmt->bindParam(":email", $email);
|
||||||
$stmt->bindParam(":password", $hashedPassword);
|
$stmt->bindParam(":password", $hashedPassword);
|
||||||
|
|||||||
@@ -44,8 +44,7 @@ function isAllowedSocketUrl(string $url): bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function sendToLocationServer($action, $data) {
|
function sendToLocationServer($action, $data) {
|
||||||
// رابط سيرفر اللوكيشن الداخلي أو العام
|
$url = getenv('LOCATION_SERVER_URL') ?: 'http://188.68.36.205:2021';
|
||||||
$url = "http://188.68.36.205:2021";
|
|
||||||
if (!isAllowedSocketUrl($url)) {
|
if (!isAllowedSocketUrl($url)) {
|
||||||
error_log("[SSRF_BLOCKED] Attempted connection to: $url");
|
error_log("[SSRF_BLOCKED] Attempted connection to: $url");
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -41,13 +41,12 @@ $passengerId = filterRequest("passengerId");
|
|||||||
$paymentAmount = filterRequest("paymentAmount");
|
$paymentAmount = filterRequest("paymentAmount");
|
||||||
$paymentMethod = filterRequest("paymentMethod");
|
$paymentMethod = filterRequest("paymentMethod");
|
||||||
$walletChecked = filterRequest("walletChecked"); // 'true' or 'false'
|
$walletChecked = filterRequest("walletChecked"); // 'true' or 'false'
|
||||||
$passengerWalletBurc = filterRequest("passengerWalletBurc"); // passenger balance before operation
|
|
||||||
$authToken = filterRequest("authToken"); // kept for logging/audit, not used for auth
|
$authToken = filterRequest("authToken"); // kept for logging/audit, not used for auth
|
||||||
|
|
||||||
// --- Validate required fields ---
|
// --- Validate required fields ---
|
||||||
if (empty($rideId) || empty($driverId) || empty($passengerId) ||
|
if (empty($rideId) || empty($driverId) || empty($passengerId) ||
|
||||||
!isset($paymentAmount) || empty($paymentMethod) ||
|
!isset($paymentAmount) || empty($paymentMethod) ||
|
||||||
!isset($walletChecked) || !isset($passengerWalletBurc)) {
|
!isset($walletChecked)) {
|
||||||
printFailure("Missing required parameters for payment processing.");
|
printFailure("Missing required parameters for payment processing.");
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
@@ -79,35 +78,61 @@ try {
|
|||||||
|
|
||||||
// 3b. Deduct from passenger wallet (if wallet payment)
|
// 3b. Deduct from passenger wallet (if wallet payment)
|
||||||
if ($walletChecked === 'true') {
|
if ($walletChecked === 'true') {
|
||||||
|
// Check actual balance with row lock
|
||||||
|
$stmtBalance = $con->prepare(
|
||||||
|
"SELECT COALESCE(SUM(balance), 0) AS current_balance
|
||||||
|
FROM passengerWallet
|
||||||
|
WHERE passenger_id = :passenger_id
|
||||||
|
FOR UPDATE"
|
||||||
|
);
|
||||||
|
$stmtBalance->execute([':passenger_id' => $passengerId]);
|
||||||
|
$balanceRow = $stmtBalance->fetch(PDO::FETCH_ASSOC);
|
||||||
|
$currentBalance = floatval($balanceRow['current_balance']);
|
||||||
|
|
||||||
|
$deductionAmount = floatval($paymentAmount);
|
||||||
|
if ($currentBalance < $deductionAmount) {
|
||||||
|
throw new Exception("Insufficient wallet balance. Required: $deductionAmount, Available: $currentBalance");
|
||||||
|
}
|
||||||
|
|
||||||
$stmtPassengerWallet = $con->prepare(
|
$stmtPassengerWallet = $con->prepare(
|
||||||
"INSERT INTO `passengerWallet` (`passenger_id`, `balance`)
|
"INSERT INTO `passengerWallet` (`passenger_id`, `balance`)
|
||||||
VALUES (:passenger_id, :balance)"
|
VALUES (:passenger_id, :balance)"
|
||||||
);
|
);
|
||||||
$stmtPassengerWallet->execute([
|
$stmtPassengerWallet->execute([
|
||||||
':passenger_id' => $passengerId,
|
':passenger_id' => $passengerId,
|
||||||
':balance' => (-1) * floatval($paymentAmount),
|
':balance' => (-1) * $deductionAmount,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if ($stmtPassengerWallet->rowCount() <= 0) {
|
if ($stmtPassengerWallet->rowCount() <= 0) {
|
||||||
throw new Exception("Failed to deduct from passenger wallet.");
|
throw new Exception("Failed to deduct from passenger wallet.");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// 3c. Settle existing passenger debt (if balance was negative)
|
// 3c. Settle existing debt (use actual balance after deduction)
|
||||||
if (floatval($passengerWalletBurc) < 0) {
|
$stmtBalanceAfter = $con->prepare(
|
||||||
|
"SELECT COALESCE(SUM(balance), 0) AS balance_after
|
||||||
|
FROM passengerWallet
|
||||||
|
WHERE passenger_id = :passenger_id
|
||||||
|
FOR UPDATE"
|
||||||
|
);
|
||||||
|
$stmtBalanceAfter->execute([':passenger_id' => $passengerId]);
|
||||||
|
$balanceAfterRow = $stmtBalanceAfter->fetch(PDO::FETCH_ASSOC);
|
||||||
|
$balanceAfter = floatval($balanceAfterRow['balance_after']);
|
||||||
|
|
||||||
|
if ($balanceAfter < 0) {
|
||||||
$stmtPassengerDebt = $con->prepare(
|
$stmtPassengerDebt = $con->prepare(
|
||||||
"INSERT INTO `passengerWallet` (`passenger_id`, `balance`)
|
"INSERT INTO `passengerWallet` (`passenger_id`, `balance`)
|
||||||
VALUES (:passenger_id, :balance)"
|
VALUES (:passenger_id, :balance)"
|
||||||
);
|
);
|
||||||
$stmtPassengerDebt->execute([
|
$stmtPassengerDebt->execute([
|
||||||
':passenger_id' => $passengerId,
|
':passenger_id' => $passengerId,
|
||||||
':balance' => (-1) * floatval($passengerWalletBurc),
|
':balance' => (-1) * $balanceAfter,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if ($stmtPassengerDebt->rowCount() <= 0) {
|
if ($stmtPassengerDebt->rowCount() <= 0) {
|
||||||
throw new Exception("Failed to settle passenger debt.");
|
throw new Exception("Failed to settle passenger debt.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 3d. Deduct driver points (8% of payment amount)
|
// 3d. Deduct driver points (8% of payment amount)
|
||||||
$pointsSubtraction = floatval($paymentAmount) * (-0.08);
|
$pointsSubtraction = floatval($paymentAmount) * (-0.08);
|
||||||
|
|||||||
Reference in New Issue
Block a user