Commit Graph
88 Commits
Author SHA1 Message Date
Hamza-Ayed 1dfc302a4f Update: 2026-07-26 01:03:40 2026-07-26 01:03:41 +03:00
Hamza-Ayed e03b9c30d5 Update: 2026-07-25 18:43:44 2026-07-25 18:43:44 +03:00
Hamza-Ayed 8d3e63d1c7 Update: 2026-07-25 18:40:38 2026-07-25 18:40:38 +03:00
Hamza-AyedandClaude Opus 5 2135edcf43 Close the remaining ciphertext joins and a SQL injection in email verification
- Customer-service notes joined to the account by comparing encrypted phone
  columns. Both notes tables now carry phone_key, written when a note is
  saved, and the three joins match on it.
- The email_verifications join was comparing a plaintext column against an
  encrypted one, so it never matched and `verified` was always NULL in both
  passenger and driver sign-in. It is now resolved in PHP against the
  decrypted address, which fixes a pre-existing bug rather than only
  preparing for GCM.
- auth/sendVerifyEmail.php built all three of its statements by interpolating
  the request values into SQL. Any caller could inject through the email or
  token field. Now parameterised.
- serviceapp/register.php duplicate detection consults the users indexes and
  writes them with the row.

Sweep confirms no join or lookup compares two encrypted columns any more.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-25 16:48:10 +03:00
Hamza-AyedandClaude Opus 5 35a66935aa Repair verification joins broken by the OTP key change; extend backfill
Storing the verification phone as a keyed HMAC fixed OTP lookups but broke
every query that joined those tables back to the account, because
phone_verification*.phone_number no longer holds the same value as
driver.phone / passengers.phone. Six joins were affected, and four of them
feed the `verified` flag that the rider and driver apps check at sign-in — so
this was already failing under the current CBC mode, not only after a switch
to GCM.

Accounts now carry phone_key, computed exactly as otpPhoneKey() does, and the
joins match on it. It is written at registration for both apps and populated
for existing rows by the backfill.

The backfill also covers the columns added for the remaining lookups:
users.email_bidx/phone_bidx and driver.national_bidx, which were migrated but
never populated, and honours a per-field prefix so phone_key reproduces
otpPhoneKey's exact output.

Insert column/value counts verified with a paren-aware parser after editing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-25 16:40:53 +03:00
Hamza-AyedandClaude Opus 5 8d7e3118b5 Migrate remaining encrypted-column lookups to the blind index
Completes the set of queries that matched a freshly encrypted value against a
stored one, which only works while encryption is deterministic. Each keeps its
original comparison and adds an index comparison in the same WHERE, so nothing
changes today.

- passenger sign-in by email, service-staff sign-in, Firebase token lookup
- driver lookup by phone and by national number
- admin ride lookup and ride monitor (both tables)
- nabeh: driver status, user resolution, ride history, complaint submission

transit_org_admins lives in the transit database and has no index column, so
login there falls back to decrypting the small set of active admins and
comparing normalised numbers.

Schema: adds users.email_bidx/phone_bidx and driver.national_bidx with their
indexes.

Verified that every :*_bidx placeholder introduced is actually bound — an
unbound one is a fatal error at request time, not a silent miss.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-25 16:36:32 +03:00
Hamza-AyedandClaude Opus 5 39b5a7fc7f Keep OTP phone numbers recoverable for customer-service follow-up
Storing the verification phone as a keyed HMAC made OTP lookups independent
of the encryption mode, but the hash is one-way — and customer service reads
those same rows to chase people who requested a code and never finished
registering. That workflow would have lost the number entirely.

The verification tables now carry both forms: phone_number holds the lookup
key, and a new phone_enc column holds the encrypted number, which is
decryptable when a human needs to call.

The two follow-up queries also compared the verification row against the
driver/passengers tables and the notes tables by matching ciphertext, which
only ever worked because encryption was deterministic. Under GCM every number
would have looked unregistered and every note would have disappeared. Both now
read the number from phone_enc and match on normalised plaintext, so they are
correct under either mode.

