Make sure we don't pass the psbt in GET url

This commit is contained in:
nicolas.dorier
2019-11-08 20:21:33 +09:00
parent 28396206de
commit 5b37a9df0b
9 changed files with 95 additions and 50 deletions

View File

@@ -68,7 +68,6 @@ namespace BTCPayServer.Tests
var vmLedger = await walletController.WalletSend(walletId, sendModel, command: "ledger").AssertViewModelAsync<WalletSendLedgerModel>();
PSBT.Parse(vmLedger.PSBT, user.SupportedNetwork.NBitcoinNetwork);
BitcoinAddress.Create(vmLedger.HintChange, user.SupportedNetwork.NBitcoinNetwork);
Assert.NotNull(vmLedger.SuccessPath);
Assert.NotNull(vmLedger.WebsocketPath);
var redirectedPSBT = (string)Assert.IsType<RedirectToActionResult>(await walletController.WalletSend(walletId, sendModel, command: "analyze-psbt")).RouteValues["psbt"];

View File

@@ -69,6 +69,8 @@ namespace BTCPayServer.Controllers
WalletId walletId,
WalletPSBTViewModel vm, string command = null)
{
if (command == null)
return await WalletPSBT(walletId, vm);
var network = NetworkProvider.GetNetwork<BTCPayNetwork>(walletId.CryptoCode);
var psbt = await vm.GetPSBT(network.NBitcoinNetwork);
if (psbt == null)
@@ -78,7 +80,7 @@ namespace BTCPayServer.Controllers
}
switch (command)
{
case null:
case "decode":
vm.Decoded = psbt.ToString();
ModelState.Remove(nameof(vm.PSBT));
ModelState.Remove(nameof(vm.FileName));
@@ -97,7 +99,7 @@ namespace BTCPayServer.Controllers
return View(vm);
}
TempData[WellKnownTempData.SuccessMessage] = "PSBT updated!";
return RedirectToAction(nameof(WalletPSBT), new { walletId = walletId, psbt = psbt.ToBase64(), FileName = vm.FileName });
return RedirectToWalletPSBT(walletId, psbt, vm.FileName);
case "seed":
return SignWithSeed(walletId, psbt.ToBase64());
case "broadcast":
@@ -258,6 +260,8 @@ namespace BTCPayServer.Controllers
[ModelBinder(typeof(WalletIdModelBinder))]
WalletId walletId, WalletPSBTReadyViewModel vm, string command = null)
{
if (command == null)
return await WalletPSBTReady(walletId, vm.PSBT, vm.SigningKey, vm.SigningKeyPath);
PSBT psbt = null;
var network = NetworkProvider.GetNetwork<BTCPayNetwork>(walletId.CryptoCode);
try
@@ -299,7 +303,7 @@ namespace BTCPayServer.Controllers
}
else if (command == "analyze-psbt")
{
return RedirectToAction(nameof(WalletPSBT), new { walletId = walletId, psbt = psbt.ToBase64() });
return RedirectToWalletPSBT(walletId, psbt);
}
else
{
@@ -308,27 +312,6 @@ namespace BTCPayServer.Controllers
}
}
private IActionResult ViewPSBT<T>(PSBT psbt, IEnumerable<T> errors = null)
{
return ViewPSBT(psbt, null, errors?.Select(e => e.ToString()).ToList());
}
private IActionResult ViewPSBT(PSBT psbt, IEnumerable<string> errors = null)
{
return ViewPSBT(psbt, null, errors);
}
private IActionResult ViewPSBT(PSBT psbt, string fileName, IEnumerable<string> errors = null)
{
ModelState.Remove(nameof(WalletPSBTViewModel.PSBT));
ModelState.Remove(nameof(WalletPSBTViewModel.FileName));
return View(nameof(WalletPSBT), new WalletPSBTViewModel()
{
Decoded = psbt.ToString(),
FileName = fileName ?? string.Empty,
PSBT = psbt.ToBase64(),
Errors = errors?.ToList()
});
}
private IActionResult FilePSBT(PSBT psbt, string fileName)
{
return File(psbt.ToBytes(), "application/octet-stream", fileName);
@@ -354,7 +337,7 @@ namespace BTCPayServer.Controllers
}
sourcePSBT = sourcePSBT.Combine(psbt);
TempData[WellKnownTempData.SuccessMessage] = "PSBT Successfully combined!";
return ViewPSBT(sourcePSBT);
return RedirectToWalletPSBT(walletId, sourcePSBT);
}
}
}

