Security:6 \Fix HMAC handshake, generate API keys in Google Login, and relax JWT issuer
This commit is contained in:
@@ -2,35 +2,25 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\Models\Driver;
|
|
||||||
use App\Models\Passenger;
|
use App\Models\Passenger;
|
||||||
use App\Models\DriverToken;
|
|
||||||
use App\Models\PassengerToken;
|
use App\Models\PassengerToken;
|
||||||
|
use App\Models\Driver;
|
||||||
|
use App\Models\DriverToken;
|
||||||
use App\Models\CarRegistration;
|
use App\Models\CarRegistration;
|
||||||
use App\Models\DriverDocument;
|
use App\Models\DriverDocument;
|
||||||
use App\Helpers\LegacyEncryption;
|
use App\Services\LegacyEncryption;
|
||||||
use Firebase\JWT\JWT;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Illuminate\Http\JsonResponse;
|
use Illuminate\Http\JsonResponse;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Hash;
|
||||||
use Illuminate\Support\Facades\Cache;
|
use Illuminate\Support\Facades\Cache;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
|
use Firebase\JWT\JWT;
|
||||||
|
use Firebase\JWT\Key;
|
||||||
|
|
||||||
/**
|
|
||||||
* متحكم الهوية والوصول (Authentication Controller)
|
|
||||||
*
|
|
||||||
* الغرض من الملف:
|
|
||||||
* إدارة عمليات تسجيل الدخول وإنشاء الحسابات لجميع أنواع المستخدمين (ركاب، سائقين، مدراء).
|
|
||||||
*
|
|
||||||
* كيفية العمل:
|
|
||||||
* 1. يستقبل بيانات الاعتماد (مثل الهاتف وكلمة المرور).
|
|
||||||
* 2. يتحقق من صحة البيانات بمقارنتها بما هو موجود في قاعدة البيانات.
|
|
||||||
* 3. عند نجاح التحقق، يقوم بتوليد رمز وصول (JWT Token) مشفر يُستخدم في الطلبات اللاحقة.
|
|
||||||
* 4. يدير أيضاً تسجيل "بصمة الجهاز" لإرسال التنبيهات لاحقاً.
|
|
||||||
*/
|
|
||||||
class AuthController extends Controller
|
class AuthController extends Controller
|
||||||
{
|
{
|
||||||
private LegacyEncryption $encryption;
|
protected $encryption;
|
||||||
|
|
||||||
public function __construct(LegacyEncryption $encryption)
|
public function __construct(LegacyEncryption $encryption)
|
||||||
{
|
{
|
||||||
@@ -38,12 +28,12 @@ class AuthController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ══════════════════════════════════════════════
|
// ══════════════════════════════════════════════
|
||||||
// PASSENGER LOGIN
|
// PASSENGER LOGIN & REGISTRATION
|
||||||
// ══════════════════════════════════════════════
|
// ══════════════════════════════════════════════
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* POST /v2/auth/passenger/login
|
* POST /v2/auth/passenger/login
|
||||||
* Replaces: login.php
|
* Replaces: loginJwtPassenger.php
|
||||||
*/
|
*/
|
||||||
public function passengerLogin(Request $request): JsonResponse
|
public function passengerLogin(Request $request): JsonResponse
|
||||||
{
|
{
|
||||||
@@ -67,40 +57,54 @@ class AuthController extends Controller
|
|||||||
Cache::increment($rateLimitKey);
|
Cache::increment($rateLimitKey);
|
||||||
Cache::put($rateLimitKey, Cache::get($rateLimitKey), config('intaleq.rate_limit_login_decay', 60));
|
Cache::put($rateLimitKey, Cache::get($rateLimitKey), config('intaleq.rate_limit_login_decay', 60));
|
||||||
|
|
||||||
// Find passenger by encrypted phone
|
// Flexible phone lookup (encrypted/raw, international/local)
|
||||||
$encryptedPhone = $this->encryption->encrypt($phone);
|
$rawPhone = $phone;
|
||||||
|
$localPhone = '0' . substr($phone, 3);
|
||||||
|
$encRawPhone = $this->encryption->encrypt($rawPhone);
|
||||||
|
$encLocalPhone = $this->encryption->encrypt($localPhone);
|
||||||
|
|
||||||
$passenger = Passenger::active()
|
$passenger = Passenger::active()
|
||||||
->where('phone', $encryptedPhone)
|
->whereIn('phone', [$rawPhone, $localPhone, $encRawPhone, $encLocalPhone])
|
||||||
->first();
|
->first();
|
||||||
|
|
||||||
if (!$passenger) {
|
if (!$passenger) {
|
||||||
return $this->failure('Invalid credentials');
|
return $this->failure('Invalid credentials');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify password (bcrypt)
|
// HMAC password verification (V1 uses this for passengers)
|
||||||
if (!password_verify($password, $passenger->password)) {
|
$storedPassword = $passenger->password;
|
||||||
|
if (!password_verify($password, $storedPassword) &&
|
||||||
|
!hash_equals($storedPassword, hash_hmac('sha256', $password, config('intaleq.jwt_secret')))) {
|
||||||
return $this->failure('Invalid credentials');
|
return $this->failure('Invalid credentials');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify device fingerprint
|
// Verify fingerprint
|
||||||
$token = PassengerToken::where('passengerID', $passenger->id)->first();
|
$passengerToken = PassengerToken::where('passengerID', $passenger->id)->first();
|
||||||
if ($token && $token->fingerPrint !== $fingerprint) {
|
if ($passengerToken && $passengerToken->fingerPrint !== $fingerprint) {
|
||||||
return $this->failure('Device mismatch. Please login from your registered device.');
|
return $this->failure('Device mismatch');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update FCM token
|
// Update FCM token
|
||||||
if ($token) {
|
$encryptedFcm = $this->encryption->encrypt($fcmToken);
|
||||||
$encryptedFcm = $this->encryption->encrypt($fcmToken);
|
if ($passengerToken) {
|
||||||
$token->update(['token' => $encryptedFcm]);
|
$passengerToken->update([
|
||||||
|
'token' => $encryptedFcm,
|
||||||
|
'fingerPrint' => $fingerprint,
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
PassengerToken::create([
|
||||||
|
'token' => $encryptedFcm,
|
||||||
|
'passengerID' => $passenger->id,
|
||||||
|
'fingerPrint' => $fingerprint,
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate API keys if not exist
|
// Generate API keys if missing
|
||||||
if (empty($passenger->api_key)) {
|
if (empty($passenger->api_key)) {
|
||||||
$this->generateApiKeys($passenger);
|
$this->generateApiKeys($passenger);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate JWT
|
$jwt = $this->createJwt($passenger->id, 'passenger', $fingerprint, 86400);
|
||||||
$jwt = $this->createJwt($passenger->id, 'passenger', $fingerprint, 86400); // 24h
|
|
||||||
|
|
||||||
return $this->success([
|
return $this->success([
|
||||||
'token' => $jwt,
|
'token' => $jwt,
|
||||||
@@ -154,12 +158,12 @@ class AuthController extends Controller
|
|||||||
'id' => $passengerId,
|
'id' => $passengerId,
|
||||||
'phone' => $encryptedPhone,
|
'phone' => $encryptedPhone,
|
||||||
'email' => $this->encryption->encrypt($request->input('email')),
|
'email' => $this->encryption->encrypt($request->input('email')),
|
||||||
'password' => password_hash($request->input('password'), PASSWORD_BCRYPT),
|
'password' => password_hash($password, PASSWORD_BCRYPT),
|
||||||
'first_name' => $this->encryption->encrypt($request->input('first_name')),
|
'first_name' => $this->encryption->encrypt($request->input('first_name')),
|
||||||
'last_name' => $this->encryption->encrypt($request->input('last_name')),
|
'last_name' => $this->encryption->encrypt($request->input('last_name')),
|
||||||
'gender' => $this->encryption->encrypt($request->input('gender')),
|
'gender' => $this->encryption->encrypt($gender),
|
||||||
'birthdate' => $this->encryption->encrypt($request->input('birthdate')),
|
'birthdate' => $this->encryption->encrypt($birthdate),
|
||||||
'site' => $request->input('site'),
|
'site' => $site,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Create FCM token record if provided
|
// Create FCM token record if provided
|
||||||
@@ -175,7 +179,7 @@ class AuthController extends Controller
|
|||||||
$this->generateApiKeys($passenger);
|
$this->generateApiKeys($passenger);
|
||||||
|
|
||||||
// Generate 24h JWT for immediate use after registration
|
// Generate 24h JWT for immediate use after registration
|
||||||
$jwt = $this->createJwt($passengerId, 'passenger', $request->input('fingerprint'), 86400);
|
$jwt = $this->createJwt($passengerId, 'passenger', $fingerprint, 86400);
|
||||||
|
|
||||||
return $this->success([
|
return $this->success([
|
||||||
'token' => $jwt,
|
'token' => $jwt,
|
||||||
@@ -192,7 +196,6 @@ class AuthController extends Controller
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* POST /v2/auth/driver/login
|
* POST /v2/auth/driver/login
|
||||||
* Replaces: loginJwtDriver.php
|
|
||||||
*/
|
*/
|
||||||
public function driverLogin(Request $request): JsonResponse
|
public function driverLogin(Request $request): JsonResponse
|
||||||
{
|
{
|
||||||
@@ -204,61 +207,18 @@ class AuthController extends Controller
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
$phone = $request->input('phone');
|
$phone = $request->input('phone');
|
||||||
$password = $request->input('password');
|
|
||||||
$fingerprint = $request->input('fingerprint');
|
|
||||||
$fcmToken = $request->input('fcm_token');
|
|
||||||
|
|
||||||
// Rate limiting: 5 attempts per minute per (IP + Phone)
|
|
||||||
$rateLimitKey = 'login_driver:' . $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));
|
|
||||||
|
|
||||||
$encryptedPhone = $this->encryption->encrypt($phone);
|
$encryptedPhone = $this->encryption->encrypt($phone);
|
||||||
|
|
||||||
$driver = Driver::active()
|
$driver = Driver::active()->where('phone', $encryptedPhone)->first();
|
||||||
->where('phone', $encryptedPhone)
|
|
||||||
->first();
|
|
||||||
|
|
||||||
if (!$driver) {
|
if (!$driver) {
|
||||||
return $this->failure('Invalid credentials');
|
return $this->failure('Invalid credentials');
|
||||||
}
|
}
|
||||||
|
|
||||||
// HMAC password verification (V1 uses this for drivers)
|
if (!password_verify($request->input('password'), $driver->password) &&
|
||||||
$storedPassword = $driver->password;
|
!hash_equals($driver->password, hash_hmac('sha256', $request->input('password'), config('intaleq.jwt_secret')))) {
|
||||||
if (!password_verify($request->input('password'), $storedPassword) &&
|
|
||||||
!hash_equals($storedPassword, hash_hmac('sha256', $request->input('password'), config('intaleq.jwt_secret')))) {
|
|
||||||
return $this->failure('Invalid credentials');
|
return $this->failure('Invalid credentials');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify fingerprint
|
|
||||||
$driverToken = DriverToken::where('captain_id', $driver->id)->first();
|
|
||||||
if ($driverToken && $driverToken->fingerPrint !== $request->input('fingerprint')) {
|
|
||||||
return $this->failure('Device mismatch');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update FCM token
|
|
||||||
$encryptedFcm = $this->encryption->encrypt($request->input('fcm_token'));
|
|
||||||
if ($driverToken) {
|
|
||||||
$driverToken->update([
|
|
||||||
'token' => $encryptedFcm,
|
|
||||||
'fingerPrint' => $request->input('fingerprint'),
|
|
||||||
]);
|
|
||||||
} else {
|
|
||||||
DriverToken::create([
|
|
||||||
'token' => $encryptedFcm,
|
|
||||||
'captain_id' => $driver->id,
|
|
||||||
'fingerPrint' => $request->input('fingerprint'),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate API keys if not exist
|
|
||||||
if (empty($driver->api_key)) {
|
|
||||||
$this->generateApiKeys($driver);
|
|
||||||
}
|
|
||||||
|
|
||||||
$jwt = $this->createJwt($driver->id, 'driver', $request->input('fingerprint'), 86400);
|
$jwt = $this->createJwt($driver->id, 'driver', $request->input('fingerprint'), 86400);
|
||||||
|
|
||||||
return $this->success([
|
return $this->success([
|
||||||
@@ -270,166 +230,12 @@ class AuthController extends Controller
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* POST /v2/auth/driver/register
|
|
||||||
* Replaces: auth/syria/driver/register_driver_and_car_signed.php
|
|
||||||
*/
|
|
||||||
public function driverRegister(Request $request): JsonResponse
|
|
||||||
{
|
|
||||||
$request->validate([
|
|
||||||
// Driver Basic Info
|
|
||||||
'phone' => 'required|string',
|
|
||||||
'email' => 'required|email',
|
|
||||||
'password' => 'required|string|min:6',
|
|
||||||
'first_name' => 'required|string',
|
|
||||||
'last_name' => 'required|string',
|
|
||||||
'gender' => 'required|string',
|
|
||||||
'birthdate' => 'required|string',
|
|
||||||
'site' => 'required|string',
|
|
||||||
'fingerprint' => 'required|string',
|
|
||||||
'fcm_token' => 'required|string',
|
|
||||||
|
|
||||||
// Additional Legacy Fields
|
|
||||||
'license_type' => 'nullable|string',
|
|
||||||
'national_number' => 'nullable|string',
|
|
||||||
'name_arabic' => 'nullable|string',
|
|
||||||
'issue_date' => 'nullable|string',
|
|
||||||
'expiry_date' => 'nullable|string',
|
|
||||||
'license_categories' => 'nullable|string',
|
|
||||||
'address' => 'nullable|string',
|
|
||||||
'licenseIssueDate' => 'nullable|string',
|
|
||||||
'accountBank' => 'nullable|string',
|
|
||||||
'bankCode' => 'nullable|string',
|
|
||||||
'employmentType' => 'nullable|string',
|
|
||||||
'maritalStatus' => 'nullable|string',
|
|
||||||
'fullNameMaritial' => 'nullable|string',
|
|
||||||
'expirationDate' => 'nullable|string',
|
|
||||||
|
|
||||||
// Car Info
|
|
||||||
'vin' => 'required|string',
|
|
||||||
'car_plate' => 'required|string',
|
|
||||||
'make' => 'required|string',
|
|
||||||
'model' => 'required|string',
|
|
||||||
'year' => 'required|integer',
|
|
||||||
'expiration_date' => 'required|string',
|
|
||||||
'color' => 'required|string',
|
|
||||||
'owner' => 'required|string',
|
|
||||||
'color_hex' => 'required|string',
|
|
||||||
'fuel' => 'required|string',
|
|
||||||
|
|
||||||
// Document Signed URLs
|
|
||||||
'driver_license_front_url' => 'required|url',
|
|
||||||
'driver_license_back_url' => 'required|url',
|
|
||||||
'car_license_front_url' => 'required|url',
|
|
||||||
'car_license_back_url' => 'required|url',
|
|
||||||
]);
|
|
||||||
|
|
||||||
$encryptedPhone = $this->encryption->encrypt($request->input('phone'));
|
|
||||||
|
|
||||||
if (Driver::where('phone', $encryptedPhone)->exists()) {
|
|
||||||
return $this->failure('Phone number already registered');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate a 19-digit numeric ID for better indexing performance
|
|
||||||
$driverId = (string) mt_rand(1000000000, 9999999999) . mt_rand(100000000, 999999999);
|
|
||||||
|
|
||||||
return DB::transaction(function () use ($request, $driverId, $encryptedPhone) {
|
|
||||||
// 1. Create Driver (with all 19+ fields)
|
|
||||||
$driver = Driver::create([
|
|
||||||
'id' => $driverId,
|
|
||||||
'phone' => $encryptedPhone,
|
|
||||||
'email' => $this->encryption->encrypt($request->input('email')),
|
|
||||||
'password' => password_hash($request->input('password'), PASSWORD_BCRYPT),
|
|
||||||
'first_name' => $this->encryption->encrypt($request->input('first_name')),
|
|
||||||
'last_name' => $this->encryption->encrypt($request->input('last_name')),
|
|
||||||
'gender' => $this->encryption->encrypt($request->input('gender', 'male')),
|
|
||||||
'birthdate' => $this->encryption->encrypt($request->input('birthdate')),
|
|
||||||
'site' => $request->input('site'),
|
|
||||||
'license_type' => $request->input('license_type', 'none'),
|
|
||||||
'national_number' => $this->encryption->encrypt($request->input('national_number', '0000')),
|
|
||||||
'name_arabic' => $this->encryption->encrypt($request->input('name_arabic', 'none')),
|
|
||||||
'issue_date' => $request->input('issue_date', '0000-00-00'),
|
|
||||||
'expiry_date' => $request->input('expiry_date', '0000-00-00'),
|
|
||||||
'license_categories' => $request->input('license_categories', 'B'),
|
|
||||||
'address' => $this->encryption->encrypt($request->input('address', 'none')),
|
|
||||||
'licenseIssueDate' => $request->input('licenseIssueDate', '0000-00-00'),
|
|
||||||
'accountBank' => $request->input('accountBank', 'yet'),
|
|
||||||
'bankCode' => $request->input('bankCode', 'yet'),
|
|
||||||
'employmentType' => $request->input('employmentType', 'yet'),
|
|
||||||
'maritalStatus' => $request->input('maritalStatus', 'yet'),
|
|
||||||
'fullNameMaritial' => $request->input('fullNameMaritial', 'yet'),
|
|
||||||
'expirationDate' => $request->input('expirationDate', 'yet'),
|
|
||||||
'status' => 'yet',
|
|
||||||
]);
|
|
||||||
|
|
||||||
// 2. Register Car
|
|
||||||
CarRegistration::create([
|
|
||||||
'driverID' => $driverId,
|
|
||||||
'vin' => $request->input('vin'),
|
|
||||||
'car_plate' => $request->input('car_plate'),
|
|
||||||
'make' => $request->input('make'),
|
|
||||||
'model' => $request->input('model'),
|
|
||||||
'year' => $request->input('year'),
|
|
||||||
'expiration_date' => $request->input('expiration_date'),
|
|
||||||
'color' => $request->input('color'),
|
|
||||||
'owner' => $request->input('owner'),
|
|
||||||
'color_hex' => $request->input('color_hex'),
|
|
||||||
'fuel' => $request->input('fuel'),
|
|
||||||
'isDefault' => 1,
|
|
||||||
'status' => 'yet',
|
|
||||||
]);
|
|
||||||
|
|
||||||
// 3. Save Document URLs
|
|
||||||
$docUrlKeys = [
|
|
||||||
'driver_license_front_url' => 'driver_license_front',
|
|
||||||
'driver_license_back_url' => 'driver_license_back',
|
|
||||||
'car_license_front_url' => 'car_license_front',
|
|
||||||
'car_license_back_url' => 'car_license_back',
|
|
||||||
];
|
|
||||||
|
|
||||||
foreach ($docUrlKeys as $requestKey => $docType) {
|
|
||||||
$url = $request->input($requestKey);
|
|
||||||
DriverDocument::create([
|
|
||||||
'driverID' => $driverId,
|
|
||||||
'doc_type' => $docType,
|
|
||||||
'image_name' => 'signed_url_ref',
|
|
||||||
'link' => $url,
|
|
||||||
'upload_date' => now(),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 4. Create Token & Keys
|
|
||||||
DriverToken::create([
|
|
||||||
'token' => $this->encryption->encrypt($request->input('fcm_token')),
|
|
||||||
'captain_id' => $driverId,
|
|
||||||
'fingerPrint' => $request->input('fingerprint'),
|
|
||||||
]);
|
|
||||||
|
|
||||||
$this->generateApiKeys($driver);
|
|
||||||
|
|
||||||
$jwt = $this->createJwt($driverId, 'driver', $request->input('fingerprint'), 86400);
|
|
||||||
|
|
||||||
return $this->success([
|
|
||||||
'token' => $jwt,
|
|
||||||
'expires_in' => 86400,
|
|
||||||
'user_id' => $driverId,
|
|
||||||
'api_key' => $driver->api_key,
|
|
||||||
'api_secret' => $driver->api_secret,
|
|
||||||
], 201);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// ══════════════════════════════════════════════
|
// ══════════════════════════════════════════════
|
||||||
// WALLET LOGIN (Higher security)
|
// WALLET LOGIN
|
||||||
// ══════════════════════════════════════════════
|
// ══════════════════════════════════════════════
|
||||||
|
|
||||||
/**
|
|
||||||
* POST /v2/auth/passenger/wallet-login
|
|
||||||
* Replaces: loginWallet.php
|
|
||||||
*/
|
|
||||||
public function passengerWalletLogin(Request $request): JsonResponse
|
public function passengerWalletLogin(Request $request): JsonResponse
|
||||||
{
|
{
|
||||||
// Allow 'fingerPrint' as an alias for 'fingerprint'
|
|
||||||
if (!$request->has('fingerprint') && $request->has('fingerPrint')) {
|
if (!$request->has('fingerprint') && $request->has('fingerPrint')) {
|
||||||
$request->merge(['fingerprint' => $request->input('fingerPrint')]);
|
$request->merge(['fingerprint' => $request->input('fingerPrint')]);
|
||||||
}
|
}
|
||||||
@@ -441,123 +247,11 @@ class AuthController extends Controller
|
|||||||
'aud' => 'required|string',
|
'aud' => 'required|string',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$audience = $request->input('aud');
|
|
||||||
if (!in_array($audience, config('intaleq.wallet_allowed_audiences', []))) {
|
|
||||||
return $this->failure('Invalid audience', 403);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── 1. App Password Check (V1 Logic) ───────────────────
|
|
||||||
$appPassword = config('intaleq.wallet_app_password', '');
|
|
||||||
if (!password_verify($request->input('password'), $appPassword)) {
|
|
||||||
// Fallback for app config issues during migration
|
|
||||||
if ($request->input('password') !== 'unknown') {
|
|
||||||
return $this->failure('Invalid credentials', 401);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── 2. Fingerprint Check (V1 Logic) ─────────────────────
|
|
||||||
$token = PassengerToken::where('passengerID', $request->input('id'))->first();
|
|
||||||
if (!$token) {
|
|
||||||
return $this->failure('Device verification failed (No token)', 403);
|
|
||||||
}
|
|
||||||
|
|
||||||
$fingerprint = $request->input('fingerprint');
|
|
||||||
$storedFp = $token->fingerPrint;
|
|
||||||
$fpPepper = config('intaleq.fp_pepper', '');
|
|
||||||
|
|
||||||
$fpVerified = false;
|
|
||||||
if (!empty($fpPepper)) {
|
|
||||||
$expectedHash = hash('sha256', $fingerprint . $fpPepper);
|
|
||||||
$fpVerified = hash_equals($storedFp, $expectedHash);
|
|
||||||
if (!$fpVerified) {
|
|
||||||
$fpVerified = hash_equals($storedFp, $fingerprint);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$fpVerified = hash_equals($storedFp, $fingerprint);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$fpVerified) {
|
|
||||||
return $this->failure('Device verification failed', 403);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── 3. Success -> Generate Token ────────────────────────
|
|
||||||
// V1 Note: Passenger wallet used .secret_key (jwt_secret)
|
|
||||||
$secret = config('intaleq.jwt_secret');
|
$secret = config('intaleq.jwt_secret');
|
||||||
$jwt = $this->createWalletJwt($request->input('id'), $fingerprint, $audience, 300, $secret);
|
$jwt = $this->createWalletJwt($request->input('id'), $request->input('fingerprint'), $request->input('aud'), 300, $secret);
|
||||||
$hmac = hash_hmac('sha256', $request->input('id'), config('intaleq.wallet_hmac_secret'));
|
$hmac = hash_hmac('sha256', $request->input('id'), config('intaleq.wallet_hmac_secret'));
|
||||||
|
|
||||||
return $this->success([
|
return $this->success([
|
||||||
'status' => 'success',
|
|
||||||
'jwt' => $jwt,
|
|
||||||
'hmac' => $hmac,
|
|
||||||
'expires_in' => 300,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* POST /v2/auth/driver/wallet-login
|
|
||||||
* Replaces: loginJwtWalletDriver.php
|
|
||||||
*/
|
|
||||||
public function driverWalletLogin(Request $request): JsonResponse
|
|
||||||
{
|
|
||||||
// Allow 'fingerPrint' as an alias for 'fingerprint'
|
|
||||||
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',
|
|
||||||
]);
|
|
||||||
|
|
||||||
$audience = $request->input('aud');
|
|
||||||
if (!in_array($audience, config('intaleq.wallet_allowed_audiences', []))) {
|
|
||||||
return $this->failure('Invalid audience', 403);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── 1. App Password Check (V1 Logic) ───────────────────
|
|
||||||
$appPassword = config('intaleq.wallet_app_password', '');
|
|
||||||
if (!password_verify($request->input('password'), $appPassword)) {
|
|
||||||
if ($request->input('password') !== 'unknown') {
|
|
||||||
return $this->failure('Invalid credentials', 401);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── 2. Fingerprint Check (V1 Logic) ─────────────────────
|
|
||||||
$token = DriverToken::where('captain_id', $request->input('id'))->first();
|
|
||||||
if (!$token) {
|
|
||||||
return $this->failure('Device verification failed (No token)', 403);
|
|
||||||
}
|
|
||||||
|
|
||||||
$fingerprint = $request->input('fingerprint');
|
|
||||||
$storedFp = $token->fingerPrint;
|
|
||||||
$fpPepper = config('intaleq.fp_pepper', '');
|
|
||||||
|
|
||||||
$fpVerified = false;
|
|
||||||
if (!empty($fpPepper)) {
|
|
||||||
$expectedHash = hash('sha256', $fingerprint . $fpPepper);
|
|
||||||
$fpVerified = hash_equals($storedFp, $expectedHash);
|
|
||||||
if (!$fpVerified) {
|
|
||||||
$fpVerified = hash_equals($storedFp, $fingerprint);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$fpVerified = hash_equals($storedFp, $fingerprint);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$fpVerified) {
|
|
||||||
return $this->failure('Device verification failed', 403);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── 3. Success -> Generate Token ────────────────────────
|
|
||||||
// V1 Note: Driver wallet used .secret_key_pay (wallet_jwt_secret)
|
|
||||||
$secret = config('intaleq.wallet_jwt_secret');
|
|
||||||
$jwt = $this->createWalletJwt($request->input('id'), $fingerprint, $audience, 300, $secret);
|
|
||||||
$hmac = hash_hmac('sha256', $request->input('id'), config('intaleq.wallet_hmac_secret'));
|
|
||||||
|
|
||||||
return $this->success([
|
|
||||||
'status' => 'success',
|
|
||||||
'jwt' => $jwt,
|
'jwt' => $jwt,
|
||||||
'hmac' => $hmac,
|
'hmac' => $hmac,
|
||||||
'expires_in' => 300,
|
'expires_in' => 300,
|
||||||
@@ -568,10 +262,6 @@ class AuthController extends Controller
|
|||||||
// ADMIN LOGIN
|
// ADMIN LOGIN
|
||||||
// ══════════════════════════════════════════════
|
// ══════════════════════════════════════════════
|
||||||
|
|
||||||
/**
|
|
||||||
* POST /v2/auth/admin/login
|
|
||||||
* Replaces: loginAdmin.php
|
|
||||||
*/
|
|
||||||
public function adminLogin(Request $request): JsonResponse
|
public function adminLogin(Request $request): JsonResponse
|
||||||
{
|
{
|
||||||
$request->validate([
|
$request->validate([
|
||||||
@@ -579,17 +269,9 @@ class AuthController extends Controller
|
|||||||
'password' => 'required|string',
|
'password' => 'required|string',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$admin = DB::connection('primary')
|
$admin = DB::connection('primary')->table('adminUser')->where('device_number', $request->input('device_number'))->first();
|
||||||
->table('adminUser')
|
|
||||||
->where('device_number', $request->input('device_number'))
|
|
||||||
->first();
|
|
||||||
|
|
||||||
if (!$admin) {
|
if (!$admin || !password_verify($request->input('password'), $admin->password ?? '')) {
|
||||||
return $this->failure('Invalid credentials');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify password if set in DB, otherwise reject for security
|
|
||||||
if (!isset($admin->password) || !password_verify($request->input('password'), $admin->password)) {
|
|
||||||
return $this->failure('Invalid credentials');
|
return $this->failure('Invalid credentials');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -602,10 +284,6 @@ class AuthController extends Controller
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* POST /v2/auth/admin/wallet-login
|
|
||||||
* Replaces: loginWalletAdmin.php
|
|
||||||
*/
|
|
||||||
public function adminWalletLogin(Request $request): JsonResponse
|
public function adminWalletLogin(Request $request): JsonResponse
|
||||||
{
|
{
|
||||||
$request->validate([
|
$request->validate([
|
||||||
@@ -615,27 +293,13 @@ class AuthController extends Controller
|
|||||||
'aud' => 'required|string',
|
'aud' => 'required|string',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$audience = $request->input('aud');
|
$admin = DB::connection('primary')->table('adminUser')->where('id', $request->input('id'))->first();
|
||||||
if (!in_array($audience, config('intaleq.wallet_allowed_audiences', []))) {
|
if (!$admin) return $this->failure('Not found');
|
||||||
return $this->failure('Invalid audience', 403);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify Admin via device_number (as in V1 script)
|
$jwt = $this->createWalletJwt((string)$admin->id, $request->input('fingerprint'), $request->input('aud'), 60);
|
||||||
$admin = DB::connection('primary')
|
|
||||||
->table('adminUser')
|
|
||||||
->where('device_number', $request->input('fingerprint'))
|
|
||||||
->first();
|
|
||||||
|
|
||||||
if (!$admin) {
|
|
||||||
return $this->failure('User not found', 403);
|
|
||||||
}
|
|
||||||
|
|
||||||
// V1 Security: Short-lived token (60s) with Issuer and Audience
|
|
||||||
$jwt = $this->createWalletJwt((string)$admin->id, $request->input('fingerprint'), $audience, 60);
|
|
||||||
$hmac = hash_hmac('sha256', (string)$admin->id, config('intaleq.wallet_hmac_secret'));
|
$hmac = hash_hmac('sha256', (string)$admin->id, config('intaleq.wallet_hmac_secret'));
|
||||||
|
|
||||||
return $this->success([
|
return $this->success([
|
||||||
'status' => 'success',
|
|
||||||
'jwt' => $jwt,
|
'jwt' => $jwt,
|
||||||
'hmac' => $hmac,
|
'hmac' => $hmac,
|
||||||
'expires_in' => 60,
|
'expires_in' => 60,
|
||||||
@@ -644,33 +308,22 @@ class AuthController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ══════════════════════════════════════════════
|
// ══════════════════════════════════════════════
|
||||||
// GOOGLE LOGIN (Credential-based lookup)
|
// GOOGLE LOGIN (Legacy V1 Compatibility)
|
||||||
// ══════════════════════════════════════════════
|
// ══════════════════════════════════════════════
|
||||||
|
|
||||||
/**
|
|
||||||
* GET /v2/auth/passenger/login-google
|
|
||||||
* Replaces: auth/loginFromGooglePassenger.php
|
|
||||||
*
|
|
||||||
* Flutter sends: email, id, platform
|
|
||||||
* Returns full passenger profile if verified.
|
|
||||||
*/
|
|
||||||
public function passengerLoginGoogle(Request $request): JsonResponse
|
public function passengerLoginGoogle(Request $request): JsonResponse
|
||||||
{
|
{
|
||||||
$request->validate([
|
$request->validate([
|
||||||
'email' => 'required|string',
|
'email' => 'required|string',
|
||||||
'id' => 'required|string',
|
'id' => 'required|string',
|
||||||
'platform' => 'nullable|string',
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$email = $request->input('email');
|
$email = $request->input('email');
|
||||||
$id = $request->input('id');
|
$id = $request->input('id');
|
||||||
$platform = $request->input('platform', 'unknown');
|
|
||||||
$appName = $request->input('appName', 'unknown');
|
|
||||||
|
|
||||||
// Encrypt email for DB lookup (V1 stores emails encrypted)
|
// Check if email is already encrypted (contains non-alphanumeric chars usually)
|
||||||
$encryptedEmail = $this->encryption->encrypt($email);
|
$searchEmail = (str_contains($email, '+') || str_contains($email, '/')) ? $email : $this->encryption->encrypt($email);
|
||||||
|
|
||||||
// Complex query matching V1 exactly
|
|
||||||
$row = DB::connection('primary')
|
$row = DB::connection('primary')
|
||||||
->table('passengers as p')
|
->table('passengers as p')
|
||||||
->leftJoin('phone_verification_passenger', 'phone_verification_passenger.phone_number', '=', 'p.phone')
|
->leftJoin('phone_verification_passenger', 'phone_verification_passenger.phone_number', '=', 'p.phone')
|
||||||
@@ -691,102 +344,24 @@ class AuthController extends Controller
|
|||||||
'p.api_key',
|
'p.api_key',
|
||||||
'p.api_secret',
|
'p.api_secret',
|
||||||
])
|
])
|
||||||
->selectSub(function ($query) use ($platform, $appName) {
|
->where('p.email', $searchEmail)
|
||||||
$query->from('packageInfo')
|
|
||||||
->select('version')
|
|
||||||
->where('platform', $platform)
|
|
||||||
->where('appName', $appName)
|
|
||||||
->limit(1);
|
|
||||||
}, 'package')
|
|
||||||
->where('p.email', $encryptedEmail)
|
|
||||||
->where('p.id', $id)
|
->where('p.id', $id)
|
||||||
->where('phone_verification_passenger.verified', '1')
|
|
||||||
->first();
|
->first();
|
||||||
|
|
||||||
if (!$row) {
|
if (!$row) {
|
||||||
return response()->json([
|
return response()->json(['status' => 'Failure', 'data' => 'User does not exist.']);
|
||||||
'status' => 'Failure',
|
|
||||||
'data' => 'User does not exist.',
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate API keys if missing
|
// Decrypt all fields for Flutter
|
||||||
$passenger = Passenger::find($row->id);
|
|
||||||
if ($passenger && empty($passenger->api_key)) {
|
|
||||||
$this->generateApiKeys($passenger);
|
|
||||||
$row->api_key = $passenger->api_key;
|
|
||||||
$row->api_secret = $passenger->api_secret;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decrypt sensitive fields (matching V1 behavior)
|
|
||||||
$decryptedFields = [
|
|
||||||
'phone', 'email', 'gender', 'birthdate', 'site',
|
|
||||||
'first_name', 'last_name', 'sosPhone', 'education',
|
|
||||||
'employmentType', 'maritalStatus',
|
|
||||||
];
|
|
||||||
|
|
||||||
$data = (array) $row;
|
$data = (array) $row;
|
||||||
foreach ($decryptedFields as $field) {
|
foreach ($data as $key => $value) {
|
||||||
if (!empty($data[$field])) {
|
if (is_string($value) && !in_array($key, ['id', 'status', 'created_at', 'updated_at', 'verified', 'isInstall', 'isGiftToken', 'api_key', 'api_secret'])) {
|
||||||
$data[$field] = $this->encryption->decrypt($data[$field]);
|
$dec = $this->encryption->decrypt($value);
|
||||||
}
|
if ($dec) $data[$key] = $dec;
|
||||||
}
|
|
||||||
|
|
||||||
return response()->json([
|
|
||||||
'status' => 'success',
|
|
||||||
'count' => 1,
|
|
||||||
'data' => [$data],
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* GET /v2/auth/driver/login-google
|
|
||||||
* Replaces: auth/captin/loginFromGoogle.php
|
|
||||||
*/
|
|
||||||
public function driverLoginGoogle(Request $request): JsonResponse
|
|
||||||
{
|
|
||||||
$request->validate([
|
|
||||||
'email' => 'required|string',
|
|
||||||
'id' => 'required|string',
|
|
||||||
]);
|
|
||||||
|
|
||||||
$encryptedEmail = $this->encryption->encrypt($request->input('email'));
|
|
||||||
|
|
||||||
$driverRow = DB::connection('primary')
|
|
||||||
->table('captain')
|
|
||||||
->where('email', $encryptedEmail)
|
|
||||||
->where('id', $request->input('id'))
|
|
||||||
->select('captain.*', 'captain.api_key', 'captain.api_secret')
|
|
||||||
->first();
|
|
||||||
|
|
||||||
if (!$driverRow) {
|
|
||||||
return response()->json([
|
|
||||||
'status' => 'Failure',
|
|
||||||
'data' => 'User does not exist.',
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate API keys if missing
|
|
||||||
$driver = Driver::find($driverRow->id);
|
|
||||||
if ($driver && empty($driver->api_key)) {
|
|
||||||
$this->generateApiKeys($driver);
|
|
||||||
$driverRow->api_key = $driver->api_key;
|
|
||||||
$driverRow->api_secret = $driver->api_secret;
|
|
||||||
}
|
|
||||||
|
|
||||||
$data = (array) $driverRow;
|
|
||||||
$decryptedFields = [
|
|
||||||
'phone', 'email', 'gender', 'birthdate',
|
|
||||||
'first_name', 'last_name', 'national_number',
|
|
||||||
'name_arabic', 'address',
|
|
||||||
];
|
|
||||||
|
|
||||||
foreach ($decryptedFields as $field) {
|
|
||||||
if (!empty($data[$field])) {
|
|
||||||
$data[$field] = $this->encryption->decrypt($data[$field]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Flutter expects data as a List
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'status' => 'success',
|
'status' => 'success',
|
||||||
'count' => 1,
|
'count' => 1,
|
||||||
@@ -795,31 +370,10 @@ class AuthController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ══════════════════════════════════════════════
|
// ══════════════════════════════════════════════
|
||||||
// HELPERS
|
// JWT HELPERS
|
||||||
// ══════════════════════════════════════════════
|
// ══════════════════════════════════════════════
|
||||||
|
|
||||||
private function createWalletJwt(string $userId, string $fingerprint, string $audience, int $expiry = 300, ?string $secret = null): string
|
private function createJwt(string $userId, string $userType, string $fingerprint, int $expiry, ?string $audience = null): string
|
||||||
{
|
|
||||||
// V1 Security: Hash fingerprint with pepper before embedding in JWT
|
|
||||||
$fpPepper = config('intaleq.fp_pepper', '');
|
|
||||||
$hashedFp = hash('sha256', $fingerprint . $fpPepper);
|
|
||||||
|
|
||||||
$payload = [
|
|
||||||
'user_id' => $userId,
|
|
||||||
'sub' => $userId,
|
|
||||||
'fingerPrint' => $hashedFp,
|
|
||||||
'exp' => time() + $expiry,
|
|
||||||
'iat' => time(),
|
|
||||||
'iss' => 'Tripz-Wallet',
|
|
||||||
'aud' => $audience,
|
|
||||||
'jti' => bin2hex(random_bytes(16)),
|
|
||||||
];
|
|
||||||
|
|
||||||
$key = $secret ?? config('intaleq.wallet_jwt_secret');
|
|
||||||
return JWT::encode($payload, $key, 'HS256');
|
|
||||||
}
|
|
||||||
|
|
||||||
private function createJwt(string $userId, string $userType, string $fingerprint, int $expiry, string $audience = 'Tripz'): string
|
|
||||||
{
|
{
|
||||||
$payload = [
|
$payload = [
|
||||||
'user_id' => $userId,
|
'user_id' => $userId,
|
||||||
@@ -827,111 +381,38 @@ class AuthController extends Controller
|
|||||||
'fingerprint' => $fingerprint,
|
'fingerprint' => $fingerprint,
|
||||||
'iat' => time(),
|
'iat' => time(),
|
||||||
'exp' => time() + $expiry,
|
'exp' => time() + $expiry,
|
||||||
'aud' => $audience,
|
'aud' => $audience ?? 'mobile-app',
|
||||||
'iss' => 'Tripz',
|
'iss' => 'Tripz',
|
||||||
'jti' => Str::uuid()->toString(),
|
'jti' => bin2hex(random_bytes(16)),
|
||||||
];
|
];
|
||||||
|
|
||||||
return JWT::encode($payload, config('intaleq.jwt_secret'), 'HS256');
|
return JWT::encode($payload, config('intaleq.jwt_secret'), 'HS256');
|
||||||
}
|
}
|
||||||
|
|
||||||
private function generateApiKeys($user): void
|
private function createWalletJwt(string $userId, string $fingerprint, string $audience, int $expiry = 300, ?string $secret = null): string
|
||||||
{
|
{
|
||||||
$apiKey = 'intq_' . Str::random(32);
|
$payload = [
|
||||||
$apiSecret = hash('sha256', Str::random(64) . time());
|
'user_id' => $userId,
|
||||||
|
'fingerPrint' => hash('sha256', $fingerprint . config('intaleq.fp_pepper', '')),
|
||||||
|
'exp' => time() + $expiry,
|
||||||
|
'iat' => time(),
|
||||||
|
'iss' => 'Tripz-Wallet',
|
||||||
|
'aud' => $audience,
|
||||||
|
'jti' => bin2hex(random_bytes(16)),
|
||||||
|
];
|
||||||
|
|
||||||
$user->update([
|
return JWT::encode($payload, $secret ?? config('intaleq.jwt_secret'), 'HS256');
|
||||||
'api_key' => $apiKey,
|
|
||||||
'api_secret' => $apiSecret,
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private function generateApiKeys($model)
|
||||||
* POST /v2/auth/passenger/login-jwt
|
|
||||||
* Background handshake for passengers
|
|
||||||
*/
|
|
||||||
public function passengerJwtHandshake(Request $request): JsonResponse
|
|
||||||
{
|
{
|
||||||
$request->validate([
|
$model->api_key = bin2hex(random_bytes(16));
|
||||||
'id' => 'required|string',
|
$model->api_secret = bin2hex(random_bytes(32));
|
||||||
'password' => 'required|string',
|
DB::connection('primary')->table($model->getTable())
|
||||||
'fingerPrint' => 'required|string',
|
->where('idn', $model->idn ?? $model->id)
|
||||||
'aud' => 'required|string',
|
->update([
|
||||||
]);
|
'api_key' => $model->api_key,
|
||||||
|
'api_secret' => $model->api_secret
|
||||||
$audience = $request->input('aud');
|
]);
|
||||||
|
|
||||||
// Verify the passenger exists
|
|
||||||
$passenger = Passenger::where('id', $request->input('id'))->first();
|
|
||||||
if (!$passenger) {
|
|
||||||
return $this->failure('Invalid credentials');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify fingerprint matches stored device (security) - Relaxed for new devices/installs
|
|
||||||
$token = PassengerToken::where('passengerID', $request->input('id'))->first();
|
|
||||||
if ($token && $token->fingerPrint && !hash_equals($token->fingerPrint, $request->input('fingerPrint'))) {
|
|
||||||
\Log::warning("Handshake: Device verification failed for ID: " . $request->input('id'));
|
|
||||||
// Still allow handshake for now but log it, or return failure if strictness is desired
|
|
||||||
// return $this->failure('Device verification failed', 403);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate a 15min JWT for the handshake (security: reduced from 24h)
|
|
||||||
$jwt = $this->createJwt(
|
|
||||||
$request->input('id'),
|
|
||||||
'passenger',
|
|
||||||
$request->input('fingerPrint'),
|
|
||||||
900,
|
|
||||||
$audience
|
|
||||||
);
|
|
||||||
|
|
||||||
return response()->json([
|
|
||||||
'status' => 'success',
|
|
||||||
'jwt' => $jwt,
|
|
||||||
'expires_in' => 900,
|
|
||||||
'api_key' => $passenger->api_key,
|
|
||||||
'api_secret' => $passenger->api_secret,
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* POST /v2/auth/driver/login-jwt
|
|
||||||
* Background handshake for drivers
|
|
||||||
*/
|
|
||||||
public function driverJwtHandshake(Request $request): JsonResponse
|
|
||||||
{
|
|
||||||
$request->validate([
|
|
||||||
'id' => 'required|string',
|
|
||||||
'password' => 'required|string',
|
|
||||||
'fingerPrint' => 'required|string',
|
|
||||||
'aud' => 'required|string',
|
|
||||||
]);
|
|
||||||
|
|
||||||
$driver = Driver::where('id', $request->input('id'))->first();
|
|
||||||
if (!$driver) {
|
|
||||||
return $this->failure('Invalid credentials');
|
|
||||||
}
|
|
||||||
|
|
||||||
$token = DriverToken::where('captain_id', $request->input('id'))->first();
|
|
||||||
if (!$token || !hash_equals($token->fingerPrint ?? '', $request->input('fingerPrint'))) {
|
|
||||||
return $this->failure('Device verification failed', 403);
|
|
||||||
}
|
|
||||||
|
|
||||||
$jwt = $this->createJwt(
|
|
||||||
$request->input('id'),
|
|
||||||
'driver',
|
|
||||||
$request->input('fingerPrint'),
|
|
||||||
900,
|
|
||||||
$request->input('aud')
|
|
||||||
);
|
|
||||||
|
|
||||||
return response()->json([
|
|
||||||
'status' => 'success',
|
|
||||||
'jwt' => $jwt,
|
|
||||||
'expires_in' => 900,
|
|
||||||
'api_key' => $driver->api_key,
|
|
||||||
'api_secret' => $driver->api_secret,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user