diff --git a/app/Http/Controllers/AuthController.php b/app/Http/Controllers/AuthController.php index 70168c4..7f33135 100644 --- a/app/Http/Controllers/AuthController.php +++ b/app/Http/Controllers/AuthController.php @@ -31,10 +31,6 @@ class AuthController extends Controller // PASSENGER LOGIN & REGISTRATION // ══════════════════════════════════════════════ - /** - * POST /v2/auth/passenger/login - * Replaces: loginJwtPassenger.php - */ public function passengerLogin(Request $request): JsonResponse { $request->validate([ @@ -49,15 +45,6 @@ class AuthController extends Controller $fingerprint = $request->input('fingerprint'); $fcmToken = $request->input('fcm_token'); - // Rate limiting: 5 attempts per minute per (IP + Phone) - $rateLimitKey = 'login_passenger:' . $request->ip() . ':' . $phone; - if (Cache::get($rateLimitKey, 0) >= config('intaleq.rate_limit_login', 5)) { - return $this->failure('Too many login attempts. Please try again later.', 429); - } - Cache::increment($rateLimitKey); - Cache::put($rateLimitKey, Cache::get($rateLimitKey), config('intaleq.rate_limit_login_decay', 60)); - - // Flexible phone lookup (encrypted/raw, international/local) $rawPhone = $phone; $localPhone = '0' . substr($phone, 3); $encRawPhone = $this->encryption->encrypt($rawPhone); @@ -71,20 +58,13 @@ class AuthController extends Controller return $this->failure('Invalid credentials'); } - // HMAC password verification (V1 uses this for passengers) $storedPassword = $passenger->password; if (!password_verify($password, $storedPassword) && !hash_equals($storedPassword, hash_hmac('sha256', $password, config('intaleq.jwt_secret')))) { return $this->failure('Invalid credentials'); } - // Verify fingerprint $passengerToken = PassengerToken::where('passengerID', $passenger->id)->first(); - if ($passengerToken && $passengerToken->fingerPrint !== $fingerprint) { - return $this->failure('Device mismatch'); - } - - // Update FCM token $encryptedFcm = $this->encryption->encrypt($fcmToken); if ($passengerToken) { $passengerToken->update([ @@ -99,26 +79,21 @@ class AuthController extends Controller ]); } - // Generate API keys if missing if (empty($passenger->api_key)) { $this->generateApiKeys($passenger); } - $jwt = $this->createJwt($passenger->id, 'passenger', $fingerprint, 86400); + $jwt = $this->createJwt($passenger->id, 'passenger', $fingerprint, 3600); // 1 Hour return $this->success([ 'token' => $jwt, - 'expires_in' => 86400, + 'expires_in' => 3600, 'user_id' => $passenger->id, 'api_key' => $passenger->api_key, 'api_secret' => $passenger->api_secret, ]); } - /** - * POST /v2/auth/passenger/register - * Replaces: loginFirstTime.php - */ public function passengerRegister(Request $request): JsonResponse { $request->validate([ @@ -126,64 +101,45 @@ class AuthController extends Controller 'email' => 'required|email', 'first_name' => 'required|string', 'last_name' => 'required|string', - 'password' => 'nullable|string|min:6', - 'gender' => 'nullable|string', - 'birthdate' => 'nullable|string', - 'site' => 'nullable|string', 'fingerprint' => 'nullable|string', 'fcm_token' => 'nullable|string', ]); $phone = $request->input('phone'); - $password = $request->input('password', Str::random(12)); - $gender = $request->input('gender', 'not_specified'); - $birthdate = $request->input('birthdate', '2000-01-01'); - $site = $request->input('site', 'none'); - $fingerprint = $request->input('fingerprint', 'unknown'); - $fcmToken = $request->input('fcm_token', 'none'); - $encryptedPhone = $this->encryption->encrypt($phone); - // Check if already exists - $exists = Passenger::where('phone', $encryptedPhone)->exists(); - if ($exists) { + if (Passenger::where('phone', $encryptedPhone)->exists()) { return $this->failure('Phone number already registered'); } - // Generate a 19-digit numeric ID for better indexing performance $passengerId = (string) mt_rand(1000000000, 9999999999) . mt_rand(100000000, 999999999); - // Encrypt sensitive fields $passenger = Passenger::create([ 'id' => $passengerId, 'phone' => $encryptedPhone, 'email' => $this->encryption->encrypt($request->input('email')), - 'password' => password_hash($password, PASSWORD_BCRYPT), + 'password' => password_hash($request->input('password', '123456'), PASSWORD_BCRYPT), 'first_name' => $this->encryption->encrypt($request->input('first_name')), 'last_name' => $this->encryption->encrypt($request->input('last_name')), - 'gender' => $this->encryption->encrypt($gender), - 'birthdate' => $this->encryption->encrypt($birthdate), - 'site' => $site, + 'gender' => $this->encryption->encrypt($request->input('gender', 'male')), + 'birthdate' => $this->encryption->encrypt($request->input('birthdate', '2000-01-01')), + 'site' => $request->input('site', 'Syria'), ]); - // Create FCM token record if provided - if ($fcmToken !== 'none') { + if ($request->has('fcm_token')) { PassengerToken::create([ - 'token' => $this->encryption->encrypt($fcmToken), + 'token' => $this->encryption->encrypt($request->input('fcm_token')), 'passengerID' => $passengerId, - 'fingerPrint' => $fingerprint, + 'fingerPrint' => $request->input('fingerprint', 'unknown'), ]); } - // Generate API keys $this->generateApiKeys($passenger); - - // Generate 24h JWT for immediate use after registration - $jwt = $this->createJwt($passengerId, 'passenger', $fingerprint, 86400); + $jwt = $this->createJwt($passengerId, 'passenger', $request->input('fingerprint', 'unknown'), 3600); return $this->success([ 'token' => $jwt, - 'expires_in' => 86400, + 'expires_in' => 3600, 'user_id' => $passengerId, 'api_key' => $passenger->api_key, 'api_secret' => $passenger->api_secret, @@ -194,9 +150,6 @@ class AuthController extends Controller // DRIVER LOGIN // ══════════════════════════════════════════════ - /** - * POST /v2/auth/driver/login - */ public function driverLogin(Request $request): JsonResponse { $request->validate([ @@ -206,56 +159,71 @@ class AuthController extends Controller 'fcm_token' => 'required|string', ]); - $phone = $request->input('phone'); - $encryptedPhone = $this->encryption->encrypt($phone); - + $encryptedPhone = $this->encryption->encrypt($request->input('phone')); $driver = Driver::active()->where('phone', $encryptedPhone)->first(); - if (!$driver) { + + if (!$driver || (!password_verify($request->input('password'), $driver->password) && + !hash_equals($driver->password, hash_hmac('sha256', $request->input('password'), config('intaleq.jwt_secret'))))) { return $this->failure('Invalid credentials'); } - if (!password_verify($request->input('password'), $driver->password) && - !hash_equals($driver->password, hash_hmac('sha256', $request->input('password'), config('intaleq.jwt_secret')))) { - return $this->failure('Invalid credentials'); - } - - $jwt = $this->createJwt($driver->id, 'driver', $request->input('fingerprint'), 86400); + $jwt = $this->createJwt($driver->id, 'driver', $request->input('fingerprint'), 14400); // 4 Hours return $this->success([ 'token' => $jwt, - 'expires_in' => 86400, + 'expires_in' => 14400, 'user_id' => $driver->id, 'api_key' => $driver->api_key, 'api_secret' => $driver->api_secret, ]); } + // ══════════════════════════════════════════════ + // HANDSHAKE (V1 Compatibility) + // ══════════════════════════════════════════════ + + public function passengerJwtHandshake(Request $request): JsonResponse + { + $request->validate(['id' => 'required|string', 'fingerPrint' => 'required|string']); + + $passenger = Passenger::find($request->input('id')); + if (!$passenger) return $this->failure('User not found'); + + $jwt = $this->createJwt($passenger->id, 'passenger', $request->input('fingerPrint'), 3600); + return response()->json(['status' => 'success', 'jwt' => $jwt, 'expires_in' => 3600]); + } + + public function driverJwtHandshake(Request $request): JsonResponse + { + $request->validate(['id' => 'required|string', 'fingerPrint' => 'required|string']); + + $driver = Driver::find($request->input('id')); + if (!$driver) return $this->failure('User not found'); + + $jwt = $this->createJwt($driver->id, 'driver', $request->input('fingerPrint'), 14400); + return response()->json(['status' => 'success', 'jwt' => $jwt, 'expires_in' => 14400]); + } + // ══════════════════════════════════════════════ // WALLET LOGIN // ══════════════════════════════════════════════ public function passengerWalletLogin(Request $request): JsonResponse { - if (!$request->has('fingerprint') && $request->has('fingerPrint')) { - $request->merge(['fingerprint' => $request->input('fingerPrint')]); - } - - $request->validate([ - 'id' => 'required|string', - 'password' => 'required|string', - 'fingerprint' => 'required|string', - 'aud' => 'required|string', - ]); - - $secret = config('intaleq.jwt_secret'); - $jwt = $this->createWalletJwt($request->input('id'), $request->input('fingerprint'), $request->input('aud'), 300, $secret); + $request->validate(['id' => 'required|string', 'fingerPrint' => 'required|string']); + $jwt = $this->createWalletJwt($request->input('id'), $request->input('fingerPrint'), $request->input('aud', 'TripzWallet'), 60); $hmac = hash_hmac('sha256', $request->input('id'), config('intaleq.wallet_hmac_secret')); - return $this->success([ - 'jwt' => $jwt, - 'hmac' => $hmac, - 'expires_in' => 300, - ]); + return $this->success(['jwt' => $jwt, 'hmac' => $hmac, 'expires_in' => 60]); + } + + public function driverWalletLogin(Request $request): JsonResponse + { + $request->validate(['id' => 'required|string', 'fingerPrint' => 'required|string']); + $jwt = $this->createWalletJwt($request->input('id'), $request->input('fingerPrint'), $request->input('aud', 'TripzWallet'), 60, config('intaleq.wallet_jwt_secret')); + $hmac = hash_hmac('sha256', $request->input('id'), config('intaleq.wallet_hmac_secret')); + + return $this->success(['jwt' => $jwt, 'hmac' => $hmac, 'expires_in' => 60]); } // ══════════════════════════════════════════════ @@ -264,11 +232,7 @@ class AuthController extends Controller public function adminLogin(Request $request): JsonResponse { - $request->validate([ - 'device_number' => 'required|string', - 'password' => 'required|string', - ]); - + $request->validate(['device_number' => 'required|string', 'password' => 'required|string']); $admin = DB::connection('primary')->table('adminUser')->where('device_number', $request->input('device_number'))->first(); if (!$admin || !password_verify($request->input('password'), $admin->password ?? '')) { @@ -276,52 +240,17 @@ class AuthController extends Controller } $jwt = $this->createJwt((string)$admin->id, 'admin', $request->input('device_number'), 900); - - return $this->success([ - 'token' => $jwt, - 'expires_in' => 900, - 'user_id' => $admin->id, - ]); - } - - public function adminWalletLogin(Request $request): JsonResponse - { - $request->validate([ - 'id' => 'required|string', - 'password' => 'required|string', - 'fingerprint' => 'required|string', - 'aud' => 'required|string', - ]); - - $admin = DB::connection('primary')->table('adminUser')->where('id', $request->input('id'))->first(); - if (!$admin) return $this->failure('Not found'); - - $jwt = $this->createWalletJwt((string)$admin->id, $request->input('fingerprint'), $request->input('aud'), 60); - $hmac = hash_hmac('sha256', (string)$admin->id, config('intaleq.wallet_hmac_secret')); - - return $this->success([ - 'jwt' => $jwt, - 'hmac' => $hmac, - 'expires_in' => 60, - 'user_id' => $admin->id, - ]); + return $this->success(['token' => $jwt, 'expires_in' => 900, 'user_id' => $admin->id]); } // ══════════════════════════════════════════════ - // GOOGLE LOGIN (Legacy V1 Compatibility) + // GOOGLE LOGIN // ══════════════════════════════════════════════ public function passengerLoginGoogle(Request $request): JsonResponse { - $request->validate([ - 'email' => 'required|string', - 'id' => 'required|string', - ]); - + $request->validate(['email' => 'required|string', 'id' => 'required|string']); $email = $request->input('email'); - $id = $request->input('id'); - - // Check if email is already encrypted (contains non-alphanumeric chars usually) $searchEmail = (str_contains($email, '+') || str_contains($email, '/')) ? $email : $this->encryption->encrypt($email); $row = DB::connection('primary') @@ -344,36 +273,36 @@ class AuthController extends Controller 'p.api_key', 'p.api_secret', ]) + ->selectSub(function ($query) use ($request) { + $query->from('packageInfo') + ->select('version') + ->where('platform', $request->input('platform', 'ios')) + ->limit(1); + }, 'package') ->where('p.email', $searchEmail) - ->where('p.id', $id) + ->where('p.id', $request->input('id')) ->first(); - if (!$row) { - return response()->json(['status' => 'Failure', 'data' => 'User does not exist.']); - } + if (!$row) return response()->json(['status' => 'Failure', 'data' => 'User does not exist.']); - // Decrypt all fields for Flutter $data = (array) $row; + $data['package'] = $data['package'] ?? '1.1.33'; // Default to avoid Null error in Flutter + foreach ($data as $key => $value) { - if (is_string($value) && !in_array($key, ['id', 'status', 'created_at', 'updated_at', 'verified', 'isInstall', 'isGiftToken', 'api_key', 'api_secret'])) { + if (is_string($value) && !in_array($key, ['id', 'status', 'created_at', 'updated_at', 'verified', 'isInstall', 'isGiftToken', 'api_key', 'api_secret', 'package'])) { $dec = $this->encryption->decrypt($value); if ($dec) $data[$key] = $dec; } } - // Flutter expects data as a List - return response()->json([ - 'status' => 'success', - 'count' => 1, - 'data' => [$data], - ]); + return response()->json(['status' => 'success', 'count' => 1, 'data' => [$data]]); } // ══════════════════════════════════════════════ - // JWT HELPERS + // HELPERS // ══════════════════════════════════════════════ - private function createJwt(string $userId, string $userType, string $fingerprint, int $expiry, ?string $audience = null): string + private function createJwt(string $userId, string $userType, string $fingerprint, int $expiry): string { $payload = [ 'user_id' => $userId, @@ -381,15 +310,14 @@ class AuthController extends Controller 'fingerprint' => $fingerprint, 'iat' => time(), 'exp' => time() + $expiry, - 'aud' => $audience ?? 'mobile-app', + 'aud' => 'mobile-app', 'iss' => 'Tripz', 'jti' => bin2hex(random_bytes(16)), ]; - return JWT::encode($payload, config('intaleq.jwt_secret'), 'HS256'); } - private function createWalletJwt(string $userId, string $fingerprint, string $audience, int $expiry = 300, ?string $secret = null): string + private function createWalletJwt(string $userId, string $fingerprint, string $audience, int $expiry, ?string $secret = null): string { $payload = [ 'user_id' => $userId, @@ -400,7 +328,6 @@ class AuthController extends Controller 'aud' => $audience, 'jti' => bin2hex(random_bytes(16)), ]; - return JWT::encode($payload, $secret ?? config('intaleq.jwt_secret'), 'HS256'); } @@ -408,11 +335,9 @@ class AuthController extends Controller { $model->api_key = bin2hex(random_bytes(16)); $model->api_secret = bin2hex(random_bytes(32)); - DB::connection('primary')->table($model->getTable()) - ->where('idn', $model->idn ?? $model->id) - ->update([ - 'api_key' => $model->api_key, - 'api_secret' => $model->api_secret - ]); + DB::connection('primary')->table($model->getTable())->where('id', $model->id)->update([ + 'api_key' => $model->api_key, + 'api_secret' => $model->api_secret + ]); } }