View File

@@ -456,21 +456,59 @@ namespace BTCPayServer.Controllers
case "analyze-psbt":
var name =
$"Send-{string.Join('_', vm.Outputs.Select(output => $"{output.Amount}->{output.DestinationAddress}{(output.SubtractFeesFromOutput ? "-Fees" : string.Empty)}"))}.psbt";
return RedirectToAction(nameof(WalletPSBT), new { walletId = walletId, psbt = psbt.PSBT.ToBase64(), FileName = name });
return RedirectToWalletPSBT(walletId, psbt.PSBT, name);
default:
return View(vm);
}
}
private IActionResult RedirectToWalletPSBT(WalletId walletId, PSBT psbt, string fileName = null)
{
var vm = new PostRedictViewModel()
{
AspController = "Wallets",
AspAction = nameof(WalletPSBT),
Parameters =
{
new KeyValuePair<string, string>("psbt", psbt.ToBase64())
}
};
if (!string.IsNullOrEmpty(fileName))
vm.Parameters.Add(new KeyValuePair<string, string>("fileName", fileName));
return View("PostRedirect", vm);
}
void SetAmbientPSBT(PSBT psbt)
{
if (psbt != null)
TempData["AmbientPSBT"] = psbt.ToBase64();
else
TempData.Remove("AmbientPSBT");
}
PSBT GetAmbientPSBT(Network network, bool peek)
{
if (network == null)
throw new ArgumentNullException(nameof(network));
if ((peek ? TempData.Peek("AmbientPSBT") : TempData["AmbientPSBT"]) is string str)
{
try
{
return PSBT.Parse(str, network);
}
catch { }
}
return null;
}
private ViewResult ViewWalletSendLedger(PSBT psbt, BitcoinAddress hintChange = null)
{
SetAmbientPSBT(psbt);
return View("WalletSendLedger", new WalletSendLedgerModel()
{
PSBT = psbt.ToBase64(),
HintChange = hintChange?.ToString(),
WebsocketPath = this.Url.Action(nameof(LedgerConnection)),
SuccessPath = this.Url.Action(nameof(WalletPSBTReady))
WebsocketPath = this.Url.Action(nameof(LedgerConnection))
});
}
@@ -702,7 +740,6 @@ namespace BTCPayServer.Controllers
// getxpub
int account = 0,
// sendtoaddress
string psbt = null,
string hintChange = null
)
{
@@ -712,6 +749,7 @@ namespace BTCPayServer.Controllers
var network = NetworkProvider.GetNetwork<BTCPayNetwork>(walletId.CryptoCode);
if (network == null)
throw new FormatException("Invalid value for crypto code");
PSBT psbt = GetAmbientPSBT(network.NBitcoinNetwork, true);
var derivationSettings = GetDerivationSchemeSettings(walletId);
var webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync();
@@ -721,7 +759,6 @@ namespace BTCPayServer.Controllers
{
normalOperationTimeout.CancelAfter(TimeSpan.FromMinutes(30));
var hw = new LedgerHardwareWalletService(webSocket);
var model = new WalletSendLedgerModel();
object result = null;
try
{
@@ -775,18 +812,12 @@ namespace BTCPayServer.Controllers
await Repository.UpdateStore(storeData);
}
var psbtResponse = new CreatePSBTResponse()
{
PSBT = PSBT.Parse(psbt, network.NBitcoinNetwork),
ChangeAddress = string.IsNullOrEmpty(hintChange) ? null : BitcoinAddress.Create(hintChange, network.NBitcoinNetwork)
};
derivationSettings.RebaseKeyPaths(psbtResponse.PSBT);
derivationSettings.RebaseKeyPaths(psbt);
var changeAddress = string.IsNullOrEmpty(hintChange) ? null : BitcoinAddress.Create(hintChange, network.NBitcoinNetwork);
signTimeout.CancelAfter(TimeSpan.FromMinutes(5));
psbtResponse.PSBT = await hw.SignTransactionAsync(psbtResponse.PSBT, accountKey.GetRootedKeyPath(), accountKey.AccountKey, psbtResponse.ChangeAddress?.ScriptPubKey, signTimeout.Token);
result = new SendToAddressResult() { PSBT = psbtResponse.PSBT.ToBase64() };
psbt = await hw.SignTransactionAsync(psbt, accountKey.GetRootedKeyPath(), accountKey.AccountKey, changeAddress?.ScriptPubKey, signTimeout.Token);
SetAmbientPSBT(null);
result = new SendToAddressResult() { PSBT = psbt.ToBase64() };
}
}
catch (OperationCanceledException)

