diff --git a/backend/src/TeleWave.Infrastructure/Notifications/TelegramApi.cs b/backend/src/TeleWave.Infrastructure/Notifications/TelegramApi.cs index 8f122b6..984a177 100644 --- a/backend/src/TeleWave.Infrastructure/Notifications/TelegramApi.cs +++ b/backend/src/TeleWave.Infrastructure/Notifications/TelegramApi.cs @@ -185,11 +185,10 @@ public sealed class TelegramApi(ILogger logger) : ITelegramApi using var handler = CreateHandler(settings); using var client = new HttpClient(handler) { - BaseAddress = new Uri("https://api.telegram.org/"), Timeout = timeout ?? TimeSpan.FromSeconds(30), }; - var url = $"bot{settings.BotToken}/{method}"; + var url = MethodUrl(settings.BotToken, method); using var response = payload is null ? await client.PostAsync(url, null, cancellationToken) : await client.PostAsJsonAsync(url, payload, Json, cancellationToken); @@ -205,6 +204,14 @@ public sealed class TelegramApi(ILogger logger) : ITelegramApi return await response.Content.ReadFromJsonAsync(Json, cancellationToken); } + /// + /// Адрес метода — абсолютным, а не относительным к BaseAddress. Токен содержит двоеточие + /// («8613942817:AAH…»), и как относительный путь «bot8613942817:AAH…/getUpdates» разбирается + /// в схему «bot8613942817»: запрос падает с «scheme is not supported», не дойдя до сети. + /// + public static Uri MethodUrl(string token, string method) => + new($"https://api.telegram.org/bot{token}/{method}"); + /// /// Транспорт с прокси, если он задан. SOCKS5 поддерживает сам начиная /// с .NET 6 — достаточно схемы в адресе, отдельной библиотеки не нужно. diff --git a/backend/tests/TeleWave.Application.Tests/Notifications/TelegramApiUrlTests.cs b/backend/tests/TeleWave.Application.Tests/Notifications/TelegramApiUrlTests.cs new file mode 100644 index 0000000..0612434 --- /dev/null +++ b/backend/tests/TeleWave.Application.Tests/Notifications/TelegramApiUrlTests.cs @@ -0,0 +1,22 @@ +using TeleWave.Infrastructure.Notifications; +using Xunit; + +namespace TeleWave.Application.Tests.Notifications; + +/// +/// Адрес метода Bot API. Отдельный тест на одну строку — потому что ошибка в ней не видна ни при +/// сборке, ни в юнит-тестах логики: токен содержит двоеточие, и относительный путь превращается +/// в «схему» ещё до обращения к сети. +/// +public class TelegramApiUrlTests +{ + [Fact] + public void MethodUrl_KeepsTokenInPath_AndStaysHttps() + { + var url = TelegramApi.MethodUrl("8613942817:AAHrandom-part_x", "getUpdates"); + + Assert.Equal("https", url.Scheme); + Assert.Equal("api.telegram.org", url.Host); + Assert.Equal("/bot8613942817:AAHrandom-part_x/getUpdates", url.AbsolutePath); + } +} diff --git a/frontend/src/features/admin/telegram/TelegramPanel.tsx b/frontend/src/features/admin/telegram/TelegramPanel.tsx index 825f938..8455dd2 100644 --- a/frontend/src/features/admin/telegram/TelegramPanel.tsx +++ b/frontend/src/features/admin/telegram/TelegramPanel.tsx @@ -101,7 +101,15 @@ export function TelegramPanel() {

)} -
+ {/* Форма, а не просто панель: поле пароля вне
браузер считает ошибкой разметки — + менеджеру паролей не к чему его привязать. Заодно работает отправка по Enter. */} + { + e.preventDefault() + save.mutate() + }} + > patch({ botToken: trimmed(e.target.value) })} @@ -212,7 +220,7 @@ export function TelegramPanel() { patch({ proxyPassword: trimmed(e.target.value) })} @@ -222,7 +230,7 @@ export function TelegramPanel() { )}
- {settings?.lastContactAt && ( @@ -231,7 +239,7 @@ export function TelegramPanel() { )}
-
+