mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2026-02-01 12:24:24 +01:00
Merge pull request #7000 from NicolasDorier/fix-linkgenerator
Fix: Spurious EF error on CallbackGenerator
This commit is contained in:
@@ -117,7 +117,7 @@ namespace BTCPayServer.Controllers.Greenfield
|
||||
|
||||
if (user.RequiresApproval)
|
||||
{
|
||||
var loginLink = _callbackGenerator.ForLogin(user, Request);
|
||||
var loginLink = _callbackGenerator.ForLogin(user);
|
||||
return await _userService.SetUserApproval(user.Id, request.Approved, loginLink)
|
||||
? Ok()
|
||||
: this.CreateAPIError("invalid-state", $"User is already {(request.Approved ? "approved" : "unapproved")}");
|
||||
@@ -416,8 +416,8 @@ namespace BTCPayServer.Controllers.Greenfield
|
||||
var currentUser = await _userManager.GetUserAsync(User);
|
||||
var userEvent = currentUser switch
|
||||
{
|
||||
{ } invitedBy => await UserEvent.Invited.Create(user, invitedBy, _callbackGenerator, Request, request.SendInvitationEmail is not false),
|
||||
_ => await UserEvent.Registered.Create(user, _callbackGenerator, Request)
|
||||
{ } invitedBy => await UserEvent.Invited.Create(user, invitedBy, _callbackGenerator, request.SendInvitationEmail is not false),
|
||||
_ => await UserEvent.Registered.Create(user, _callbackGenerator)
|
||||
};
|
||||
_eventAggregator.Publish(userEvent);
|
||||
|
||||
|
||||
@@ -267,7 +267,7 @@ namespace BTCPayServer.Controllers
|
||||
{
|
||||
RememberMe = rememberMe,
|
||||
UserId = user.Id,
|
||||
LNURLEndpoint = new Uri(callbackGenerator.ForLNUrlAuth(user, r, Request))
|
||||
LNURLEndpoint = new Uri(callbackGenerator.ForLNUrlAuth(user, r))
|
||||
};
|
||||
}
|
||||
return null;
|
||||
@@ -573,7 +573,7 @@ namespace BTCPayServer.Controllers
|
||||
RegisteredAdmin = true;
|
||||
}
|
||||
|
||||
eventAggregator.Publish(await UserEvent.Registered.Create(user, callbackGenerator, Request));
|
||||
eventAggregator.Publish(await UserEvent.Registered.Create(user, callbackGenerator));
|
||||
RegisteredUserId = user.Id;
|
||||
|
||||
TempData[WellKnownTempData.SuccessMessage] = StringLocalizer["Account created."].Value;
|
||||
@@ -640,7 +640,7 @@ namespace BTCPayServer.Controllers
|
||||
var result = await userManager.ConfirmEmailAsync(user, code);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
var approvalLink = callbackGenerator.ForApproval(user, Request);
|
||||
var approvalLink = callbackGenerator.ForApproval(user);
|
||||
eventAggregator.Publish(new UserEvent.ConfirmedEmail(user, approvalLink));
|
||||
|
||||
var hasPassword = await userManager.HasPasswordAsync(user);
|
||||
@@ -686,7 +686,7 @@ namespace BTCPayServer.Controllers
|
||||
{
|
||||
return RedirectToAction(nameof(ForgotPasswordConfirmation));
|
||||
}
|
||||
var callbackUri = await callbackGenerator.ForPasswordReset(user, Request);
|
||||
var callbackUri = await callbackGenerator.ForPasswordReset(user);
|
||||
eventAggregator.Publish(new UserEvent.PasswordResetRequested(user, callbackUri));
|
||||
return RedirectToAction(nameof(ForgotPasswordConfirmation));
|
||||
}
|
||||
|
||||
@@ -219,7 +219,7 @@ namespace BTCPayServer.Controllers
|
||||
throw new ApplicationException($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
|
||||
}
|
||||
|
||||
var callbackUrl = await _callbackGenerator.ForEmailConfirmation(user, Request);
|
||||
var callbackUrl = await _callbackGenerator.ForEmailConfirmation(user);
|
||||
_eventAggregator.Publish(new UserEvent.ConfirmationEmailRequested(user, callbackUrl));
|
||||
TempData[WellKnownTempData.SuccessMessage] = StringLocalizer["Verification email sent. Please check your email."].Value;
|
||||
return RedirectToAction(nameof(Index));
|
||||
|
||||
@@ -69,7 +69,7 @@ namespace BTCPayServer.Controllers
|
||||
InvitationUrl =
|
||||
string.IsNullOrEmpty(blob?.InvitationToken)
|
||||
? null
|
||||
: _callbackGenerator.ForInvitation(u.Id, blob.InvitationToken, Request),
|
||||
: _callbackGenerator.ForInvitation(u.Id, blob.InvitationToken),
|
||||
EmailConfirmed = u.RequiresEmailConfirmation ? u.EmailConfirmed : null,
|
||||
Approved = u.RequiresApproval ? u.Approved : null,
|
||||
Created = u.Created,
|
||||
@@ -95,7 +95,7 @@ namespace BTCPayServer.Controllers
|
||||
Id = user.Id,
|
||||
Email = user.Email,
|
||||
Name = blob?.Name,
|
||||
InvitationUrl = string.IsNullOrEmpty(blob?.InvitationToken) ? null : _callbackGenerator.ForInvitation(user.Id, blob.InvitationToken, Request),
|
||||
InvitationUrl = string.IsNullOrEmpty(blob?.InvitationToken) ? null : _callbackGenerator.ForInvitation(user.Id, blob.InvitationToken),
|
||||
ImageUrl = string.IsNullOrEmpty(blob?.ImageUrl) ? null : await _uriResolver.Resolve(Request.GetAbsoluteRootUri(), UnresolvedUri.Create(blob.ImageUrl)),
|
||||
EmailConfirmed = user.RequiresEmailConfirmation ? user.EmailConfirmed : null,
|
||||
Approved = user.RequiresApproval ? user.Approved : null,
|
||||
@@ -117,7 +117,7 @@ namespace BTCPayServer.Controllers
|
||||
|
||||
if (user.RequiresApproval && viewModel.Approved.HasValue && user.Approved != viewModel.Approved.Value)
|
||||
{
|
||||
var loginLink = _callbackGenerator.ForLogin(user, Request);
|
||||
var loginLink = _callbackGenerator.ForLogin(user);
|
||||
approvalStatusChanged = await _userService.SetUserApproval(user.Id, viewModel.Approved.Value, loginLink);
|
||||
}
|
||||
if (user.RequiresEmailConfirmation && viewModel.EmailConfirmed.HasValue && user.EmailConfirmed != viewModel.EmailConfirmed)
|
||||
@@ -261,7 +261,7 @@ namespace BTCPayServer.Controllers
|
||||
var currentUser = await _UserManager.GetUserAsync(HttpContext.User);
|
||||
var sendEmail = model.SendInvitationEmail && ViewData["CanSendEmail"] is true;
|
||||
|
||||
var evt = await UserEvent.Invited.Create(user, currentUser, _callbackGenerator, Request, sendEmail);
|
||||
var evt = await UserEvent.Invited.Create(user, currentUser, _callbackGenerator, sendEmail);
|
||||
_eventAggregator.Publish(evt);
|
||||
|
||||
var info = sendEmail
|
||||
@@ -383,7 +383,7 @@ namespace BTCPayServer.Controllers
|
||||
if (user == null)
|
||||
return NotFound();
|
||||
|
||||
var loginLink = _callbackGenerator.ForLogin(user, Request);
|
||||
var loginLink = _callbackGenerator.ForLogin(user);
|
||||
await _userService.SetUserApproval(userId, approved, loginLink);
|
||||
|
||||
TempData[WellKnownTempData.SuccessMessage] = approved
|
||||
@@ -411,7 +411,7 @@ namespace BTCPayServer.Controllers
|
||||
throw new ApplicationException($"Unable to load user with ID '{userId}'.");
|
||||
}
|
||||
|
||||
var callbackUrl = await _callbackGenerator.ForEmailConfirmation(user, Request);
|
||||
var callbackUrl = await _callbackGenerator.ForEmailConfirmation(user);
|
||||
_eventAggregator.Publish(new UserEvent.ConfirmationEmailRequested(user, callbackUrl));
|
||||
TempData[WellKnownTempData.SuccessMessage] = StringLocalizer["Verification email sent"].Value;
|
||||
return RedirectToAction(nameof(ListUsers));
|
||||
|
||||
@@ -74,7 +74,7 @@ public partial class UIStoresController
|
||||
(await _userManager.CreateAsync(user)) is { Succeeded: true })
|
||||
{
|
||||
var invitationEmail = await _emailSenderFactory.IsComplete();
|
||||
var evt = await UserEvent.Invited.Create(user!, currentUser, _callbackGenerator, Request, invitationEmail);
|
||||
var evt = await UserEvent.Invited.Create(user!, currentUser, _callbackGenerator, invitationEmail);
|
||||
_eventAggregator.Publish(evt);
|
||||
inviteInfo = invitationEmail
|
||||
? StringLocalizer["An invitation email has been sent.<br/>You may alternatively share this link with them: <a class='alert-link' href='{0}'>{0}</a>", evt.InvitationLink]
|
||||
|
||||
@@ -30,10 +30,10 @@ public class UserEvent(ApplicationUser user)
|
||||
{
|
||||
public string ApprovalLink { get; } = approvalLink;
|
||||
public string ConfirmationEmailLink { get; set; } = confirmationEmail;
|
||||
public static async Task<Registered> Create(ApplicationUser user, CallbackGenerator callbackGenerator, HttpRequest request)
|
||||
public static async Task<Registered> Create(ApplicationUser user, CallbackGenerator callbackGenerator)
|
||||
{
|
||||
var approvalLink = callbackGenerator.ForApproval(user, request);
|
||||
var confirmationEmail = await callbackGenerator.ForEmailConfirmation(user, request);
|
||||
var approvalLink = callbackGenerator.ForApproval(user);
|
||||
var confirmationEmail = await callbackGenerator.ForEmailConfirmation(user);
|
||||
return new Registered(user, approvalLink, confirmationEmail);
|
||||
}
|
||||
}
|
||||
@@ -43,11 +43,11 @@ public class UserEvent(ApplicationUser user)
|
||||
public ApplicationUser InvitedByUser { get; } = invitedBy;
|
||||
public string InvitationLink { get; } = invitationLink;
|
||||
|
||||
public static async Task<Invited> Create(ApplicationUser user, ApplicationUser currentUser, CallbackGenerator callbackGenerator, HttpRequest request, bool sendEmail)
|
||||
public static async Task<Invited> Create(ApplicationUser user, ApplicationUser currentUser, CallbackGenerator callbackGenerator, bool sendEmail)
|
||||
{
|
||||
var invitationLink = await callbackGenerator.ForInvitation(user, request);
|
||||
var approvalLink = callbackGenerator.ForApproval(user, request);
|
||||
var confirmationEmail = await callbackGenerator.ForEmailConfirmation(user, request);
|
||||
var invitationLink = await callbackGenerator.ForInvitation(user);
|
||||
var approvalLink = callbackGenerator.ForApproval(user);
|
||||
var confirmationEmail = await callbackGenerator.ForEmailConfirmation(user);
|
||||
return new Invited(user, currentUser, invitationLink, approvalLink, confirmationEmail)
|
||||
{
|
||||
SendInvitationEmail = sendEmail
|
||||
|
||||
@@ -87,7 +87,7 @@ namespace BTCPayServer.Hosting
|
||||
}
|
||||
public static IServiceCollection AddBTCPayServer(this IServiceCollection services, IConfiguration configuration, Logs logs)
|
||||
{
|
||||
services.TryAddSingleton<CallbackGenerator>();
|
||||
services.TryAddScoped<CallbackGenerator>();
|
||||
services.TryAddSingleton<IStringLocalizerFactory, LocalizerFactory>();
|
||||
services.TryAddSingleton<IHtmlLocalizerFactory, LocalizerFactory>();
|
||||
services.TryAddSingleton<LocalizerService>();
|
||||
|
||||
@@ -15,118 +15,93 @@ using Microsoft.AspNetCore.Mvc.Routing;
|
||||
using Microsoft.AspNetCore.Http.Extensions;
|
||||
using NBitcoin.DataEncoders;
|
||||
using System.Runtime.CompilerServices;
|
||||
using BTCPayServer.Abstractions;
|
||||
|
||||
namespace BTCPayServer.Services
|
||||
{
|
||||
public class CallbackGenerator(LinkGenerator linkGenerator, UserManager<ApplicationUser> userManager)
|
||||
public class CallbackGenerator(
|
||||
LinkGenerator linkGenerator,
|
||||
UserManager<ApplicationUser> userManager,
|
||||
IHttpContextAccessor httpContextAccessor)
|
||||
{
|
||||
public LinkGenerator LinkGenerator { get; } = linkGenerator;
|
||||
public UserManager<ApplicationUser> UserManager { get; } = userManager;
|
||||
|
||||
public string ForLNUrlAuth(ApplicationUser user, byte[] r, HttpRequest request)
|
||||
{
|
||||
return LinkGenerator.GetUriByAction(
|
||||
action: nameof(UILNURLAuthController.LoginResponse),
|
||||
controller: "UILNURLAuth",
|
||||
values: new { userId = user.Id, action = "login", tag = "login", k1 = Encoders.Hex.EncodeData(r) },
|
||||
request.Scheme,
|
||||
request.Host,
|
||||
request.PathBase) ?? throw Bug();
|
||||
}
|
||||
public string ForLNUrlAuth(ApplicationUser user, byte[] r)
|
||||
=> LinkGenerator.GetUriByAction(
|
||||
action: nameof(UILNURLAuthController.LoginResponse),
|
||||
controller: "UILNURLAuth",
|
||||
values: new { userId = user.Id, action = "login", tag = "login", k1 = Encoders.Hex.EncodeData(r) },
|
||||
GetRequestBaseUrl());
|
||||
|
||||
public string StoreUsersLink(string storeId, HttpRequest request)
|
||||
{
|
||||
return LinkGenerator.GetUriByAction(nameof(UIStoresController.StoreUsers), "UIStores",
|
||||
new { storeId }, request.Scheme, request.Host, request.PathBase) ?? throw Bug();
|
||||
}
|
||||
private RequestBaseUrl GetRequestBaseUrl()
|
||||
=> httpContextAccessor.HttpContext?.Request.GetRequestBaseUrl() ?? throw new InvalidOperationException($"You should be in a HttpContext to call this method");
|
||||
|
||||
public async Task<string> ForEmailConfirmation(ApplicationUser user, HttpRequest request)
|
||||
public string StoreUsersLink(string storeId)
|
||||
=> LinkGenerator.GetUriByAction(nameof(UIStoresController.StoreUsers), "UIStores",
|
||||
new { storeId }, GetRequestBaseUrl());
|
||||
|
||||
public async Task<string> ForEmailConfirmation(ApplicationUser user)
|
||||
{
|
||||
var code = await UserManager.GenerateEmailConfirmationTokenAsync(user);
|
||||
return LinkGenerator.GetUriByAction(nameof(UIAccountController.ConfirmEmail), "UIAccount",
|
||||
new { userId = user.Id, code }, request.Scheme, request.Host, request.PathBase) ?? throw Bug();
|
||||
new { userId = user.Id, code }, GetRequestBaseUrl());
|
||||
}
|
||||
public async Task<string> ForInvitation(ApplicationUser user, HttpRequest request)
|
||||
|
||||
public async Task<string> ForInvitation(ApplicationUser user)
|
||||
{
|
||||
var code = await UserManager.GenerateInvitationTokenAsync<ApplicationUser>(user.Id) ?? throw Bug();
|
||||
return ForInvitation(user.Id, code, request);
|
||||
var code = await UserManager.GenerateInvitationTokenAsync<ApplicationUser>(user.Id);
|
||||
return ForInvitation(user.Id, code ?? "???");
|
||||
}
|
||||
public string ForInvitation(string userId, string code, HttpRequest request)
|
||||
{
|
||||
return LinkGenerator.GetUriByAction(nameof(UIAccountController.AcceptInvite), "UIAccount",
|
||||
new { userId, code }, request.Scheme, request.Host, request.PathBase) ?? throw Bug();
|
||||
}
|
||||
public async Task<string> ForPasswordReset(ApplicationUser user, HttpRequest request)
|
||||
|
||||
public string ForInvitation(string userId, string code)
|
||||
=> LinkGenerator.GetUriByAction(nameof(UIAccountController.AcceptInvite), "UIAccount",
|
||||
new { userId, code }, GetRequestBaseUrl());
|
||||
|
||||
public async Task<string> ForPasswordReset(ApplicationUser user)
|
||||
{
|
||||
var code = await UserManager.GeneratePasswordResetTokenAsync(user);
|
||||
return LinkGenerator.GetUriByAction(
|
||||
action: nameof(UIAccountController.SetPassword),
|
||||
controller: "UIAccount",
|
||||
values: new { userId = user.Id, code },
|
||||
scheme: request.Scheme,
|
||||
host: request.Host,
|
||||
pathBase: request.PathBase
|
||||
) ?? throw Bug();
|
||||
GetRequestBaseUrl());
|
||||
}
|
||||
|
||||
public string ForApproval(ApplicationUser user, HttpRequest request)
|
||||
{
|
||||
return LinkGenerator.GetUriByAction(nameof(UIServerController.User), "UIServer",
|
||||
new { userId = user.Id }, request.Scheme, request.Host, request.PathBase) ?? throw Bug();
|
||||
}
|
||||
public string ForLogin(ApplicationUser user, HttpRequest request)
|
||||
{
|
||||
return LinkGenerator.GetUriByAction(nameof(UIAccountController.Login), "UIAccount", new { email = user.Email }, request.Scheme, request.Host, request.PathBase) ?? throw Bug();
|
||||
}
|
||||
public string ForApproval(ApplicationUser user)
|
||||
=> LinkGenerator.GetUriByAction(nameof(UIServerController.User), "UIServer",
|
||||
new { userId = user.Id }, GetRequestBaseUrl());
|
||||
|
||||
private Exception Bug([CallerMemberName] string? name = null) => new InvalidOperationException($"Error generating link for {name} (Report this bug to BTCPay Server github repository)");
|
||||
public string ForLogin(ApplicationUser user)
|
||||
=> LinkGenerator.GetUriByAction(nameof(UIAccountController.Login), "UIAccount",
|
||||
new { email = user.Email }, GetRequestBaseUrl());
|
||||
|
||||
public string WalletTransactionsLink(WalletId walletId, HttpRequest request)
|
||||
{
|
||||
return LinkGenerator.GetUriByAction(
|
||||
action: nameof(UIWalletsController.WalletTransactions),
|
||||
controller: "UIWallets",
|
||||
values: new { walletId = walletId.ToString() },
|
||||
scheme: request.Scheme,
|
||||
host: request.Host,
|
||||
pathBase: request.PathBase
|
||||
) ?? throw Bug();
|
||||
}
|
||||
public string WalletTransactionsLink(WalletId walletId)
|
||||
=> LinkGenerator.GetUriByAction(
|
||||
action: nameof(UIWalletsController.WalletTransactions),
|
||||
controller: "UIWallets",
|
||||
values: new { walletId = walletId.ToString() },
|
||||
GetRequestBaseUrl());
|
||||
|
||||
public string PaymentRequestByIdLink(string payReqId, HttpRequest request)
|
||||
{
|
||||
return LinkGenerator.GetUriByAction(
|
||||
action: nameof(UIPaymentRequestController.ViewPaymentRequest),
|
||||
controller: "UIPaymentRequest",
|
||||
values: new { payReqId },
|
||||
scheme: request.Scheme,
|
||||
host: request.Host,
|
||||
pathBase: request.PathBase
|
||||
) ?? throw Bug();
|
||||
}
|
||||
public string PaymentRequestByIdLink(string payReqId)
|
||||
=> LinkGenerator.GetUriByAction(
|
||||
action: nameof(UIPaymentRequestController.ViewPaymentRequest),
|
||||
controller: "UIPaymentRequest",
|
||||
values: new { payReqId },
|
||||
GetRequestBaseUrl());
|
||||
|
||||
public string PaymentRequestListLink(string storeId, HttpRequest request)
|
||||
{
|
||||
return LinkGenerator.GetUriByAction(
|
||||
action: nameof(UIPaymentRequestController.GetPaymentRequests),
|
||||
controller: "UIPaymentRequest",
|
||||
values: new { storeId },
|
||||
scheme: request.Scheme,
|
||||
host: request.Host,
|
||||
pathBase: request.PathBase
|
||||
) ?? throw Bug();
|
||||
}
|
||||
public string PaymentRequestListLink(string storeId)
|
||||
=> LinkGenerator.GetUriByAction(
|
||||
action: nameof(UIPaymentRequestController.GetPaymentRequests),
|
||||
controller: "UIPaymentRequest",
|
||||
values: new { storeId },
|
||||
GetRequestBaseUrl());
|
||||
|
||||
public string InvoiceLink(string invoiceId, HttpRequest request)
|
||||
{
|
||||
return LinkGenerator.GetUriByAction(
|
||||
action: nameof(UIInvoiceController.Invoice),
|
||||
controller: "UIInvoice",
|
||||
values: new { invoiceId },
|
||||
scheme: request.Scheme,
|
||||
host: request.Host,
|
||||
pathBase: request.PathBase
|
||||
) ?? throw Bug();
|
||||
}
|
||||
public string InvoiceLink(string invoiceId)
|
||||
=> LinkGenerator.GetUriByAction(
|
||||
action: nameof(UIInvoiceController.Invoice),
|
||||
controller: "UIInvoice",
|
||||
values: new { invoiceId },
|
||||
GetRequestBaseUrl());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ namespace BTCPayServer.Services
|
||||
? null
|
||||
: await uriResolver.Resolve(request.GetAbsoluteRootUri(), UnresolvedUri.Create(blob.ImageUrl)),
|
||||
InvitationUrl = string.IsNullOrEmpty(blob.InvitationToken) ? null
|
||||
: callbackGenerator.ForInvitation(data.Id, blob.InvitationToken, request)
|
||||
: callbackGenerator.ForInvitation(data.Id, blob.InvitationToken)
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -123,7 +123,7 @@
|
||||
<div class="d-inline-flex align-items-center gap-3">
|
||||
<a asp-action="ViewPaymentRequest" asp-route-payReqId="@item.Id" id="PaymentRequest-@item.Id" target="_blank" text-translate="true">View</a>
|
||||
<button type="button" class="btn btn-link p-0 clipboard-button"
|
||||
data-clipboard="@CallbackGenerator.PaymentRequestByIdLink(item.Id, this.Context.Request)"
|
||||
data-clipboard="@CallbackGenerator.PaymentRequestByIdLink(item.Id)"
|
||||
title="Copy Link">
|
||||
<vc:icon symbol="actions-copy" />
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user