mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2025-12-18 06:24:24 +01:00
Validate scopes of service injections in tests
This commit is contained in:
@@ -169,6 +169,10 @@ namespace BTCPayServer.Tests
|
||||
#endif
|
||||
var conf = confBuilder.Build();
|
||||
_Host = new WebHostBuilder()
|
||||
.UseDefaultServiceProvider(options =>
|
||||
{
|
||||
options.ValidateScopes = true;
|
||||
})
|
||||
.UseConfiguration(conf)
|
||||
.UseContentRoot(FindBTCPayServerDirectory())
|
||||
.UseWebRoot(Path.Combine(FindBTCPayServerDirectory(), "wwwroot"))
|
||||
@@ -284,10 +288,7 @@ namespace BTCPayServer.Tests
|
||||
public string IntegratedLightning { get; internal set; }
|
||||
public bool InContainer { get; internal set; }
|
||||
|
||||
public T GetService<T>()
|
||||
{
|
||||
return _Host.Services.GetRequiredService<T>();
|
||||
}
|
||||
public T GetService<T>() => _Host.Services.GetRequiredService<T>();
|
||||
|
||||
public IServiceProvider ServiceProvider => _Host.Services;
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ using ExchangeSharp;
|
||||
using LNURL;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Playwright;
|
||||
using static Microsoft.Playwright.Assertions;
|
||||
using NBitcoin;
|
||||
@@ -200,7 +201,8 @@ namespace BTCPayServer.Tests
|
||||
await s.Page.FillAsync("#Email", changedEmail);
|
||||
await s.ClickPagePrimary();
|
||||
await s.FindAlertMessage();
|
||||
var manager = tester.PayTester.GetService<UserManager<ApplicationUser>>();
|
||||
using var scope = tester.PayTester.ServiceProvider.CreateScope();
|
||||
var manager = scope.ServiceProvider.GetRequiredService<UserManager<ApplicationUser>>();
|
||||
Assert.NotNull(await manager.FindByNameAsync(changedEmail));
|
||||
Assert.NotNull(await manager.FindByEmailAsync(changedEmail));
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ using BTCPayServer.Services.Wallets;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using NBitcoin;
|
||||
using NBitcoin.DataEncoders;
|
||||
using NBitcoin.Payment;
|
||||
@@ -58,7 +59,8 @@ namespace BTCPayServer.Tests
|
||||
|
||||
public async Task MakeAdmin(bool isAdmin = true)
|
||||
{
|
||||
var userManager = parent.PayTester.GetService<UserManager<ApplicationUser>>();
|
||||
using var scope = parent.PayTester.ServiceProvider.CreateScope();
|
||||
var userManager = scope.ServiceProvider.GetRequiredService<UserManager<ApplicationUser>>();
|
||||
var u = await userManager.FindByIdAsync(UserId);
|
||||
if (isAdmin)
|
||||
await userManager.AddToRoleAsync(u, Roles.ServerAdmin);
|
||||
|
||||
@@ -15,7 +15,6 @@ using BTCPayServer.Data;
|
||||
using BTCPayServer.Plugins.Webhooks.Controllers;
|
||||
using BTCPayServer.Security;
|
||||
using BTCPayServer.Security.Greenfield;
|
||||
using BTCPayServer.Plugins.Emails.Services;
|
||||
using BTCPayServer.Services.Stores;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
@@ -38,26 +37,13 @@ using WebhookDeliveryData = BTCPayServer.Client.Models.WebhookDeliveryData;
|
||||
|
||||
namespace BTCPayServer.Controllers.Greenfield
|
||||
{
|
||||
public class BTCPayServerClientFactory : IBTCPayServerClientFactory
|
||||
public class BTCPayServerClientFactory(
|
||||
StoreRepository storeRepository,
|
||||
IOptionsMonitor<IdentityOptions> identityOptions,
|
||||
IServiceProvider serviceProvider,
|
||||
IServiceScopeFactory servicesScopeFactory)
|
||||
: IBTCPayServerClientFactory
|
||||
{
|
||||
private readonly StoreRepository _storeRepository;
|
||||
private readonly IOptionsMonitor<IdentityOptions> _identityOptions;
|
||||
private readonly UserManager<ApplicationUser> _userManager;
|
||||
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
|
||||
public BTCPayServerClientFactory(
|
||||
StoreRepository storeRepository,
|
||||
IOptionsMonitor<IdentityOptions> identityOptions,
|
||||
UserManager<ApplicationUser> userManager,
|
||||
IServiceProvider serviceProvider)
|
||||
{
|
||||
_storeRepository = storeRepository;
|
||||
_identityOptions = identityOptions;
|
||||
_userManager = userManager;
|
||||
_serviceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
public Task<BTCPayServerClient> Create(string userId, params string[] storeIds)
|
||||
{
|
||||
return Create(userId, storeIds, new DefaultHttpContext()
|
||||
@@ -74,17 +60,19 @@ namespace BTCPayServer.Controllers.Greenfield
|
||||
|
||||
public async Task<BTCPayServerClient> Create(string userId, string[] storeIds, HttpContext context)
|
||||
{
|
||||
using var scope = servicesScopeFactory.CreateScope();
|
||||
var userManager = scope.ServiceProvider.GetRequiredService<UserManager<ApplicationUser>>();
|
||||
if (!string.IsNullOrEmpty(userId))
|
||||
{
|
||||
var user = await _userManager.FindByIdAsync(userId);
|
||||
var user = await userManager.FindByIdAsync(userId);
|
||||
List<Claim> claims = new List<Claim>
|
||||
{
|
||||
new Claim(_identityOptions.CurrentValue.ClaimsIdentity.UserIdClaimType, userId),
|
||||
new Claim(identityOptions.CurrentValue.ClaimsIdentity.UserIdClaimType, userId),
|
||||
new Claim(GreenfieldConstants.ClaimTypes.Permission,
|
||||
Permission.Create(Policies.Unrestricted).ToString())
|
||||
};
|
||||
claims.AddRange((await _userManager.GetRolesAsync(user)).Select(s =>
|
||||
new Claim(_identityOptions.CurrentValue.ClaimsIdentity.RoleClaimType, s)));
|
||||
claims.AddRange((await userManager.GetRolesAsync(user)).Select(s =>
|
||||
new Claim(identityOptions.CurrentValue.ClaimsIdentity.RoleClaimType, s)));
|
||||
context.User =
|
||||
new ClaimsPrincipal(new ClaimsIdentity(claims,
|
||||
$"Local{GreenfieldConstants.AuthenticationType}WithUser"));
|
||||
@@ -95,22 +83,22 @@ namespace BTCPayServer.Controllers.Greenfield
|
||||
new ClaimsPrincipal(new ClaimsIdentity(
|
||||
new List<Claim>()
|
||||
{
|
||||
new(_identityOptions.CurrentValue.ClaimsIdentity.RoleClaimType, Roles.ServerAdmin)
|
||||
new(identityOptions.CurrentValue.ClaimsIdentity.RoleClaimType, Roles.ServerAdmin)
|
||||
},
|
||||
$"Local{GreenfieldConstants.AuthenticationType}"));
|
||||
}
|
||||
|
||||
if (storeIds?.Any() is true)
|
||||
{
|
||||
context.SetStoreData(await _storeRepository.FindStore(storeIds.First()));
|
||||
context.SetStoresData(await _storeRepository.GetStoresByUserId(userId, storeIds));
|
||||
context.SetStoreData(await storeRepository.FindStore(storeIds.First()));
|
||||
context.SetStoresData(await storeRepository.GetStoresByUserId(userId, storeIds));
|
||||
}
|
||||
else
|
||||
{
|
||||
context.SetStoresData(await _storeRepository.GetStoresByUserId(userId));
|
||||
context.SetStoresData(await storeRepository.GetStoresByUserId(userId));
|
||||
}
|
||||
|
||||
return ActivatorUtilities.CreateInstance<LocalBTCPayServerClient>(_serviceProvider,
|
||||
return ActivatorUtilities.CreateInstance<LocalBTCPayServerClient>(serviceProvider,
|
||||
new LocalHttpContextAccessor() { HttpContext = context });
|
||||
|
||||
}
|
||||
|
||||
@@ -39,7 +39,6 @@ namespace BTCPayServer.Controllers
|
||||
public partial class UIInvoiceController : Controller
|
||||
{
|
||||
readonly InvoiceRepository _InvoiceRepository;
|
||||
private readonly WalletRepository _walletRepository;
|
||||
readonly RateFetcher _RateProvider;
|
||||
readonly StoreRepository _StoreRepository;
|
||||
readonly UserManager<ApplicationUser> _UserManager;
|
||||
@@ -71,14 +70,12 @@ namespace BTCPayServer.Controllers
|
||||
|
||||
public UIInvoiceController(
|
||||
InvoiceRepository invoiceRepository,
|
||||
WalletRepository walletRepository,
|
||||
DisplayFormatter displayFormatter,
|
||||
CurrencyNameTable currencyNameTable,
|
||||
UserManager<ApplicationUser> userManager,
|
||||
RateFetcher rateProvider,
|
||||
StoreRepository storeRepository,
|
||||
EventAggregator eventAggregator,
|
||||
ContentSecurityPolicies csp,
|
||||
BTCPayNetworkProvider networkProvider,
|
||||
PayoutMethodHandlerDictionary payoutHandlers,
|
||||
PaymentMethodHandlerDictionary paymentMethodHandlerDictionary,
|
||||
@@ -105,7 +102,6 @@ namespace BTCPayServer.Controllers
|
||||
_CurrencyNameTable = currencyNameTable ?? throw new ArgumentNullException(nameof(currencyNameTable));
|
||||
_StoreRepository = storeRepository ?? throw new ArgumentNullException(nameof(storeRepository));
|
||||
_InvoiceRepository = invoiceRepository ?? throw new ArgumentNullException(nameof(invoiceRepository));
|
||||
_walletRepository = walletRepository;
|
||||
_RateProvider = rateProvider ?? throw new ArgumentNullException(nameof(rateProvider));
|
||||
_UserManager = userManager;
|
||||
_EventAggregator = eventAggregator;
|
||||
|
||||
@@ -43,15 +43,13 @@ namespace BTCPayServer.Data.Payouts.LightningLike
|
||||
public const string LightningLikePayoutHandlerClearnetNamedClient =
|
||||
nameof(LightningLikePayoutHandlerClearnetNamedClient);
|
||||
private readonly IHttpClientFactory _httpClientFactory;
|
||||
private readonly UserService _userService;
|
||||
private readonly IAuthorizationService _authorizationService;
|
||||
|
||||
public LightningLikePayoutHandler(
|
||||
PayoutMethodId payoutMethodId,
|
||||
IOptions<LightningNetworkOptions> options,
|
||||
BTCPayNetwork network,
|
||||
PaymentMethodHandlerDictionary paymentHandlers,
|
||||
IHttpClientFactory httpClientFactory, UserService userService, IAuthorizationService authorizationService)
|
||||
IHttpClientFactory httpClientFactory)
|
||||
{
|
||||
_paymentHandlers = paymentHandlers;
|
||||
Network = network;
|
||||
@@ -59,8 +57,6 @@ namespace BTCPayServer.Data.Payouts.LightningLike
|
||||
_options = options;
|
||||
PaymentMethodId = PaymentTypes.LN.GetPaymentMethodId(network.CryptoCode);
|
||||
_httpClientFactory = httpClientFactory;
|
||||
_userService = userService;
|
||||
_authorizationService = authorizationService;
|
||||
Currency = network.CryptoCode;
|
||||
}
|
||||
|
||||
|
||||
@@ -427,7 +427,7 @@ o.GetRequiredService<IEnumerable<IPaymentLinkExtension>>().ToDictionary(o => o.P
|
||||
services.AddSingleton<PayoutMethodHandlerDictionary>();
|
||||
|
||||
services.AddSingleton<NotificationManager>();
|
||||
services.AddScoped<NotificationSender>();
|
||||
services.AddSingleton<NotificationSender>();
|
||||
|
||||
RegisterExchangeRecommendations(services);
|
||||
services.AddSingleton<DefaultRulesCollection>();
|
||||
|
||||
@@ -11,6 +11,7 @@ using BTCPayServer.Services;
|
||||
using BTCPayServer.Services.Notifications;
|
||||
using BTCPayServer.Services.Notifications.Blobs;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using QRCoder;
|
||||
|
||||
@@ -18,14 +19,12 @@ namespace BTCPayServer.Plugins.Emails.HostedServices;
|
||||
|
||||
public class UserEventHostedService(
|
||||
EventAggregator eventAggregator,
|
||||
UserManager<ApplicationUser> userManager,
|
||||
IServiceScopeFactory serviceScopeFactory,
|
||||
ISettingsAccessor<ServerSettings> serverSettings,
|
||||
NotificationSender notificationSender,
|
||||
Logs logs)
|
||||
: EventHostedServiceBase(eventAggregator, logs)
|
||||
{
|
||||
public UserManager<ApplicationUser> UserManager { get; } = userManager;
|
||||
|
||||
protected override void SubscribeToEvents()
|
||||
{
|
||||
SubscribeAny<UserEvent>();
|
||||
@@ -117,7 +116,9 @@ public class UserEventHostedService(
|
||||
|
||||
private async Task<TriggerEvent> CreateTriggerEvent(string trigger, JObject model, ApplicationUser user)
|
||||
{
|
||||
var admins = await UserManager.GetUsersInRoleAsync(Roles.ServerAdmin);
|
||||
using var scope = serviceScopeFactory.CreateScope();
|
||||
var userManager = scope.ServiceProvider.GetRequiredService<UserManager<ApplicationUser>>();
|
||||
var admins = await userManager.GetUsersInRoleAsync(Roles.ServerAdmin);
|
||||
var adminMailboxes = string.Join(", ", admins.Select(a => a.GetMailboxAddress().ToString()).ToArray());
|
||||
model["Admins"] = new JObject()
|
||||
{
|
||||
|
||||
@@ -18,6 +18,7 @@ using BTCPayServer.Services.Rates;
|
||||
using Dapper;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using static BTCPayServer.Data.Subscriptions.SubscriberData;
|
||||
@@ -30,7 +31,7 @@ public class SubscriptionHostedService(
|
||||
EventAggregator eventAggregator,
|
||||
ApplicationDbContextFactory applicationDbContextFactory,
|
||||
SettingsRepository settingsRepository,
|
||||
UIInvoiceController invoiceController,
|
||||
IServiceScopeFactory scopeFactory,
|
||||
CurrencyNameTable currencyNameTable,
|
||||
LinkGenerator linkGenerator,
|
||||
Logs logger) : EventHostedServiceBase(eventAggregator, logger), IPeriodicTask
|
||||
@@ -162,6 +163,8 @@ public class SubscriptionHostedService(
|
||||
|
||||
if (amount > 0)
|
||||
{
|
||||
using var scope = scopeFactory.CreateScope();
|
||||
var invoiceController = scope.ServiceProvider.GetRequiredService<UIInvoiceController>();
|
||||
var request = await invoiceController.CreateInvoiceCoreRaw(new()
|
||||
{
|
||||
Currency = plan.Currency,
|
||||
|
||||
@@ -26,6 +26,10 @@ public class BTCPayServerSecurityStampValidator(
|
||||
ConcurrentDictionary<string, DateTimeOffset> _DisabledUsers = new ConcurrentDictionary<string, DateTimeOffset>();
|
||||
public bool HasAny => !_DisabledUsers.IsEmpty;
|
||||
|
||||
/// <summary>
|
||||
/// Note that you also need to invalidate the security stamp of the user
|
||||
/// </summary>
|
||||
/// <param name="user"></param>
|
||||
public void Add(string user)
|
||||
{
|
||||
_DisabledUsers.TryAdd(user, DateTimeOffset.UtcNow);
|
||||
|
||||
@@ -6,6 +6,7 @@ using BTCPayServer.Abstractions.Contracts;
|
||||
using BTCPayServer.Data;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace BTCPayServer.Services.Notifications
|
||||
{
|
||||
@@ -13,25 +14,15 @@ namespace BTCPayServer.Services.Notifications
|
||||
{
|
||||
public string UserId { get; set; }
|
||||
}
|
||||
public class NotificationSender
|
||||
public class NotificationSender(ApplicationDbContextFactory contextFactory, IServiceScopeFactory scopeFactory, NotificationManager notificationManager)
|
||||
{
|
||||
private readonly ApplicationDbContextFactory _contextFactory;
|
||||
private readonly UserManager<ApplicationUser> _userManager;
|
||||
private readonly NotificationManager _notificationManager;
|
||||
|
||||
public NotificationSender(ApplicationDbContextFactory contextFactory, UserManager<ApplicationUser> userManager, NotificationManager notificationManager)
|
||||
{
|
||||
_contextFactory = contextFactory;
|
||||
_userManager = userManager;
|
||||
_notificationManager = notificationManager;
|
||||
}
|
||||
|
||||
public async Task SendNotification(INotificationScope scope, BaseNotification notification)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(scope);
|
||||
ArgumentNullException.ThrowIfNull(notification);
|
||||
var users = await GetUsers(scope, notification.Identifier);
|
||||
await using (var db = _contextFactory.CreateContext())
|
||||
await using (var db = contextFactory.CreateContext())
|
||||
{
|
||||
foreach (var uid in users)
|
||||
{
|
||||
@@ -48,7 +39,7 @@ namespace BTCPayServer.Services.Notifications
|
||||
}
|
||||
await db.SaveChangesAsync();
|
||||
}
|
||||
_notificationManager.InvalidateNotificationCache(users);
|
||||
notificationManager.InvalidateNotificationCache(users);
|
||||
}
|
||||
|
||||
public BaseNotification GetBaseNotification(NotificationData notificationData)
|
||||
@@ -58,7 +49,7 @@ namespace BTCPayServer.Services.Notifications
|
||||
|
||||
private async Task<string[]> GetUsers(INotificationScope scope, string notificationIdentifier)
|
||||
{
|
||||
await using var ctx = _contextFactory.CreateContext();
|
||||
await using var ctx = contextFactory.CreateContext();
|
||||
|
||||
var split = notificationIdentifier.Split('_', StringSplitOptions.None);
|
||||
var terms = new List<string>();
|
||||
@@ -71,8 +62,8 @@ namespace BTCPayServer.Services.Notifications
|
||||
{
|
||||
case AdminScope _:
|
||||
{
|
||||
query = _userManager.GetUsersInRoleAsync(Roles.ServerAdmin).Result.AsQueryable();
|
||||
|
||||
using var s = scopeFactory.CreateScope();
|
||||
query = s.ServiceProvider.GetService<UserManager<ApplicationUser>>().GetUsersInRoleAsync(Roles.ServerAdmin).Result.AsQueryable();
|
||||
break;
|
||||
}
|
||||
case StoreScope s:
|
||||
|
||||
Reference in New Issue
Block a user