mirror of
https://github.com/JustArchiNET/ArchiSteamFarm
synced 2024-11-10 23:24:36 +00:00
IPC: Add optional SRI support for ASF-ui
In theory, this is required only in specific proxy/CDN solutions accessing ASF data over http that would somehow want to transform the responses https://github.com/JustArchiNET/ASF-ui/pull/1470
This commit is contained in:
parent
dcacdd802c
commit
f58a9be02a
1 changed files with 57 additions and 25 deletions
|
@ -41,10 +41,12 @@ using JetBrains.Annotations;
|
|||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Headers;
|
||||
using Microsoft.AspNetCore.HttpOverrides;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
|
@ -70,35 +72,60 @@ namespace ArchiSteamFarm.IPC {
|
|||
throw new ArgumentNullException(nameof(env));
|
||||
}
|
||||
|
||||
// The order of dependency injection is super important, doing things in wrong order will break everything
|
||||
// https://docs.microsoft.com/aspnet/core/fundamentals/middleware
|
||||
|
||||
// This one is easy, it's always in the beginning
|
||||
if (Debugging.IsUserDebugging) {
|
||||
app.UseDeveloperExceptionPage();
|
||||
}
|
||||
|
||||
// The order of dependency injection matters, pay attention to it
|
||||
// Add support for proxies, this one comes usually after developer exception page, but could be before
|
||||
app.UseForwardedHeaders();
|
||||
|
||||
// TODO: Try to get rid of this workaround for missing PathBase feature, https://github.com/aspnet/AspNetCore/issues/5898
|
||||
// Add support for response compression - must be called before static files as we want to compress those as well
|
||||
app.UseResponseCompression();
|
||||
|
||||
// It's not apparent when UsePathBase() should be called, but definitely before we get down to static files
|
||||
// TODO: Maybe eventually we can get rid of this, https://github.com/aspnet/AspNetCore/issues/5898
|
||||
PathString pathBase = Configuration.GetSection("Kestrel").GetValue<PathString>("PathBase");
|
||||
|
||||
if (!string.IsNullOrEmpty(pathBase) && (pathBase != "/")) {
|
||||
app.UsePathBase(pathBase);
|
||||
}
|
||||
|
||||
// Add support for proxies
|
||||
app.UseForwardedHeaders();
|
||||
|
||||
// Add support for response compression
|
||||
app.UseResponseCompression();
|
||||
|
||||
// Add support for websockets used in /Api/NLog
|
||||
app.UseWebSockets();
|
||||
|
||||
// We're using index for URL routing in our static files so re-execute all non-API calls on /
|
||||
// The default HTML file (usually index.html) is responsible for IPC GUI routing, so re-execute all non-API calls on /
|
||||
// This must be called before default files, because we don't know the exact file name that will be used for index page
|
||||
app.UseWhen(context => !context.Request.Path.StartsWithSegments("/Api", StringComparison.OrdinalIgnoreCase), appBuilder => appBuilder.UseStatusCodePagesWithReExecute("/"));
|
||||
|
||||
// We need static files support for IPC GUI
|
||||
// Add support for default root path redirection (GET / -> GET /index.html), must come before static files
|
||||
app.UseDefaultFiles();
|
||||
app.UseStaticFiles();
|
||||
|
||||
// Add support for static files (e.g. HTML, CSS and JS from IPC GUI)
|
||||
app.UseStaticFiles(
|
||||
new StaticFileOptions {
|
||||
OnPrepareResponse = context => {
|
||||
// Add support for SRI-protected static files
|
||||
if (context.File.Exists && !context.File.IsDirectory && !string.IsNullOrEmpty(context.File.Name)) {
|
||||
string extension = Path.GetExtension(context.File.Name);
|
||||
|
||||
switch (extension.ToUpperInvariant()) {
|
||||
case ".CSS":
|
||||
case ".JS":
|
||||
ResponseHeaders headers = context.Context.Response.GetTypedHeaders();
|
||||
|
||||
headers.CacheControl = new CacheControlHeaderValue {
|
||||
NoTransform = true
|
||||
};
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Use routing for our API controllers, this should be called once we're done with all the static files mess
|
||||
#if !NETFRAMEWORK
|
||||
app.UseRouting();
|
||||
#endif
|
||||
|
@ -106,25 +133,28 @@ namespace ArchiSteamFarm.IPC {
|
|||
string? ipcPassword = ASF.GlobalConfig != null ? ASF.GlobalConfig.IPCPassword : GlobalConfig.DefaultIPCPassword;
|
||||
|
||||
if (!string.IsNullOrEmpty(ipcPassword)) {
|
||||
// We need ApiAuthenticationMiddleware for IPCPassword
|
||||
// We want to protect our API with IPCPassword, this should be called after routing, so the middleware won't have to deal with API endpoints that do not exist
|
||||
app.UseWhen(context => context.Request.Path.StartsWithSegments("/Api", StringComparison.OrdinalIgnoreCase), appBuilder => appBuilder.UseMiddleware<ApiAuthenticationMiddleware>());
|
||||
|
||||
// We want to apply CORS policy in order to allow userscripts and other third-party integrations to communicate with ASF API
|
||||
// We apply CORS policy only with IPCPassword set as extra authentication measure
|
||||
// We want to apply CORS policy in order to allow userscripts and other third-party integrations to communicate with ASF API, this should be called before response compression, but can't be due to how our flow works
|
||||
// We apply CORS policy only with IPCPassword set as an extra authentication measure
|
||||
app.UseCors();
|
||||
}
|
||||
|
||||
// Add support for mapping controllers
|
||||
// Add support for websockets that we use e.g. in /Api/NLog
|
||||
app.UseWebSockets();
|
||||
|
||||
// Finally register proper API endpoints once we're done with routing
|
||||
#if NETFRAMEWORK
|
||||
app.UseMvcWithDefaultRoute();
|
||||
#else
|
||||
app.UseEndpoints(endpoints => endpoints.MapControllers());
|
||||
#endif
|
||||
|
||||
// Use swagger for automatic API documentation generation
|
||||
// Add support for swagger, responsible for automatic API documentation generation, this should be on the end, once we're done with API
|
||||
app.UseSwagger();
|
||||
|
||||
// Use friendly swagger UI
|
||||
// Add support for swagger UI, this should be after swagger, obviously
|
||||
app.UseSwaggerUI(
|
||||
options => {
|
||||
options.DisplayRequestDuration();
|
||||
|
@ -140,9 +170,10 @@ namespace ArchiSteamFarm.IPC {
|
|||
throw new ArgumentNullException(nameof(services));
|
||||
}
|
||||
|
||||
// The order of dependency injection matters, pay attention to it
|
||||
// The order of dependency injection is super important, doing things in wrong order will break everything
|
||||
// Order in Configure() method is a good start
|
||||
|
||||
// Add support for custom reverse proxy endpoints
|
||||
// Prepare knownNetworks that we'll use in a second
|
||||
HashSet<string>? knownNetworksTexts = Configuration.GetSection("Kestrel:KnownNetworks").Get<HashSet<string>>();
|
||||
|
||||
HashSet<IPNetwork>? knownNetworks = null;
|
||||
|
@ -182,12 +213,13 @@ namespace ArchiSteamFarm.IPC {
|
|||
|
||||
string? ipcPassword = ASF.GlobalConfig != null ? ASF.GlobalConfig.IPCPassword : GlobalConfig.DefaultIPCPassword;
|
||||
|
||||
// Add CORS to allow userscripts and third-party apps
|
||||
if (!string.IsNullOrEmpty(ipcPassword)) {
|
||||
// We want to apply CORS policy in order to allow userscripts and other third-party integrations to communicate with ASF API
|
||||
// We apply CORS policy only with IPCPassword set as an extra authentication measure
|
||||
services.AddCors(options => options.AddDefaultPolicy(policyBuilder => policyBuilder.AllowAnyOrigin()));
|
||||
}
|
||||
|
||||
// Add swagger documentation generation
|
||||
// Add support for swagger, responsible for automatic API documentation generation
|
||||
services.AddSwaggerGen(
|
||||
options => {
|
||||
options.AddSecurityDefinition(
|
||||
|
@ -244,7 +276,7 @@ namespace ArchiSteamFarm.IPC {
|
|||
}
|
||||
);
|
||||
|
||||
// Add Newtonsoft.Json support for SwaggerGen, this one must be executed after AddSwaggerGen()
|
||||
// Add support for Newtonsoft.Json in swagger, this one must be executed after AddSwaggerGen()
|
||||
services.AddSwaggerGenNewtonsoftSupport();
|
||||
|
||||
// We need MVC for /Api, but we're going to use only a small subset of all available features
|
||||
|
|
Loading…
Reference in a new issue