using BTCPayServer.Configuration; using Microsoft.AspNetCore.Hosting; using System; using System.Collections.Generic; using System.Text; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.AspNetCore.Http; using NBitpayClient; using NBitcoin; using BTCPayServer.Data; using Microsoft.EntityFrameworkCore; using System.IO; using Microsoft.Data.Sqlite; using NBXplorer; using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.Hosting; using BTCPayServer.Services; using BTCPayServer.Servcices.Invoices; using BTCPayServer.Services.Rates; using BTCPayServer.Services.Stores; using BTCPayServer.Services.Fees; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Rewrite; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Options; using Microsoft.AspNetCore.Authorization; using BTCPayServer.Controllers; using BTCPayServer.Services.Mails; using Microsoft.AspNetCore.Identity; using BTCPayServer.Models; using System.Threading.Tasks; using System.Threading; using BTCPayServer.Services.Wallets; using BTCPayServer.Authentication; namespace BTCPayServer.Hosting { public static class BTCPayServerServices { public class OwnStoreAuthorizationRequirement : IAuthorizationRequirement { public OwnStoreAuthorizationRequirement() { } public OwnStoreAuthorizationRequirement(string role) { Role = role; } public string Role { get; set; } } public class OwnStoreHandler : AuthorizationHandler { StoreRepository _StoreRepository; UserManager _UserManager; public OwnStoreHandler(StoreRepository storeRepository, UserManager userManager) { _StoreRepository = storeRepository; _UserManager = userManager; } protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, OwnStoreAuthorizationRequirement requirement) { object storeId = null; if(!((Microsoft.AspNetCore.Mvc.ActionContext)context.Resource).RouteData.Values.TryGetValue("storeId", out storeId)) context.Succeed(requirement); else { var store = await _StoreRepository.FindStore((string)storeId, _UserManager.GetUserId(((Microsoft.AspNetCore.Mvc.ActionContext)context.Resource).HttpContext.User)); if(store != null) if(requirement.Role == null || requirement.Role == store.Role) context.Succeed(requirement); } } } class BTCPayServerConfigureOptions : IConfigureOptions { BTCPayServerOptions _Options; public BTCPayServerConfigureOptions(BTCPayServerOptions options) { _Options = options; } public void Configure(MvcOptions options) { if(_Options.RequireHttps) options.Filters.Add(new RequireHttpsAttribute()); } } public static IServiceCollection AddBTCPayServer(this IServiceCollection services) { services.AddDbContext((provider, o) => { var factory = provider.GetRequiredService(); factory.ConfigureBuilder(o); }); services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddSingleton(o => o.GetRequiredService>().Value); services.TryAddSingleton, BTCPayServerConfigureOptions>(); services.TryAddSingleton(o => { var runtime = new BTCPayServerRuntime(); runtime.Configure(o.GetRequiredService()); return runtime; }); services.TryAddSingleton(); services.TryAddSingleton(o => o.GetRequiredService().InvoiceRepository); services.TryAddSingleton(o => o.GetRequiredService().Network); services.TryAddSingleton(o => o.GetRequiredService().DBFactory); services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddSingleton(o => new NBXplorerFeeProvider() { Fallback = new FeeRate(100, 1), BlockTarget = 20, ExplorerClient = o.GetRequiredService() }); services.TryAddSingleton(o => { var runtime = o.GetRequiredService(); return runtime.Explorer; }); services.TryAddSingleton(o => { if(o.GetRequiredService().Network == Network.Main) return new Bitpay(new Key(), new Uri("https://bitpay.com/")); else return new Bitpay(new Key(), new Uri("https://test.bitpay.com/")); }); services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddSingleton(o => o.GetRequiredService()); services.TryAddScoped(); services.TryAddSingleton(); services.AddTransient(); services.AddTransient(); // Add application services. services.AddTransient(); services.AddAuthorization(o => { o.AddPolicy("CanAccessStore", builder => { builder.AddRequirements(new OwnStoreAuthorizationRequirement()); }); o.AddPolicy("OwnStore", builder => { builder.AddRequirements(new OwnStoreAuthorizationRequirement("Owner")); }); }); return services; } public static IApplicationBuilder UsePayServer(this IApplicationBuilder app) { if(app.ApplicationServices.GetRequiredService().RequireHttps) { var options = new RewriteOptions().AddRedirectToHttps(); app.UseRewriter(options); } using(var scope = app.ApplicationServices.GetService().CreateScope()) { //Wait the DB is ready Retry(() => { scope.ServiceProvider.GetRequiredService().Database.Migrate(); }); } app.UseMiddleware(); return app; } static void Retry(Action act) { CancellationTokenSource cts = new CancellationTokenSource(10000); while(true) { try { act(); return; } catch { if(cts.IsCancellationRequested) throw; Thread.Sleep(1000); } } } } }