feature
This commit is contained in:
@@ -60,7 +60,10 @@ CORUNA_7Z_BIN=
|
|||||||
# Telegram (outbound alerts + inbound Nutgram commands)
|
# Telegram (outbound alerts + inbound Nutgram commands)
|
||||||
TELEGRAM_BOT_TOKEN=
|
TELEGRAM_BOT_TOKEN=
|
||||||
TELEGRAM_OWNER_CHAT_ID=
|
TELEGRAM_OWNER_CHAT_ID=
|
||||||
|
# Optional; if set, register via: php artisan telegram:set-webhook
|
||||||
TELEGRAM_WEBHOOK_SECRET=
|
TELEGRAM_WEBHOOK_SECRET=
|
||||||
|
# Do not enable unless you understand Nutgram's md5(APP_KEY) secret check
|
||||||
|
# NUTGRAM_SAFE_MODE=false
|
||||||
|
|
||||||
# /transfer: recipient (fromAddress is the command arg; mnemonic from DB)
|
# /transfer: recipient (fromAddress is the command arg; mnemonic from DB)
|
||||||
# Usage: /transfer <fromAddress> [TRX|USDT] [amount] — omit amount = all
|
# Usage: /transfer <fromAddress> [TRX|USDT] [amount] — omit amount = all
|
||||||
|
|||||||
@@ -17,18 +17,20 @@ class TelegramWebhookController extends Controller
|
|||||||
$chatId = $message['chat']['id'] ?? ($update['callback_query']['message']['chat']['id'] ?? null);
|
$chatId = $message['chat']['id'] ?? ($update['callback_query']['message']['chat']['id'] ?? null);
|
||||||
$text = is_string($message['text'] ?? null) ? $message['text'] : 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', [
|
Log::info('telegram webhook hit', [
|
||||||
'ip' => $request->ip(),
|
'ip' => $request->ip(),
|
||||||
'update_id' => $update['update_id'] ?? null,
|
'update_id' => $update['update_id'] ?? null,
|
||||||
'chat_id' => $chatId,
|
'chat_id' => $chatId,
|
||||||
'text' => $text,
|
'text' => $text,
|
||||||
'has_secret_header' => $request->headers->has('X-Telegram-Bot-Api-Secret-Token'),
|
'has_secret_header' => $header !== '',
|
||||||
|
'secret_configured' => $secret !== '',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$secret = (string) config('coruna.telegram.webhook_secret', '');
|
|
||||||
if ($secret !== '') {
|
if ($secret !== '') {
|
||||||
$header = (string) $request->header('X-Telegram-Bot-Api-Secret-Token', '');
|
if ($header === '' || ! hash_equals($secret, $header)) {
|
||||||
if (! hash_equals($secret, $header)) {
|
|
||||||
Log::warning('telegram webhook rejected: bad secret', [
|
Log::warning('telegram webhook rejected: bad secret', [
|
||||||
'ip' => $request->ip(),
|
'ip' => $request->ip(),
|
||||||
'update_id' => $update['update_id'] ?? null,
|
'update_id' => $update['update_id'] ?? null,
|
||||||
@@ -42,6 +44,7 @@ class TelegramWebhookController extends Controller
|
|||||||
Log::info('telegram webhook handled', [
|
Log::info('telegram webhook handled', [
|
||||||
'update_id' => $update['update_id'] ?? null,
|
'update_id' => $update['update_id'] ?? null,
|
||||||
'chat_id' => $chatId,
|
'chat_id' => $chatId,
|
||||||
|
'handler' => $bot->currentHandler()?->getPattern(),
|
||||||
]);
|
]);
|
||||||
} catch (\InvalidArgumentException $e) {
|
} catch (\InvalidArgumentException $e) {
|
||||||
// FakeNutgram with no update (unit tests) — still ACK the webhook probe.
|
// FakeNutgram with no update (unit tests) — still ACK the webhook probe.
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ use App\Services\CorunaArchive;
|
|||||||
use App\Services\CorunaCrypto;
|
use App\Services\CorunaCrypto;
|
||||||
use App\Services\SettingsService;
|
use App\Services\SettingsService;
|
||||||
use Illuminate\Support\ServiceProvider;
|
use Illuminate\Support\ServiceProvider;
|
||||||
|
use Nutgram\Laravel\RunningMode\LaravelWebhook;
|
||||||
|
use SergiX44\Nutgram\Nutgram;
|
||||||
|
|
||||||
class AppServiceProvider extends ServiceProvider
|
class AppServiceProvider extends ServiceProvider
|
||||||
{
|
{
|
||||||
@@ -32,5 +34,23 @@ class AppServiceProvider extends ServiceProvider
|
|||||||
} catch (\Throwable) {
|
} catch (\Throwable) {
|
||||||
// settings table may not exist yet during migrate
|
// settings table may not exist yet during migrate
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Override Nutgram's production safe_mode (md5 APP_KEY) so webhook updates
|
||||||
|
// are not silently dropped when Telegram secret_token is unset/mismatched.
|
||||||
|
$this->app->afterResolving(Nutgram::class, function (Nutgram $bot): void {
|
||||||
|
if ($this->app->runningUnitTests() || $this->app->runningInConsole()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$secret = (string) config('coruna.telegram.webhook_secret', '');
|
||||||
|
$webhook = $secret !== ''
|
||||||
|
? new LaravelWebhook(
|
||||||
|
getToken: static fn () => request()?->header('X-Telegram-Bot-Api-Secret-Token'),
|
||||||
|
secretToken: $secret,
|
||||||
|
)
|
||||||
|
: new LaravelWebhook;
|
||||||
|
$webhook->setSafeMode($secret !== '');
|
||||||
|
$bot->setRunningMode($webhook);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Telegram\Middleware;
|
namespace App\Telegram\Middleware;
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
use SergiX44\Nutgram\Nutgram;
|
use SergiX44\Nutgram\Nutgram;
|
||||||
|
|
||||||
class AuthorizedChat
|
class AuthorizedChat
|
||||||
@@ -10,11 +11,18 @@ class AuthorizedChat
|
|||||||
{
|
{
|
||||||
$expected = (string) config('coruna.telegram.owner_chat_id', '');
|
$expected = (string) config('coruna.telegram.owner_chat_id', '');
|
||||||
if ($expected === '') {
|
if ($expected === '') {
|
||||||
|
Log::warning('telegram AuthorizedChat: TELEGRAM_OWNER_CHAT_ID empty');
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
$chatId = $bot->chatId();
|
$chatId = $bot->chatId();
|
||||||
if ($chatId === null || (string) $chatId !== $expected) {
|
if ($chatId === null || (string) $chatId !== $expected) {
|
||||||
|
Log::info('telegram AuthorizedChat: chat rejected', [
|
||||||
|
'chat_id' => $chatId,
|
||||||
|
'expected' => $expected,
|
||||||
|
]);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,10 @@ return [
|
|||||||
'token' => env('TELEGRAM_BOT_TOKEN', env('TELEGRAM_TOKEN')),
|
'token' => env('TELEGRAM_BOT_TOKEN', env('TELEGRAM_TOKEN')),
|
||||||
|
|
||||||
|
|
||||||
// if the webhook mode must validate the incoming IP range is from a telegram server
|
// Nutgram LaravelWebhook secret check (md5(APP_KEY) when true via package default).
|
||||||
'safe_mode' => env('APP_ENV', 'local') === 'production',
|
// Keep false — TelegramWebhookController validates TELEGRAM_WEBHOOK_SECRET instead.
|
||||||
|
// Production + true + no matching secret_token = updates silently dropped (no reply).
|
||||||
|
'safe_mode' => (bool) env('NUTGRAM_SAFE_MODE', false),
|
||||||
|
|
||||||
// Extra or specific configurations
|
// Extra or specific configurations
|
||||||
'config' => [],
|
'config' => [],
|
||||||
|
|||||||
Reference in New Issue
Block a user