These are the paths that must stop depending on deterministic encryption before storage can move to AES-GCM. Each keeps its original ciphertext comparison in the same statement, so behaviour is unchanged today and no account becomes unreachable during the transition. Lookups: - auth/login.php — passenger sign-in matched the raw value against the encrypted column, which only works because encryptData() is CBC with a fixed IV. - auth/passenger/register.php and auth/driver/register.php — duplicate detection. Without the index these would stop detecting existing accounts under GCM and allow the same phone to register twice. Writes now populate the index in the same statement as the value: - both registration paths write phone/email/name indexes with the row; driver indexes are computed before the encryption pass, since the raw values are unavailable afterwards. - passenger profile update and admin driver update refresh the index when the underlying field changes. For the composite name index the untouched half is read back from the row. Adds --audit to the backfill script: recomputes every index from its encrypted value and reports missing or stale entries. Drift here is silent by nature — it surfaces only when a real search fails. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
62 lines
2.2 KiB
PHP
62 lines
2.2 KiB
PHP
<?php
|
|
require_once __DIR__ . '/../../connect.php';
|
|
|
|
$id = filterRequest("id");
|
|
|
|
$fields = [];
|
|
$params = [":id" => $id];
|
|
|
|
$encryptedFields = [
|
|
"phone", "sosPhone", "birthdate", "site", "gender",
|
|
"first_name", "last_name", "education", "employmentType", "maritalStatus"
|
|
];
|
|
|
|
// أي تعديل على حقل مفهرس يجب أن يُحدّث فهرسه في نفس العبارة، وإلا بقي
|
|
// الفهرس يشير إلى القيمة القديمة وأصبح البحث يعطي نتيجة خاطئة.
|
|
global $blindIndex;
|
|
$plain = [];
|
|
|
|
foreach ($encryptedFields as $field) {
|
|
if (isset($_POST[$field]) && !empty($_POST[$field])) {
|
|
$value = filterRequest($field);
|
|
$plain[$field] = $value;
|
|
$encryptedValue = $encryptionHelper->encryptData($value);
|
|
$fields[] = "`$field` = :$field";
|
|
$params[":$field"] = $encryptedValue;
|
|
}
|
|
}
|
|
|
|
if ($blindIndex) {
|
|
if (isset($plain['phone'])) {
|
|
$fields[] = "`phone_bidx` = :phone_bidx";
|
|
$params[':phone_bidx'] = $blindIndex->index('passengers.phone', $plain['phone']);
|
|
}
|
|
if (isset($plain['first_name']) || isset($plain['last_name'])) {
|
|
// الاسم مركّب من عمودين: نقرأ الجزء غير المُعدَّل من السجل الحالي
|
|
$current = $con->prepare("SELECT first_name, last_name FROM passengers WHERE id = :id");
|
|
$current->execute([':id' => $id]);
|
|
$row = $current->fetch(PDO::FETCH_ASSOC) ?: [];
|
|
|
|
$first = $plain['first_name'] ?? $encryptionHelper->decryptData($row['first_name'] ?? null) ?: '';
|
|
$last = $plain['last_name'] ?? $encryptionHelper->decryptData($row['last_name'] ?? null) ?: '';
|
|
|
|
$fields[] = "`name_bidx` = :name_bidx";
|
|
$params[':name_bidx'] = $blindIndex->index('passengers.name', trim("$first $last"));
|
|
}
|
|
}
|
|
|
|
if (!empty($fields)) {
|
|
$setClause = implode(", ", $fields);
|
|
$sql = "UPDATE `passengers` SET $setClause WHERE `id` = :id";
|
|
$stmt = $con->prepare($sql);
|
|
$stmt->execute($params);
|
|
|
|
if ($stmt->rowCount() > 0) {
|
|
jsonSuccess(null, "Passenger data updated successfully");
|
|
} else {
|
|
jsonError("Failed to update passenger data");
|
|
}
|
|
} else {
|
|
jsonError("No fields to update");
|
|
}
|
|
?>
|