Implement rate limiting and enhance authentication flow
CI / Backend (build + test) (push) Successful in 1m17s
CI / Frontend (lint + typecheck + build) (push) Successful in 35s

- Added rate limiting configuration for authentication endpoints, allowing customizable request limits via environment variables.
- Updated authentication flow to utilize HttpRequest for cookie management, ensuring secure handling of refresh tokens.
- Introduced a new endpoint to retrieve user subscription details.
- Enhanced the handling of Telegram bot token validation to prevent errors with empty tokens.
- Updated the application to serialize enums as strings for better documentation and compatibility with TypeScript.
- Improved test coverage for new features and adjustments in command handlers.
This commit is contained in:
Leonid Pershin
2026-07-02 12:40:23 +03:00
parent ed07221ca5
commit 8067be3c35
106 changed files with 8823 additions and 172 deletions
+17 -3
View File
@@ -1,3 +1,4 @@
using System.Text.Json.Serialization;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.AspNetCore.RateLimiting;
using Microsoft.Extensions.Options;
@@ -40,11 +41,17 @@ builder.Services.AddSignalR();
builder.Services.AddSingleton<IRealtimeNotifier, SignalRRealtimeNotifier>();
// Telegram-бот: presentation-адаптер, хостится в процессе Api (long polling). Клиент регистрируем
// всегда (даже с пустым токеном) — TelegramBotHostedService сам решает не стартовать без токена.
// всегда (даже с пустым токеном) — TelegramBotHostedService сам решает не стартовать без токена,
// а TelegramNotifier — не слать сообщения. TelegramBotClient(...) при этом валидирует формат токена
// и падает на пустой строке, поэтому при пустом BotToken подставляем синтаксически валидную заглушку —
// реальный HTTP-вызов через неё никогда не происходит (все вызывающие места сами проверяют BotToken).
builder.Services.AddSingleton<ITelegramBotClient>(sp =>
{
var options = sp.GetRequiredService<IOptions<TelegramOptions>>();
return new TelegramBotClient(options.Value.BotToken ?? string.Empty);
var token = options.Value.BotToken;
return new TelegramBotClient(string.IsNullOrWhiteSpace(token)
? "0:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
: token);
});
// Scoped — зависит от IIdentityService (scoped), не Singleton.
builder.Services.AddScoped<ITelegramNotifier, TelegramNotifier>();
@@ -55,13 +62,20 @@ builder.Services.AddRateLimiter(options =>
{
options.AddFixedWindowLimiter(RateLimiting.AuthPolicy, limiterOptions =>
{
limiterOptions.PermitLimit = 20;
// Настраиваемо через конфиг, чтобы интеграционные тесты (общий TestServer/host на весь
// collection, все запросы — от одного "клиента") могли поднять лимит и не ловить 429.
limiterOptions.PermitLimit = builder.Configuration.GetValue("RateLimiting:AuthPermitLimit", 20);
limiterOptions.Window = TimeSpan.FromMinutes(1);
limiterOptions.QueueLimit = 0;
});
options.RejectionStatusCode = StatusCodes.Status429TooManyRequests;
});
// Энумы сериализуются строками ("Vless", "Active", ...), не числами — самодокументируемый JSON,
// корректные строковые литералы при генерации TS-типов из OpenAPI-схемы (см. docs/frontend.md).
builder.Services.ConfigureHttpJsonOptions(options =>
options.SerializerOptions.Converters.Add(new JsonStringEnumConverter()));
builder.Services.AddProblemDetails();
builder.Services.AddOpenApi();
builder.Services.AddHealthChecks()