Files
GmRelayBot/src/GmRelay.Web/Program.cs
T
Toutsu 1c4cfb71c0
Deploy Telegram Bot / build-and-push (push) Successful in 7m25s
Deploy Telegram Bot / deploy (push) Successful in 18s
fix: close web access to foreign groups and sessions
2026-04-23 20:09:22 +03:00

114 lines
3.6 KiB
C#

using GmRelay.Web.Components;
using GmRelay.Web.Services;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.DataProtection;
using System.Security.Claims;
using Telegram.Bot;
using Npgsql;
var builder = WebApplication.CreateBuilder(args);
// Add Aspire service defaults
builder.AddServiceDefaults();
// Add Data Protection
builder.Services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo("/app/dataprotection-keys"));
// Add Npgsql
builder.AddNpgsqlDataSource("gmrelaydb");
// Add Services
builder.Services.AddSingleton<TelegramAuthService>();
builder.Services.AddSingleton<ISessionStore, SessionService>();
builder.Services.AddScoped<AuthorizedSessionService>();
// Add Bot Client
builder.Services.AddSingleton<ITelegramBotClient>(sp =>
{
var config = sp.GetRequiredService<IConfiguration>();
var token = config["Telegram__BotToken"] ?? config["Telegram:BotToken"]
?? throw new InvalidOperationException("Telegram__BotToken is required.");
return new TelegramBotClient(token);
});
// Add Authentication with hardened cookie settings
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(options =>
{
options.LoginPath = "/login";
options.AccessDeniedPath = "/access-denied";
options.Cookie.HttpOnly = true;
options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
options.Cookie.SameSite = SameSiteMode.Strict;
options.ExpireTimeSpan = TimeSpan.FromDays(7);
options.SlidingExpiration = true;
});
builder.Services.AddAuthorization();
builder.Services.AddCascadingAuthenticationState();
// Add services to the container.
builder.Services.AddRazorComponents()
.AddInteractiveServerComponents();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error", createScopeForErrors: true);
app.UseHsts();
}
app.UseHttpsRedirection();
// Security headers middleware
app.Use(async (context, next) =>
{
context.Response.Headers["X-Content-Type-Options"] = "nosniff";
context.Response.Headers["X-Frame-Options"] = "DENY";
context.Response.Headers["Referrer-Policy"] = "strict-origin-when-cross-origin";
context.Response.Headers["Permissions-Policy"] = "camera=(), microphone=(), geolocation=()";
await next();
});
app.UseAuthentication();
app.UseAuthorization();
app.UseAntiforgery();
app.MapStaticAssets();
app.MapRazorComponents<App>()
.AddInteractiveServerRenderMode();
// Endpoint to handle Telegram Login callback
app.MapGet("/auth/telegram", async (HttpContext context, TelegramAuthService authService) =>
{
if (authService.Verify(context.Request.Query, out var telegramId, out var name))
{
var claims = new List<Claim>
{
new Claim(ClaimTypes.NameIdentifier, telegramId.ToString()),
new Claim(ClaimTypes.Name, name),
new Claim("TelegramId", telegramId.ToString())
};
var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
var authProperties = new AuthenticationProperties { IsPersistent = true };
await context.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(claimsIdentity), authProperties);
return Results.Redirect("/");
}
return Results.Redirect("/login?error=auth_failed");
});
app.MapPost("/auth/logout", async (HttpContext context) =>
{
await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
return Results.Redirect("/");
});
app.Run();