fix: reserved addresses label filtering after label changes and initLabelManager error
What changed, and why it matters
This commit fixes a UI bug in BTCPay Server's wallet address list. Previously, when a user changed labels on a reserved Bitcoin address, the label filter on the page did not update to reflect the new labels, and an error in the label manager initialization could break the feature. The patch makes the address list listen for label-change events and refresh its internal label data so filtering works correctly after edits.
No immediate security action required. Treat as a routine bug fix. Reviewers may want to verify that label values are still properly sanitized by the existing label manager backend/frontend before display, though the diff itself does not introduce new sanitization concerns.
Security signals we found
Fixes client-side state synchronization bug that could cause UI to display stale address labels
No obvious injection vector: labels are passed through existing label manager, event data is consumed locally by Vue component
CustomEvent detail includes walletObjectId and labels, but is handled within same-origin page context
Evidence from the diff
The change adds a CustomEvent listener for ‘labelmanager:changed’ in ReservedAddresses.cshtml’s Vue.js component. When a label manager fires the event, the component merges the new labels into the address object’s labels array using Vue.$set for reactivity. The site.js change updates initLabelManager’s onChange handler to accept the selected values, normalize them to an array, and dispatch the custom event with walletObjectId and labels. This fixes two issues: (1) label filtering not updating after label changes, and (2) an initLabelManager error likely caused by the previous onChange signature mismatch.
Changed components
BTCPayServer/Views/UIWallets/ReservedAddresses.cshtmlBTCPayServer/wwwroot/main/site.jsWallet reserved addresses label management UIInspect captured patch +24 / −1
diff --git a/BTCPayServer/Views/UIWallets/ReservedAddresses.cshtml b/BTCPayServer/Views/UIWallets/ReservedAddresses.cshtml
index 45c09f7..50bc1b4 100644
--- a/BTCPayServer/Views/UIWallets/ReservedAddresses.cshtml
+++ b/BTCPayServer/Views/UIWallets/ReservedAddresses.cshtml
@@ -145,6 +145,21 @@
},
mounted() {
initLabelManagers();
+
+ const labelManagerList = document.querySelectorAll("input.label-manager");
+ labelManagerList.forEach(labelManager => {
+ labelManager.addEventListener("labelmanager:changed", ({ detail }) => {
+ const { walletObjectId, labels: newLabels } = detail;
+
+ const targetAddress = this.addresses.find(addr => addr.address === walletObjectId);
+ if (!targetAddress) return;
+
+ const existingLabels = targetAddress.labels?.map(l => l.text) || [];
+ const merged = Array.from(new Set([...existingLabels, ...newLabels])).map(text => ({ text }));
+
+ this.$set(targetAddress, 'labels', merged);
+ });
+ });
},
methods: {
setPageSize(size) {
diff --git a/BTCPayServer/wwwroot/main/site.js b/BTCPayServer/wwwroot/main/site.js
index ea04a41..f83d96b 100644
--- a/BTCPayServer/wwwroot/main/site.js
+++ b/BTCPayServer/wwwroot/main/site.js
@@ -104,7 +104,15 @@ async function initLabelManager (elementId) {
detail: val
}));
},
- async onChange () {
+ async onChange (values) {
+ const labels = Array.isArray(values) ? values : values.split(',');
+ element.dispatchEvent(new CustomEvent("labelmanager:changed", {
+ detail: {
+ walletObjectId,
+ labels: labels
+ }
+ }));
+
const selectElementI = selectElement ? document.getElementById(selectElement) : null;
if (selectElementI) {
while (selectElementI.options.length > 0) {
Why this scored 23/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.