btcpayserver/BTCPayServer/Hosting/Startup.cs

226 lines
9.4 KiB
C#
Raw Normal View History

2020-06-29 04:44:35 +02:00
using System;
2017-09-25 10:18:13 +02:00
using System.IO;
2018-02-12 19:27:36 +01:00
using System.Net;
2020-06-28 10:55:27 +02:00
using BTCPayServer.Configuration;
using BTCPayServer.Data;
using BTCPayServer.Filters;
using BTCPayServer.Logging;
2019-02-22 11:37:45 +01:00
using BTCPayServer.PaymentRequest;
2020-06-28 10:55:27 +02:00
using BTCPayServer.Security;
using BTCPayServer.Services.Apps;
using BTCPayServer.Storage;
2020-06-28 10:55:27 +02:00
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Net.Http.Headers;
2017-09-13 08:47:34 +02:00
namespace BTCPayServer.Hosting
{
public class Startup
{
2019-10-03 10:06:49 +02:00
public Startup(IConfiguration conf, IWebHostEnvironment env, ILoggerFactory loggerFactory)
{
Configuration = conf;
_Env = env;
LoggerFactory = loggerFactory;
}
readonly IWebHostEnvironment _Env;
public IConfiguration Configuration
{
get; set;
}
public ILoggerFactory LoggerFactory { get; }
2017-09-13 08:47:34 +02:00
public void ConfigureServices(IServiceCollection services)
{
Logs.Configure(LoggerFactory);
services.ConfigureBTCPayServer(Configuration);
services.AddMemoryCache();
2020-01-26 07:02:40 +01:00
services.AddDataProtection()
.SetApplicationName("BTCPay Server")
.PersistKeysToFileSystem(GetDataDir());
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
2019-10-08 08:21:30 +02:00
.AddDefaultTokenProviders();
services.AddBTCPayServer(Configuration);
services.AddProviderStorage();
services.AddSession();
services.AddSignalR();
services.AddMvc(o =>
{
o.Filters.Add(new XFrameOptionsAttribute("DENY"));
2018-07-11 18:43:16 +02:00
o.Filters.Add(new XContentTypeOptionsAttribute("nosniff"));
2018-07-11 19:23:54 +02:00
o.Filters.Add(new XXSSProtectionAttribute());
2018-07-11 19:38:08 +02:00
o.Filters.Add(new ReferrerPolicyAttribute("same-origin"));
2018-07-12 11:19:43 +02:00
//o.Filters.Add(new ContentSecurityPolicyAttribute()
//{
// FontSrc = "'self' https://fonts.gstatic.com/",
// ImgSrc = "'self' data:",
// DefaultSrc = "'none'",
// StyleSrc = "'self' 'unsafe-inline'",
// ScriptSrc = "'self' 'unsafe-inline'"
//});
2019-10-06 08:54:19 +02:00
})
.ConfigureApiBehaviorOptions(options =>
{
var builtInFactory = options.InvalidModelStateResponseFactory;
options.InvalidModelStateResponseFactory = context =>
{
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.UnprocessableEntity;
return builtInFactory(context);
};
})
.AddRazorOptions(o =>
{
// /Components/{View Component Name}/{View Name}.cshtml
o.ViewLocationFormats.Add("/{0}.cshtml");
o.PageViewLocationFormats.Add("/{0}.cshtml");
})
2019-10-06 08:54:19 +02:00
.AddNewtonsoftJson()
#if RAZOR_RUNTIME_COMPILE
.AddRazorRuntimeCompilation()
2019-10-06 08:54:19 +02:00
#endif
.AddControllersAsServices();
2018-07-12 10:38:21 +02:00
services.TryAddScoped<ContentSecurityPolicies>();
2018-01-04 14:56:49 +01:00
services.Configure<IdentityOptions>(options =>
{
options.Password.RequireDigit = false;
options.Password.RequiredLength = 6;
2018-01-04 14:56:49 +01:00
options.Password.RequireLowercase = false;
options.Password.RequireNonAlphanumeric = false;
options.Password.RequireUppercase = false;
2018-09-12 13:36:44 +02:00
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);
options.Lockout.MaxFailedAccessAttempts = 5;
options.Lockout.AllowedForNewUsers = true;
2019-10-08 08:21:30 +02:00
options.Password.RequireUppercase = false;
2018-01-04 14:56:49 +01:00
});
// If the HTTPS certificate path is not set this logic will NOT be used and the default Kestrel binding logic will be.
string httpsCertificateFilePath = Configuration.GetOrDefault<string>("HttpsCertificateFilePath", null);
bool useDefaultCertificate = Configuration.GetOrDefault<bool>("HttpsUseDefaultCertificate", false);
bool hasCertPath = !String.IsNullOrEmpty(httpsCertificateFilePath);
2019-07-12 05:23:13 +02:00
services.Configure<KestrelServerOptions>(kestrel =>
{
kestrel.Limits.MaxRequestLineSize = 8_192 * 10 * 5; // Around 500K, transactions passed in URI should not be bigger than this
});
if (hasCertPath || useDefaultCertificate)
{
var bindAddress = Configuration.GetOrDefault<IPAddress>("bind", IPAddress.Any);
int bindPort = Configuration.GetOrDefault<int>("port", 443);
services.Configure<KestrelServerOptions>(kestrel =>
{
if (hasCertPath && !File.Exists(httpsCertificateFilePath))
{
// Note that by design this is a fatal error condition that will cause the process to exit.
throw new ConfigException($"The https certificate file could not be found at {httpsCertificateFilePath}.");
}
2019-10-08 08:21:30 +02:00
if (hasCertPath && useDefaultCertificate)
{
throw new ConfigException($"Conflicting settings: if HttpsUseDefaultCertificate is true, HttpsCertificateFilePath should not be used");
}
kestrel.Listen(bindAddress, bindPort, l =>
{
if (hasCertPath)
{
Logs.Configuration.LogInformation($"Using HTTPS with the certificate located in {httpsCertificateFilePath}.");
l.UseHttps(httpsCertificateFilePath, Configuration.GetOrDefault<string>("HttpsCertificateFilePassword", null));
}
else
{
Logs.Configuration.LogInformation($"Using HTTPS with the default certificate");
l.UseHttps();
}
});
});
}
}
public void Configure(
IApplicationBuilder app,
2019-10-03 10:06:49 +02:00
IWebHostEnvironment env,
IServiceProvider prov,
2018-04-05 08:50:23 +02:00
BTCPayServerOptions options,
ILoggerFactory loggerFactory)
2018-04-05 08:50:23 +02:00
{
Logs.Configuration.LogInformation($"Root Path: {options.RootPath}");
if (options.RootPath.Equals("/", StringComparison.OrdinalIgnoreCase))
{
2018-04-09 07:41:52 +02:00
ConfigureCore(app, env, prov, loggerFactory, options);
2018-04-05 08:50:23 +02:00
}
else
{
app.Map(options.RootPath, appChild =>
{
2018-04-09 07:41:52 +02:00
ConfigureCore(appChild, env, prov, loggerFactory, options);
2018-04-05 08:50:23 +02:00
});
}
}
2020-02-24 16:40:04 +01:00
private DirectoryInfo GetDataDir()
{
return new DirectoryInfo(Configuration.GetDataDir(DefaultConfiguration.GetNetworkType(Configuration)));
}
2018-04-05 08:50:23 +02:00
2019-10-03 10:06:49 +02:00
private static void ConfigureCore(IApplicationBuilder app, IWebHostEnvironment env, IServiceProvider prov, ILoggerFactory loggerFactory, BTCPayServerOptions options)
{
Logs.Configure(loggerFactory);
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHeadersOverride();
2019-03-04 14:34:14 +01:00
var forwardingOptions = new ForwardedHeadersOptions()
{
2019-03-04 14:34:14 +01:00
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
};
forwardingOptions.KnownNetworks.Clear();
forwardingOptions.KnownProxies.Clear();
forwardingOptions.ForwardedHeaders = ForwardedHeaders.All;
app.UseForwardedHeaders(forwardingOptions);
app.UseStatusCodePagesWithReExecute("/Error/Handle", "?statusCode={0}");
app.UsePayServer();
app.UseRouting();
app.UseCors();
app.UseStaticFiles(new StaticFileOptions
{
OnPrepareResponse = ctx =>
{
// Cache static assets for one year, set asp-append-version="true" on references to update on change.
// https://andrewlock.net/adding-cache-control-headers-to-static-files-in-asp-net-core/
const int durationInSeconds = 60 * 60 * 24 * 365;
ctx.Context.Response.Headers[HeaderNames.CacheControl] = "public,max-age=" + durationInSeconds;
}
});
2020-06-28 10:55:27 +02:00
app.UseProviderStorage(options);
app.UseAuthentication();
2019-10-05 18:21:00 +02:00
app.UseAuthorization();
app.UseSession();
2020-01-12 05:30:54 +01:00
app.UseWebSockets();
2020-01-12 05:30:54 +01:00
2019-10-03 11:46:09 +02:00
app.UseEndpoints(endpoints =>
{
AppHub.Register(endpoints);
PaymentRequestHub.Register(endpoints);
2019-10-05 18:21:00 +02:00
endpoints.MapControllers();
2019-10-03 11:46:09 +02:00
endpoints.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}");
});
}
}
2017-09-13 08:47:34 +02:00
}