header('X-Client-Id'); $timestamp = $request->header('X-Timestamp'); $nonce = $request->header('X-Nonce'); $signature = $request->header('X-Signature'); if (!$clientId || !$timestamp || !$nonce || !$signature) { abort(401, 'Missing HMAC headers'); } if ($clientId !== config('services.node.client_id')) { abort(401, 'Invalid client id'); } /** ✅ اینجا SECRET واقعاً استفاده می‌شود */ $secret = config('services.node.secret'); if (!$secret) { abort(500, 'Node shared secret not configured'); } $data = json_decode($request->getContent(), true); ksort($data); $normalized = json_encode( $data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES ); $bodyHash = hash('sha256', $normalized); // $bodyHash = hash('sha256', $request->getContent() ?? ''); $canonical = implode("\n", [ strtoupper($request->method()), '/' . ltrim($request->path(), '/'), $bodyHash, $timestamp, $nonce, ]); $expectedSignature = hash_hmac( 'sha256', $canonical, $secret ); if (!hash_equals($expectedSignature, $signature)) { abort(401, 'Invalid HMAC signature'); } // return $next($request); //ANTI REPLAY $timestamp = (int)$request->header('X-Timestamp'); $nonce = $request->header('X-Nonce'); if (abs(time() - $timestamp) > 99999999999999999) { abort(401, 'Expired request'); } $key = "node_nonce:{$nonce}"; if (Cache::has($key)) { abort(401, 'Replay attack detected'); } Cache::put($key, true, 60); return $next($request); } }