#nullable enable using System.Collections.Generic; using System.Threading.Tasks; using BTCPayServer.Data; using BTCPayServer.Abstractions.Constants; using BTCPayServer.HostedServices; using BTCPayServer.Services; using BTCPayServer.Services.Apps; using BTCPayServer.Services.Invoices; using BTCPayServer.Services.PaymentRequests; using BTCPayServer.Services.Stores; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; namespace BTCPayServer.Security; // Note: Plugins should rather put controller-specific filters rather than this global one public class SetContextFilter( PaymentRequestRepository paymentRequestRepository, InvoiceRepository invoiceRepository, AppService appService, PullPaymentHostedService pullPaymentHostedService, StoreRepository storeRepository) : IAsyncActionFilter { public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { var httpContext = context.HttpContext; var userId = context.HttpContext.User.GetId(); var isCookie = context.HttpContext.User.Identity is { AuthenticationType: AuthenticationSchemes.Cookie }; if (httpContext.Items.TryGetValue(BuiltInPermissionHandler.StoreKey, out var oo) && oo is StoreData store) { httpContext.SetStoreData(store); if (isCookie) httpContext.SetNavStoreData(store); } else if (isCookie && httpContext.GetUserPrefsCookie()?.CurrentStoreId is string preferredStoreId) { var nav = httpContext.GetCachedStoreData(preferredStoreId); if (nav is null) { nav = await storeRepository.FindStore(preferredStoreId, httpContext.User, true); if (nav is not null) httpContext.AddCachedStoreData(nav); } httpContext.SetNavStoreData(nav); } if (httpContext.Items.TryGetValue(BuiltInPermissionHandler.StoresKey, out var ooo) && ooo is StoreData[] stores) httpContext.SetStoresData(stores); //TODO: We should probably do this on controller specific filters, this would be better example for plugins if (httpContext.Items.TryGetValue(BuiltInPermissionScopeProvider.AdditionalScopeKey, out var o) && o is IEnumerable additionalScopes) { foreach (var additionalScope in additionalScopes) { switch (additionalScope.ScopeName) { case "appId": var app = await appService.GetAppData(userId, additionalScope.Scope); if (app is not null) httpContext.SetAppData(app); break; case "payReqId" or "paymentRequestId": var paymentRequest = await paymentRequestRepository.FindPaymentRequest(additionalScope.Scope, userId); if (paymentRequest is not null) httpContext.SetPaymentRequestData(paymentRequest); break; case "invoiceId": var invoice = await invoiceRepository.GetInvoice(additionalScope.Scope, true); if (invoice is not null) httpContext.SetInvoiceData(invoice); break; case "pullPaymentId": { var pp = await pullPaymentHostedService.GetPullPayment(additionalScope.Scope, false); if (pp is not null) httpContext.SetPullPaymentData(pp); break; } } } } await next(); } }