-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathProgram.cs
More file actions
149 lines (126 loc) · 4.29 KB
/
Program.cs
File metadata and controls
149 lines (126 loc) · 4.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
using System.Text.Json.Serialization;
using Microsoft.AspNetCore.Identity;
using QuestLog.Backend.Database;
using QuestLog.Backend.Endpoints;
using QuestLog.Backend.Extensions;
using QuestLog.Backend.Models;
using QuestLog.Backend.Settings;
using Resend;
using Scalar.AspNetCore;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddOpenApi();
// Get the questlog settings quickly for use in other builder.Services method calls
var questLogSettings = builder.Configuration
.GetSection("QuestLogSettings")
.Get<QuestLogSettings>();
if (questLogSettings is null)
{
throw new InvalidOperationException("QuestLogSettings are missing in appsettings.json");
}
builder.Services.AddCors(options =>
{
options.AddPolicy("Frontend", policy =>
{
policy.WithOrigins(
"http://localhost:5173",
"https://questlog-five.vercel.app",
questLogSettings.FrontEndUrl)
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials();
});
});
// Setup RESEND API
builder.Services.AddOptions();
builder.Services.AddHttpClient<ResendClient>();
builder.Services.Configure<ResendClientOptions>(option =>
{
option.ApiToken = builder.Configuration["RESEND_API_TOKEN"]!;
});
builder.Services.AddTransient<IResend, ResendClient>();
// Setup Authentication/Authorization
builder.Services.AddAuthorization();
builder.Services.AddAuthentication(options =>
{
options.DefaultScheme = IdentityConstants.ApplicationScheme;
options.DefaultChallengeScheme = IdentityConstants.ApplicationScheme;
})
.AddCookie(IdentityConstants.ApplicationScheme)
// Temporary holding cookie for google auth
.AddCookie(IdentityConstants.ExternalScheme)
.AddGoogle(googleOptions =>
{
var clientId = builder.Configuration["Authentication:Google:ClientId"];
var clientSecret = builder.Configuration["Authentication:Google:ClientSecret"];
if (clientId is null || clientSecret is null)
{
throw new InvalidOperationException("Google authentication is not configured");
}
googleOptions.ClientId = clientId;
googleOptions.ClientSecret = clientSecret;
googleOptions.SignInScheme = IdentityConstants.ExternalScheme;
});
builder.Services.AddIdentityCore<User>(options =>
{
options.User.RequireUniqueEmail = true;
options.SignIn.RequireConfirmedEmail = true;
})
.AddEntityFrameworkStores<QuestLogDbContext>()
.AddApiEndpoints();
// Set up DB Connection and Seeding
builder.SetupDb();
// Modify Cookie
builder.Services.ConfigureApplicationCookie(options =>
{
options.Cookie.HttpOnly = true;
if (builder.Environment.IsDevelopment())
{
options.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest;
options.Cookie.SameSite = SameSiteMode.None;
}
else
{
options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
options.Cookie.SameSite = SameSiteMode.None;
}
// Cookie expires in 15 days of inactivity
options.ExpireTimeSpan = TimeSpan.FromDays(15);
options.SlidingExpiration = true;
// Just send an unauthorized status code, the React frontend will handle the redirection
options.Events.OnRedirectToLogin = context =>
{
context.Response.StatusCode = 401;
return Task.CompletedTask;
};
});
// Load and validate app settings
builder.Services.AddOptions<QuestLogSettings>()
.Bind(builder.Configuration.GetSection("QuestLogSettings"))
.ValidateDataAnnotations()
.ValidateOnStart();
builder.Services.ConfigureHttpJsonOptions(options =>
{
// Convert enum values to their string representation
options.SerializerOptions.Converters.Add(new JsonStringEnumConverter());
});
var app = builder.Build();
app.UseHttpsRedirection();
app.UseDefaultFiles();
app.UseStaticFiles();
// app.UseCors("Frontend");
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.MapOpenApi();
app.ApplyMigrations();
app.MapScalarApiReference();
}
app.UseAuthentication();
app.UseAuthorization();
app.MapAuthEndpoints();
app.MapCharacterClassEndpoints();
app.MapAdventurerEndpoints();
app.MapQuestEndpoints();
// Hand a route request to React if .NET doesn't find a matching API endpoint
app.MapFallbackToFile("index.html");
app.Run();