Initial V2 commit 4\5

This commit is contained in:
Hamza-Ayed
2026-04-22 23:56:02 +03:00
parent 3f4afd0f5c
commit d64a423db9
2 changed files with 83 additions and 24 deletions

View File

@@ -7,6 +7,8 @@ use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Cache;
use App\Services\PayloadCrypto;
/**
* وسيط التحقق من التوقيع الرقمي (HMAC Validation Middleware)
*
@@ -16,12 +18,18 @@ use Illuminate\Support\Facades\Cache;
* كيفية العمل:
* 1. يتطلب وجود "توقيع" (Signature) في رأس الطلب (Headers).
* 2. يقوم الخادم بإعادة حساب التوقيع باستخدام مفتاح سري (API Secret) ومقارنته بالتوقيع المرسل.
* 3. يحمي من هجمات "إعادة الإرسال" (Replay Attacks) عن طريق التحقق من الـ Nonce والـ Timestamp.
* 3. حماية البيانات: إذا كانت البيانات مشفرة، يقوم بفك تشفيرها باستخدام نفس المفتاح السري (API Secret).
* 4. يضمن أن البيانات لم تتغير في الطريق (Data Integrity).
*/
class HmacAuthMiddleware
{
private const ALGORITHM = 'sha256';
private PayloadCrypto $crypto;
public function __construct(PayloadCrypto $crypto)
{
$this->crypto = $crypto;
}
public function handle(Request $request, Closure $next)
{
@@ -49,16 +57,12 @@ class HmacAuthMiddleware
], 401);
}
// 3. Check nonce uniqueness (if provided)
// 3. Check nonce uniqueness
if ($nonce) {
$nonceKey = "nonce:{$nonce}";
if (Cache::has($nonceKey)) {
return response()->json([
'status' => 'failure',
'message' => 'Duplicate request'
], 401);
return response()->json(['status' => 'failure', 'message' => 'Duplicate request'], 401);
}
// Store nonce for double the tolerance window
Cache::put($nonceKey, true, $tolerance * 2);
}
@@ -66,10 +70,7 @@ class HmacAuthMiddleware
$credentials = $this->getApiCredentials($apiKey);
if (!$credentials) {
return response()->json([
'status' => 'failure',
'message' => 'Invalid API key'
], 401);
return response()->json(['status' => 'failure', 'message' => 'Invalid API key'], 401);
}
// 5. Reconstruct and verify HMAC signature
@@ -78,13 +79,41 @@ class HmacAuthMiddleware
$expectedSignature = hash_hmac(self::ALGORITHM, $message, $credentials->api_secret);
if (!hash_equals($expectedSignature, $signature)) {
return response()->json([
'status' => 'failure',
'message' => 'Invalid signature'
], 401);
return response()->json(['status' => 'failure', 'message' => 'Invalid signature'], 401);
}
// 6. Attach user info to request for controllers
// 6. Optional: Auto-Decrypt Payload if it's encrypted
// We assume if it's a non-JSON string, it might be encrypted
if (!empty($payload) && !str_starts_with(trim($payload), '{')) {
try {
$this->crypto->setKeyFromSecret($credentials->api_secret);
$decrypted = $this->crypto->decrypt($payload);
if ($decrypted) {
// Replace request content with decrypted data
$request->initialize(
$request->query->all(),
$request->request->all(),
$request->attributes->all(),
$request->cookies->all(),
$request->files->all(),
$request->server->all(),
$decrypted
);
// Also merge decrypted JSON into request data
$jsonData = json_decode($decrypted, true);
if (is_array($jsonData)) {
$request->merge($jsonData);
}
}
} catch (\Exception $e) {
// If decryption fails, we might still want to proceed if it wasn't meant to be encrypted
// but usually, a failed signature check (above) would have caught tampering.
}
}
// 7. Attach user info to request for controllers
$request->merge([
'_auth_user_id' => $credentials->user_id,
'_auth_user_type' => $credentials->user_type,