btcpayserver/BTCPayServer/Hosting/BTCPayServerServices.cs

354 lines
17 KiB
C#
Raw Normal View History

2020-06-28 21:44:35 -05:00
using System;
2017-09-13 15:47:34 +09:00
using System.IO;
2017-09-27 23:56:43 +09:00
using System.Threading;
2020-06-28 17:55:27 +09:00
using BTCPayServer.Configuration;
2020-07-28 22:48:51 +02:00
using BTCPayServer.Contracts;
2020-06-28 17:55:27 +09:00
using BTCPayServer.Controllers;
using BTCPayServer.Data;
using BTCPayServer.HostedServices;
2020-06-28 17:55:27 +09:00
using BTCPayServer.Logging;
2019-01-14 22:43:29 +01:00
using BTCPayServer.PaymentRequest;
2019-05-24 06:11:38 +00:00
using BTCPayServer.Payments;
using BTCPayServer.Payments.Bitcoin;
2019-01-07 09:52:27 +01:00
using BTCPayServer.Payments.Lightning;
2020-01-06 13:57:32 +01:00
using BTCPayServer.Payments.PayJoin;
2018-04-30 02:33:42 +09:00
using BTCPayServer.Security;
2019-10-12 20:35:30 +09:00
using BTCPayServer.Security.Bitpay;
2020-03-27 12:55:21 +09:00
using BTCPayServer.Security.GreenField;
2020-06-28 17:55:27 +09:00
using BTCPayServer.Services;
using BTCPayServer.Services.Apps;
using BTCPayServer.Services.Fees;
using BTCPayServer.Services.Invoices;
using BTCPayServer.Services.Labels;
2020-06-28 17:55:27 +09:00
using BTCPayServer.Services.Mails;
using BTCPayServer.Services.Notifications;
2020-06-16 23:29:25 +09:00
using BTCPayServer.Services.Notifications.Blobs;
2020-06-28 17:55:27 +09:00
using BTCPayServer.Services.PaymentRequests;
using BTCPayServer.Services.Rates;
using BTCPayServer.Services.Shopify;
2020-06-28 17:55:27 +09:00
using BTCPayServer.Services.Stores;
using BTCPayServer.Services.Wallets;
using BTCPayServer.U2F;
using BundlerMinifier.TagHelpers;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using NBitcoin;
using NBitpayClient;
using NBXplorer.DerivationStrategy;
2020-06-24 10:34:09 +09:00
using Newtonsoft.Json;
2020-06-28 17:55:27 +09:00
using NicolasDorier.RateLimits;
using Serilog;
#if ALTCOINS
2020-07-28 22:48:51 +02:00
using BTCPayServer.Services.Altcoins.Monero;
using BTCPayServer.Services.Altcoins.Ethereum;
2020-07-28 22:48:51 +02:00
#endif
2017-09-13 15:47:34 +09:00
namespace BTCPayServer.Hosting
{
public static class BTCPayServerServices
{
2020-06-24 10:34:09 +09:00
public static IServiceCollection RegisterJsonConverter(this IServiceCollection services, Func<BTCPayNetwork, JsonConverter> create)
{
services.AddSingleton<IJsonConverterRegistration, JsonConverterRegistration>((s) => new JsonConverterRegistration(create));
return services;
}
public static IServiceCollection AddBTCPayServer(this IServiceCollection services, IConfiguration configuration)
{
2020-06-28 17:55:27 +09:00
services.AddSingleton<MvcNewtonsoftJsonOptions>(o => o.GetRequiredService<IOptions<MvcNewtonsoftJsonOptions>>().Value);
services.AddDbContext<ApplicationDbContext>((provider, o) =>
{
var factory = provider.GetRequiredService<ApplicationDbContextFactory>();
factory.ConfigureBuilder(o);
});
2018-08-21 14:33:13 +09:00
services.AddHttpClient();
2019-06-18 13:37:24 +09:00
services.AddHttpClient(nameof(ExplorerClientProvider), httpClient =>
{
httpClient.Timeout = Timeout.InfiniteTimeSpan;
});
2020-06-24 10:34:09 +09:00
services.AddSingleton<BTCPayNetworkJsonSerializerSettings>();
services.RegisterJsonConverter(n => new ClaimDestinationJsonConverter(n));
2020-01-06 13:57:32 +01:00
services.AddPayJoinServices();
#if ALTCOINS
services.AddMoneroLike();
services.AddEthereumLike();
2020-07-28 22:48:51 +02:00
#endif
services.TryAddSingleton<SettingsRepository>();
services.TryAddSingleton<LabelFactory>();
services.TryAddSingleton<TorServices>();
services.TryAddSingleton<SocketFactory>();
services.TryAddSingleton<LightningClientFactoryService>();
services.TryAddSingleton<InvoicePaymentNotification>();
services.TryAddSingleton<BTCPayServerOptions>(o =>
o.GetRequiredService<IOptions<BTCPayServerOptions>>().Value);
services.AddStartupTask<MigrationStartupTask>();
services.TryAddSingleton<InvoiceRepository>(o =>
{
var opts = o.GetRequiredService<BTCPayServerOptions>();
var dbContext = o.GetRequiredService<ApplicationDbContextFactory>();
var dbpath = Path.Combine(opts.DataDir, "InvoiceDB");
if (!Directory.Exists(dbpath))
Directory.CreateDirectory(dbpath);
2020-07-24 09:40:37 +02:00
return new InvoiceRepository(dbContext, dbpath, o.GetRequiredService<BTCPayNetworkProvider>(), o.GetService<EventAggregator>());
});
services.AddSingleton<BTCPayServerEnvironment>();
services.TryAddSingleton<TokenRepository>();
services.TryAddSingleton<WalletRepository>();
services.TryAddSingleton<EventAggregator>();
2019-01-14 22:43:29 +01:00
services.TryAddSingleton<PaymentRequestService>();
services.TryAddSingleton<U2FService>();
2020-06-28 17:55:27 +09:00
services.TryAddSingleton<ApplicationDbContextFactory>(o =>
{
var opts = o.GetRequiredService<BTCPayServerOptions>();
ApplicationDbContextFactory dbContext = null;
if (!string.IsNullOrEmpty(opts.PostgresConnectionString))
{
Logs.Configuration.LogInformation($"Postgres DB used");
dbContext = new ApplicationDbContextFactory(DatabaseType.Postgres, opts.PostgresConnectionString);
}
else if (!string.IsNullOrEmpty(opts.MySQLConnectionString))
{
Logs.Configuration.LogInformation($"MySQL DB used");
2019-09-06 15:13:26 +09:00
Logs.Configuration.LogWarning("MySQL is not widely tested and should be considered experimental, we advise you to use postgres instead.");
dbContext = new ApplicationDbContextFactory(DatabaseType.MySQL, opts.MySQLConnectionString);
}
else if (!string.IsNullOrEmpty(opts.SQLiteFileName))
{
var connStr = "Data Source=" +(Path.IsPathRooted(opts.SQLiteFileName)
? opts.SQLiteFileName
: Path.Combine(opts.DataDir, opts.SQLiteFileName));
Logs.Configuration.LogInformation($"SQLite DB used");
Logs.Configuration.LogWarning("SQLite is not widely tested and should be considered experimental, we advise you to use postgres instead.");
dbContext = new ApplicationDbContextFactory(DatabaseType.Sqlite, connStr);
}
else
{
throw new ConfigException("No database option was configured.");
}
2020-06-28 17:55:27 +09:00
return dbContext;
});
2020-06-28 17:55:27 +09:00
services.TryAddSingleton<BTCPayNetworkProvider>(o =>
{
var opts = o.GetRequiredService<BTCPayServerOptions>();
return opts.NetworkProvider;
});
2019-02-19 13:04:58 +09:00
services.TryAddSingleton<AppService>();
services.AddSingleton<ExtensionService>();
services.TryAddTransient<Safe>();
services.TryAddSingleton<Ganss.XSS.HtmlSanitizer>(o =>
{
var htmlSanitizer = new Ganss.XSS.HtmlSanitizer();
htmlSanitizer.RemovingAtRule += (sender, args) =>
{
};
htmlSanitizer.RemovingTag += (sender, args) =>
{
if (args.Tag.TagName.Equals("img", StringComparison.InvariantCultureIgnoreCase))
{
if (!args.Tag.ClassList.Contains("img-fluid"))
{
args.Tag.ClassList.Add("img-fluid");
}
args.Cancel = true;
}
};
htmlSanitizer.RemovingAttribute += (sender, args) =>
{
if (args.Tag.TagName.Equals("img", StringComparison.InvariantCultureIgnoreCase) &&
args.Attribute.Name.Equals("src", StringComparison.InvariantCultureIgnoreCase) &&
args.Reason == Ganss.XSS.RemoveReason.NotAllowedUrlValue)
{
args.Cancel = true;
}
};
htmlSanitizer.RemovingStyle += (sender, args) => { args.Cancel = true; };
htmlSanitizer.AllowedAttributes.Add("class");
htmlSanitizer.AllowedTags.Add("iframe");
htmlSanitizer.AllowedTags.Add("style");
htmlSanitizer.AllowedTags.Remove("img");
htmlSanitizer.AllowedAttributes.Add("webkitallowfullscreen");
htmlSanitizer.AllowedAttributes.Add("allowfullscreen");
return htmlSanitizer;
});
2018-07-22 18:38:14 +09:00
services.TryAddSingleton<LightningConfigurationProvider>();
2018-03-23 17:27:48 +09:00
services.TryAddSingleton<LanguageService>();
2018-01-08 04:14:35 +09:00
services.TryAddSingleton<NBXplorerDashboard>();
2020-07-28 22:48:51 +02:00
services.TryAddSingleton<ISyncSummaryProvider, NBXSyncSummaryProvider>();
services.TryAddSingleton<StoreRepository>();
2019-01-14 22:43:29 +01:00
services.TryAddSingleton<PaymentRequestRepository>();
services.TryAddSingleton<BTCPayWalletProvider>();
services.TryAddSingleton<WalletReceiveStateService>();
services.TryAddSingleton<CurrencyNameTable>(CurrencyNameTable.Instance);
services.TryAddSingleton<IFeeProviderFactory>(o => new NBXplorerFeeProviderFactory(o.GetRequiredService<ExplorerClientProvider>())
{
Fallback = new FeeRate(100L, 1)
});
services.AddSingleton<CssThemeManager>();
2020-06-28 17:55:27 +09:00
services.Configure<MvcOptions>((o) =>
{
2018-07-26 22:32:24 +09:00
o.Filters.Add(new ContentSecurityPolicyCssThemeManager());
o.ModelMetadataDetailsProviders.Add(new SuppressChildValidationMetadataProvider(typeof(WalletId)));
o.ModelMetadataDetailsProviders.Add(new SuppressChildValidationMetadataProvider(typeof(DerivationStrategyBase)));
});
services.AddSingleton<IHostedService, CssThemeManagerHostedService>();
services.AddSingleton<HostedServices.CheckConfigurationHostedService>();
services.AddSingleton<IHostedService, HostedServices.CheckConfigurationHostedService>(o => o.GetRequiredService<CheckConfigurationHostedService>());
2020-06-24 10:34:09 +09:00
services.AddSingleton<HostedServices.PullPaymentHostedService>();
services.AddSingleton<IHostedService, HostedServices.PullPaymentHostedService>(o => o.GetRequiredService<PullPaymentHostedService>());
2019-05-24 06:11:38 +00:00
services.AddSingleton<BitcoinLikePaymentHandler>();
services.AddSingleton<IPaymentMethodHandler>(provider => provider.GetService<BitcoinLikePaymentHandler>());
services.AddSingleton<IHostedService, NBXplorerListener>();
2019-01-07 09:52:27 +01:00
services.AddSingleton<LightningLikePaymentHandler>();
2019-05-24 06:11:38 +00:00
services.AddSingleton<IPaymentMethodHandler>(provider => provider.GetService<LightningLikePaymentHandler>());
services.AddSingleton<IHostedService, LightningListener>();
services.AddSingleton<PaymentMethodHandlerDictionary>();
services.AddSingleton<NotificationManager>();
services.AddScoped<NotificationSender>();
services.AddSingleton<IHostedService, NBXplorerWaiters>();
services.AddSingleton<IHostedService, InvoiceNotificationManager>();
services.AddSingleton<IHostedService, InvoiceWatcher>();
services.AddSingleton<IHostedService, RatesHostedService>();
2019-01-16 19:14:45 +09:00
services.AddSingleton<IHostedService, BackgroundJobSchedulerHostedService>();
services.AddSingleton<IHostedService, AppHubStreamer>();
services.AddSingleton<IHostedService, AppInventoryUpdaterHostedService>();
services.AddSingleton<IHostedService, TransactionLabelMarkerHostedService>();
services.AddSingleton<IHostedService, UserEventHostedService>();
2019-07-24 17:59:30 +09:00
services.AddSingleton<IHostedService, DynamicDnsHostedService>();
2019-03-17 21:07:24 +09:00
services.AddSingleton<IHostedService, TorServicesHostedService>();
2019-01-14 22:43:29 +01:00
services.AddSingleton<IHostedService, PaymentRequestStreamer>();
services.AddSingleton<IHostedService, WalletReceiveCacheUpdater>();
2019-01-16 19:14:45 +09:00
services.AddSingleton<IBackgroundJobClient, BackgroundJobClient>();
2019-10-12 20:35:30 +09:00
services.AddScoped<IAuthorizationHandler, CookieAuthorizationHandler>();
services.AddScoped<IAuthorizationHandler, BitpayAuthorizationHandler>();
2020-07-30 20:43:44 -05:00
services.AddSingleton<IVersionFetcher, GithubVersionFetcher>();
services.AddSingleton<IHostedService, NewVersionCheckerHostedService>();
2020-06-16 23:29:25 +09:00
services.AddSingleton<INotificationHandler, NewVersionNotification.Handler>();
services.AddSingleton<INotificationHandler, InvoiceEventNotification.Handler>();
2020-06-24 10:34:09 +09:00
services.AddSingleton<INotificationHandler, PayoutNotification.Handler>();
2020-09-18 17:20:31 +02:00
services.AddShopify();
#if DEBUG
services.AddSingleton<INotificationHandler, JunkNotification.Handler>();
#endif
services.TryAddSingleton<ExplorerClientProvider>();
services.TryAddSingleton<Bitpay>(o =>
{
2018-04-19 16:54:25 +09:00
if (o.GetRequiredService<BTCPayServerOptions>().NetworkType == NetworkType.Mainnet)
return new Bitpay(new Key(), new Uri("https://bitpay.com/"));
else
return new Bitpay(new Key(), new Uri("https://test.bitpay.com/"));
});
services.TryAddSingleton<RateProviderFactory>();
services.TryAddSingleton<RateFetcher>();
services.TryAddScoped<IHttpContextAccessor, HttpContextAccessor>();
services.AddTransient<AccessTokenController>();
services.AddTransient<InvoiceController>();
2018-12-28 12:07:15 +01:00
services.AddTransient<AppsPublicController>();
2019-01-14 22:43:29 +01:00
services.AddTransient<PaymentRequestController>();
// Add application services.
2019-01-06 15:53:37 +01:00
services.AddSingleton<EmailSenderFactory>();
2020-06-28 17:55:27 +09:00
services.AddAPIKeyAuthentication();
services.AddBtcPayServerAuthenticationSchemes();
2019-10-12 20:35:30 +09:00
services.AddAuthorization(o => o.AddBTCPayPolicies());
// bundling
services.AddSingleton<IBundleProvider, ResourceBundleProvider>();
services.AddTransient<BundleOptions>(provider =>
{
var opts = provider.GetRequiredService<BTCPayServerOptions>();
var bundle = new BundleOptions();
2018-08-25 23:08:46 +09:00
bundle.UseBundles = opts.BundleJsCss;
bundle.AppendVersion = true;
return bundle;
});
2017-09-15 19:25:02 +09:00
services.AddCors(options =>
{
options.AddPolicy(CorsPolicies.All, p => p.AllowAnyHeader().AllowAnyMethod().AllowAnyOrigin());
});
services.AddSingleton(provider =>
{
var btcPayEnv = provider.GetService<BTCPayServerEnvironment>();
var rateLimits = new RateLimitService();
2020-07-30 20:43:44 -05:00
if (btcPayEnv.IsDeveloping)
{
rateLimits.SetZone($"zone={ZoneLimits.Login} rate=1000r/min burst=100 nodelay");
rateLimits.SetZone($"zone={ZoneLimits.Register} rate=1000r/min burst=100 nodelay");
2020-01-06 13:57:32 +01:00
rateLimits.SetZone($"zone={ZoneLimits.PayJoin} rate=1000r/min burst=100 nodelay");
rateLimits.SetZone($"zone={ZoneLimits.Shopify} rate=1000r/min burst=100 nodelay");
}
else
{
rateLimits.SetZone($"zone={ZoneLimits.Login} rate=5r/min burst=3 nodelay");
rateLimits.SetZone($"zone={ZoneLimits.Register} rate=2r/min burst=2 nodelay");
2020-03-13 16:52:50 +01:00
rateLimits.SetZone($"zone={ZoneLimits.PayJoin} rate=5r/min burst=3 nodelay");
rateLimits.SetZone($"zone={ZoneLimits.Shopify} rate=20r/min burst=3 nodelay");
}
return rateLimits;
});
services.AddLogging(logBuilder =>
{
var debugLogFile = BTCPayServerOptions.GetDebugLog(configuration);
if (!string.IsNullOrEmpty(debugLogFile))
{
Serilog.Log.Logger = new LoggerConfiguration()
.Enrich.FromLogContext()
.MinimumLevel.Is(BTCPayServerOptions.GetDebugLogLevel(configuration))
.WriteTo.File(debugLogFile, rollingInterval: RollingInterval.Day, fileSizeLimitBytes: MAX_DEBUG_LOG_FILE_SIZE, rollOnFileSizeLimit: true, retainedFileCountLimit: 1)
.CreateLogger();
2020-01-16 14:00:31 +09:00
logBuilder.AddProvider(new Serilog.Extensions.Logging.SerilogLoggerProvider(Log.Logger));
}
});
return services;
}
private const long MAX_DEBUG_LOG_FILE_SIZE = 2000000; // If debug log is in use roll it every N MB.
private static void AddBtcPayServerAuthenticationSchemes(this IServiceCollection services)
{
services.AddAuthentication()
.AddCookie()
.AddBitpayAuthentication()
.AddAPIKeyAuthentication();
}
2017-09-13 15:47:34 +09:00
public static IApplicationBuilder UsePayServer(this IApplicationBuilder app)
{
app.UseMiddleware<BTCPayMiddleware>();
2020-06-28 17:55:27 +09:00
return app;
}
public static IApplicationBuilder UseHeadersOverride(this IApplicationBuilder app)
{
app.UseMiddleware<HeadersOverrideMiddleware>();
return app;
}
}
2017-09-13 15:47:34 +09:00
}