btcpayserver/BTCPayServer/HostedServices/UserEventHostedService.cs
Kukks 371b33a2e1 Allow admins to invite new users
* This refactors the email sending so that all the logic related to users and emails are now contained in one location.
* The Reset password screen has been updated from its ugly plain self to use the same layout as the login.
* An admin can now create a new account without specifying a password. A link is generated that can be given to the intended user to configure the password. If emails are configured, it also sends an email
* An admin can now create accounts that still require the user to verify their if the setting is enabled from the server settings. A link is generated that can be given to the intended user to configure the password. If emails are configured, it also sends an email.
* The above features can be used in conjunction: An email will have to verify their email through a link. Once verified, the user is redirected to setting the password.
* When an email has been verified OR a password has been set, users are now redirected to the login page with the email filled in and a success status message shown instead of a dedicated thank you page.
2020-09-16 08:54:24 +02:00

93 lines
4.5 KiB
C#

using System;
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.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
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 SubscribeToEvents()
{
Subscribe<UserRegisteredEvent>();
Subscribe<UserPasswordResetRequestedEvent>();
}
protected override async Task ProcessEvent(object evt, CancellationToken cancellationToken)
{
string code;
string callbackUrl;
UserPasswordResetRequestedEvent userPasswordResetRequestedEvent;
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)
{
code = await _userManager.GenerateEmailConfirmationTokenAsync(userRegisteredEvent.User);
callbackUrl = _generator.EmailConfirmationLink(userRegisteredEvent.User.Id, code,
userRegisteredEvent.RequestUri.Scheme,
new HostString(userRegisteredEvent.RequestUri.Host, userRegisteredEvent.RequestUri.Port),
userRegisteredEvent.RequestUri.PathAndQuery);
userRegisteredEvent.CallbackUrlGenerated?.SetResult(new Uri(callbackUrl));
_emailSenderFactory.GetEmailSender()
.SendEmailConfirmation(userRegisteredEvent.User.Email, callbackUrl);
}
else if (!await _userManager.HasPasswordAsync(userRegisteredEvent.User))
{
userPasswordResetRequestedEvent = new UserPasswordResetRequestedEvent()
{
CallbackUrlGenerated = userRegisteredEvent.CallbackUrlGenerated,
User = userRegisteredEvent.User,
RequestUri = userRegisteredEvent.RequestUri
};
goto passwordSetter;
}
else
{
userRegisteredEvent.CallbackUrlGenerated?.SetResult(null);
}
break;
case UserPasswordResetRequestedEvent userPasswordResetRequestedEvent2:
userPasswordResetRequestedEvent = userPasswordResetRequestedEvent2;
passwordSetter:
code = await _userManager.GeneratePasswordResetTokenAsync(userPasswordResetRequestedEvent.User);
var newPassword = await _userManager.HasPasswordAsync(userPasswordResetRequestedEvent.User);
callbackUrl = _generator.ResetPasswordCallbackLink(userPasswordResetRequestedEvent.User.Id, code,
userPasswordResetRequestedEvent.RequestUri.Scheme,
new HostString(userPasswordResetRequestedEvent.RequestUri.Host,
userPasswordResetRequestedEvent.RequestUri.Port),
userPasswordResetRequestedEvent.RequestUri.PathAndQuery);
userPasswordResetRequestedEvent.CallbackUrlGenerated?.SetResult(new Uri(callbackUrl));
_emailSenderFactory.GetEmailSender()
.SendSetPasswordConfirmation(userPasswordResetRequestedEvent.User.Email, callbackUrl,
newPassword);
break;
}
}
}
}