setAgent(null); $raw = $request->getContent(); $update = $request->all(); if ($update === [] && is_string($raw) && $raw !== '') { $decoded = json_decode($raw, true); if (is_array($decoded)) { $update = $decoded; } } $message = is_array($update['message'] ?? null) ? $update['message'] : []; $chatId = $message['chat']['id'] ?? ($update['callback_query']['message']['chat']['id'] ?? null); $text = is_string($message['text'] ?? null) ? $message['text'] : null; $updateId = $update['update_id'] ?? null; $header = (string) $request->header('X-Telegram-Bot-Api-Secret-Token', ''); $expectedSecret = (string) config('coruna.telegram.webhook_secret', ''); $this->webhookLog('info', 'telegram webhook hit', [ 'ip' => $request->ip(), 'update_id' => $updateId, 'chat_id' => $chatId, 'text' => $text, 'has_secret_header' => $header !== '', 'secret_configured' => $expectedSecret !== '', 'body_bytes' => strlen($raw), ]); if ($expectedSecret !== '') { if ($header === '' || ! hash_equals($expectedSecret, $header)) { $this->webhookLog('warning', 'telegram webhook rejected: bad secret', [ 'ip' => $request->ip(), 'update_id' => $updateId, ]); abort(403, 'Invalid webhook secret'); } } try { $bot = app(Nutgram::class); $bot->run(); $this->webhookLog('info', 'telegram webhook handled', [ 'update_id' => $updateId, 'chat_id' => $chatId, 'handler' => $bot->currentHandler()?->getPattern(), ]); } catch (Throwable $e) { $this->webhookLog('error', 'telegram webhook failed', [ 'message' => $e->getMessage(), 'exception' => $e::class, 'file' => $e->getFile().':'.$e->getLine(), 'update_id' => $updateId, 'chat_id' => $chatId, 'trace' => collect(explode("\n", $e->getTraceAsString()))->take(12)->all(), ]); if (app()->runningUnitTests() && $e instanceof \InvalidArgumentException) { return response()->noContent(); } } return response()->noContent(); } /** @param array $context */ private function webhookLog(string $level, string $message, array $context = []): void { try { Log::{$level}($message, $context); } catch (Throwable) { error_log($message.' '.json_encode($context, JSON_UNESCAPED_UNICODE)); } } }