Introduce Spam protection

fixes #1958

Adds 2 new options:
* Do not allow stores to use the email settings of the server. Instead, they would need to fill in the email settings in their own store
* Do not allow user creation through the API unless you are an admin.

Both are opt-in and turned off by default.
This commit is contained in:
Kukks 2020-12-04 08:08:05 +01:00
parent ba027de3f7
commit c17b8e4d9e
4 changed files with 35 additions and 11 deletions

View file

@ -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.DisableUnauthenticatedUserApi))
{
// 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;

View file

@ -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);
}
}
}

View file

@ -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 = "Disable unauthenticated Create User API")]
public bool DisableUnauthenticatedUserApi { get; set; }
[Display(Name = "Display app on website root")]
public string RootAppId { get; set; }

View file

@ -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="DisableUnauthenticatedUserApi" type="checkbox" class="form-check-input"/>
<label asp-for="DisableUnauthenticatedUserApi" class="form-check-label"></label>
<span asp-validation-for="DisableUnauthenticatedUserApi" class="text-danger"></span>
</div>
@if (ViewBag.UpdateUrlPresent)
{
<div class="form-check">