all(); $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; $secret = (string) config('coruna.telegram.webhook_secret', ''); $header = (string) $request->header('X-Telegram-Bot-Api-Secret-Token', ''); Log::info('telegram webhook hit', [ 'ip' => $request->ip(), 'update_id' => $update['update_id'] ?? null, 'chat_id' => $chatId, 'text' => $text, 'has_secret_header' => $header !== '', 'secret_configured' => $secret !== '', ]); if ($secret !== '') { if ($header === '' || ! hash_equals($secret, $header)) { Log::warning('telegram webhook rejected: bad secret', [ 'ip' => $request->ip(), 'update_id' => $update['update_id'] ?? null, ]); abort(403, 'Invalid webhook secret'); } } try { $bot->run(); Log::info('telegram webhook handled', [ 'update_id' => $update['update_id'] ?? null, 'chat_id' => $chatId, 'handler' => $bot->currentHandler()?->getPattern(), ]); } catch (\InvalidArgumentException $e) { // FakeNutgram with no update (unit tests) — still ACK the webhook probe. if (! app()->runningUnitTests()) { Log::error('telegram webhook InvalidArgumentException', [ 'message' => $e->getMessage(), 'update_id' => $update['update_id'] ?? null, ]); throw $e; } } catch (\Throwable $e) { Log::error('telegram webhook failed', [ 'message' => $e->getMessage(), 'update_id' => $update['update_id'] ?? null, 'chat_id' => $chatId, ]); throw $e; } return response()->noContent(); } }