summaryrefslogtreecommitdiffstats
path: root/server/src/Program.cs
diff options
context:
space:
mode:
authorivarlovlie <git@ivarlovlie.no>2022-06-01 22:10:32 +0200
committerivarlovlie <git@ivarlovlie.no>2022-06-01 22:10:32 +0200
commita640703f2da8815dc26ad1600a6f206be1624379 (patch)
treedbda195fb5783d16487e557e06471cf848b75427 /server/src/Program.cs
downloadgreatoffice-a640703f2da8815dc26ad1600a6f206be1624379.tar.xz
greatoffice-a640703f2da8815dc26ad1600a6f206be1624379.zip
feat: Initial after clean slate
Diffstat (limited to 'server/src/Program.cs')
-rw-r--r--server/src/Program.cs261
1 files changed, 261 insertions, 0 deletions
diff --git a/server/src/Program.cs b/server/src/Program.cs
new file mode 100644
index 0000000..b449117
--- /dev/null
+++ b/server/src/Program.cs
@@ -0,0 +1,261 @@
+global using System;
+global using System.Linq;
+global using System.IO;
+global using System.Net.Mail;
+global using System.Net;
+global using System.Threading;
+global using System.Threading.Tasks;
+global using System.Collections.Generic;
+global using System.Runtime.Serialization;
+global using System.ComponentModel.DataAnnotations.Schema;
+global using System.Security.Claims;
+global using System.Text.Json;
+global using System.Text.Json.Serialization;
+global using IOL.GreatOffice.Api.Data.Database;
+global using IOL.GreatOffice.Api.Data.Exceptions;
+global using IOL.GreatOffice.Api.Data.Dtos;
+global using IOL.GreatOffice.Api.Data.Enums;
+global using IOL.GreatOffice.Api.Data.Models;
+global using IOL.GreatOffice.Api.Data.Results;
+global using IOL.Helpers;
+global using Microsoft.OpenApi.Models;
+global using Microsoft.AspNetCore.Authentication.Cookies;
+global using Microsoft.AspNetCore.Builder;
+global using Microsoft.AspNetCore.DataProtection;
+global using Microsoft.AspNetCore.Hosting;
+global using Microsoft.AspNetCore.Authorization;
+global using Microsoft.AspNetCore.Http;
+global using Microsoft.AspNetCore.Authentication;
+global using Microsoft.AspNetCore.Mvc;
+global using Microsoft.EntityFrameworkCore;
+global using Microsoft.Extensions.Configuration;
+global using Microsoft.Extensions.DependencyInjection;
+global using Microsoft.Extensions.Hosting;
+global using Microsoft.Extensions.Logging;
+global using Serilog;
+global using IOL.GreatOffice.Api.Data;
+global using IOL.GreatOffice.Api.Data.Static;
+global using IOL.GreatOffice.Api.Services;
+global using IOL.GreatOffice.Api.Utilities;
+using System.Diagnostics;
+using System.Reflection;
+using IOL.GreatOffice.Api.Endpoints.V1;
+using IOL.GreatOffice.Api.Jobs;
+using Microsoft.AspNetCore.HttpOverrides;
+using Microsoft.AspNetCore.Mvc.Versioning;
+using Quartz;
+
+namespace IOL.GreatOffice.Api;
+
+public static class Program
+{
+ public static WebApplicationBuilder CreateAppBuilder(string[] args) {
+ var builder = WebApplication.CreateBuilder(args);
+
+ var seqUrl = builder.Configuration.GetValue<string>(AppEnvironmentVariables.SEQ_API_URL);
+ var seqKey = builder.Configuration.GetValue<string>(AppEnvironmentVariables.SEQ_API_KEY);
+ var logger = new LoggerConfiguration()
+ .Enrich.FromLogContext()
+ .ReadFrom.Configuration(builder.Configuration)
+ .WriteTo.Console();
+
+ if (!builder.Environment.IsDevelopment() && seqUrl.HasValue() && seqKey.HasValue()) {
+ logger.WriteTo.Seq(seqUrl, apiKey: seqKey);
+ }
+
+ Log.Logger = logger.CreateLogger();
+ Log.Information("Starting web host"
+ + JsonSerializer.Serialize(new {
+ DateTime.UtcNow,
+ PID = Environment.ProcessId,
+ DB_HOST = builder.Configuration.GetValue<string>(AppEnvironmentVariables.DB_HOST),
+ DB_PORT = builder.Configuration.GetValue<string>(AppEnvironmentVariables.DB_PORT),
+ DB_USER = builder.Configuration.GetValue<string>(AppEnvironmentVariables.DB_USER),
+ DB_NAME = builder.Configuration.GetValue<string>(AppEnvironmentVariables.DB_NAME),
+ DB_PASS = builder.Configuration.GetValue<string>(AppEnvironmentVariables.DB_PASSWORD).Obfuscate() ?? "!!!Empty!!!",
+ QUARTZ_DB_HOST = builder.Configuration.GetValue<string>(AppEnvironmentVariables.QUARTZ_DB_HOST),
+ QUARTZ_DB_PORT = builder.Configuration.GetValue<string>(AppEnvironmentVariables.QUARTZ_DB_PORT),
+ QUARTZ_DB_USER = builder.Configuration.GetValue<string>(AppEnvironmentVariables.QUARTZ_DB_USER),
+ QUARTZ_DB_NAME = builder.Configuration.GetValue<string>(AppEnvironmentVariables.QUARTZ_DB_NAME),
+ QUARTZ_DB_PASS = builder.Configuration.GetValue<string>(AppEnvironmentVariables.QUARTZ_DB_PASSWORD).Obfuscate()
+ ?? "!!!Empty!!!",
+ },
+ new JsonSerializerOptions() {
+ WriteIndented = true
+ }));
+
+ builder.Host.UseSerilog(Log.Logger);
+ builder.WebHost.ConfigureKestrel(kestrel => {
+ kestrel.AddServerHeader = false;
+ });
+
+ if (builder.Environment.IsDevelopment()) {
+ builder.Services.AddCors();
+ }
+
+ if (builder.Environment.IsProduction()) {
+ builder.Services.Configure<ForwardedHeadersOptions>(options => {
+ options.ForwardedHeaders = ForwardedHeaders.XForwardedProto;
+ });
+ }
+
+ builder.Services.AddDataProtection().PersistKeysToFileSystem(new DirectoryInfo(AppPaths.DataProtectionKeys.HostPath));
+
+ builder.Services.Configure(JsonSettings.Default);
+ builder.Services.AddQuartz(options => {
+ options.UsePersistentStore(o => {
+ o.UsePostgres(builder.Configuration.GetQuartzDatabaseConnectionString());
+ o.UseSerializer<QuartzJsonSerializer>();
+ });
+ options.UseMicrosoftDependencyInjectionJobFactory();
+ options.RegisterJobs();
+ });
+ builder.Services.AddQuartzHostedService(options => {
+ options.WaitForJobsToComplete = true;
+ });
+
+ builder.Services.AddAuthentication(options => {
+ options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
+ options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
+ })
+ .AddCookie(options => {
+ options.Cookie.Name = "go_session";
+ options.Cookie.SameSite = SameSiteMode.Strict;
+ options.Cookie.HttpOnly = true;
+ options.Cookie.SecurePolicy = builder.Environment.IsDevelopment() ? CookieSecurePolicy.SameAsRequest : CookieSecurePolicy.Always;
+ options.Cookie.IsEssential = true;
+ options.SlidingExpiration = true;
+ options.Events.OnRedirectToAccessDenied =
+ options.Events.OnRedirectToLogin = c => {
+ c.Response.StatusCode = StatusCodes.Status401Unauthorized;
+ return Task.FromResult<object>(null);
+ };
+ })
+ .AddGitHub(options => {
+ options.ClientSecret = builder.Configuration.GetValue<string>(AppEnvironmentVariables.GITHUB_CLIENT_SECRET);
+ options.ClientId = builder.Configuration.GetValue<string>(AppEnvironmentVariables.GITHUB_CLIENT_ID);
+ options.SaveTokens = true;
+ options.CorrelationCookie.Name = "gh_correlation";
+ options.CorrelationCookie.SameSite = SameSiteMode.Lax;
+ options.CorrelationCookie.SecurePolicy = CookieSecurePolicy.Always;
+ options.CorrelationCookie.HttpOnly = true;
+ options.Events.OnCreatingTicket = context => GithubAuthenticationHelpers.HandleGithubTicketCreation(context, builder.Configuration);
+ })
+ .AddScheme<AuthenticationSchemeOptions, BasicAuthenticationHandler>(AppConstants.BASIC_AUTH_SCHEME, default);
+
+
+ builder.Services.AddDbContext<AppDbContext>(options => {
+ options.UseNpgsql(builder.Configuration.GetAppDatabaseConnectionString(),
+ npgsqlDbContextOptionsBuilder => {
+ npgsqlDbContextOptionsBuilder.UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery);
+ npgsqlDbContextOptionsBuilder.EnableRetryOnFailure(5, TimeSpan.FromSeconds(10), default);
+ })
+ .UseSnakeCaseNamingConvention();
+ if (builder.Environment.IsDevelopment()) {
+ options.EnableSensitiveDataLogging();
+ }
+ });
+
+ builder.Services.AddApiVersioning(options => {
+ options.ApiVersionReader = new UrlSegmentApiVersionReader();
+ options.ReportApiVersions = true;
+ options.AssumeDefaultVersionWhenUnspecified = false;
+ });
+ builder.Services.AddVersionedApiExplorer(options => {
+ options.SubstituteApiVersionInUrl = true;
+ });
+ builder.Services.AddSwaggerGen(options => {
+ options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, Assembly.GetExecutingAssembly().GetName().Name + ".xml"));
+ options.UseApiEndpoints();
+ options.OperationFilter<SwaggerDefaultValues>();
+ options.SwaggerDoc(ApiSpecV1.Document.VersionName, ApiSpecV1.Document.OpenApiInfo);
+ options.AddSecurityDefinition("Basic",
+ new OpenApiSecurityScheme {
+ Name = "Authorization",
+ Type = SecuritySchemeType.ApiKey,
+ Scheme = "Basic",
+ BearerFormat = "Basic",
+ In = ParameterLocation.Header,
+ Description =
+ "Enter your token in the text input below.\r\n\r\nExample: \"Basic 12345abcdef\"",
+ });
+
+ options.AddSecurityRequirement(new OpenApiSecurityRequirement {
+ {
+ new OpenApiSecurityScheme {
+ Reference = new OpenApiReference {
+ Type = ReferenceType.SecurityScheme,
+ Id = "Basic"
+ }
+ },
+ Array.Empty<string>()
+ }
+ });
+ });
+
+ builder.Services.AddScoped<MailService>();
+ builder.Services.AddScoped<ForgotPasswordService>();
+ builder.Services.AddScoped<UserService>();
+ builder.Services.AddLogging();
+ builder.Services.AddHttpClient();
+ builder.Services
+ .AddControllers()
+ .AddJsonOptions(JsonSettings.Default);
+
+
+ return builder;
+ }
+
+ public static WebApplication CreateWebApplication(WebApplicationBuilder builder) {
+ var app = builder.Build();
+
+ if (app.Environment.IsDevelopment()) {
+ app.UseDeveloperExceptionPage();
+ app.UseCors(cors => {
+ cors.AllowAnyMethod();
+ cors.AllowAnyHeader();
+ cors.WithOrigins("http://localhost:3000", "http://localhost:3002", "http://localhost:3001");
+ cors.AllowCredentials();
+ });
+ }
+
+ if (app.Environment.IsProduction()) {
+ app.UseForwardedHeaders();
+ }
+
+ app.UseDefaultFiles()
+ .UseStaticFiles()
+ .UseRouting()
+ .UseSerilogRequestLogging()
+ .UseStatusCodePages()
+ .UseAuthentication()
+ .UseAuthorization()
+ .UseSwagger()
+ .UseSwaggerUI(options => {
+ options.SwaggerEndpoint(ApiSpecV1.Document.SwaggerPath, ApiSpecV1.Document.VersionName);
+ options.DocumentTitle = AppConstants.API_NAME;
+ })
+ .UseEndpoints(endpoints => {
+ endpoints.MapControllers();
+ });
+ return app;
+ }
+
+ public static int Main(string[] args) {
+ try {
+ CreateWebApplication(CreateAppBuilder(args)).Run();
+ return 0;
+ } catch (Exception ex) {
+ // This is subject to change in future .net versions, see https://github.com/dotnet/runtime/issues/60600.
+ if (ex.GetType().Name.Equals("StopTheHostException", StringComparison.Ordinal)) {
+ throw;
+ }
+
+ Log.Fatal(ex, "Unhandled exception");
+ return 1;
+ } finally {
+ Log.Information("Shut down complete, flusing logs...");
+ Log.CloseAndFlush();
+ }
+ }
+}