Allplmpliedl manual JWT check and restored all driver fields68j2
This commit is contained in:
61
app/Http/Controllers/Api/PaymentTokenController.php
Normal file
61
app/Http/Controllers/Api/PaymentTokenController.php
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Api;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Firebase\JWT\JWT;
|
||||||
|
use Illuminate\Support\Facades\File;
|
||||||
|
|
||||||
|
class PaymentTokenController extends Controller
|
||||||
|
{
|
||||||
|
// 1. مسار الراكب
|
||||||
|
public function generatePassengerToken(Request $request)
|
||||||
|
{
|
||||||
|
// تحقق خاص بالراكب (لا يوجد بصمة سيارة مثلاً)
|
||||||
|
return $this->buildToken($request->user()->id, 'android/ios_passenger', $request->input('fingerPrint'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. مسار السائق
|
||||||
|
public function generateDriverToken(Request $request)
|
||||||
|
{
|
||||||
|
// تحقق خاص بالسائق (ضرورة وجود بصمة جهاز قوية)
|
||||||
|
return $this->buildToken($request->user()->id, 'android/ios_driver', $request->input('fingerPrint'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. مسار المدير
|
||||||
|
public function generateAdminToken(Request $request)
|
||||||
|
{
|
||||||
|
// المدراء لديهم صلاحيات أوسع، قد يكون الـ aud مختلفاً
|
||||||
|
return $this->buildToken($request->user()->id, 'web_admin', 'admin_secure_context');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. دالة البناء المركزية (Private)
|
||||||
|
private function buildToken($userId, $audience, $fingerprint)
|
||||||
|
{
|
||||||
|
$keyPath = env('PAYMENT_INTERNAL_KEY_PATH');
|
||||||
|
|
||||||
|
if (!File::exists($keyPath)) {
|
||||||
|
return response()->json(['status' => 'error', 'message' => 'Security Key Missing'], 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
$internalSecret = trim(File::get_contents($keyPath));
|
||||||
|
|
||||||
|
$payload = [
|
||||||
|
'iss' => 'Intaleq_V2',
|
||||||
|
'sub' => $userId,
|
||||||
|
'aud' => $audience,
|
||||||
|
'iat' => time(),
|
||||||
|
'exp' => time() + 60,
|
||||||
|
'fingerprint' => $fingerprint
|
||||||
|
];
|
||||||
|
|
||||||
|
$token = JWT::encode($payload, $internalSecret, 'HS256');
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'status' => 'success',
|
||||||
|
'token' => $token,
|
||||||
|
'hmac' => hash_hmac('sha256', $token, $internalSecret)
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -323,25 +323,28 @@ class AuthController extends Controller
|
|||||||
'created_at' => now(),
|
'created_at' => now(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// 11. Insert Documents
|
// 11. Insert Documents (Wait, the user said registration response MUST return jwt, api_secret, and hmac immediately to allow subsequent protected file uploads)
|
||||||
|
// So we don't need to insert documents here if they are uploaded later. But keeping the existing code won't hurt, just the response changes.
|
||||||
$docKeys = [
|
$docKeys = [
|
||||||
'driver_license_front', 'driver_license_back',
|
'driver_license_front', 'driver_license_back',
|
||||||
'car_license_front', 'car_license_back'
|
'car_license_front', 'car_license_back'
|
||||||
];
|
];
|
||||||
$docUrls = [];
|
$docUrls = [];
|
||||||
foreach ($docKeys as $k) {
|
foreach ($docKeys as $k) {
|
||||||
$url = $request->input($k);
|
if ($request->has($k)) {
|
||||||
$docUrls[$k] = $url;
|
$url = $request->input($k);
|
||||||
$name = basename(parse_url($url, PHP_URL_PATH) ?? '');
|
$docUrls[$k] = $url;
|
||||||
if ($name === '') { $name = $k . '_' . time() . '.jpg'; }
|
$name = basename(parse_url($url, PHP_URL_PATH) ?? '');
|
||||||
|
if ($name === '') { $name = $k . '_' . time() . '.jpg'; }
|
||||||
|
|
||||||
DB::connection('primary')->table('driver_documents')->insert([
|
DB::connection('primary')->table('driver_documents')->insert([
|
||||||
'driverID' => $data['id'],
|
'driverID' => $data['id'],
|
||||||
'doc_type' => $k,
|
'doc_type' => $k,
|
||||||
'image_name' => $name,
|
'image_name' => $name,
|
||||||
'link' => $url,
|
'link' => $url,
|
||||||
'upload_date' => now(),
|
'upload_date' => now(),
|
||||||
]);
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DB::connection('primary')->commit();
|
DB::connection('primary')->commit();
|
||||||
@@ -360,11 +363,29 @@ class AuthController extends Controller
|
|||||||
\Illuminate\Support\Facades\Log::error("FCM Admin notification failed: " . $e->getMessage());
|
\Illuminate\Support\Facades\Log::error("FCM Admin notification failed: " . $e->getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Generate JWT and API Keys
|
||||||
|
$fingerprint = $request->input('fingerprint', 'unknown');
|
||||||
|
$jwt = $this->createJwt($data['id'], 'driver', $fingerprint, 14400);
|
||||||
|
|
||||||
|
$apiKey = bin2hex(random_bytes(16));
|
||||||
|
$apiSecret = bin2hex(random_bytes(32));
|
||||||
|
DB::connection('primary')->table('driver')->where('id', $data['id'])->update([
|
||||||
|
'api_key' => $apiKey,
|
||||||
|
'api_secret' => $apiSecret
|
||||||
|
]);
|
||||||
|
|
||||||
|
// To be compatible with frontend, generate Wallet HMAC
|
||||||
|
$hmac = hash_hmac('sha256', $jwt, config('intaleq.secret_key_hmac', ''));
|
||||||
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'status' => 'success',
|
'status' => 'success',
|
||||||
'driverID' => $data['id'],
|
'driverID' => $data['id'],
|
||||||
'carRegID' => $carRegId,
|
'carRegID' => $carRegId,
|
||||||
'documents' => $docUrls
|
'documents' => $docUrls,
|
||||||
|
'jwt' => $jwt,
|
||||||
|
'api_key' => $apiKey,
|
||||||
|
'api_secret' => $apiSecret,
|
||||||
|
'hmac' => $hmac
|
||||||
]);
|
]);
|
||||||
|
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ class UploadController extends Controller
|
|||||||
{
|
{
|
||||||
$request->validate([
|
$request->validate([
|
||||||
'image' => 'required|file',
|
'image' => 'required|file',
|
||||||
'doc_type' => 'required|string|in:license,registration,criminal,id_front,id_back',
|
'doc_type' => 'required|string|in:license,registration,criminal,id_front,id_back,driver_license_front,driver_license_back,car_license_front,car_license_back',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return $this->handleImageUpload($request, 'driver_documents', 'documents');
|
return $this->handleImageUpload($request, 'driver_documents', 'documents');
|
||||||
|
|||||||
@@ -81,10 +81,16 @@ class HmacAuthMiddleware
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Compute expected signature
|
// Compute expected signature
|
||||||
// METHOD:PATH:TIMESTAMP:NONCE:BODY
|
|
||||||
$method = strtoupper($request->method());
|
$method = strtoupper($request->method());
|
||||||
$path = $request->path(); // returns path without leading slash (e.g. v2/ride/create)
|
$path = $request->path(); // returns path without leading slash (e.g. v2/ride/create)
|
||||||
$body = $request->getContent();
|
|
||||||
|
if (str_contains(strtolower($request->header('Content-Type', '')), 'multipart/form-data')) {
|
||||||
|
$inputs = $request->except(array_keys($request->allFiles()));
|
||||||
|
ksort($inputs);
|
||||||
|
$body = json_encode($inputs);
|
||||||
|
} else {
|
||||||
|
$body = $request->getContent();
|
||||||
|
}
|
||||||
|
|
||||||
$payload = "$method:$path:$timestamp:$nonce:$body";
|
$payload = "$method:$path:$timestamp:$nonce:$body";
|
||||||
$expected = hash_hmac(self::ALGORITHM, $payload, $user->api_secret);
|
$expected = hash_hmac(self::ALGORITHM, $payload, $user->api_secret);
|
||||||
|
|||||||
@@ -67,6 +67,8 @@ return [
|
|||||||
'Tripz-Walletios',
|
'Tripz-Walletios',
|
||||||
'TripzWallet:android',
|
'TripzWallet:android',
|
||||||
'TripzWallet:ios',
|
'TripzWallet:ios',
|
||||||
|
'allowedWallet1android',
|
||||||
|
'allowedWallet1ios',
|
||||||
],
|
],
|
||||||
'wallet_app_password' => env('passwordnewpassenger', ''),
|
'wallet_app_password' => env('passwordnewpassenger', ''),
|
||||||
'fp_pepper' => env('FP_PEPPER', ''),
|
'fp_pepper' => env('FP_PEPPER', ''),
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ use App\Http\Controllers\MiscController;
|
|||||||
use App\Http\Controllers\InviteController;
|
use App\Http\Controllers\InviteController;
|
||||||
use App\Http\Controllers\DriverDocController;
|
use App\Http\Controllers\DriverDocController;
|
||||||
use App\Http\Controllers\SupportController;
|
use App\Http\Controllers\SupportController;
|
||||||
|
use App\Http\Controllers\Api\PaymentTokenController;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
@@ -48,7 +50,8 @@ Route::prefix('v2/auth')->group(function () {
|
|||||||
// Passenger
|
// Passenger
|
||||||
Route::post('/passenger/login', [AuthController::class, 'passengerLogin']);
|
Route::post('/passenger/login', [AuthController::class, 'passengerLogin']);
|
||||||
Route::post('/passenger/register', [AuthController::class, 'passengerRegister']);
|
Route::post('/passenger/register', [AuthController::class, 'passengerRegister']);
|
||||||
Route::post('/passenger/wallet-login', [AuthController::class, 'passengerWalletLogin']);
|
// to be replaced by dedicated PaymentTokenController for better separation of concerns
|
||||||
|
// Route::post('/passenger/wallet-login', [AuthController::class, 'passengerWalletLogin']);
|
||||||
Route::get('/passenger/login-google', [AuthController::class, 'passengerLoginGoogle']);
|
Route::get('/passenger/login-google', [AuthController::class, 'passengerLoginGoogle']);
|
||||||
|
|
||||||
// Driver
|
// Driver
|
||||||
@@ -63,9 +66,16 @@ Route::prefix('v2/auth')->group(function () {
|
|||||||
// Silent JWT Handshake (Compatibility with V1 background flow)
|
// Silent JWT Handshake (Compatibility with V1 background flow)
|
||||||
Route::post('/passenger/login-jwt', [AuthController::class, 'passengerJwtHandshake']);
|
Route::post('/passenger/login-jwt', [AuthController::class, 'passengerJwtHandshake']);
|
||||||
Route::post('/driver/login-jwt', [AuthController::class, 'driverJwtHandshake']);
|
Route::post('/driver/login-jwt', [AuthController::class, 'driverJwtHandshake']);
|
||||||
Route::post('/driver/wallet-token', [AuthController::class, 'getWalletToken']);
|
// Route::post('/driver/wallet-token', [AuthController::class, 'getWalletToken']);
|
||||||
|
// to be replaced by dedicated PaymentTokenController for better separation of concerns
|
||||||
|
});
|
||||||
|
Route::prefix('v2/payment')->middleware(['hmac.auth', 'jwt.auth'])->group(function () {
|
||||||
|
Route::post('/passenger/generate-token', [PaymentTokenController::class, 'generatePassengerToken']);
|
||||||
|
Route::post('/driver/generate-token', [PaymentTokenController::class, 'generateDriverToken']);
|
||||||
|
|
||||||
|
// يفضل إضافة مسار الإدارة داخل مجموعة الإدارة الموجودة مسبقاً أو حمايته بـ middleware إضافي
|
||||||
|
Route::post('/admin/generate-token', [PaymentTokenController::class, 'generateAdminToken'])->middleware('admin');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Admin Error Logging (public — accepts error reports from Flutter apps)
|
// Admin Error Logging (public — accepts error reports from Flutter apps)
|
||||||
Route::post('v2/admin/errors', [MiscController::class, 'logClientError']);
|
Route::post('v2/admin/errors', [MiscController::class, 'logClientError']);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user