refactor: improve amount search, wallet label query and label manager icon URL
What changed, and why it matters
This commit is a code cleanup/refactor touching three areas: payment-request search, wallet label lookup, and a label-manager icon URL. The most notable change is that the payment-request search no longer compares the user's search text directly against the database's Amount column as text; instead it tries to parse the search text as a decimal number and, if successful, compares it numerically. The wallet-label query is rewritten from LINQ to raw SQL. The JavaScript change fixes an icon path to use a configurable base URL and removes an explicit 'credentials: include' flag from a fetch call. None of these changes, on their own, look like a clear security fix, but the removal of the text-based amount comparison and the credentials flag are worth noting.
Treat as a routine refactor. Review the new raw SQL in WalletRepository.cs for correctness and ensure the site.js baseUrl variable is always defined where initLabelManager is used. If the credentials: 'include' removal was intentional for CSRF hardening, verify that the endpoint still receives necessary authentication via other headers/cookies. No urgent security action is indicated by the diff alone.
Security signals we found
Payment-request search no longer casts Amount column to text for comparison with arbitrary user input; numeric path uses parameterized decimal value.
Wallet label query moved from LINQ to raw SQL but still uses parameterized values for walletId, linkedType, and label type.
JavaScript fetch call no longer sends credentials: 'include', which changes cross-origin cookie behavior for that request.
Icon URL now uses a baseUrl variable instead of a hard-coded root-relative path, reducing path-resolution issues in non-root deployments.
Evidence from the diff
The diff refactors three components. In PaymentRequestRepository.cs, the previous raw SQL used CAST(‘Amount’ AS TEXT) = {1} to compare a user-supplied search string against the Amount column as text. The new code parses the search string with decimal.TryParse using InvariantCulture and, only if it is a valid decimal, adds an OR “Amount” = {2} clause with the parsed decimal parameter. This is a correctness/performance improvement and incidentally removes a text-cast comparison that could behave unexpectedly across locales or data types. In WalletRepository.cs, a LINQ join is replaced by an equivalent raw SQL query using FromSqlRaw with parameterized inputs. In site.js, the label manager icon URL is prefixed with a baseUrl variable and the credentials: ‘include’ option is removed from a fetch request. The commit title and message describe these as ‘improvements’ and ‘refactor’; no security relevance is claimed by the vendor.
Changed components
BTCPayServer/Services/PaymentRequests/PaymentRequestRepository.csBTCPayServer/Services/WalletRepository.csBTCPayServer/wwwroot/main/site.jsInspect captured patch +49 / −26
diff --git a/BTCPayServer/Services/PaymentRequests/PaymentRequestRepository.cs b/BTCPayServer/Services/PaymentRequests/PaymentRequestRepository.cs
index b2481d1..a7f33f7 100644
--- a/BTCPayServer/Services/PaymentRequests/PaymentRequestRepository.cs
+++ b/BTCPayServer/Services/PaymentRequests/PaymentRequestRepository.cs
@@ -1,4 +1,5 @@
using System;
+using System.Globalization;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@@ -143,18 +144,35 @@ namespace BTCPayServer.Services.PaymentRequests
throw new InvalidOperationException("PaymentRequestQuery.StoreId should be specified");
var search = query.SearchText;
- queryable = context.PaymentRequests.FromSqlRaw("""
- SELECT *
- FROM "PaymentRequests"
- WHERE
- "StoreDataId" = {0}
- AND (
- "ReferenceId" = {1}
- OR "Id" = {1}
- OR jsonb_extract_path_text("Blob2", 'title') = {1}
- OR CAST("Amount" AS TEXT) = {1}
- )
- """, query.StoreId, search);
+ if (decimal.TryParse(search, NumberStyles.Number, CultureInfo.InvariantCulture, out var amount))
+ {
+ queryable = context.PaymentRequests.FromSqlRaw("""
+ SELECT *
+ FROM "PaymentRequests"
+ WHERE
+ "StoreDataId" = {0}
+ AND (
+ "ReferenceId" = {1}
+ OR "Id" = {1}
+ OR jsonb_extract_path_text("Blob2", 'title') = {1}
+ OR "Amount" = {2}
+ )
+ """, query.StoreId, search, amount);
+ }
+ else
+ {
+ queryable = context.PaymentRequests.FromSqlRaw("""
+ SELECT *
+ FROM "PaymentRequests"
+ WHERE
+ "StoreDataId" = {0}
+ AND (
+ "ReferenceId" = {1}
+ OR "Id" = {1}
+ OR jsonb_extract_path_text("Blob2", 'title') = {1}
+ )
+ """, query.StoreId, search);
+ }
}
else
{
diff --git a/BTCPayServer/Services/WalletRepository.cs b/BTCPayServer/Services/WalletRepository.cs
index 4f948ac..6f75e61 100644
--- a/BTCPayServer/Services/WalletRepository.cs
+++ b/BTCPayServer/Services/WalletRepository.cs
@@ -308,19 +308,25 @@ namespace BTCPayServer.Services
public async Task<(string Label, string Color)[]> GetWalletLabelsByLinkedType(WalletId walletId, string linkedType)
{
await using var ctx = _ContextFactory.CreateContext();
- var walletIdString = walletId.ToString();
- var query =
- from link in ctx.WalletObjectLinks.AsNoTracking()
- join labelObj in ctx.WalletObjects.AsNoTracking()
- on new { link.WalletId, Type = link.AType, Id = link.AId }
- equals new { labelObj.WalletId, labelObj.Type, labelObj.Id }
- where link.WalletId == walletIdString
- && link.AType == WalletObjectData.Types.Label
- && link.BType == linkedType
- select labelObj;
-
- var labelObjects = await query.Distinct().ToArrayAsync();
+ const string sql = """
+ SELECT DISTINCT
+ wo.*,
+ wo.xmin AS "xmin"
+ FROM "WalletObjectLinks" AS wol
+ INNER JOIN "WalletObjects" AS wo
+ ON wol."WalletId" = wo."WalletId"
+ AND wol."AType" = wo."Type"
+ AND wol."AId" = wo."Id"
+ WHERE wol."WalletId" = {0}
+ AND wol."AType" = {2}
+ AND wol."BType" = {1};
+ """;
+
+ var labelObjects = await ctx.WalletObjects
+ .FromSqlRaw(sql, walletId.ToString(), linkedType, WalletObjectData.Types.Label)
+ .AsNoTracking()
+ .ToArrayAsync();
return labelObjects.Select(FormatToLabel).ToArray();
}
diff --git a/BTCPayServer/wwwroot/main/site.js b/BTCPayServer/wwwroot/main/site.js
index 4c12e02..8b122e4 100644
--- a/BTCPayServer/wwwroot/main/site.js
+++ b/BTCPayServer/wwwroot/main/site.js
@@ -144,7 +144,7 @@ async function initLabelManager (elementId) {
svg.classList.add('icon', 'icon-info');
const use = document.createElementNS('http://www.w3.org/2000/svg', 'use');
- use.setAttributeNS('http://www.w3.org/1999/xlink', 'href', '/img/icon-sprite.svg#info');
+ use.setAttributeNS('http://www.w3.org/1999/xlink', 'href', `${baseUrl}/img/icon-sprite.svg#info`);
svg.appendChild(use);
a.appendChild(svg);
@@ -184,7 +184,6 @@ async function initLabelManager (elementId) {
try {
const response = await fetch(updateUrl, {
method: 'POST',
- credentials: 'include',
headers: {
'Content-Type': 'application/json'
},
Why this scored 28/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.