View File

@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace BTCPayServer.Models
{
public class PostRedictViewModel
{
public string AspAction { get; set; }
public string AspController { get; set; }
public List<KeyValuePair<string,string>> Parameters { get; set; } = new List<KeyValuePair<string, string>>();
}
}

View File

@@ -10,6 +10,5 @@ namespace BTCPayServer.Models.WalletViewModels
public string WebsocketPath { get; set; }
public string PSBT { get; set; }
public string HintChange { get; set; }
public string SuccessPath { get; set; }
}
}

View File

@@ -0,0 +1,18 @@
@model PostRedictViewModel
@{
Layout = null;
}
<html>
<head></head>
<body>
<form method="post" id="postform" asp-action="@Model.AspAction" asp-controller="@Model.AspController">
@foreach(var o in Model.Parameters) {
<input type="hidden" name="@o.Key" value="@o.Value" />
}
</form>
<script type="text/javascript">
document.forms.item(0).submit();
</script>
</body>
</html>

View File

@@ -65,7 +65,7 @@
<label asp-for="UploadedPSBTFile"></label>
<input type="file" class="form-control-file" asp-for="UploadedPSBTFile">
</div>
<button type="submit" class="btn btn-primary">Decode</button>
<button type="submit" name="command" value="decode" class="btn btn-primary">Decode</button>
</form>
</div>
</div>

View File

@@ -12,10 +12,11 @@
</div>
<div class="row">
<div class="col-md-10">
<input type="hidden" asp-for="PSBT" />
<input type="hidden" asp-for="HintChange" />
<input type="hidden" asp-for="SuccessPath" />
<input type="hidden" asp-for="WebsocketPath" />
<form id="broadcastForm" asp-action="WalletPSBTReady" method="post" style="display:none;">
<input type="hidden" id="PSBT" asp-for="PSBT" />
<input type="hidden" asp-for="HintChange" />
<input type="hidden" asp-for="WebsocketPath" />
</form>
<p>
You can send money received by this store to an address with the help of your Ledger Wallet. <br />
If you don't have a Ledger Wallet, use Electrum with your favorite hardware wallet to transfer crypto. <br />

View File

@@ -1,7 +1,6 @@
$(function () {
var psbt = $("#PSBT").val();
var hintChange = $("#HintChange").val();
var successPath = $("#SuccessPath").val();
var websocketPath = $("#WebsocketPath").val();
var loc = window.location, ws_uri;
@@ -62,7 +61,8 @@
if (result.error) {
WriteAlert("danger", result.error);
} else {
window.location.replace(loc.protocol + "//" + loc.host + successPath + "?psbt=" + encodeURIComponent(result.psbt));
$("#PSBT").val(result.psbt);
$("#broadcastForm").submit();
}
});
};