using CPRNIMS.Domain.UIContracts.Account; using CPRNIMS.Domain.UIContracts.Canvass; using CPRNIMS.Domain.UIContracts.CaptCha; using CPRNIMS.Domain.UIContracts.Common; using CPRNIMS.Domain.UIContracts.Finance; using CPRNIMS.Domain.UIContracts.Inventory; using CPRNIMS.Domain.UIContracts.Items; using CPRNIMS.Domain.UIContracts.PO; using CPRNIMS.Domain.UIContracts.PR; using CPRNIMS.Domain.UIContracts.Receiving; using CPRNIMS.Domain.UIContracts.SMTP; using CPRNIMS.Domain.UIServices.Account; using CPRNIMS.Domain.UIServices.Canvass; using CPRNIMS.Domain.UIServices.CaptCha; using CPRNIMS.Domain.UIServices.Common; using CPRNIMS.Domain.UIServices.Finance; using CPRNIMS.Domain.UIServices.Inventory; using CPRNIMS.Domain.UIServices.Items; using CPRNIMS.Domain.UIServices.PO; using CPRNIMS.Domain.UIServices.PR; using CPRNIMS.Domain.UIServices.Receiving; using CPRNIMS.Domain.UIServices.SMTP; using CPRNIMS.Infrastructure.Database; using CPRNIMS.Infrastructure.Helper; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Http.Features; using Microsoft.EntityFrameworkCore; namespace CPRNIMS.WebApps.Common { public static class ServiceExtensions { public static void AddApplicationServices(this IServiceCollection services, WebApplicationBuilder builder) { ConfigureHttpClient(builder); AddScopedServices(builder); AddSessionAndAuthentication(builder); AddDbContext(builder); FileSizeHelper(builder); CacheUpdater(services); } private static void CacheUpdater(IServiceCollection services) { services.AddControllersWithViews().AddRazorRuntimeCompilation(); services.AddSignalR(); } private static void FileSizeHelper(WebApplicationBuilder builder) { builder.Services.Configure(options => { options.ValueCountLimit = int.MaxValue; options.MultipartBodyLengthLimit = long.MaxValue; options.MemoryBufferThreshold = int.MaxValue; }); } private static void ConfigureHttpClient(WebApplicationBuilder builder) { builder.Services.AddHttpClient("AuthApi", client => { client.BaseAddress = new Uri(builder.Configuration["CommonEndpoints:ApiDefaultHeaders:BaseUrl"]); //This code block should be removed once deployed in production }).ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler { ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => true }); } private static void AddScopedServices(WebApplicationBuilder builder) { builder.Services.AddHttpContextAccessor(); builder.Services.AddTransient(); builder.Services.AddScoped(); builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddScoped(); } private static void AddSessionAndAuthentication(WebApplicationBuilder builder) { builder.Services.AddDistributedMemoryCache(); // Configure Session with proper settings builder.Services.AddSession(options => { options.IdleTimeout = TimeSpan.FromHours(2); options.Cookie.Name = ".CPRNIMS.Session"; options.Cookie.HttpOnly = true; options.Cookie.IsEssential = true; options.Cookie.SameSite = SameSiteMode.Lax; options.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest; }); // Configure Authentication builder.Services.AddAuthentication(options => { options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme; }) .AddCookie(options => { options.LoginPath = "/Home/Index"; options.LogoutPath = "/Home/Logout"; options.AccessDeniedPath = "/Home/AccessDenied"; options.Cookie.Name = ".CPRNIMS.Auth"; options.SlidingExpiration = true; options.ExpireTimeSpan = TimeSpan.FromHours(2); options.Cookie.HttpOnly = true; options.Cookie.SameSite = SameSiteMode.Lax; options.Cookie.IsEssential = true; options.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest; options.Events = new CookieAuthenticationEvents { OnValidatePrincipal = async context => { var tokenExpiryClaim = context.Principal?.FindFirst("TokenExpiry"); if (tokenExpiryClaim != null) { if (DateTime.TryParse(tokenExpiryClaim.Value, out DateTime expiry)) { if (DateTime.UtcNow.AddMinutes(5) >= expiry) { // Token is expiring soon - trigger refresh var tokenHelper = context.HttpContext.RequestServices .GetRequiredService(); var newToken = await tokenHelper.GetValidTokenAsync(); if (string.IsNullOrEmpty(newToken)) { context.RejectPrincipal(); await context.HttpContext.SignOutAsync( CookieAuthenticationDefaults.AuthenticationScheme); } } } } }, OnRedirectToLogin = context => { if (context.Request.Path.StartsWithSegments("/api")) { context.Response.StatusCode = StatusCodes.Status401Unauthorized; } else { context.Response.Redirect(context.RedirectUri); } return Task.CompletedTask; } }; }); } private static void AddDbContext(WebApplicationBuilder builder) { builder.Services.AddDbContext(options => options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection"))); } } }