From 7564c3c2bd26f1c8bd044e10269bf84bd8bfc132 Mon Sep 17 00:00:00 2001 From: Nicolas Dorier Date: Tue, 21 May 2024 10:52:55 +0900 Subject: [PATCH] Fix: Some valid taproot PSBT couldn't parsed and show better error message (Fix #5715) (#5993) --- .../BTCPayServer.Client.csproj | 2 +- .../BTCPayServer.Common.csproj | 2 +- BTCPayServer.Data/BTCPayServer.Data.csproj | 2 +- .../BTCPayServer.Rating.csproj | 2 +- .../docker-compose.altcoins.yml | 2 +- BTCPayServer.Tests/docker-compose.yml | 2 +- .../Controllers/UIWalletsController.PSBT.cs | 16 ++++++--------- .../WalletPSBTCombineViewModel.cs | 18 ++++++++++------- .../WalletViewModels/WalletPSBTViewModel.cs | 20 +++++++++++++------ 9 files changed, 37 insertions(+), 29 deletions(-) diff --git a/BTCPayServer.Client/BTCPayServer.Client.csproj b/BTCPayServer.Client/BTCPayServer.Client.csproj index 084d8d951..e19700961 100644 --- a/BTCPayServer.Client/BTCPayServer.Client.csproj +++ b/BTCPayServer.Client/BTCPayServer.Client.csproj @@ -31,7 +31,7 @@ - + diff --git a/BTCPayServer.Common/BTCPayServer.Common.csproj b/BTCPayServer.Common/BTCPayServer.Common.csproj index a085e891c..3cdf1ac7a 100644 --- a/BTCPayServer.Common/BTCPayServer.Common.csproj +++ b/BTCPayServer.Common/BTCPayServer.Common.csproj @@ -4,7 +4,7 @@ - + diff --git a/BTCPayServer.Data/BTCPayServer.Data.csproj b/BTCPayServer.Data/BTCPayServer.Data.csproj index 4883815a2..3ebf14f06 100644 --- a/BTCPayServer.Data/BTCPayServer.Data.csproj +++ b/BTCPayServer.Data/BTCPayServer.Data.csproj @@ -8,7 +8,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/BTCPayServer.Rating/BTCPayServer.Rating.csproj b/BTCPayServer.Rating/BTCPayServer.Rating.csproj index eaff1b7e4..43cab0e2f 100644 --- a/BTCPayServer.Rating/BTCPayServer.Rating.csproj +++ b/BTCPayServer.Rating/BTCPayServer.Rating.csproj @@ -6,7 +6,7 @@ - + diff --git a/BTCPayServer.Tests/docker-compose.altcoins.yml b/BTCPayServer.Tests/docker-compose.altcoins.yml index 65fc058e2..f2468ea2b 100644 --- a/BTCPayServer.Tests/docker-compose.altcoins.yml +++ b/BTCPayServer.Tests/docker-compose.altcoins.yml @@ -100,7 +100,7 @@ services: custom: nbxplorer: - image: nicolasdorier/nbxplorer:2.5.0 + image: nicolasdorier/nbxplorer:2.5.3 restart: unless-stopped ports: - "32838:32838" diff --git a/BTCPayServer.Tests/docker-compose.yml b/BTCPayServer.Tests/docker-compose.yml index dbc6d56ab..6888ed530 100644 --- a/BTCPayServer.Tests/docker-compose.yml +++ b/BTCPayServer.Tests/docker-compose.yml @@ -97,7 +97,7 @@ services: custom: nbxplorer: - image: nicolasdorier/nbxplorer:2.5.0 + image: nicolasdorier/nbxplorer:2.5.3 restart: unless-stopped ports: - "32838:32838" diff --git a/BTCPayServer/Controllers/UIWalletsController.PSBT.cs b/BTCPayServer/Controllers/UIWalletsController.PSBT.cs index 4b5ec44be..384469819 100644 --- a/BTCPayServer/Controllers/UIWalletsController.PSBT.cs +++ b/BTCPayServer/Controllers/UIWalletsController.PSBT.cs @@ -151,13 +151,12 @@ namespace BTCPayServer.Controllers WalletId walletId, WalletPSBTViewModel vm, string command = null) { var network = NetworkProvider.GetNetwork(walletId.CryptoCode); - var psbt = await vm.GetPSBT(network.NBitcoinNetwork); + var psbt = await vm.GetPSBT(network.NBitcoinNetwork, ModelState); vm.BackUrl ??= HttpContext.Request.GetTypedHeaders().Referer?.AbsolutePath; if (psbt is null || vm.InvalidPSBT) { - ModelState.AddModelError(nameof(vm.PSBT), "Invalid PSBT"); return View("WalletSigningOptions", new WalletSigningOptionsModel { SigningContext = vm.SigningContext, @@ -241,10 +240,9 @@ namespace BTCPayServer.Controllers vm.NBXSeedAvailable = await CanUseHotWallet() && derivationSchemeSettings.IsHotWallet; vm.BackUrl ??= HttpContext.Request.GetTypedHeaders().Referer?.AbsolutePath; - var psbt = await vm.GetPSBT(network.NBitcoinNetwork); + var psbt = await vm.GetPSBT(network.NBitcoinNetwork, ModelState); if (vm.InvalidPSBT) { - ModelState.AddModelError(nameof(vm.PSBT), "Invalid PSBT"); return View(vm); } if (psbt is null) @@ -477,7 +475,7 @@ namespace BTCPayServer.Controllers WalletId walletId, WalletPSBTViewModel vm, string command, CancellationToken cancellationToken = default) { var network = NetworkProvider.GetNetwork(walletId.CryptoCode); - PSBT psbt = await vm.GetPSBT(network.NBitcoinNetwork); + PSBT psbt = await vm.GetPSBT(network.NBitcoinNetwork, ModelState); if (vm.InvalidPSBT || psbt is null) { if (vm.InvalidPSBT) @@ -637,16 +635,14 @@ namespace BTCPayServer.Controllers WalletId walletId, WalletPSBTCombineViewModel vm) { var network = NetworkProvider.GetNetwork(walletId.CryptoCode); - var psbt = await vm.GetPSBT(network.NBitcoinNetwork); + var psbt = await vm.GetPSBT(network.NBitcoinNetwork, ModelState); if (psbt == null) { - ModelState.AddModelError(nameof(vm.PSBT), "Invalid PSBT"); return View(vm); } - var sourcePSBT = vm.GetSourcePSBT(network.NBitcoinNetwork); - if (sourcePSBT == null) + var sourcePSBT = vm.GetSourcePSBT(network.NBitcoinNetwork, ModelState); + if (sourcePSBT is null) { - ModelState.AddModelError(nameof(vm.OtherPSBT), "Invalid PSBT"); return View(vm); } sourcePSBT = sourcePSBT.Combine(psbt); diff --git a/BTCPayServer/Models/WalletViewModels/WalletPSBTCombineViewModel.cs b/BTCPayServer/Models/WalletViewModels/WalletPSBTCombineViewModel.cs index 4b565665a..d411cf25a 100644 --- a/BTCPayServer/Models/WalletViewModels/WalletPSBTCombineViewModel.cs +++ b/BTCPayServer/Models/WalletViewModels/WalletPSBTCombineViewModel.cs @@ -2,6 +2,7 @@ using System; using System.ComponentModel.DataAnnotations; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc.ModelBinding; using NBitcoin; namespace BTCPayServer.Models.WalletViewModels @@ -17,7 +18,7 @@ namespace BTCPayServer.Models.WalletViewModels public string BackUrl { get; set; } public string ReturnUrl { get; set; } - public PSBT GetSourcePSBT(Network network) + public PSBT GetSourcePSBT(Network network, ModelStateDictionary modelState) { if (!string.IsNullOrEmpty(OtherPSBT)) { @@ -25,12 +26,12 @@ namespace BTCPayServer.Models.WalletViewModels { return NBitcoin.PSBT.Parse(OtherPSBT, network); } - catch - { } + catch (Exception ex) + { modelState.AddModelError(nameof(OtherPSBT), ex.Message); } } return null; } - public async Task GetPSBT(Network network) + public async Task GetPSBT(Network network, ModelStateDictionary modelState) { if (UploadedPSBTFile != null) { @@ -45,8 +46,9 @@ namespace BTCPayServer.Models.WalletViewModels { return NBitcoin.PSBT.Load(bytes, network); } - catch + catch (FormatException ex) { + modelState.AddModelError(nameof(UploadedPSBTFile), ex.Message); return null; } } @@ -56,8 +58,10 @@ namespace BTCPayServer.Models.WalletViewModels { return NBitcoin.PSBT.Parse(PSBT, network); } - catch - { } + catch (FormatException ex) + { + modelState.AddModelError(nameof(UploadedPSBTFile), ex.Message); + } } return null; } diff --git a/BTCPayServer/Models/WalletViewModels/WalletPSBTViewModel.cs b/BTCPayServer/Models/WalletViewModels/WalletPSBTViewModel.cs index 88b16a929..875f27ce6 100644 --- a/BTCPayServer/Models/WalletViewModels/WalletPSBTViewModel.cs +++ b/BTCPayServer/Models/WalletViewModels/WalletPSBTViewModel.cs @@ -4,6 +4,7 @@ using System.ComponentModel.DataAnnotations; using System.IO; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc.ModelBinding; using NBitcoin; namespace BTCPayServer.Models.WalletViewModels @@ -35,9 +36,9 @@ namespace BTCPayServer.Models.WalletViewModels public IFormFile UploadedPSBTFile { get; set; } - public async Task GetPSBT(Network network) + public async Task GetPSBT(Network network, ModelStateDictionary modelState) { - var psbt = await GetPSBTCore(network); + var psbt = await GetPSBTCore(network, modelState); if (psbt != null) { Decoded = psbt.ToString(); @@ -52,7 +53,7 @@ namespace BTCPayServer.Models.WalletViewModels } public bool InvalidPSBT { get; set; } - async Task GetPSBTCore(Network network) + async Task GetPSBTCore(Network network, ModelStateDictionary modelState) { if (UploadedPSBTFile != null) { @@ -68,16 +69,20 @@ namespace BTCPayServer.Models.WalletViewModels } return NBitcoin.PSBT.Load(bytes, network); } - catch (Exception) + catch (Exception ex) { using var stream = new StreamReader(UploadedPSBTFile.OpenReadStream()); PSBT = await stream.ReadToEndAsync(); + modelState.Remove(nameof(PSBT)); + modelState.AddModelError(nameof(PSBT), ex.Message); InvalidPSBT = true; } } if (SigningContext != null && !string.IsNullOrEmpty(SigningContext.PSBT)) { PSBT = SigningContext.PSBT; + modelState.Remove(nameof(PSBT)); + InvalidPSBT = false; } if (!string.IsNullOrEmpty(PSBT)) { @@ -86,8 +91,11 @@ namespace BTCPayServer.Models.WalletViewModels InvalidPSBT = false; return NBitcoin.PSBT.Parse(PSBT, network); } - catch - { InvalidPSBT = true; } + catch (Exception ex) when (!InvalidPSBT) + { + modelState.AddModelError(nameof(PSBT), ex.Message); + InvalidPSBT = true; + } } return null; }