yavsc/src/Yavsc.Api/Program.cs

150 lines
5.5 KiB
C#
Raw Normal View History

2025-02-11 04:45:05 +00:00
2026-06-06 21:10:48 +01:00
using Anthropic.SDK;
2025-02-15 19:57:08 +00:00
using IdentityModel;
using Microsoft.AspNetCore.Identity;
2025-02-14 00:20:35 +00:00
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection.Extensions;
2026-06-06 21:10:48 +01:00
using Yavsc.Abstract.Interfaces;
2025-02-26 18:59:08 +00:00
using Yavsc.Helpers;
2025-02-15 12:45:27 +00:00
using Yavsc.Interface;
using Yavsc.Interfaces;
2025-02-14 00:20:35 +00:00
using Yavsc.Models;
using Yavsc;
using Yavsc.Server.Helpers;
2025-02-15 12:45:27 +00:00
using Yavsc.Services;
2026-10-03 22:47:47 +01:00
using Yavsc.Server.Hubs;
2025-02-11 04:45:05 +00:00
internal class Program
{
private static async Task Main(string[] args)
{
Console.Title = "API";
var builder = WebApplication.CreateBuilder(args);
builder.AddConfiguration("api");
2025-02-11 04:45:05 +00:00
var services = builder.Services;
2026-06-06 21:10:48 +01:00
// Anthropic client
builder.Services.AddSingleton<AnthropicClient>(_ =>
new AnthropicClient(
new APIAuthentication(
builder.Configuration["ANTHROPIC_API_KEY"]
?? throw new InvalidOperationException("ANTHROPIC_API_KEY manquante")
)
)
);
// Service de modération
if (builder.Environment.IsDevelopment())
builder.Services.AddScoped<IModerationService, MockModerationService>();
else
builder.Services.AddScoped<IModerationService, ClaudeModerationService>();
2025-02-11 04:45:05 +00:00
// accepts any access token issued by identity server
2025-02-15 19:57:08 +00:00
// adds an authorization policy for scope 'scope1'
2025-02-17 23:56:28 +00:00
2025-02-11 04:45:05 +00:00
services
.AddAuthorization(options =>
{
options.AddPolicy("ApiScope", policy =>
{
policy
.RequireAuthenticatedUser()
2026-06-19 23:09:43 +01:00
.RequireClaim(JwtClaimTypes.Scope, new string[] { "api" });
2025-02-11 04:45:05 +00:00
});
options.AddPolicy("AdministratorOnly", policy =>
{
policy
.RequireAuthenticatedUser()
.RequireClaim(Constants.RoleClaimType, Constants.AdminGroupName);
});
2025-02-11 04:45:05 +00:00
})
Split Site:Audience into Site:ExternalUrl + Site:CorsAllowedOrigins The Site:Audience setting was conflating two distinct concepts: an OAuth JWT audience (a single resource identifier) and a CORS allow-list (an array of origins). Collapsing them caused several latent bugs: - OAuth/JWT validation expected a single string while CORS WithOrigins accepts an array. - Password-reset callback URLs and OAuth client RedirectUri/Origin were being built from what was meant to be an audience identifier, not a base URL. - Yavsc.Org's main CORS policy was hardcoded to '*', with no way to restrict it without code changes. Changes: - SiteSettings.Audience (string) replaced with CorsAllowedOrigins (IList<string>). - OAuth JWT Authority still reads Site:Authority; Audience now reads Site:ExternalUrl (Org only; Api/Blogs use ValidateAudience=false). - MailSender and AccountController build reset-callback URLs from Site:ExternalUrl. - ClientController uses Site:ExternalUrl for OAuth RedirectUri/Origin defaults on newly created clients. - Yavsc.Api and Yavsc.Blogs now read CORS origins from Site:CorsAllowedOrigins instead of hardcoded URLs. Add shared AddYavscCors / AddYavscJwtBearer extension methods in Yavsc.Server/Helpers/ServiceExtensions.cs to enforce a single configuration contract across all runtime services (Api, Blogs, Org). Fails closed when CorsAllowedOrigins is empty; fails fast at startup when Site:Authority is missing. Remove obsolete ConfigurationHelpers.GetAudience (no remaining callers). Local appsettings-*.json files (which carry deployment-specific values and are gitignored) must be updated to add Site:CorsAllowedOrigins.
2026-06-19 13:15:21 +01:00
.AddYavscCors(builder.Configuration)
.AddControllersWithViews();
// Binds the "Site" section (Bills, TempDir, Avatars, …) used by
// the document-generation flow and BillingController.
services.Configure<SiteSettings>(builder.Configuration.GetSection("Site"));
2025-02-11 04:45:05 +00:00
// accepts any access token issued by identity server
Split Site:Audience into Site:ExternalUrl + Site:CorsAllowedOrigins The Site:Audience setting was conflating two distinct concepts: an OAuth JWT audience (a single resource identifier) and a CORS allow-list (an array of origins). Collapsing them caused several latent bugs: - OAuth/JWT validation expected a single string while CORS WithOrigins accepts an array. - Password-reset callback URLs and OAuth client RedirectUri/Origin were being built from what was meant to be an audience identifier, not a base URL. - Yavsc.Org's main CORS policy was hardcoded to '*', with no way to restrict it without code changes. Changes: - SiteSettings.Audience (string) replaced with CorsAllowedOrigins (IList<string>). - OAuth JWT Authority still reads Site:Authority; Audience now reads Site:ExternalUrl (Org only; Api/Blogs use ValidateAudience=false). - MailSender and AccountController build reset-callback URLs from Site:ExternalUrl. - ClientController uses Site:ExternalUrl for OAuth RedirectUri/Origin defaults on newly created clients. - Yavsc.Api and Yavsc.Blogs now read CORS origins from Site:CorsAllowedOrigins instead of hardcoded URLs. Add shared AddYavscCors / AddYavscJwtBearer extension methods in Yavsc.Server/Helpers/ServiceExtensions.cs to enforce a single configuration contract across all runtime services (Api, Blogs, Org). Fails closed when CorsAllowedOrigins is empty; fails fast at startup when Site:Authority is missing. Remove obsolete ConfigurationHelpers.GetAudience (no remaining callers). Local appsettings-*.json files (which carry deployment-specific values and are gitignored) must be updated to add Site:CorsAllowedOrigins.
2026-06-19 13:15:21 +01:00
services.AddAuthentication("Bearer")
.AddYavscJwtBearer(builder.Configuration);
2026-06-04 22:04:20 +01:00
services.AddSignalR()
// ChatRoomInfo et d'autres DTO de hub exposent des champs
// publics (pas des propriétés) : STJ ne les sérialise pas
// sans IncludeFields, et le client recevrait des objets vides.
.AddJsonProtocol(options =>
options.PayloadSerializerOptions.IncludeFields = true);
2026-09-13 03:09:12 +01:00
services.AddSingleton<IConnexionManager, HubConnectionManager>();
2026-08-31 00:25:53 +01:00
// DbContextBuilder
2025-02-17 23:56:28 +00:00
services.AddDbContext<ApplicationDbContext>(options =>
2026-08-31 00:25:53 +01:00
options.UseNpgsql(builder.Configuration.GetConnectionString(
Yavsc.Constants.YavscConnectionStringName)));
2025-02-17 23:56:28 +00:00
services.AddIdentityCore<ApplicationUser>(options =>
{
options.ClaimsIdentity.UserNameClaimType = JwtClaimTypes.PreferredUserName;
options.ClaimsIdentity.RoleClaimType = Constants.RoleClaimType;
})
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders()
.AddSignInManager();
2026-06-04 22:04:20 +01:00
services.AddLocalization(options =>
{
options.ResourcesPath = "Resources";
});
//
2026-06-04 22:04:20 +01:00
services.AddTransient<Microsoft.AspNetCore.Identity.IEmailSender<ApplicationUser>, MailSender>();
2025-02-17 23:56:28 +00:00
services.AddTransient<ITrueEmailSender, MailSender>()
2026-06-04 22:04:20 +01:00
.AddTransient<Microsoft.AspNetCore.Identity.UI.Services.IEmailSender,
MailSender>()
.TryAddSingleton<ISmtpClientFactory, SmtpClientFactory>();
services
2025-02-17 23:56:28 +00:00
.AddTransient<IBillingService, BillingService>()
2026-09-12 13:57:25 +01:00
.AddTransient<ICalendarManager, CalendarManager>()
.AddTransient<IYavscMessageSender, YavscMessageSender>();
2025-02-26 18:59:08 +00:00
services.AddTransient<IFileSystemAuthManager, FileSystemAuthManager>();
2026-06-04 22:04:20 +01:00
builder.Services.AddSession(options =>
{
options.IdleTimeout = TimeSpan.FromMinutes(30);
options.Cookie.HttpOnly = true;
options.Cookie.IsEssential = false;
});
builder.Services.AddDistributedMemoryCache();
builder.Services.Configure<RequestLocalizationOptions>(options =>
{
var supportedCultures = new[] { "fr", "en", "pt" };
options.SetDefaultCulture(supportedCultures[0])
.AddSupportedCultures(supportedCultures)
.AddSupportedUICultures(supportedCultures);
});
2025-02-26 18:59:08 +00:00
WorkflowHelpers.ConfigureBillingService();
2025-02-11 04:45:05 +00:00
using (var app = builder.Build())
{
if (app.Environment.IsDevelopment())
app.UseDeveloperExceptionPage();
app.UseMiddleware<ResourceUsageTelemetryMiddleware>();
2025-02-11 04:45:05 +00:00
app
.UseRouting()
.UseAuthentication()
2025-02-16 17:28:38 +00:00
.UseAuthorization()
2026-10-03 22:47:47 +01:00
.UseCors("default");
2026-06-04 22:04:20 +01:00
app.MapIdentityApi<ApplicationUser>().RequireAuthorization("ApiScope");
2025-02-16 22:40:51 +00:00
app.MapDefaultControllerRoute();
2026-06-04 22:04:20 +01:00
app.UseSession();
2026-10-03 22:47:47 +01:00
app.MapHub<ChatHub>("/" + Constants.ChatHubPath);
2025-02-11 04:45:05 +00:00
await app.RunAsync();
2025-02-17 23:56:28 +00:00
}
2025-02-11 04:45:05 +00:00
}
}