yavsc/src/Yavsc.Org/Extensions/HostingExtensions.cs

610 lines
24 KiB
C#
Raw Normal View History

2024-02-25 18:05:10 +00:00
using System.Globalization;
2026-04-19 16:02:50 +01:00
using System.IdentityModel.Tokens.Jwt;
using System.Reflection;
2024-02-25 18:05:10 +00:00
using Google.Apis.Util.Store;
2026-04-19 16:02:50 +01:00
using IdentityModel;
2025-02-08 20:06:24 +00:00
using IdentityServer8;
2026-04-19 16:02:50 +01:00
using IdentityServer8.EntityFramework.Entities;
using IdentityServer8.EntityFramework.Services;
using IdentityServer8.EntityFramework.Stores;
2025-08-24 16:07:53 +01:00
using IdentityServer8.Stores;
2026-04-19 16:02:50 +01:00
using IdentityServer8.Validation;
2024-02-25 18:05:10 +00:00
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Identity;
2026-04-19 16:02:50 +01:00
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
2024-02-25 18:05:10 +00:00
using Microsoft.AspNetCore.Localization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Options;
using Microsoft.Net.Http.Headers;
using Newtonsoft.Json;
using Yavsc.Helpers;
using Yavsc.Interface;
2026-04-19 16:02:50 +01:00
using Yavsc.Interfaces;
2024-02-25 18:05:10 +00:00
using Yavsc.Models;
2026-04-19 16:02:50 +01:00
using Yavsc.Server.Helpers;
2024-02-25 18:05:10 +00:00
using Yavsc.Services;
2026-05-24 19:35:35 +01:00
using Yavsc.Services.Kyc;
2024-02-25 18:05:10 +00:00
using Yavsc.Settings;
2024-11-10 23:12:02 +00:00
using Yavsc.ViewModels.Auth;
2026-06-10 16:59:23 +01:00
using static IdentityServer8.IdentityServerConstants;
2024-02-25 18:05:10 +00:00
2024-11-06 13:00:34 +00:00
namespace Yavsc.Extensions;
2024-02-25 18:05:10 +00:00
2025-02-14 00:20:35 +00:00
public static class HostingExtensions
2024-02-25 18:05:10 +00:00
{
2026-05-28 22:18:26 +01:00
private const string InMemoryProviderName = "InMemory";
2025-08-18 09:22:09 +01:00
2025-07-14 18:58:04 +01:00
public static WebApplication ConfigureWebAppServices(this WebApplicationBuilder builder)
2024-02-25 18:05:10 +00:00
{
2026-02-07 23:47:12 +00:00
builder.Services.AddSwaggerGen();
2025-02-14 00:20:35 +00:00
IServiceCollection services = LoadConfiguration(builder);
2025-02-09 12:04:14 +00:00
2024-11-06 13:00:34 +00:00
services.AddSession();
2024-11-12 08:32:15 +00:00
2025-02-08 20:06:24 +00:00
// TODO .AddServerSideSessionStore<YavscServerSideSessionStore>()
2024-02-25 18:05:10 +00:00
2025-02-08 20:06:24 +00:00
// Add the system clock service
_ = services.AddSingleton<IConnexionManager, HubConnectionManager>();
_ = services.AddSingleton<ILiveProcessor, LiveProcessor>();
_ = services.AddTransient<IFileSystemAuthManager, FileSystemAuthManager>();
2025-07-31 11:44:02 +01:00
AddIdentityDBAndStores(builder)
.AddDefaultTokenProviders();
2025-02-16 22:40:51 +00:00
AddIdentityServer(builder);
2024-02-25 18:05:10 +00:00
2025-02-16 22:40:51 +00:00
services.AddSignalR(o =>
{
o.EnableDetailedErrors = true;
});
2025-08-18 09:22:09 +01:00
2025-02-08 20:06:24 +00:00
services.AddMvc(config =>
{
/* var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
config.Filters.Add(new AuthorizeFilter(policy)); */
config.Filters.Add(new ProducesAttribute("application/json"));
// config.ModelBinders.Insert(0,new MyDateTimeModelBinder());
// config.ModelBinders.Insert(0,new MyDecimalModelBinder());
config.EnableEndpointRouting = true;
}).AddFormatterMappings(
config => config.SetMediaTypeMappingForFormat("text/pdf",
new MediaTypeHeaderValue("text/pdf"))
).AddFormatterMappings(
config => config.SetMediaTypeMappingForFormat("text/x-tex",
new MediaTypeHeaderValue("text/x-tex"))
)
.AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix,
options =>
{
options.ResourcesPath = "Resources";
}).AddDataAnnotationsLocalization();
services.AddTransient<ITrueEmailSender, MailSender>()
.AddTransient<Microsoft.AspNetCore.Identity.UI.Services.IEmailSender, MailSender>();
2026-04-20 00:35:51 +01:00
services.AddTransient<IYavscMessageSender, YavscMessageSender>()
2025-02-14 00:20:35 +00:00
.AddTransient<IBillingService, BillingService>()
.AddTransient<IDataStore, FileDataStore>((sp) => new FileDataStore("googledatastore", false))
2025-06-29 16:12:16 +01:00
.AddTransient<ICalendarManager, CalendarManager>()
2026-03-09 02:07:09 +00:00
.AddTransient<BlogSpotService>()
.AddTransient<ValidatingClientStore<ClientStore>>();
2024-02-25 18:05:10 +00:00
2025-02-08 20:06:24 +00:00
// TODO for SMS: services.AddTransient<ISmsSender, AuthMessageSender>();
2024-02-25 18:05:10 +00:00
2025-02-08 20:06:24 +00:00
_ = services.AddLocalization(options =>
{
options.ResourcesPath = "Resources";
});
2025-02-14 00:20:35 +00:00
var dataDirConfig = builder.Configuration["Site:DataDir"] ?? "DataDir";
var dataDir = new DirectoryInfo(dataDirConfig);
2025-02-08 20:06:24 +00:00
// Add session related services.
2024-02-25 18:05:10 +00:00
2025-02-08 20:06:24 +00:00
services.AddDataProtection().PersistKeysToFileSystem(dataDir);
2025-02-14 00:20:35 +00:00
AddYavscPolicies(services);
2025-02-23 20:23:23 +00:00
services.AddScoped<IAuthorizationHandler, PermissionHandler>();
2025-07-10 15:19:28 +01:00
services.AddTransient<IExternalIdentityManager, ExternalIdentityManager>();
2025-02-14 00:20:35 +00:00
2026-02-17 21:50:17 +00:00
services.AddAuthentication("Bearer")
.AddJwtBearer("Bearer", options =>
{
options.IncludeErrorDetails = true;
options.Authority = builder.Configuration.GetSection("Site")["Authority"];
2026-02-18 00:34:22 +00:00
options.Audience = builder.Configuration.GetSection("Site")["Audience"];
2026-02-17 21:50:17 +00:00
options.TokenValidationParameters =
2026-02-21 20:51:35 +00:00
new()
{
2026-02-18 00:34:22 +00:00
ValidateAudience = false,
2026-05-30 19:34:22 +01:00
RoleClaimType = YavscConstants.RoleClaimType
2026-02-18 00:34:22 +00:00
};
2026-02-17 21:50:17 +00:00
options.MapInboundClaims = true;
});
2025-08-18 09:22:09 +01:00
2025-07-31 11:44:02 +01:00
services.AddTransient<RoleManager<IdentityRole>>();
services.AddTransient<IRoleStore<IdentityRole>, RoleStore<IdentityRole, ApplicationDbContext>>();
2026-05-24 19:35:35 +01:00
services.Configure<KycOptions>(builder.Configuration.GetSection("Kyc"));
services.AddScoped<ITrustTokenService, TrustTokenService>();
2025-02-14 00:20:35 +00:00
return builder.Build();
}
public static IdentityBuilder AddIdentityDBAndStores(this WebApplicationBuilder builder)
{
IServiceCollection services = builder.Services;
2026-05-30 19:34:22 +01:00
var connectionString = builder.Configuration.GetConnectionString(YavscConstants.YavscConnectionStringName);
2026-04-20 00:35:51 +01:00
services.AddDbContext<ApplicationDbContext>(options =>
{
2026-05-28 22:18:26 +01:00
if (UsesInMemoryProvider(connectionString))
{
options.UseInMemoryDatabase(connectionString);
}
else
{
options.UseNpgsql(connectionString,
options => options.MigrationsAssembly(typeof(Program).Assembly));
}
2026-04-20 00:35:51 +01:00
});
2025-02-14 00:20:35 +00:00
2026-04-19 16:02:50 +01:00
var identityBuilder = services.AddIdentity<ApplicationUser, IdentityRole>(
2025-07-11 13:27:31 +01:00
options =>
{
2026-02-17 19:24:30 +00:00
options.SignIn.RequireConfirmedAccount = builder.Environment.IsEnvironment(
builder.Environment.EnvironmentName);
2025-07-31 11:44:02 +01:00
options.ClaimsIdentity.UserNameClaimType = JwtClaimTypes.PreferredUserName;
2026-05-30 19:34:22 +01:00
options.ClaimsIdentity.RoleClaimType = YavscConstants.RoleClaimType;
2025-07-11 13:27:31 +01:00
}
)
2025-07-31 11:44:02 +01:00
.AddEntityFrameworkStores<ApplicationDbContext>();
2026-04-19 16:02:50 +01:00
services.AddScoped<IUserClaimsPrincipalFactory<ApplicationUser>, UserClaimsPrincipalFactory<ApplicationUser, IdentityRole>>();
return identityBuilder;
2025-02-14 00:20:35 +00:00
}
private static void AddYavscPolicies(IServiceCollection services)
{
2025-02-08 20:06:24 +00:00
services.AddAuthorization(options =>
{
2025-02-08 21:58:23 +00:00
options.AddPolicy("ApiScope", policy =>
2025-02-11 04:45:05 +00:00
{
policy.RequireAuthenticatedUser()
.RequireClaim("scope", "scope2");
});
2025-08-25 13:32:31 +01:00
2025-02-09 16:57:10 +00:00
options.AddPolicy("Performer", policy =>
{
policy
.RequireAuthenticatedUser()
2026-05-30 19:34:22 +01:00
.RequireClaim(YavscConstants.RoleClaimType,
new string[] { YavscConstants.PerformerGroupName, YavscConstants.AdminGroupName })
2025-08-18 11:27:13 +01:00
;
2025-02-09 16:57:10 +00:00
});
2025-02-08 20:06:24 +00:00
options.AddPolicy("AdministratorOnly", policy =>
2024-02-25 18:05:10 +00:00
{
2025-07-07 07:49:18 +01:00
_ = policy
.RequireAuthenticatedUser()
2026-05-30 19:34:22 +01:00
.RequireClaim(YavscConstants.RoleClaimType, YavscConstants.AdminGroupName);
2024-02-25 18:05:10 +00:00
});
2026-05-30 19:34:22 +01:00
options.AddPolicy("FrontOffice", policy => policy.RequireRole(YavscConstants.FrontOfficeGroupName));
2025-02-14 00:20:35 +00:00
2025-02-08 20:06:24 +00:00
// options.AddPolicy("EmployeeId", policy => policy.RequireClaim("EmployeeId", "123", "456"));
// options.AddPolicy("BuildingEntry", policy => policy.Requirements.Add(new OfficeEntryRequirement()));
options.AddPolicy("Authenticated", policy => policy.RequireAuthenticatedUser());
2025-06-29 16:20:37 +01:00
options.AddPolicy("TheAuthor", policy => policy.Requirements.Add(new EditPermission()));
2025-02-11 04:45:05 +00:00
})
.AddCors(options =>
{
2025-02-12 20:41:14 +00:00
options.AddPolicy("default", builder =>
2025-02-11 04:45:05 +00:00
{
_ = builder.WithOrigins("*")
.AllowAnyHeader()
.AllowAnyMethod();
});
2025-02-08 20:06:24 +00:00
});
2025-02-14 00:20:35 +00:00
}
2025-02-08 20:06:24 +00:00
2025-02-14 00:20:35 +00:00
public static IServiceCollection LoadConfiguration(this WebApplicationBuilder builder)
{
var siteSection = builder.Configuration.GetSection("Site");
2026-02-17 21:50:17 +00:00
2025-02-14 00:20:35 +00:00
var smtpSection = builder.Configuration.GetSection("Smtp");
var paypalSection = builder.Configuration.GetSection("Authentication:PayPal");
// OAuth2AppSettings
var googleAuthSettings = builder.Configuration.GetSection("Authentication:Google");
2026-02-17 19:24:30 +00:00
LoadGoogleConfig(builder.Configuration);
2025-02-14 00:20:35 +00:00
2025-08-18 09:22:09 +01:00
2025-02-14 00:20:35 +00:00
var services = builder.Services;
_ = services.AddControllersWithViews()
.AddNewtonsoftJson();
2025-08-18 09:22:09 +01:00
2025-02-14 00:20:35 +00:00
services.Configure<SiteSettings>(siteSection);
services.Configure<SmtpSettings>(smtpSection);
services.Configure<PayPalSettings>(paypalSection);
services.Configure<GoogleAuthSettings>(googleAuthSettings);
ConfigureRequestLocalization(services);
2024-11-10 23:12:02 +00:00
2025-02-14 00:20:35 +00:00
return services;
}
2025-02-11 04:45:05 +00:00
2025-02-16 22:40:51 +00:00
private static void AddAuthentication(WebApplicationBuilder builder)
2025-02-15 14:46:40 +00:00
{
2025-08-18 09:22:09 +01:00
IServiceCollection services = builder.Services;
IConfigurationRoot configurationRoot = builder.Configuration;
2025-02-16 22:40:51 +00:00
string? googleClientId = configurationRoot["Authentication:Google:ClientId"];
2025-02-15 14:46:40 +00:00
string? googleClientSecret = configurationRoot["Authentication:Google:ClientSecret"];
2025-08-18 09:22:09 +01:00
2025-02-16 22:40:51 +00:00
var authenticationBuilder = services.AddAuthentication();
2025-02-15 14:46:40 +00:00
2025-08-18 09:22:09 +01:00
if (googleClientId != null && googleClientSecret != null)
authenticationBuilder.AddGoogle(options =>
{
options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
// register your IdentityServer with Google at https://console.developers.google.com
// enable the Google+ API
// set the redirect URI to https://localhost:5001/signin-google
options.ClientId = googleClientId;
options.ClientSecret = googleClientSecret;
});
2025-02-15 14:46:40 +00:00
}
2026-04-19 16:02:50 +01:00
public static IIdentityServerBuilder AddIdentityServer(WebApplicationBuilder builder)
2025-02-14 00:20:35 +00:00
{
2026-02-21 20:51:35 +00:00
builder.Services.Configure<IdentityOptions>(options =>
{
options.ClaimsIdentity.UserIdClaimType = JwtClaimTypes.Subject;
options.ClaimsIdentity.UserNameClaimType = JwtClaimTypes.Name;
2026-05-30 19:34:22 +01:00
options.ClaimsIdentity.RoleClaimType = YavscConstants.RoleClaimType;
2026-02-21 20:51:35 +00:00
});
2026-02-22 23:39:56 +00:00
var migrationsAssembly = typeof(Program).GetTypeInfo().Assembly.GetName().Name;
2026-05-30 19:34:22 +01:00
var connectionString = builder.Configuration.GetConnectionString(YavscConstants.YavscConnectionStringName);
2026-04-20 00:35:51 +01:00
string sqliteConnectionString = $"Data Source={Path.Combine(Path.GetTempPath(), "yavsc_test.db")}";
2025-08-24 16:07:53 +01:00
2025-02-16 22:40:51 +00:00
var identityServerBuilder = builder.Services.AddIdentityServer(options =>
{
options.Events.RaiseErrorEvents = true;
options.Events.RaiseInformationEvents = true;
options.Events.RaiseFailureEvents = true;
options.Events.RaiseSuccessEvents = true;
// see https://IdentityServer8.readthedocs.io/en/latest/topics/resources.html
options.EmitStaticAudienceClaim = true;
2025-08-18 09:22:09 +01:00
2025-02-16 22:40:51 +00:00
})
2026-02-09 01:03:33 +00:00
.AddAspNetIdentity<ApplicationUser>()
.AddClientStore<ClientStore>()
2026-03-09 02:07:09 +00:00
.AddClientConfigurationValidator<DefaultClientConfigurationValidator>()
2026-02-09 01:03:33 +00:00
.AddCorsPolicyService<CorsPolicyService>()
.AddResourceStore<ResourceStore>()
2025-08-24 16:07:53 +01:00
.AddConfigurationStore(options =>
{
2026-05-28 22:18:26 +01:00
options.ConfigureDbContext = b =>
{
if (UsesInMemoryProvider(connectionString))
{
b.UseInMemoryDatabase(connectionString);
}
else
{
b.UseNpgsql(connectionString,
sql => sql.MigrationsAssembly(migrationsAssembly));
}
2026-06-10 11:10:15 +01:00
b.UseSeeding(EnsureDefaultConfiguration());
2026-05-28 22:18:26 +01:00
};
2025-08-24 16:07:53 +01:00
})
.AddOperationalStore(options =>
{
2026-05-28 22:18:26 +01:00
options.ConfigureDbContext = b =>
{
if (UsesInMemoryProvider(connectionString))
{
b.UseInMemoryDatabase(connectionString);
}
else
{
b.UseNpgsql(connectionString,
sql => sql.MigrationsAssembly(migrationsAssembly));
}
};
2026-04-20 00:35:51 +01:00
2026-02-09 01:03:33 +00:00
});
2025-08-18 09:22:09 +01:00
2025-02-14 00:20:35 +00:00
if (builder.Environment.IsDevelopment())
{
identityServerBuilder.AddDeveloperSigningCredential();
}
return identityServerBuilder;
2024-02-25 18:05:10 +00:00
}
2025-02-14 00:20:35 +00:00
2026-05-28 22:18:26 +01:00
private static bool UsesInMemoryProvider(string connectionString)
{
return string.Equals(connectionString, InMemoryProviderName, StringComparison.OrdinalIgnoreCase);
}
2026-04-20 00:35:51 +01:00
private static Action<DbContext, bool> EnsureDefaultApplicationScopes()
{
return (context, _) =>
{
2026-06-06 21:30:41 +01:00
foreach (String scope in Constants.BuildInApiScopes)
2026-04-20 00:35:51 +01:00
{
var existentScope = context.Set<ApiScope>().FirstOrDefault(b => b.Name == scope);
if (existentScope == null)
{
context.Set<ApiScope>().Add(new ApiScope { Name = scope });
context.SaveChanges();
}
}
2026-06-10 11:10:15 +01:00
};
}
private static Action<DbContext, bool> EnsureDefaultConfiguration()
{
return (context, _) =>
{
EnsureDefaultApplicationScopes()(context, _);
2026-04-20 00:35:51 +01:00
2026-06-10 16:59:23 +01:00
var existingClient = context.Set<IdentityServer8.EntityFramework.Entities.Client>().FirstOrDefault(c => c.ClientId == "postit");
2026-06-10 11:10:15 +01:00
if (existingClient == null)
{
2026-06-10 16:59:23 +01:00
var client = new IdentityServer8.EntityFramework.Entities.Client
2026-06-10 11:10:15 +01:00
{
ClientId = "postit",
Enabled = true,
RequireClientSecret = true,
ProtocolType = "oidc",
RequireConsent = false,
};
context.Set<Client>().Add(client);
2026-06-10 16:59:23 +01:00
// allow authorization code (interactive) and client credentials (m2m)
context.Set<ClientGrantType>().Add(new IdentityServer8.EntityFramework.Entities.ClientGrantType
{
Client = client,
GrantType = "authorization_code"
});
context.Set<ClientGrantType>().Add(new IdentityServer8.EntityFramework.Entities.ClientGrantType
2026-06-10 11:10:15 +01:00
{
Client = client,
GrantType = "client_credentials"
});
2026-06-10 16:59:23 +01:00
context.Set<ClientScope>().Add(new IdentityServer8.EntityFramework.Entities.ClientScope
2026-06-10 11:10:15 +01:00
{
Client = client,
Scope = "blog"
});
2026-06-10 16:59:23 +01:00
context.Set<ClientScope>().Add(new IdentityServer8.EntityFramework.Entities.ClientScope
{
Client = client,
Scope = IdentityServer8.IdentityServerConstants.StandardScopes.OpenId
});
context.Set<ClientScope>().Add(new IdentityServer8.EntityFramework.Entities.ClientScope
{
Client = client,
Scope = IdentityServer8.IdentityServerConstants.StandardScopes.Profile
});
context.Set<ClientRedirectUri>().Add(new IdentityServer8.EntityFramework.Entities.ClientRedirectUri
{
Client = client,
RedirectUri = "http://127.0.0.1:7890/"
});
context.Set<ClientSecret>().Add(new IdentityServer8.EntityFramework.Entities.ClientSecret
2026-06-10 11:10:15 +01:00
{
Client = client,
2026-06-10 16:59:23 +01:00
Value = "postit-secret".ToSha256(),
2026-06-10 11:10:15 +01:00
});
context.SaveChanges();
}
2026-04-20 00:35:51 +01:00
};
}
2025-02-14 00:20:35 +00:00
private static void ConfigureRequestLocalization(IServiceCollection services)
{
services.Configure<RequestLocalizationOptions>(options =>
{
CultureInfo[] supportedCultures = new[]
{
2026-02-17 19:24:30 +00:00
new CultureInfo("en"),
new CultureInfo("fr"),
new CultureInfo("pt")
2025-02-14 00:20:35 +00:00
};
CultureInfo[] supportedUICultures = new[]
{
2026-02-17 19:24:30 +00:00
new CultureInfo("fr"),
new CultureInfo("en"),
new CultureInfo("pt")
2025-02-14 00:20:35 +00:00
};
// You must explicitly state which cultures your application supports.
// These are the cultures the app supports for formatting numbers, dates, etc.
options.SupportedCultures = supportedCultures;
// These are the cultures the app supports for UI strings, i.e. we have localized resources for.
options.SupportedUICultures = supportedUICultures;
options.RequestCultureProviders = new List<IRequestCultureProvider>
2026-02-17 19:24:30 +00:00
{
new QueryStringRequestCultureProvider { Options = options },
new CookieRequestCultureProvider { Options = options, CookieName="ASPNET_CULTURE" },
new AcceptLanguageHeaderRequestCultureProvider { Options = options }
};
2025-02-14 00:20:35 +00:00
});
}
2025-07-14 18:58:04 +01:00
public async static Task<WebApplication> ConfigurePipeline(this WebApplication app)
2025-02-08 20:06:24 +00:00
{
ILoggerFactory loggerFactory = app.Services.GetRequiredService<ILoggerFactory>();
var logger = loggerFactory.CreateLogger<Program>();
2025-02-08 20:06:24 +00:00
2025-09-14 00:41:35 +01:00
AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);
2025-09-14 23:52:21 +01:00
JwtSecurityTokenHandler.DefaultMapInboundClaims = true;
2024-02-25 18:05:10 +00:00
if (app.Environment.IsDevelopment())
{
2026-02-07 23:47:12 +00:00
app.UseDeveloperExceptionPage();
2024-02-25 18:05:10 +00:00
}
2025-02-08 20:06:24 +00:00
else
2024-11-12 08:32:15 +00:00
{
app.UseExceptionHandler("/Home/Error");
2026-03-01 20:14:54 +00:00
app.MigrateDatabase();
2024-11-12 08:32:15 +00:00
}
2025-08-18 09:22:09 +01:00
app.Use(async (context, next) =>
{
if (context.Request.Path.StartsWithSegments("/robots.txt"))
{
2025-07-10 18:32:58 +01:00
var robotsTxtPath = System.IO.Path.Combine(app.Environment.WebRootPath, $"robots.txt");
string output = "User-agent: * \nDisallow: /";
2025-08-18 09:22:09 +01:00
if (File.Exists(robotsTxtPath))
{
2025-07-10 18:32:58 +01:00
output = await File.ReadAllTextAsync(robotsTxtPath);
}
context.Response.ContentType = "text/plain";
await context.Response.WriteAsync(output);
2025-08-18 09:22:09 +01:00
}
else await next();
2025-07-10 18:32:58 +01:00
});
2026-02-07 23:47:12 +00:00
2026-02-09 01:03:33 +00:00
app.UseSwagger();
2026-02-07 23:47:12 +00:00
app.UseSwaggerUI();
2024-02-25 18:05:10 +00:00
app.UseStaticFiles();
app.UseRouting();
app.UseIdentityServer();
app.UseAuthorization();
2025-02-12 20:41:14 +00:00
app.UseCors("default");
2025-02-16 22:40:51 +00:00
app.MapDefaultControllerRoute();
2025-07-07 07:49:18 +01:00
//app.MapRazorPages();
2024-03-04 01:02:19 +00:00
app.MapHub<ChatHub>("/chatHub");
2025-08-18 09:22:09 +01:00
2025-02-26 18:59:08 +00:00
WorkflowHelpers.ConfigureBillingService();
2025-08-18 09:22:09 +01:00
2024-02-25 18:05:10 +00:00
var services = app.Services;
var siteSettings = services.GetRequiredService<IOptions<SiteSettings>>();
var smtpSettings = services.GetRequiredService<IOptions<SmtpSettings>>();
var payPalSettings = services.GetRequiredService<IOptions<PayPalSettings>>();
var googleAuthSettings = services.GetRequiredService<IOptions<GoogleAuthSettings>>();
2025-08-31 18:27:53 +01:00
var localization = services.GetRequiredService<IStringLocalizer<Startup>>();
2025-02-23 20:23:23 +00:00
Startup.Configure(app, siteSettings, smtpSettings,
2024-02-25 18:05:10 +00:00
payPalSettings, googleAuthSettings, localization, loggerFactory,
2025-02-08 20:06:24 +00:00
app.Environment.EnvironmentName);
2024-02-25 18:05:10 +00:00
app.ConfigureFileServerApp();
2026-02-09 01:03:33 +00:00
app.UseSession();
2024-02-25 18:05:10 +00:00
return app;
}
2026-03-16 23:16:12 +00:00
2026-03-01 20:14:54 +00:00
private static void MigrateDatabase(this IApplicationBuilder app)
2025-08-24 16:07:53 +01:00
{
2026-02-07 23:47:12 +00:00
using (var serviceScope = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>().CreateScope())
2025-08-24 16:07:53 +01:00
{
2025-08-25 13:32:31 +01:00
2025-08-25 14:18:26 +01:00
try
2025-08-24 16:07:53 +01:00
{
2026-02-28 14:22:33 +00:00
foreach (Type contextType in new Type[]
{
typeof(ApplicationDbContext)
})
{
((DbContext)serviceScope.ServiceProvider
.GetRequiredService(contextType))
.Database.Migrate();
}
2025-09-14 23:52:21 +01:00
}
2025-08-25 14:18:26 +01:00
catch (InvalidOperationException ex)
{
app.Properties["DegradedDBContext"] = ex.Message;
2025-08-24 16:07:53 +01:00
}
}
}
2024-02-25 18:05:10 +00:00
2025-02-08 20:06:24 +00:00
static void LoadGoogleConfig(IConfigurationRoot configuration)
2024-02-25 18:05:10 +00:00
{
string? googleClientFile = configuration["Authentication:Google:GoogleWebClientJson"];
string? googleServiceAccountJsonFile = configuration["Authentication:Google:GoogleServiceAccountJson"];
if (googleClientFile != null)
{
Config.GoogleWebClientConfiguration = new ConfigurationBuilder().AddJsonFile(googleClientFile).Build();
}
if (googleServiceAccountJsonFile != null)
{
FileInfo safile = new FileInfo(googleServiceAccountJsonFile);
Config.GServiceAccount = JsonConvert.DeserializeObject<GoogleServiceAccount>(safile.OpenText().ReadToEnd());
}
}
2025-08-18 09:22:09 +01:00
2025-07-10 09:16:58 +01:00
public static IApplicationBuilder ConfigureFileServerApp(this IApplicationBuilder app,
bool enableDirectoryBrowsing = false)
2025-07-07 07:49:18 +01:00
{
2025-07-10 09:16:58 +01:00
var userFilesDirInfo = new DirectoryInfo(Config.SiteSetup.Blog);
AbstractFileSystemHelpers.UserFilesDirName = userFilesDirInfo.FullName;
2025-07-07 07:49:18 +01:00
2025-07-10 09:16:58 +01:00
if (!userFilesDirInfo.Exists) userFilesDirInfo.Create();
2025-07-07 07:49:18 +01:00
2025-07-10 09:16:58 +01:00
Config.UserFilesOptions = new FileServerOptions()
{
FileProvider = new PhysicalFileProvider(AbstractFileSystemHelpers.UserFilesDirName),
2026-05-30 19:34:22 +01:00
RequestPath = PathString.FromUriComponent(YavscConstants.UserFilesPath),
2025-07-10 09:16:58 +01:00
EnableDirectoryBrowsing = enableDirectoryBrowsing,
};
Config.UserFilesOptions.EnableDefaultFiles = true;
Config.UserFilesOptions.StaticFileOptions.ServeUnknownFileTypes = true;
2025-07-07 07:49:18 +01:00
2025-07-10 09:16:58 +01:00
var avatarsDirInfo = new DirectoryInfo(Config.SiteSetup.Avatars);
if (!avatarsDirInfo.Exists) avatarsDirInfo.Create();
Config.AvatarsDirName = avatarsDirInfo.FullName;
2025-07-07 07:49:18 +01:00
2025-07-10 09:16:58 +01:00
Config.AvatarsOptions = new FileServerOptions()
{
FileProvider = new PhysicalFileProvider(Config.AvatarsDirName),
2026-05-30 19:34:22 +01:00
RequestPath = PathString.FromUriComponent(YavscConstants.AvatarsPath),
2025-07-10 09:16:58 +01:00
EnableDirectoryBrowsing = enableDirectoryBrowsing
};
2025-07-07 07:49:18 +01:00
2025-07-10 09:16:58 +01:00
var gitdirinfo = new DirectoryInfo(Config.SiteSetup.GitRepository);
Config.GitDirName = gitdirinfo.FullName;
if (!gitdirinfo.Exists) gitdirinfo.Create();
Config.GitOptions = new FileServerOptions()
{
FileProvider = new PhysicalFileProvider(Config.GitDirName),
2026-05-30 19:34:22 +01:00
RequestPath = PathString.FromUriComponent(YavscConstants.GitPath),
2025-07-10 09:16:58 +01:00
EnableDirectoryBrowsing = enableDirectoryBrowsing,
};
Config.GitOptions.DefaultFilesOptions.DefaultFileNames.Add("index.md");
Config.GitOptions.StaticFileOptions.ServeUnknownFileTypes = true;
2025-07-07 07:49:18 +01:00
2025-07-10 09:16:58 +01:00
app.UseFileServer(Config.UserFilesOptions);
2025-07-07 07:49:18 +01:00
2025-07-10 09:16:58 +01:00
app.UseFileServer(Config.AvatarsOptions);
2025-07-07 07:49:18 +01:00
2025-07-10 09:16:58 +01:00
app.UseFileServer(Config.GitOptions);
app.UseStaticFiles();
return app;
2025-07-07 07:49:18 +01:00
}
}