2020-06-29 04:44:35 +02:00
|
|
|
using System;
|
2017-09-13 08:47:34 +02:00
|
|
|
using System.Text.Encodings.Web;
|
|
|
|
using System.Threading.Tasks;
|
2020-11-17 13:46:23 +01:00
|
|
|
using BTCPayServer.Abstractions.Constants;
|
2021-12-31 08:36:38 +01:00
|
|
|
using BTCPayServer.Client;
|
2020-06-28 10:55:27 +02:00
|
|
|
using BTCPayServer.Data;
|
2021-09-13 03:16:52 +02:00
|
|
|
using BTCPayServer.Fido2;
|
2021-10-09 05:18:37 +02:00
|
|
|
using BTCPayServer.Models;
|
2017-09-13 08:47:34 +02:00
|
|
|
using BTCPayServer.Models.ManageViewModels;
|
2022-01-14 05:05:23 +01:00
|
|
|
using BTCPayServer.Security.Greenfield;
|
2017-09-13 08:47:34 +02:00
|
|
|
using BTCPayServer.Services;
|
2020-06-28 10:55:27 +02:00
|
|
|
using BTCPayServer.Services.Mails;
|
2017-09-15 09:06:57 +02:00
|
|
|
using BTCPayServer.Services.Stores;
|
|
|
|
using BTCPayServer.Services.Wallets;
|
2020-06-28 10:55:27 +02:00
|
|
|
using Microsoft.AspNetCore.Authorization;
|
|
|
|
using Microsoft.AspNetCore.Hosting;
|
|
|
|
using Microsoft.AspNetCore.Identity;
|
|
|
|
using Microsoft.AspNetCore.Mvc;
|
2020-03-13 11:47:22 +01:00
|
|
|
using Microsoft.AspNetCore.Routing;
|
2020-06-28 10:55:27 +02:00
|
|
|
using Microsoft.Extensions.Logging;
|
2017-09-13 08:47:34 +02:00
|
|
|
|
|
|
|
namespace BTCPayServer.Controllers
|
|
|
|
{
|
2021-12-31 08:59:02 +01:00
|
|
|
|
2021-12-31 08:36:38 +01:00
|
|
|
[Authorize(AuthenticationSchemes = AuthenticationSchemes.Cookie, Policy = Policies.CanViewProfile)]
|
2022-01-14 12:16:28 +01:00
|
|
|
[Route("account/{action:lowercase=Index}")]
|
2022-01-07 04:32:00 +01:00
|
|
|
public partial class UIManageController : Controller
|
2017-10-27 10:53:04 +02:00
|
|
|
{
|
|
|
|
private readonly UserManager<ApplicationUser> _userManager;
|
|
|
|
private readonly SignInManager<ApplicationUser> _signInManager;
|
2019-01-06 15:53:37 +01:00
|
|
|
private readonly EmailSenderFactory _EmailSenderFactory;
|
2017-10-27 10:53:04 +02:00
|
|
|
private readonly ILogger _logger;
|
|
|
|
private readonly UrlEncoder _urlEncoder;
|
2019-05-02 14:01:08 +02:00
|
|
|
private readonly BTCPayServerEnvironment _btcPayServerEnvironment;
|
2020-02-24 14:36:15 +01:00
|
|
|
private readonly APIKeyRepository _apiKeyRepository;
|
2021-12-31 08:59:02 +01:00
|
|
|
private readonly IAuthorizationService _authorizationService;
|
2021-09-13 03:16:52 +02:00
|
|
|
private readonly Fido2Service _fido2Service;
|
2020-03-13 11:47:22 +01:00
|
|
|
private readonly LinkGenerator _linkGenerator;
|
2021-12-24 09:27:00 +01:00
|
|
|
private readonly UserLoginCodeService _userLoginCodeService;
|
2021-10-09 05:18:37 +02:00
|
|
|
private readonly UserService _userService;
|
2020-06-29 05:07:48 +02:00
|
|
|
readonly StoreRepository _StoreRepository;
|
2021-12-31 08:59:02 +01:00
|
|
|
|
2022-01-07 04:32:00 +01:00
|
|
|
public UIManageController(
|
2017-10-27 10:53:04 +02:00
|
|
|
UserManager<ApplicationUser> userManager,
|
|
|
|
SignInManager<ApplicationUser> signInManager,
|
2019-01-06 15:53:37 +01:00
|
|
|
EmailSenderFactory emailSenderFactory,
|
2022-01-07 04:32:00 +01:00
|
|
|
ILogger<UIManageController> logger,
|
2017-10-27 10:53:04 +02:00
|
|
|
UrlEncoder urlEncoder,
|
|
|
|
StoreRepository storeRepository,
|
2020-02-24 14:36:15 +01:00
|
|
|
BTCPayServerEnvironment btcPayServerEnvironment,
|
|
|
|
APIKeyRepository apiKeyRepository,
|
2020-03-13 11:47:22 +01:00
|
|
|
IAuthorizationService authorizationService,
|
2021-09-13 03:16:52 +02:00
|
|
|
Fido2Service fido2Service,
|
2021-10-09 05:18:37 +02:00
|
|
|
LinkGenerator linkGenerator,
|
2021-12-24 09:27:00 +01:00
|
|
|
UserService userService,
|
2021-12-31 08:59:02 +01:00
|
|
|
UserLoginCodeService userLoginCodeService
|
2020-02-24 14:36:15 +01:00
|
|
|
)
|
2017-10-27 10:53:04 +02:00
|
|
|
{
|
|
|
|
_userManager = userManager;
|
|
|
|
_signInManager = signInManager;
|
2019-01-06 15:53:37 +01:00
|
|
|
_EmailSenderFactory = emailSenderFactory;
|
2017-10-27 10:53:04 +02:00
|
|
|
_logger = logger;
|
|
|
|
_urlEncoder = urlEncoder;
|
2019-05-02 14:01:08 +02:00
|
|
|
_btcPayServerEnvironment = btcPayServerEnvironment;
|
2020-02-24 14:36:15 +01:00
|
|
|
_apiKeyRepository = apiKeyRepository;
|
|
|
|
_authorizationService = authorizationService;
|
2021-09-13 03:16:52 +02:00
|
|
|
_fido2Service = fido2Service;
|
2020-03-13 11:47:22 +01:00
|
|
|
_linkGenerator = linkGenerator;
|
2021-12-24 09:27:00 +01:00
|
|
|
_userLoginCodeService = userLoginCodeService;
|
2021-10-09 05:18:37 +02:00
|
|
|
_userService = userService;
|
2017-10-27 10:53:04 +02:00
|
|
|
_StoreRepository = storeRepository;
|
|
|
|
}
|
|
|
|
|
|
|
|
[HttpGet]
|
|
|
|
public async Task<IActionResult> Index()
|
|
|
|
{
|
|
|
|
var user = await _userManager.GetUserAsync(User);
|
|
|
|
if (user == null)
|
|
|
|
{
|
|
|
|
throw new ApplicationException($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
|
|
|
|
}
|
|
|
|
|
|
|
|
var model = new IndexViewModel
|
|
|
|
{
|
|
|
|
Username = user.UserName,
|
|
|
|
Email = user.Email,
|
2019-10-31 04:29:59 +01:00
|
|
|
IsEmailConfirmed = user.EmailConfirmed
|
2017-10-27 10:53:04 +02:00
|
|
|
};
|
|
|
|
return View(model);
|
|
|
|
}
|
|
|
|
|
2021-11-26 15:13:41 +01:00
|
|
|
[HttpPost]
|
|
|
|
[ValidateAntiForgeryToken]
|
|
|
|
public async Task<IActionResult> DisableShowInvoiceStatusChangeHint()
|
|
|
|
{
|
|
|
|
|
|
|
|
var user = await _userManager.GetUserAsync(User);
|
|
|
|
if (user == null)
|
|
|
|
{
|
|
|
|
throw new ApplicationException($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
|
|
|
|
}
|
|
|
|
|
|
|
|
var blob = user.GetBlob();
|
|
|
|
blob.ShowInvoiceStatusChangeHint = false;
|
|
|
|
if (user.SetBlob(blob))
|
|
|
|
{
|
|
|
|
await _userManager.UpdateAsync(user);
|
|
|
|
}
|
|
|
|
return RedirectToAction(nameof(Index));
|
|
|
|
}
|
2021-12-31 08:59:02 +01:00
|
|
|
|
2017-10-27 10:53:04 +02:00
|
|
|
[HttpPost]
|
|
|
|
[ValidateAntiForgeryToken]
|
|
|
|
public async Task<IActionResult> Index(IndexViewModel model)
|
|
|
|
{
|
|
|
|
if (!ModelState.IsValid)
|
|
|
|
{
|
|
|
|
return View(model);
|
|
|
|
}
|
|
|
|
|
|
|
|
var user = await _userManager.GetUserAsync(User);
|
|
|
|
if (user == null)
|
|
|
|
{
|
|
|
|
throw new ApplicationException($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
|
|
|
|
}
|
|
|
|
|
|
|
|
var email = user.Email;
|
|
|
|
if (model.Email != email)
|
|
|
|
{
|
2021-02-12 04:21:29 +01:00
|
|
|
if (!(await _userManager.FindByEmailAsync(model.Email) is null))
|
2019-03-24 16:09:36 +01:00
|
|
|
{
|
2021-02-12 08:48:26 +01:00
|
|
|
TempData[WellKnownTempData.ErrorMessage] = "The email address is already in use with an other account.";
|
2021-02-12 04:21:29 +01:00
|
|
|
return RedirectToAction(nameof(Index));
|
2017-10-27 10:53:04 +02:00
|
|
|
}
|
2021-02-12 04:21:29 +01:00
|
|
|
var setUserResult = await _userManager.SetUserNameAsync(user, model.Email);
|
|
|
|
if (!setUserResult.Succeeded)
|
2017-10-27 10:53:04 +02:00
|
|
|
{
|
2021-02-12 04:21:29 +01:00
|
|
|
throw new ApplicationException($"Unexpected error occurred setting email for user with ID '{user.Id}'.");
|
2017-10-27 10:53:04 +02:00
|
|
|
}
|
2021-02-12 04:21:29 +01:00
|
|
|
var setEmailResult = await _userManager.SetEmailAsync(user, model.Email);
|
|
|
|
if (!setEmailResult.Succeeded)
|
2017-10-27 10:53:04 +02:00
|
|
|
{
|
2021-02-12 04:21:29 +01:00
|
|
|
throw new ApplicationException($"Unexpected error occurred setting email for user with ID '{user.Id}'.");
|
2017-10-27 10:53:04 +02:00
|
|
|
}
|
|
|
|
}
|
2019-10-31 04:29:59 +01:00
|
|
|
TempData[WellKnownTempData.SuccessMessage] = "Your profile has been updated";
|
2017-10-27 10:53:04 +02:00
|
|
|
return RedirectToAction(nameof(Index));
|
|
|
|
}
|
|
|
|
|
|
|
|
[HttpPost]
|
|
|
|
[ValidateAntiForgeryToken]
|
|
|
|
public async Task<IActionResult> SendVerificationEmail(IndexViewModel model)
|
|
|
|
{
|
|
|
|
if (!ModelState.IsValid)
|
|
|
|
{
|
2020-04-05 05:30:23 +02:00
|
|
|
return View(nameof(Index), model);
|
2017-10-27 10:53:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
var user = await _userManager.GetUserAsync(User);
|
|
|
|
if (user == null)
|
|
|
|
{
|
|
|
|
throw new ApplicationException($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
|
|
|
|
}
|
|
|
|
|
|
|
|
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
|
2020-04-10 08:59:39 +02:00
|
|
|
var callbackUrl = _linkGenerator.EmailConfirmationLink(user.Id, code, Request.Scheme, Request.Host, Request.PathBase);
|
2017-10-27 10:53:04 +02:00
|
|
|
var email = user.Email;
|
2021-07-27 14:08:54 +02:00
|
|
|
(await _EmailSenderFactory.GetEmailSender()).SendEmailConfirmation(email, callbackUrl);
|
2019-10-31 04:29:59 +01:00
|
|
|
TempData[WellKnownTempData.SuccessMessage] = "Verification email sent. Please check your email.";
|
2017-10-27 10:53:04 +02:00
|
|
|
return RedirectToAction(nameof(Index));
|
|
|
|
}
|
|
|
|
|
|
|
|
[HttpGet]
|
|
|
|
public async Task<IActionResult> ChangePassword()
|
|
|
|
{
|
|
|
|
var user = await _userManager.GetUserAsync(User);
|
|
|
|
if (user == null)
|
|
|
|
{
|
|
|
|
throw new ApplicationException($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
|
|
|
|
}
|
|
|
|
|
|
|
|
var hasPassword = await _userManager.HasPasswordAsync(user);
|
|
|
|
if (!hasPassword)
|
|
|
|
{
|
|
|
|
return RedirectToAction(nameof(SetPassword));
|
|
|
|
}
|
|
|
|
|
2019-10-31 04:29:59 +01:00
|
|
|
var model = new ChangePasswordViewModel();
|
2017-10-27 10:53:04 +02:00
|
|
|
return View(model);
|
|
|
|
}
|
|
|
|
|
|
|
|
[HttpPost]
|
|
|
|
[ValidateAntiForgeryToken]
|
|
|
|
public async Task<IActionResult> ChangePassword(ChangePasswordViewModel model)
|
|
|
|
{
|
|
|
|
if (!ModelState.IsValid)
|
|
|
|
{
|
|
|
|
return View(model);
|
|
|
|
}
|
|
|
|
|
|
|
|
var user = await _userManager.GetUserAsync(User);
|
|
|
|
if (user == null)
|
|
|
|
{
|
|
|
|
throw new ApplicationException($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
|
|
|
|
}
|
|
|
|
|
|
|
|
var changePasswordResult = await _userManager.ChangePasswordAsync(user, model.OldPassword, model.NewPassword);
|
|
|
|
if (!changePasswordResult.Succeeded)
|
|
|
|
{
|
|
|
|
AddErrors(changePasswordResult);
|
|
|
|
return View(model);
|
|
|
|
}
|
|
|
|
|
|
|
|
await _signInManager.SignInAsync(user, isPersistent: false);
|
|
|
|
_logger.LogInformation("User changed their password successfully.");
|
2019-10-31 04:29:59 +01:00
|
|
|
TempData[WellKnownTempData.SuccessMessage] = "Your password has been changed.";
|
2017-10-27 10:53:04 +02:00
|
|
|
|
|
|
|
return RedirectToAction(nameof(ChangePassword));
|
|
|
|
}
|
|
|
|
|
|
|
|
[HttpGet]
|
|
|
|
public async Task<IActionResult> SetPassword()
|
|
|
|
{
|
|
|
|
var user = await _userManager.GetUserAsync(User);
|
|
|
|
if (user == null)
|
|
|
|
{
|
|
|
|
throw new ApplicationException($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
|
|
|
|
}
|
|
|
|
|
|
|
|
var hasPassword = await _userManager.HasPasswordAsync(user);
|
|
|
|
|
|
|
|
if (hasPassword)
|
|
|
|
{
|
|
|
|
return RedirectToAction(nameof(ChangePassword));
|
|
|
|
}
|
|
|
|
|
2019-10-31 04:29:59 +01:00
|
|
|
var model = new SetPasswordViewModel();
|
2017-10-27 10:53:04 +02:00
|
|
|
return View(model);
|
|
|
|
}
|
|
|
|
|
|
|
|
[HttpPost]
|
|
|
|
[ValidateAntiForgeryToken]
|
|
|
|
public async Task<IActionResult> SetPassword(SetPasswordViewModel model)
|
|
|
|
{
|
|
|
|
if (!ModelState.IsValid)
|
|
|
|
{
|
|
|
|
return View(model);
|
|
|
|
}
|
|
|
|
|
|
|
|
var user = await _userManager.GetUserAsync(User);
|
|
|
|
if (user == null)
|
|
|
|
{
|
|
|
|
throw new ApplicationException($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
|
|
|
|
}
|
|
|
|
|
|
|
|
var addPasswordResult = await _userManager.AddPasswordAsync(user, model.NewPassword);
|
|
|
|
if (!addPasswordResult.Succeeded)
|
|
|
|
{
|
|
|
|
AddErrors(addPasswordResult);
|
|
|
|
return View(model);
|
|
|
|
}
|
|
|
|
|
|
|
|
await _signInManager.SignInAsync(user, isPersistent: false);
|
2019-10-31 04:29:59 +01:00
|
|
|
TempData[WellKnownTempData.SuccessMessage] = "Your password has been set.";
|
2017-10-27 10:53:04 +02:00
|
|
|
|
|
|
|
return RedirectToAction(nameof(SetPassword));
|
|
|
|
}
|
2021-10-09 05:18:37 +02:00
|
|
|
|
|
|
|
[HttpPost()]
|
|
|
|
public async Task<IActionResult> DeleteUserPost()
|
|
|
|
{
|
|
|
|
var user = await _userManager.GetUserAsync(User);
|
|
|
|
if (user == null)
|
|
|
|
{
|
2021-10-15 09:34:40 +02:00
|
|
|
return NotFound();
|
2021-10-09 05:18:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
await _userService.DeleteUserAndAssociatedData(user);
|
|
|
|
TempData[WellKnownTempData.SuccessMessage] = "Account successfully deleted.";
|
|
|
|
await _signInManager.SignOutAsync();
|
2022-01-07 04:32:00 +01:00
|
|
|
return RedirectToAction(nameof(UIAccountController.Login), "UIAccount");
|
2021-10-09 05:18:37 +02:00
|
|
|
}
|
2017-10-27 10:53:04 +02:00
|
|
|
|
|
|
|
|
|
|
|
#region Helpers
|
|
|
|
|
|
|
|
private void AddErrors(IdentityResult result)
|
|
|
|
{
|
|
|
|
foreach (var error in result.Errors)
|
|
|
|
{
|
|
|
|
ModelState.AddModelError(string.Empty, error.Description);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endregion
|
|
|
|
}
|
2017-09-13 08:47:34 +02:00
|
|
|
}
|