mirror of
https://github.com/btcpayserver/btcpayserver.git
synced 2025-01-19 13:43:46 +01:00
Merge pull request #2106 from btcpayserver/email-spam-protect
Introduce Spam protection
This commit is contained in:
commit
7c88333060
@ -31,9 +31,6 @@ namespace BTCPayServer.Tests
|
||||
public class GreenfieldAPITests
|
||||
{
|
||||
public const int TestTimeout = TestUtils.TestTimeout;
|
||||
|
||||
public const string TestApiPath = "api/test/apikey";
|
||||
|
||||
public GreenfieldAPITests(ITestOutputHelper helper)
|
||||
{
|
||||
Logs.Tester = new XUnitLog(helper) { Name = "Tests" };
|
||||
@ -247,6 +244,20 @@ namespace BTCPayServer.Tests
|
||||
Password = "afewfoiewiou",
|
||||
IsAdministrator = true
|
||||
}));
|
||||
|
||||
// If we set DisableNonAdminCreateUserApi = true, it should always fail to create a user unless you are an admin
|
||||
await settings.UpdateSetting(new PoliciesSettings() { LockSubscription = false, DisableNonAdminCreateUserApi = true});
|
||||
await AssertHttpError(403,
|
||||
async () =>
|
||||
await unauthClient.CreateUser(
|
||||
new CreateApplicationUserRequest() {Email = "test9@gmail.com", Password = "afewfoiewiou"}));
|
||||
await AssertHttpError(403,
|
||||
async () =>
|
||||
await user1Client.CreateUser(
|
||||
new CreateApplicationUserRequest() {Email = "test9@gmail.com", Password = "afewfoiewiou"}));
|
||||
await adminClient.CreateUser(
|
||||
new CreateApplicationUserRequest() {Email = "test9@gmail.com", Password = "afewfoiewiou"});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,6 +35,7 @@ using BTCPayServer.Security.Bitpay;
|
||||
using BTCPayServer.Services;
|
||||
using BTCPayServer.Services.Apps;
|
||||
using BTCPayServer.Services.Invoices;
|
||||
using BTCPayServer.Services.Mails;
|
||||
using BTCPayServer.Services.Rates;
|
||||
using BTCPayServer.Tests.Logging;
|
||||
using BTCPayServer.U2F.Models;
|
||||
@ -3345,5 +3346,57 @@ namespace BTCPayServer.Tests
|
||||
Assert.False(fn.Seen);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact(Timeout = TestTimeout)]
|
||||
[Trait("Integration", "Integration")]
|
||||
public async Task EmailSenderTests()
|
||||
{
|
||||
using (var tester = ServerTester.Create(newDb: true))
|
||||
{
|
||||
await tester.StartAsync();
|
||||
|
||||
var acc = tester.NewAccount();
|
||||
acc.GrantAccess(true);
|
||||
|
||||
var settings = tester.PayTester.GetService<SettingsRepository>();
|
||||
var emailSenderFactory = tester.PayTester.GetService<EmailSenderFactory>();
|
||||
|
||||
Assert.Null(await Assert.IsType<ServerEmailSender>(emailSenderFactory.GetEmailSender()).GetEmailSettings());
|
||||
Assert.Null(await Assert.IsType<StoreEmailSender>(emailSenderFactory.GetEmailSender(acc.StoreId)).GetEmailSettings());
|
||||
|
||||
|
||||
await settings.UpdateSetting(new PoliciesSettings() { DisableStoresToUseServerEmailSettings = false });
|
||||
await settings.UpdateSetting(new EmailSettings()
|
||||
{
|
||||
From = "admin@admin.com",
|
||||
Login = "admin@admin.com",
|
||||
Password = "admin@admin.com",
|
||||
Port = 1234,
|
||||
Server = "admin.com",
|
||||
EnableSSL = true
|
||||
});
|
||||
Assert.Equal("admin@admin.com",(await Assert.IsType<ServerEmailSender>(emailSenderFactory.GetEmailSender()).GetEmailSettings()).Login);
|
||||
Assert.Equal("admin@admin.com",(await Assert.IsType<StoreEmailSender>(emailSenderFactory.GetEmailSender(acc.StoreId)).GetEmailSettings()).Login);
|
||||
|
||||
await settings.UpdateSetting(new PoliciesSettings() { DisableStoresToUseServerEmailSettings = true });
|
||||
Assert.Equal("admin@admin.com",(await Assert.IsType<ServerEmailSender>(emailSenderFactory.GetEmailSender()).GetEmailSettings()).Login);
|
||||
Assert.Null(await Assert.IsType<StoreEmailSender>(emailSenderFactory.GetEmailSender(acc.StoreId)).GetEmailSettings());
|
||||
|
||||
Assert.IsType<RedirectToActionResult>(await acc.GetController<StoresController>().Emails(acc.StoreId, new EmailsViewModel(new EmailSettings()
|
||||
{
|
||||
From = "store@store.com",
|
||||
Login = "store@store.com",
|
||||
Password = "store@store.com",
|
||||
Port = 1234,
|
||||
Server = "store.com",
|
||||
EnableSSL = true
|
||||
}), ""));
|
||||
|
||||
Assert.Equal("store@store.com",(await Assert.IsType<StoreEmailSender>(emailSenderFactory.GetEmailSender(acc.StoreId)).GetEmailSettings()).Login);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ using BTCPayServer.Client.Models;
|
||||
using BTCPayServer.Configuration;
|
||||
using BTCPayServer.Data;
|
||||
using BTCPayServer.Events;
|
||||
using BTCPayServer.HostedServices;
|
||||
using BTCPayServer.Logging;
|
||||
using BTCPayServer.Security;
|
||||
using BTCPayServer.Security.GreenField;
|
||||
@ -35,6 +36,7 @@ namespace BTCPayServer.Controllers.GreenField
|
||||
private readonly RateLimitService _throttleService;
|
||||
private readonly BTCPayServerOptions _options;
|
||||
private readonly IAuthorizationService _authorizationService;
|
||||
private readonly CssThemeManager _themeManager;
|
||||
|
||||
public UsersController(UserManager<ApplicationUser> userManager, BTCPayServerOptions btcPayServerOptions,
|
||||
RoleManager<IdentityRole> roleManager, SettingsRepository settingsRepository,
|
||||
@ -42,7 +44,8 @@ namespace BTCPayServer.Controllers.GreenField
|
||||
IPasswordValidator<ApplicationUser> passwordValidator,
|
||||
RateLimitService throttleService,
|
||||
BTCPayServerOptions options,
|
||||
IAuthorizationService authorizationService)
|
||||
IAuthorizationService authorizationService,
|
||||
CssThemeManager themeManager)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_btcPayServerOptions = btcPayServerOptions;
|
||||
@ -53,6 +56,7 @@ namespace BTCPayServer.Controllers.GreenField
|
||||
_throttleService = throttleService;
|
||||
_options = options;
|
||||
_authorizationService = authorizationService;
|
||||
_themeManager = themeManager;
|
||||
}
|
||||
|
||||
[Authorize(Policy = Policies.CanViewProfile, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
|
||||
@ -100,7 +104,7 @@ namespace BTCPayServer.Controllers.GreenField
|
||||
if (request.IsAdministrator is true && !isAdmin)
|
||||
return Forbid(AuthenticationSchemes.GreenfieldBasic);
|
||||
|
||||
if (!isAdmin && policies.LockSubscription)
|
||||
if (!isAdmin && (policies.LockSubscription || _themeManager.Policies.DisableNonAdminCreateUserApi))
|
||||
{
|
||||
// If we are not admin and subscriptions are locked, we need to check the Policies.CanCreateUser.Key permission
|
||||
var canCreateUser = (await _authorizationService.AuthorizeAsync(User, null, new PolicyRequirement(Policies.CanCreateUser))).Succeeded;
|
||||
|
@ -1,28 +1,34 @@
|
||||
using BTCPayServer.HostedServices;
|
||||
using BTCPayServer.Services.Stores;
|
||||
|
||||
namespace BTCPayServer.Services.Mails
|
||||
{
|
||||
public class EmailSenderFactory
|
||||
{
|
||||
private readonly IBackgroundJobClient _JobClient;
|
||||
private readonly SettingsRepository _Repository;
|
||||
private readonly StoreRepository _StoreRepository;
|
||||
private readonly IBackgroundJobClient _jobClient;
|
||||
private readonly SettingsRepository _repository;
|
||||
private readonly StoreRepository _storeRepository;
|
||||
private readonly CssThemeManager _cssThemeManager;
|
||||
|
||||
public EmailSenderFactory(IBackgroundJobClient jobClient,
|
||||
SettingsRepository repository,
|
||||
StoreRepository storeRepository)
|
||||
StoreRepository storeRepository,
|
||||
CssThemeManager cssThemeManager)
|
||||
{
|
||||
_JobClient = jobClient;
|
||||
_Repository = repository;
|
||||
_StoreRepository = storeRepository;
|
||||
_jobClient = jobClient;
|
||||
_repository = repository;
|
||||
_storeRepository = storeRepository;
|
||||
_cssThemeManager = cssThemeManager;
|
||||
}
|
||||
|
||||
public IEmailSender GetEmailSender(string storeId = null)
|
||||
{
|
||||
var serverSender = new ServerEmailSender(_Repository, _JobClient);
|
||||
var serverSender = new ServerEmailSender(_repository, _jobClient);
|
||||
if (string.IsNullOrEmpty(storeId))
|
||||
return serverSender;
|
||||
return new StoreEmailSender(_StoreRepository, serverSender, _JobClient, storeId);
|
||||
return new StoreEmailSender(_storeRepository,
|
||||
!_cssThemeManager.Policies.DisableStoresToUseServerEmailSettings ? serverSender : null, _jobClient,
|
||||
storeId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,11 +12,9 @@ namespace BTCPayServer.Services.Mails
|
||||
IBackgroundJobClient backgroundJobClient,
|
||||
string storeId) : base(backgroundJobClient)
|
||||
{
|
||||
if (storeId == null)
|
||||
throw new ArgumentNullException(nameof(storeId));
|
||||
StoreId = storeId ?? throw new ArgumentNullException(nameof(storeId));
|
||||
StoreRepository = storeRepository;
|
||||
FallbackSender = fallback;
|
||||
StoreId = storeId;
|
||||
}
|
||||
|
||||
public StoreRepository StoreRepository { get; }
|
||||
@ -31,7 +29,9 @@ namespace BTCPayServer.Services.Mails
|
||||
{
|
||||
return emailSettings;
|
||||
}
|
||||
return await FallbackSender.GetEmailSettings();
|
||||
|
||||
if (FallbackSender != null) return await FallbackSender?.GetEmailSettings();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,10 @@ namespace BTCPayServer.Services
|
||||
public bool CheckForNewVersions { get; set; }
|
||||
[Display(Name = "Disable notifications automatically showing (no websockets)")]
|
||||
public bool DisableInstantNotifications { get; set; }
|
||||
[Display(Name = "Disable stores falling back to using the server's email settings")]
|
||||
public bool DisableStoresToUseServerEmailSettings { get; set; }
|
||||
[Display(Name = "Only allow admins to use the user creation API")]
|
||||
public bool DisableNonAdminCreateUserApi { get; set; }
|
||||
|
||||
[Display(Name = "Display app on website root")]
|
||||
public string RootAppId { get; set; }
|
||||
|
@ -63,6 +63,16 @@
|
||||
<label asp-for="DisableInstantNotifications" class="form-check-label"></label>
|
||||
<span asp-validation-for="DisableInstantNotifications" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input asp-for="DisableStoresToUseServerEmailSettings" type="checkbox" class="form-check-input"/>
|
||||
<label asp-for="DisableStoresToUseServerEmailSettings" class="form-check-label"></label>
|
||||
<span asp-validation-for="DisableStoresToUseServerEmailSettings" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input asp-for="DisableNonAdminCreateUserApi" type="checkbox" class="form-check-input"/>
|
||||
<label asp-for="DisableNonAdminCreateUserApi" class="form-check-label"></label>
|
||||
<span asp-validation-for="DisableNonAdminCreateUserApi" class="text-danger"></span>
|
||||
</div>
|
||||
@if (ViewBag.UpdateUrlPresent)
|
||||
{
|
||||
<div class="form-check">
|
||||
|
Loading…
Reference in New Issue
Block a user