mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2025-12-18 06:24:24 +01:00
Greenfield API: Create User
Slightly big PR because I started refactoring to reduce code duplication between the UI based business logic and the api one.
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Client.Models;
|
||||
@@ -11,5 +12,12 @@ namespace BTCPayServer.Client
|
||||
var response = await _httpClient.SendAsync(CreateHttpRequest("api/v1/users/me"), token);
|
||||
return await HandleResponse<ApplicationUserData>(response);
|
||||
}
|
||||
|
||||
public virtual async Task<ApplicationUserData> CreateUser(CreateApplicationUserRequest request,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
var response = await _httpClient.SendAsync(CreateHttpRequest("api/v1/users", null, request, HttpMethod.Post), token);
|
||||
return await HandleResponse<ApplicationUserData>(response);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -64,7 +65,7 @@ namespace BTCPayServer.Client
|
||||
var request = CreateHttpRequest(path, queryPayload, method);
|
||||
if (typeof(T).IsPrimitive || !EqualityComparer<T>.Default.Equals(bodyPayload, default(T)))
|
||||
{
|
||||
request.Content = new StringContent(JsonSerializer.Serialize(bodyPayload, _serializerOptions));
|
||||
request.Content = new StringContent(JsonSerializer.Serialize(bodyPayload, _serializerOptions), Encoding.UTF8, "application/json");
|
||||
}
|
||||
|
||||
return request;
|
||||
|
||||
@@ -2,7 +2,41 @@ namespace BTCPayServer.Client.Models
|
||||
{
|
||||
public class ApplicationUserData
|
||||
{
|
||||
/// <summary>
|
||||
/// the id of the user
|
||||
/// </summary>
|
||||
public string Id { get; set; }
|
||||
/// <summary>
|
||||
/// the email AND username of the user
|
||||
/// </summary>
|
||||
public string Email { get; set; }
|
||||
/// <summary>
|
||||
/// Whether the user has verified their email
|
||||
/// </summary>
|
||||
public bool EmailConfirmed { get; set; }
|
||||
/// <summary>
|
||||
/// whether the user needed to verify their email on account creation
|
||||
/// </summary>
|
||||
public bool RequiresEmailConfirmation { get; set; }
|
||||
}
|
||||
|
||||
public class CreateApplicationUserRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// the email AND username of the new user
|
||||
/// </summary>
|
||||
public string Email { get; set; }
|
||||
/// <summary>
|
||||
/// password of the new user
|
||||
/// </summary>
|
||||
public string Password { get; set; }
|
||||
/// <summary>
|
||||
/// Whether this user is an administrator. If left null and there are no admins in the system, the user will be created as an admin.
|
||||
/// </summary>
|
||||
public bool? IsAdministrator { get; set; }
|
||||
/// <summary>
|
||||
/// If the server requires email confirmation, this allows you to set the account as confirmed from the start
|
||||
/// </summary>
|
||||
public bool? EmailConfirmed { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Client;
|
||||
using BTCPayServer.Client.Models;
|
||||
using BTCPayServer.Controllers;
|
||||
using BTCPayServer.Controllers.RestApi.Users;
|
||||
using BTCPayServer.Tests.Logging;
|
||||
using Microsoft.AspNet.SignalR.Client;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
using CreateApplicationUserRequest = BTCPayServer.Client.Models.CreateApplicationUserRequest;
|
||||
|
||||
namespace BTCPayServer.Tests
|
||||
{
|
||||
@@ -72,6 +76,36 @@ namespace BTCPayServer.Tests
|
||||
|
||||
await Assert.ThrowsAsync<HttpRequestException>(async () => await clientInsufficient.GetCurrentUser());
|
||||
await clientServer.GetCurrentUser();
|
||||
|
||||
|
||||
await Assert.ThrowsAsync<HttpRequestException>(async () => await clientInsufficient.CreateUser(new CreateApplicationUserRequest()
|
||||
{
|
||||
Email = $"{Guid.NewGuid()}@g.com",
|
||||
Password = Guid.NewGuid().ToString()
|
||||
}) );
|
||||
|
||||
var newUser = await clientServer.CreateUser(new CreateApplicationUserRequest()
|
||||
{
|
||||
Email = $"{Guid.NewGuid()}@g.com", Password = Guid.NewGuid().ToString()
|
||||
});
|
||||
Assert.NotNull(newUser);
|
||||
|
||||
await Assert.ThrowsAsync<HttpRequestException>(async () => await clientServer.CreateUser(new CreateApplicationUserRequest()
|
||||
{
|
||||
Email = $"{Guid.NewGuid()}",
|
||||
Password = Guid.NewGuid().ToString()
|
||||
}) );
|
||||
|
||||
await Assert.ThrowsAsync<HttpRequestException>(async () => await clientServer.CreateUser(new CreateApplicationUserRequest()
|
||||
{
|
||||
Email = $"{Guid.NewGuid()}@g.com",
|
||||
}) );
|
||||
|
||||
await Assert.ThrowsAsync<HttpRequestException>(async () => await clientServer.CreateUser(new CreateApplicationUserRequest()
|
||||
{
|
||||
Password = Guid.NewGuid().ToString()
|
||||
}) );
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ using BTCPayServer.U2F.Models;
|
||||
using Newtonsoft.Json;
|
||||
using NicolasDorier.RateLimits;
|
||||
using BTCPayServer.Data;
|
||||
using BTCPayServer.Events;
|
||||
using U2F.Core.Exceptions;
|
||||
|
||||
namespace BTCPayServer.Controllers
|
||||
@@ -40,6 +41,7 @@ namespace BTCPayServer.Controllers
|
||||
Configuration.BTCPayServerOptions _Options;
|
||||
private readonly BTCPayServerEnvironment _btcPayServerEnvironment;
|
||||
public U2FService _u2FService;
|
||||
private readonly EventAggregator _eventAggregator;
|
||||
ILogger _logger;
|
||||
|
||||
public AccountController(
|
||||
@@ -51,7 +53,8 @@ namespace BTCPayServer.Controllers
|
||||
SettingsRepository settingsRepository,
|
||||
Configuration.BTCPayServerOptions options,
|
||||
BTCPayServerEnvironment btcPayServerEnvironment,
|
||||
U2FService u2FService)
|
||||
U2FService u2FService,
|
||||
EventAggregator eventAggregator)
|
||||
{
|
||||
this.storeRepository = storeRepository;
|
||||
_userManager = userManager;
|
||||
@@ -62,6 +65,7 @@ namespace BTCPayServer.Controllers
|
||||
_Options = options;
|
||||
_btcPayServerEnvironment = btcPayServerEnvironment;
|
||||
_u2FService = u2FService;
|
||||
_eventAggregator = eventAggregator;
|
||||
_logger = Logs.PayServer;
|
||||
}
|
||||
|
||||
@@ -439,7 +443,6 @@ namespace BTCPayServer.Controllers
|
||||
if (result.Succeeded)
|
||||
{
|
||||
var admin = await _userManager.GetUsersInRoleAsync(Roles.ServerAdmin);
|
||||
Logs.PayServer.LogInformation($"A new user just registered {user.Email} {(admin.Count == 0 ? "(admin)" : "")}");
|
||||
if (admin.Count == 0 || (model.IsAdmin && _Options.AllowAdminRegistration))
|
||||
{
|
||||
await _RoleManager.CreateAsync(new IdentityRole(Roles.ServerAdmin));
|
||||
@@ -456,11 +459,14 @@ namespace BTCPayServer.Controllers
|
||||
RegisteredAdmin = true;
|
||||
}
|
||||
|
||||
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
|
||||
var callbackUrl = Url.EmailConfirmationLink(user.Id, code, Request.Scheme);
|
||||
_eventAggregator.Publish(new UserRegisteredEvent()
|
||||
{
|
||||
Request = Request,
|
||||
User = user,
|
||||
Admin = RegisteredAdmin
|
||||
});
|
||||
RegisteredUserId = user.Id;
|
||||
|
||||
_EmailSenderFactory.GetEmailSender().SendEmailConfirmation(model.Email, callbackUrl);
|
||||
if (!policies.RequiresConfirmedEmail)
|
||||
{
|
||||
if (logon)
|
||||
|
||||
@@ -20,6 +20,7 @@ using BTCPayServer.Security;
|
||||
using BTCPayServer.U2F;
|
||||
using BTCPayServer.Data;
|
||||
using BTCPayServer.Security.APIKeys;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
|
||||
|
||||
namespace BTCPayServer.Controllers
|
||||
@@ -38,6 +39,7 @@ namespace BTCPayServer.Controllers
|
||||
private readonly BTCPayServerEnvironment _btcPayServerEnvironment;
|
||||
private readonly APIKeyRepository _apiKeyRepository;
|
||||
private readonly IAuthorizationService _authorizationService;
|
||||
private readonly LinkGenerator _linkGenerator;
|
||||
StoreRepository _StoreRepository;
|
||||
|
||||
|
||||
@@ -54,7 +56,8 @@ namespace BTCPayServer.Controllers
|
||||
U2FService u2FService,
|
||||
BTCPayServerEnvironment btcPayServerEnvironment,
|
||||
APIKeyRepository apiKeyRepository,
|
||||
IAuthorizationService authorizationService
|
||||
IAuthorizationService authorizationService,
|
||||
LinkGenerator linkGenerator
|
||||
)
|
||||
{
|
||||
_userManager = userManager;
|
||||
@@ -67,6 +70,7 @@ namespace BTCPayServer.Controllers
|
||||
_btcPayServerEnvironment = btcPayServerEnvironment;
|
||||
_apiKeyRepository = apiKeyRepository;
|
||||
_authorizationService = authorizationService;
|
||||
_linkGenerator = linkGenerator;
|
||||
_StoreRepository = storeRepository;
|
||||
}
|
||||
|
||||
@@ -156,7 +160,7 @@ namespace BTCPayServer.Controllers
|
||||
}
|
||||
|
||||
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
|
||||
var callbackUrl = Url.EmailConfirmationLink(user.Id, code, Request.Scheme);
|
||||
var callbackUrl = _linkGenerator.EmailConfirmationLink(user.Id, code, Request.Scheme, Request.HttpContext);
|
||||
var email = user.Email;
|
||||
_EmailSenderFactory.GetEmailSender().SendEmailConfirmation(email, callbackUrl);
|
||||
TempData[WellKnownTempData.SuccessMessage] = "Verification email sent. Please check your email.";
|
||||
|
||||
@@ -1,12 +1,18 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Client.Models;
|
||||
using BTCPayServer.Configuration;
|
||||
using BTCPayServer.Data;
|
||||
using BTCPayServer.Events;
|
||||
using BTCPayServer.Hosting.OpenApi;
|
||||
using BTCPayServer.Security;
|
||||
using BTCPayServer.Services;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using NSwag.Annotations;
|
||||
|
||||
namespace BTCPayServer.Controllers.RestApi.Users
|
||||
@@ -18,14 +24,24 @@ namespace BTCPayServer.Controllers.RestApi.Users
|
||||
public class UsersController : ControllerBase
|
||||
{
|
||||
private readonly UserManager<ApplicationUser> _userManager;
|
||||
private readonly BTCPayServerOptions _btcPayServerOptions;
|
||||
private readonly RoleManager<IdentityRole> _roleManager;
|
||||
private readonly SettingsRepository _settingsRepository;
|
||||
private readonly EventAggregator _eventAggregator;
|
||||
|
||||
public UsersController(UserManager<ApplicationUser> userManager)
|
||||
public UsersController(UserManager<ApplicationUser> userManager, BTCPayServerOptions btcPayServerOptions,
|
||||
RoleManager<IdentityRole> roleManager, SettingsRepository settingsRepository,
|
||||
EventAggregator eventAggregator)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_btcPayServerOptions = btcPayServerOptions;
|
||||
_roleManager = roleManager;
|
||||
_settingsRepository = settingsRepository;
|
||||
_eventAggregator = eventAggregator;
|
||||
}
|
||||
|
||||
[OpenApiOperation("Get current user information", "View information about the current user")]
|
||||
[SwaggerResponse(StatusCodes.Status200OK, typeof(ApiKeyData),
|
||||
[SwaggerResponse(StatusCodes.Status200OK, typeof(ApplicationUserData),
|
||||
Description = "Information about the current user")]
|
||||
[Authorize(Policy = Policies.CanModifyProfile.Key, AuthenticationSchemes = AuthenticationSchemes.ApiKey)]
|
||||
[HttpGet("~/api/v1/users/me")]
|
||||
@@ -35,13 +51,81 @@ namespace BTCPayServer.Controllers.RestApi.Users
|
||||
return FromModel(user);
|
||||
}
|
||||
|
||||
[OpenApiOperation("Create user", "Create a new user")]
|
||||
[SwaggerResponse(StatusCodes.Status201Created, typeof(ApplicationUserData),
|
||||
Description = "Information about the new user")]
|
||||
[SwaggerResponse(StatusCodes.Status422UnprocessableEntity, typeof(ValidationProblemDetails),
|
||||
Description = "A list of validation errors that occurred")]
|
||||
[SwaggerResponse(StatusCodes.Status400BadRequest, typeof(ValidationProblemDetails),
|
||||
Description = "A list of errors that occurred when creating the user")]
|
||||
[Authorize(Policy = Policies.CanCreateUser.Key, AuthenticationSchemes = AuthenticationSchemes.ApiKey)]
|
||||
[HttpPost("~/api/v1/users")]
|
||||
public async Task<ActionResult<ApplicationUserData>> CreateUser(CreateApplicationUserRequest request)
|
||||
{
|
||||
var policies = await _settingsRepository.GetSettingAsync<PoliciesSettings>() ?? new PoliciesSettings();
|
||||
var anyAdmin = (await _userManager.GetUsersInRoleAsync(Roles.ServerAdmin)).Any();
|
||||
var admin = request.IsAdministrator.GetValueOrDefault(!anyAdmin);
|
||||
var user = new ApplicationUser
|
||||
{
|
||||
UserName = request.Email,
|
||||
Email = request.Email,
|
||||
RequiresEmailConfirmation = policies.RequiresConfirmedEmail,
|
||||
EmailConfirmed = request.EmailConfirmed.GetValueOrDefault(false)
|
||||
};
|
||||
var identityResult = await _userManager.CreateAsync(user);
|
||||
if (!identityResult.Succeeded)
|
||||
{
|
||||
AddErrors(identityResult);
|
||||
return BadRequest(new ValidationProblemDetails(ModelState));
|
||||
}
|
||||
else if (admin)
|
||||
{
|
||||
await _roleManager.CreateAsync(new IdentityRole(Roles.ServerAdmin));
|
||||
await _userManager.AddToRoleAsync(user, Roles.ServerAdmin);
|
||||
}
|
||||
|
||||
_eventAggregator.Publish(new UserRegisteredEvent() {Request = Request, User = user, Admin = admin});
|
||||
|
||||
return CreatedAtAction("", user);
|
||||
}
|
||||
|
||||
private static ApplicationUserData FromModel(ApplicationUser data)
|
||||
{
|
||||
return new ApplicationUserData()
|
||||
{
|
||||
Id = data.Id,
|
||||
Email = data.Email
|
||||
Email = data.Email,
|
||||
EmailConfirmed = data.EmailConfirmed,
|
||||
RequiresEmailConfirmation = data.RequiresEmailConfirmation
|
||||
};
|
||||
}
|
||||
|
||||
private void AddErrors(IdentityResult result)
|
||||
{
|
||||
foreach (var error in result.Errors)
|
||||
{
|
||||
ModelState.AddModelError(string.Empty, error.Description);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[ModelMetadataType(typeof(CreateApplicationUserRequestMetadata))]
|
||||
public class CreateApplicationUserRequest : BTCPayServer.Client.Models.CreateApplicationUserRequest
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public class CreateApplicationUserRequestMetadata
|
||||
{
|
||||
[Required]
|
||||
[EmailAddress]
|
||||
[Display(Name = "Email")]
|
||||
public string Email { get; set; }
|
||||
|
||||
[Required]
|
||||
[StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
|
||||
[DataType(DataType.Password)]
|
||||
[Display(Name = "Password")]
|
||||
public string Password { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
12
BTCPayServer/Events/UserRegisteredEvent.cs
Normal file
12
BTCPayServer/Events/UserRegisteredEvent.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using BTCPayServer.Data;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace BTCPayServer.Events
|
||||
{
|
||||
public class UserRegisteredEvent
|
||||
{
|
||||
public ApplicationUser User { get; set; }
|
||||
public HttpRequest Request { get; set; }
|
||||
public bool Admin { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,20 +1,19 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Controllers;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc
|
||||
{
|
||||
public static class UrlHelperExtensions
|
||||
{
|
||||
public static string EmailConfirmationLink(this IUrlHelper urlHelper, string userId, string code, string scheme)
|
||||
public static string EmailConfirmationLink(this LinkGenerator urlHelper, string userId, string code, string scheme, HttpContext context)
|
||||
{
|
||||
return urlHelper.Action(
|
||||
action: nameof(AccountController.ConfirmEmail),
|
||||
controller: "Account",
|
||||
values: new { userId, code },
|
||||
protocol: scheme);
|
||||
return urlHelper.GetUriByAction(context, nameof(AccountController.ConfirmEmail), "Account",
|
||||
new {userId, code}, scheme);
|
||||
}
|
||||
|
||||
public static string ResetPasswordCallbackLink(this IUrlHelper urlHelper, string userId, string code, string scheme)
|
||||
|
||||
53
BTCPayServer/HostedServices/UserEventHostedService.cs
Normal file
53
BTCPayServer/HostedServices/UserEventHostedService.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Data;
|
||||
using BTCPayServer.Events;
|
||||
using BTCPayServer.Logging;
|
||||
using BTCPayServer.Services;
|
||||
using BTCPayServer.Services.Mails;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Routing;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace BTCPayServer.HostedServices
|
||||
{
|
||||
public class UserEventHostedService : EventHostedServiceBase
|
||||
{
|
||||
private readonly UserManager<ApplicationUser> _userManager;
|
||||
private readonly EmailSenderFactory _emailSenderFactory;
|
||||
private readonly LinkGenerator _generator;
|
||||
|
||||
public UserEventHostedService(EventAggregator eventAggregator, UserManager<ApplicationUser> userManager,
|
||||
EmailSenderFactory emailSenderFactory, LinkGenerator generator) : base(eventAggregator)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_emailSenderFactory = emailSenderFactory;
|
||||
_generator = generator;
|
||||
}
|
||||
|
||||
protected override void SubscibeToEvents()
|
||||
{
|
||||
Subscribe<UserRegisteredEvent>();
|
||||
}
|
||||
|
||||
protected override async Task ProcessEvent(object evt, CancellationToken cancellationToken)
|
||||
{
|
||||
switch (evt)
|
||||
{
|
||||
case UserRegisteredEvent userRegisteredEvent:
|
||||
Logs.PayServer.LogInformation($"A new user just registered {userRegisteredEvent.User.Email} {(userRegisteredEvent.Admin ? "(admin)" : "")}");
|
||||
if (!userRegisteredEvent.User.EmailConfirmed && userRegisteredEvent.User.RequiresEmailConfirmation)
|
||||
{
|
||||
var code = await _userManager.GenerateEmailConfirmationTokenAsync(userRegisteredEvent.User);
|
||||
var callbackUrl = _generator.EmailConfirmationLink(userRegisteredEvent.User.Id, code, userRegisteredEvent.Request.Scheme, userRegisteredEvent.Request.HttpContext);
|
||||
|
||||
_emailSenderFactory.GetEmailSender()
|
||||
.SendEmailConfirmation(userRegisteredEvent.User.Email, callbackUrl);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -204,6 +204,7 @@ namespace BTCPayServer.Hosting
|
||||
services.AddSingleton<IHostedService, BackgroundJobSchedulerHostedService>();
|
||||
services.AddSingleton<IHostedService, AppHubStreamer>();
|
||||
services.AddSingleton<IHostedService, AppInventoryUpdaterHostedService>();
|
||||
services.AddSingleton<IHostedService, UserEventHostedService>();
|
||||
services.AddSingleton<IHostedService, DynamicDnsHostedService>();
|
||||
services.AddSingleton<IHostedService, TorServicesHostedService>();
|
||||
services.AddSingleton<IHostedService, PaymentRequestStreamer>();
|
||||
|
||||
@@ -72,6 +72,16 @@ namespace BTCPayServer.Hosting
|
||||
// ScriptSrc = "'self' 'unsafe-inline'"
|
||||
//});
|
||||
})
|
||||
.ConfigureApiBehaviorOptions(options =>
|
||||
{
|
||||
var builtInFactory = options.InvalidModelStateResponseFactory;
|
||||
|
||||
options.InvalidModelStateResponseFactory = context =>
|
||||
{
|
||||
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.UnprocessableEntity;
|
||||
return builtInFactory(context);
|
||||
};
|
||||
})
|
||||
.AddNewtonsoftJson()
|
||||
#if DEBUG
|
||||
.AddRazorRuntimeCompilation()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
|
||||
@@ -29,6 +29,13 @@ namespace BTCPayServer.Security.APIKeys
|
||||
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context,
|
||||
PolicyRequirement requirement)
|
||||
{
|
||||
//if it is a create user request, and the auth is not specified, and there are no admins in the system: authorize
|
||||
if (context.User.Identity.AuthenticationType == null && requirement.Policy == Policies.CanCreateUser.Key &&
|
||||
!(await _userManager.GetUsersInRoleAsync(Roles.ServerAdmin)).Any())
|
||||
{
|
||||
context.Succeed(requirement);
|
||||
}
|
||||
|
||||
if (context.User.Identity.AuthenticationType != APIKeyConstants.AuthenticationType)
|
||||
return;
|
||||
|
||||
@@ -67,6 +74,7 @@ namespace BTCPayServer.Security.APIKeys
|
||||
}
|
||||
|
||||
break;
|
||||
case Policies.CanCreateUser.Key:
|
||||
case Policies.CanModifyServerSettings.Key:
|
||||
if (!context.HasPermissions(Permissions.ServerManagement))
|
||||
break;
|
||||
|
||||
@@ -13,6 +13,7 @@ namespace BTCPayServer.Security
|
||||
options.AddPolicy(CanModifyServerSettings.Key);
|
||||
options.AddPolicy(CanModifyServerSettings.Key);
|
||||
options.AddPolicy(CanModifyProfile.Key);
|
||||
options.AddPolicy(CanCreateUser.Key);
|
||||
return options;
|
||||
}
|
||||
|
||||
@@ -46,5 +47,10 @@ namespace BTCPayServer.Security
|
||||
{
|
||||
public const string Key = "btcpay.store.cangetrates";
|
||||
}
|
||||
|
||||
public class CanCreateUser
|
||||
{
|
||||
public const string Key = "btcpay.store.cancreateuser";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Services.Stores;
|
||||
|
||||
Reference in New Issue
Block a user