Rows written before phone_enc existed are skipped rather than shown without a
number.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-25 16:27:29 +03:00
Hamza-AyedandClaude Opus 5 a1c19b052d Make OTP verification independent of the encryption mode
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>
2026-07-25 16:18:16 +03:00
Hamza-AyedandClaude Opus 5 c9b4d14da6 Route account lookups through the blind index and keep it fresh on write
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>
2026-07-25 16:04:40 +03:00
Hamza-Ayed c35b350b31 Update: 2026-07-23 16:56:57 2026-07-23 16:56:58 +03:00
Hamza-Ayed 699b380f2b Update: 2026-07-21 20:58:30 2026-07-21 20:58:30 +03:00
Hamza-Ayed 3d0c266b7a Update: 2026-07-21 20:55:19 2026-07-21 20:55:20 +03:00
Hamza-Ayed 23f697b1c6 Update: 2026-07-21 19:43:50 2026-07-21 19:43:51 +03:00
Hamza-Ayed 1bec13634a Update: 2026-07-21 19:34:29 2026-07-21 19:34:29 +03:00
Hamza-Ayed 0ee3655c05 Update: 2026-07-21 19:31:02 2026-07-21 19:31:02 +03:00
Hamza-Ayed 4f47c0ad1d Update: 2026-07-21 19:28:08 2026-07-21 19:28:08 +03:00
Hamza-Ayed f3905bcb2c Update: 2026-07-21 19:24:57 2026-07-21 19:24:57 +03:00
Hamza-Ayed 1103f6ffcf Update: 2026-07-21 19:22:23 2026-07-21 19:22:23 +03:00
Hamza-Ayed 0351bffafc Update: 2026-07-21 19:19:15 2026-07-21 19:19:15 +03:00
Hamza-Ayed 096f6a13a0 Update: 2026-07-21 19:15:57 2026-07-21 19:15:57 +03:00
Hamza-Ayed ebd6f3734a Update: 2026-07-21 19:09:42 2026-07-21 19:09:42 +03:00
Hamza-Ayed 085b180bdb feat: implement secure OTP-based payout workflow with dynamic fee calculation and improved authentication checks 2026-07-19 01:51:39 +03:00
Hamza-Ayed 27200013ac Update: 2026-07-12 17:22:40 2026-07-12 17:22:40 +03:00
Hamza-Ayed 5fb2c25504 Update: 2026-07-10 13:41:34 2026-07-10 13:41:34 +03:00
Hamza-Ayed be6e5bed92 Update: 2026-07-10 03:07:55 2026-07-10 03:07:55 +03:00
Hamza-Ayed 87dc925ea7 Refactor(Auth): Complete auth folder restructuring, security patches, and Flutter endpoint updates 2026-07-09 05:22:05 +03:00
Hamza-Ayed 45859883a5 Update: 2026-07-09 05:02:10 2026-07-09 05:02:10 +03:00
Hamza-Ayed 2152d34a8e fix: resolve stale price display in driver ratings and remove misleading discount UI in rider ratings 2026-07-09 04:48:19 +03:00
Hamza-Ayed 628e169552 Update: 2026-07-07 04:57:50 2026-07-07 04:57:51 +03:00
Hamza-Ayed 05d047d871 Update: 2026-07-02 05:27:04 2026-07-02 05:27:05 +03:00
Hamza-Ayed 2da943e745 Update: 2026-06-29 15:29:28 2026-06-29 15:29:29 +03:00
Hamza-Ayed b8a817fc9c Update: 2026-06-29 01:12:38 2026-06-29 01:12:38 +03:00
Hamza-Ayed 0af4eed1ce Update: 2026-06-29 01:10:32 2026-06-29 01:10:32 +03:00
Hamza-Ayed d695a4e812 Update: 2026-06-29 00:07:33 2026-06-29 00:07:33 +03:00
Hamza-Ayed 2da78ccd8e Update: 2026-06-28 19:52:45 2026-06-28 19:52:45 +03:00
Hamza-Ayed f9f6890b26 Update: 2026-06-28 00:42:25 2026-06-28 00:42:26 +03:00
Hamza-Ayed f428946b30 Add tester passenger creation script 2026-06-27 23:09:04 +03:00
Hamza-Ayed 3326756dc3 Add tester driver creation script 2026-06-27 23:01:38 +03:00
Hamza-Ayed 7497bdcfae Update: 2026-06-27 05:07:43 2026-06-27 05:07:43 +03:00
Hamza-Ayed f069f2b24f Update: 2026-06-27 04:58:21 2026-06-27 04:58:21 +03:00
Hamza-Ayed a6738079a2 Update: 2026-06-27 04:23:48 2026-06-27 04:23:49 +03:00
Hamza-Ayed 8993aa0a6b Update: 2026-06-27 04:21:17 2026-06-27 04:21:17 +03:00
Hamza-Ayed 0c5088fd6d add ai_data + user_input to driver table, status=pending_review, save raw Gemini response 2026-06-25 16:54:21 +03:00
Hamza-Ayed 75e4524329 fix upload: parse nested message.url, backup retries=1, connect.php auth 2026-06-25 04:30:52 +03:00
Hamza-Ayed 0b9e5dfa03 remove random suffix from uploaded filenames: now {driverID}_{imageType}.{ext} 2026-06-25 04:21:58 +03:00
Hamza-Ayed f5a5ffc10c Update: 2026-06-25 03:58:15 2026-06-25 04:00:27 +03:00
Hamza-Ayed 5b5033b110 Update: 2026-06-25 03:56:11 2026-06-25 03:58:30 +03:00
Hamza-Ayed 4f4958defb Update: 2026-06-25 03:51:57 2026-06-25 03:55:10 +03:00
Hamza-Ayed 6db2ece2ce Update: 2026-06-25 03:43:29 2026-06-25 03:43:29 +03:00
Hamza-Ayed 89c1348f08 Update: 2026-06-25 03:28:59 2026-06-25 03:28:59 +03:00