2018-08-30 18:34:39 +02:00
|
|
|
|
using System;
|
2017-09-13 08:47:34 +02:00
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Threading.Tasks;
|
2018-08-30 18:34:39 +02:00
|
|
|
|
using BTCPayServer.Filters;
|
|
|
|
|
using BTCPayServer.Logging;
|
2018-02-19 15:13:23 +01:00
|
|
|
|
using BTCPayServer.Payments;
|
2018-08-30 18:34:39 +02:00
|
|
|
|
using Microsoft.AspNetCore.Mvc;
|
|
|
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
|
using NBitcoin;
|
|
|
|
|
using NBitcoin.Payment;
|
2017-09-13 08:47:34 +02:00
|
|
|
|
|
|
|
|
|
namespace BTCPayServer.Controllers
|
|
|
|
|
{
|
|
|
|
|
public partial class InvoiceController
|
|
|
|
|
{
|
2017-10-27 10:53:04 +02:00
|
|
|
|
[HttpGet]
|
2018-02-18 18:38:03 +01:00
|
|
|
|
[Route("i/{invoiceId}/{cryptoCode?}")]
|
2017-10-27 10:53:04 +02:00
|
|
|
|
[AcceptMediaTypeConstraint("application/bitcoin-paymentrequest")]
|
2017-12-21 07:52:04 +01:00
|
|
|
|
public async Task<IActionResult> GetInvoiceRequest(string invoiceId, string cryptoCode = null)
|
2017-10-27 10:53:04 +02:00
|
|
|
|
{
|
2017-12-21 07:52:04 +01:00
|
|
|
|
if (cryptoCode == null)
|
|
|
|
|
cryptoCode = "BTC";
|
2017-10-27 10:53:04 +02:00
|
|
|
|
var invoice = await _InvoiceRepository.GetInvoice(null, invoiceId);
|
2017-12-21 07:52:04 +01:00
|
|
|
|
var network = _NetworkProvider.GetNetwork(cryptoCode);
|
2018-02-19 07:09:05 +01:00
|
|
|
|
var paymentMethodId = new PaymentMethodId(cryptoCode, Payments.PaymentTypes.BTCLike);
|
|
|
|
|
if (invoice == null || invoice.IsExpired() || network == null || !invoice.Support(paymentMethodId))
|
2017-10-27 10:53:04 +02:00
|
|
|
|
return NotFound();
|
2017-09-13 08:47:34 +02:00
|
|
|
|
|
2017-12-21 07:52:04 +01:00
|
|
|
|
var dto = invoice.EntityToDTO(_NetworkProvider);
|
2018-02-19 07:09:05 +01:00
|
|
|
|
var paymentMethod = dto.CryptoInfo.First(c => c.GetpaymentMethodId() == paymentMethodId);
|
2017-10-27 10:53:04 +02:00
|
|
|
|
PaymentRequest request = new PaymentRequest
|
|
|
|
|
{
|
|
|
|
|
DetailsVersion = 1
|
|
|
|
|
};
|
|
|
|
|
request.Details.Expires = invoice.ExpirationTime;
|
|
|
|
|
request.Details.Memo = invoice.ProductInformation.ItemDesc;
|
2017-12-21 07:52:04 +01:00
|
|
|
|
request.Details.Network = network.NBitcoinNetwork;
|
2018-02-19 07:09:05 +01:00
|
|
|
|
request.Details.Outputs.Add(new PaymentOutput() { Amount = paymentMethod.Due, Script = BitcoinAddress.Create(paymentMethod.Address, network.NBitcoinNetwork).ScriptPubKey });
|
2017-10-27 10:53:04 +02:00
|
|
|
|
request.Details.MerchantData = Encoding.UTF8.GetBytes(invoice.Id);
|
|
|
|
|
request.Details.Time = DateTimeOffset.UtcNow;
|
|
|
|
|
request.Details.PaymentUrl = new Uri(invoice.ServerUrl.WithTrailingSlash() + ($"i/{invoice.Id}"), UriKind.Absolute);
|
2017-09-13 08:47:34 +02:00
|
|
|
|
|
2017-10-27 10:53:04 +02:00
|
|
|
|
var store = await _StoreRepository.FindStore(invoice.StoreId);
|
|
|
|
|
if (store == null)
|
|
|
|
|
throw new BitpayHttpException(401, "Unknown store");
|
2017-09-13 08:47:34 +02:00
|
|
|
|
|
2017-10-27 10:53:04 +02:00
|
|
|
|
if (store.StoreCertificate != null)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
request.Sign(store.StoreCertificate, PKIType.X509SHA256);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
Logs.PayServer.LogWarning(ex, "Error while signing payment request");
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-09-13 08:47:34 +02:00
|
|
|
|
|
2017-10-27 10:53:04 +02:00
|
|
|
|
return new PaymentRequestActionResult(request);
|
|
|
|
|
}
|
2017-09-13 08:47:34 +02:00
|
|
|
|
|
2017-10-27 10:53:04 +02:00
|
|
|
|
[HttpPost]
|
|
|
|
|
[Route("i/{invoiceId}", Order = 99)]
|
2018-01-07 18:36:41 +01:00
|
|
|
|
[Route("i/{invoiceId}/{cryptoCode}", Order = 99)]
|
2017-10-27 10:53:04 +02:00
|
|
|
|
[MediaTypeConstraint("application/bitcoin-payment")]
|
2018-01-07 18:36:41 +01:00
|
|
|
|
public async Task<IActionResult> PostPayment(string invoiceId, string cryptoCode = null)
|
2017-10-27 10:53:04 +02:00
|
|
|
|
{
|
|
|
|
|
var invoice = await _InvoiceRepository.GetInvoice(null, invoiceId);
|
2018-01-07 18:36:41 +01:00
|
|
|
|
if (cryptoCode == null)
|
|
|
|
|
cryptoCode = "BTC";
|
|
|
|
|
var network = _NetworkProvider.GetNetwork(cryptoCode);
|
2018-02-19 15:13:23 +01:00
|
|
|
|
if (network == null || invoice == null || invoice.IsExpired() || !invoice.Support(new PaymentMethodId(cryptoCode, Payments.PaymentTypes.BTCLike)))
|
2018-01-11 06:36:12 +01:00
|
|
|
|
return NotFound();
|
|
|
|
|
|
|
|
|
|
var wallet = _WalletProvider.GetWallet(network);
|
|
|
|
|
if (wallet == null)
|
|
|
|
|
return NotFound();
|
2018-06-23 17:45:57 +02:00
|
|
|
|
var payment = PaymentMessage.Load(Request.Body, network.NBitcoinNetwork);
|
2018-01-11 06:36:12 +01:00
|
|
|
|
var unused = wallet.BroadcastTransactionsAsync(payment.Transactions);
|
2018-01-11 14:52:28 +01:00
|
|
|
|
await _InvoiceRepository.AddRefundsAsync(invoiceId, payment.RefundTo.Select(p => new TxOut(p.Amount, p.Script)).ToArray(), network.NBitcoinNetwork);
|
2017-10-27 10:53:04 +02:00
|
|
|
|
return new PaymentAckActionResult(payment.CreateACK(invoiceId + " is currently processing, thanks for your purchase..."));
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-08-30 18:34:39 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public class PaymentRequestActionResult : IActionResult
|
|
|
|
|
{
|
|
|
|
|
PaymentRequest req;
|
|
|
|
|
public PaymentRequestActionResult(PaymentRequest req)
|
|
|
|
|
{
|
|
|
|
|
this.req = req;
|
|
|
|
|
}
|
|
|
|
|
public Task ExecuteResultAsync(ActionContext context)
|
|
|
|
|
{
|
|
|
|
|
context.HttpContext.Response.Headers["Content-Transfer-Encoding"] = "binary";
|
|
|
|
|
context.HttpContext.Response.ContentType = "application/bitcoin-paymentrequest";
|
|
|
|
|
req.WriteTo(context.HttpContext.Response.Body);
|
|
|
|
|
return Task.CompletedTask;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
public class PaymentAckActionResult : IActionResult
|
|
|
|
|
{
|
|
|
|
|
PaymentACK req;
|
|
|
|
|
public PaymentAckActionResult(PaymentACK req)
|
|
|
|
|
{
|
|
|
|
|
this.req = req;
|
|
|
|
|
}
|
|
|
|
|
public Task ExecuteResultAsync(ActionContext context)
|
|
|
|
|
{
|
|
|
|
|
context.HttpContext.Response.Headers["Content-Transfer-Encoding"] = "binary";
|
|
|
|
|
context.HttpContext.Response.ContentType = "application/bitcoin-paymentack";
|
|
|
|
|
req.WriteTo(context.HttpContext.Response.Body);
|
|
|
|
|
return Task.CompletedTask;
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-09-13 08:47:34 +02:00
|
|
|
|
}
|