diff --git a/BTCPayServer.Tests/BTCPayServerTester.cs b/BTCPayServer.Tests/BTCPayServerTester.cs index 88a666fd4..b2baa5c7e 100644 --- a/BTCPayServer.Tests/BTCPayServerTester.cs +++ b/BTCPayServer.Tests/BTCPayServerTester.cs @@ -1,6 +1,6 @@ using BTCPayServer.Configuration; using BTCPayServer.Hosting; -using BTCPayServer.Servcices.Invoices; +using BTCPayServer.Services.Invoices; using BTCPayServer.Services.Rates; using BTCPayServer.Tests.Logging; using BTCPayServer.Tests.Mocks; diff --git a/BTCPayServer.Tests/TestAccount.cs b/BTCPayServer.Tests/TestAccount.cs index b7b2c8804..b22b19a0b 100644 --- a/BTCPayServer.Tests/TestAccount.cs +++ b/BTCPayServer.Tests/TestAccount.cs @@ -1,7 +1,7 @@ using BTCPayServer.Controllers; using BTCPayServer.Models.AccountViewModels; using BTCPayServer.Models.StoreViewModels; -using BTCPayServer.Servcices.Invoices; +using BTCPayServer.Services.Invoices; using Microsoft.AspNetCore.Mvc; using NBitcoin; using NBitpayClient; diff --git a/BTCPayServer.Tests/UnitTest1.cs b/BTCPayServer.Tests/UnitTest1.cs index fe3bbcac2..ad7fa5847 100644 --- a/BTCPayServer.Tests/UnitTest1.cs +++ b/BTCPayServer.Tests/UnitTest1.cs @@ -9,340 +9,341 @@ using System.Threading; using Xunit; using Xunit.Abstractions; using Xunit.Sdk; -using BTCPayServer.Servcices.Invoices; +using BTCPayServer.Services.Invoices; using Newtonsoft.Json; using System.IO; using Newtonsoft.Json.Linq; using BTCPayServer.Controllers; using Microsoft.AspNetCore.Mvc; using BTCPayServer.Authentication; +using System.Diagnostics; namespace BTCPayServer.Tests { - public class UnitTest1 - { - public UnitTest1(ITestOutputHelper helper) - { - Logs.Tester = new XUnitLog(helper) { Name = "Tests" }; - Logs.LogProvider = new XUnitLogProvider(helper); - } + public class UnitTest1 + { + public UnitTest1(ITestOutputHelper helper) + { + Logs.Tester = new XUnitLog(helper) { Name = "Tests" }; + Logs.LogProvider = new XUnitLogProvider(helper); + } - [Fact] - public void CanCalculateCryptoDue() - { - var entity = new InvoiceEntity(); - entity.TxFee = Money.Coins(0.1m); - entity.Rate = 5000; - entity.Payments = new System.Collections.Generic.List(); - entity.ProductInformation = new ProductInformation() { Price = 5000 }; + [Fact] + public void CanCalculateCryptoDue() + { + var entity = new InvoiceEntity(); + entity.TxFee = Money.Coins(0.1m); + entity.Rate = 5000; + entity.Payments = new System.Collections.Generic.List(); + entity.ProductInformation = new ProductInformation() { Price = 5000 }; - Assert.Equal(Money.Coins(1.1m), entity.GetCryptoDue()); - Assert.Equal(Money.Coins(1.1m), entity.GetTotalCryptoDue()); + Assert.Equal(Money.Coins(1.1m), entity.GetCryptoDue()); + Assert.Equal(Money.Coins(1.1m), entity.GetTotalCryptoDue()); - entity.Payments.Add(new PaymentEntity() { Output = new TxOut(Money.Coins(0.5m), new Key()) }); + entity.Payments.Add(new PaymentEntity() { Output = new TxOut(Money.Coins(0.5m), new Key()) }); - //Since we need to spend one more txout, it should be 1.1 - 0,5 + 0.1 - Assert.Equal(Money.Coins(0.7m), entity.GetCryptoDue()); - Assert.Equal(Money.Coins(1.2m), entity.GetTotalCryptoDue()); + //Since we need to spend one more txout, it should be 1.1 - 0,5 + 0.1 + Assert.Equal(Money.Coins(0.7m), entity.GetCryptoDue()); + Assert.Equal(Money.Coins(1.2m), entity.GetTotalCryptoDue()); - entity.Payments.Add(new PaymentEntity() { Output = new TxOut(Money.Coins(0.2m), new Key()) }); - Assert.Equal(Money.Coins(0.6m), entity.GetCryptoDue()); - Assert.Equal(Money.Coins(1.3m), entity.GetTotalCryptoDue()); + entity.Payments.Add(new PaymentEntity() { Output = new TxOut(Money.Coins(0.2m), new Key()) }); + Assert.Equal(Money.Coins(0.6m), entity.GetCryptoDue()); + Assert.Equal(Money.Coins(1.3m), entity.GetTotalCryptoDue()); - entity.Payments.Add(new PaymentEntity() { Output = new TxOut(Money.Coins(0.6m), new Key()) }); + entity.Payments.Add(new PaymentEntity() { Output = new TxOut(Money.Coins(0.6m), new Key()) }); - Assert.Equal(Money.Zero, entity.GetCryptoDue()); - Assert.Equal(Money.Coins(1.3m), entity.GetTotalCryptoDue()); + Assert.Equal(Money.Zero, entity.GetCryptoDue()); + Assert.Equal(Money.Coins(1.3m), entity.GetTotalCryptoDue()); - entity.Payments.Add(new PaymentEntity() { Output = new TxOut(Money.Coins(0.2m), new Key()) }); + entity.Payments.Add(new PaymentEntity() { Output = new TxOut(Money.Coins(0.2m), new Key()) }); - Assert.Equal(Money.Zero, entity.GetCryptoDue()); - Assert.Equal(Money.Coins(1.3m), entity.GetTotalCryptoDue()); - } + Assert.Equal(Money.Zero, entity.GetCryptoDue()); + Assert.Equal(Money.Coins(1.3m), entity.GetTotalCryptoDue()); + } - [Fact] - public void CanPayUsingBIP70() - { - using(var tester = ServerTester.Create()) - { - tester.Start(); - var user = tester.NewAccount(); - user.GrantAccess(); - var invoice = user.BitPay.CreateInvoice(new Invoice() - { - Buyer = new Buyer() { email = "test@fwf.com" }, - Price = 5000.0, - Currency = "USD", - PosData = "posData", - OrderId = "orderId", - //RedirectURL = redirect + "redirect", - //NotificationURL = CallbackUri + "/notification", - ItemDesc = "Some description", - FullNotifications = true - }, Facade.Merchant); + [Fact] + public void CanPayUsingBIP70() + { + using (var tester = ServerTester.Create()) + { + tester.Start(); + var user = tester.NewAccount(); + user.GrantAccess(); + var invoice = user.BitPay.CreateInvoice(new Invoice() + { + Buyer = new Buyer() { email = "test@fwf.com" }, + Price = 5000.0, + Currency = "USD", + PosData = "posData", + OrderId = "orderId", + //RedirectURL = redirect + "redirect", + //NotificationURL = CallbackUri + "/notification", + ItemDesc = "Some description", + FullNotifications = true + }, Facade.Merchant); - Assert.False(invoice.Refundable); + Assert.False(invoice.Refundable); - var url = new BitcoinUrlBuilder(invoice.PaymentUrls.BIP72); - var request = url.GetPaymentRequest(); - var payment = request.CreatePayment(); + var url = new BitcoinUrlBuilder(invoice.PaymentUrls.BIP72); + var request = url.GetPaymentRequest(); + var payment = request.CreatePayment(); - Transaction tx = new Transaction(); - tx.Outputs.AddRange(request.Details.Outputs.Select(o => new TxOut(o.Amount, o.Script))); - var cashCow = tester.ExplorerNode; - tx = cashCow.FundRawTransaction(tx).Transaction; - tx = cashCow.SignRawTransaction(tx); + Transaction tx = new Transaction(); + tx.Outputs.AddRange(request.Details.Outputs.Select(o => new TxOut(o.Amount, o.Script))); + var cashCow = tester.ExplorerNode; + tx = cashCow.FundRawTransaction(tx).Transaction; + tx = cashCow.SignRawTransaction(tx); - payment.Transactions.Add(tx); + payment.Transactions.Add(tx); - payment.RefundTo.Add(new PaymentOutput(Money.Coins(1.0m), new Key().ScriptPubKey)); - var ack = payment.SubmitPayment(); - Assert.NotNull(ack); + payment.RefundTo.Add(new PaymentOutput(Money.Coins(1.0m), new Key().ScriptPubKey)); + var ack = payment.SubmitPayment(); + Assert.NotNull(ack); - Eventually(() => - { - tester.SimulateCallback(url.Address); - var localInvoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant); - Assert.Equal("paid", localInvoice.Status); - Assert.True(localInvoice.Refundable); - }); - } - } + Eventually(() => + { + tester.SimulateCallback(url.Address); + var localInvoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant); + Assert.Equal("paid", localInvoice.Status); + Assert.True(localInvoice.Refundable); + }); + } + } - [Fact] - public void CanUseServerInitiatedPairingCode() - { - using(var tester = ServerTester.Create()) - { - tester.Start(); - var acc = tester.NewAccount(); - acc.Register(); - acc.CreateStore(); + [Fact] + public void CanUseServerInitiatedPairingCode() + { + using (var tester = ServerTester.Create()) + { + tester.Start(); + var acc = tester.NewAccount(); + acc.Register(); + acc.CreateStore(); - var controller = tester.PayTester.GetController(acc.UserId); - var token = (RedirectToActionResult)controller.CreateToken(acc.StoreId, new Models.StoreViewModels.CreateTokenViewModel() - { - Facade = Facade.Merchant.ToString(), - Label = "bla", - PublicKey = null - }).GetAwaiter().GetResult(); + var controller = tester.PayTester.GetController(acc.UserId); + var token = (RedirectToActionResult)controller.CreateToken(acc.StoreId, new Models.StoreViewModels.CreateTokenViewModel() + { + Facade = Facade.Merchant.ToString(), + Label = "bla", + PublicKey = null + }).GetAwaiter().GetResult(); - var pairingCode = (string)token.RouteValues["pairingCode"]; + var pairingCode = (string)token.RouteValues["pairingCode"]; - acc.BitPay.AuthorizeClient(new PairingCode(pairingCode)).GetAwaiter().GetResult(); - Assert.True(acc.BitPay.TestAccess(Facade.Merchant)); - } - } + acc.BitPay.AuthorizeClient(new PairingCode(pairingCode)).GetAwaiter().GetResult(); + Assert.True(acc.BitPay.TestAccess(Facade.Merchant)); + } + } - [Fact] - public void CanSendIPN() - { - using(var callbackServer = new CustomServer()) - { - using(var tester = ServerTester.Create()) - { - tester.Start(); - var acc = tester.NewAccount(); - acc.GrantAccess(); - var invoice = acc.BitPay.CreateInvoice(new Invoice() - { - Price = 5.0, - Currency = "USD", - PosData = "posData", - OrderId = "orderId", - NotificationURL = callbackServer.GetUri().AbsoluteUri, - ItemDesc = "Some description", - FullNotifications = true - }); - BitcoinUrlBuilder url = new BitcoinUrlBuilder(invoice.PaymentUrls.BIP21); - tester.ExplorerNode.SendToAddress(url.Address, url.Amount); - Thread.Sleep(5000); - tester.SimulateCallback(url.Address); - callbackServer.ProcessNextRequest((ctx) => - { - var ipn = new StreamReader(ctx.Request.Body).ReadToEnd(); - JsonConvert.DeserializeObject(ipn); //can deserialize - }); - var invoice2 = acc.BitPay.GetInvoice(invoice.Id); - Assert.NotNull(invoice2); - } - } - } + [Fact] + public void CanSendIPN() + { + using (var callbackServer = new CustomServer()) + { + using (var tester = ServerTester.Create()) + { + tester.Start(); + var acc = tester.NewAccount(); + acc.GrantAccess(); + var invoice = acc.BitPay.CreateInvoice(new Invoice() + { + Price = 5.0, + Currency = "USD", + PosData = "posData", + OrderId = "orderId", + NotificationURL = callbackServer.GetUri().AbsoluteUri, + ItemDesc = "Some description", + FullNotifications = true + }); + BitcoinUrlBuilder url = new BitcoinUrlBuilder(invoice.PaymentUrls.BIP21); + tester.ExplorerNode.SendToAddress(url.Address, url.Amount); + Thread.Sleep(5000); + tester.SimulateCallback(url.Address); + callbackServer.ProcessNextRequest((ctx) => + { + var ipn = new StreamReader(ctx.Request.Body).ReadToEnd(); + JsonConvert.DeserializeObject(ipn); //can deserialize + }); + var invoice2 = acc.BitPay.GetInvoice(invoice.Id); + Assert.NotNull(invoice2); + } + } + } - [Fact] - public void CantPairTwiceWithSamePubkey() - { - using(var tester = ServerTester.Create()) - { - tester.Start(); - var acc = tester.NewAccount(); - acc.Register(); - var store = acc.CreateStore(); - var pairingCode = acc.BitPay.RequestClientAuthorization("test", Facade.Merchant); - Assert.IsType(store.Pair(pairingCode.ToString(), acc.StoreId).GetAwaiter().GetResult()); + [Fact] + public void CantPairTwiceWithSamePubkey() + { + using (var tester = ServerTester.Create()) + { + tester.Start(); + var acc = tester.NewAccount(); + acc.Register(); + var store = acc.CreateStore(); + var pairingCode = acc.BitPay.RequestClientAuthorization("test", Facade.Merchant); + Assert.IsType(store.Pair(pairingCode.ToString(), acc.StoreId).GetAwaiter().GetResult()); - pairingCode = acc.BitPay.RequestClientAuthorization("test1", Facade.Merchant); - var store2 = acc.CreateStore(); - store2.Pair(pairingCode.ToString(), store2.CreatedStoreId).GetAwaiter().GetResult(); - Assert.Contains(nameof(PairingResult.ReusedKey), store2.StatusMessage); - } - } + pairingCode = acc.BitPay.RequestClientAuthorization("test1", Facade.Merchant); + var store2 = acc.CreateStore(); + store2.Pair(pairingCode.ToString(), store2.CreatedStoreId).GetAwaiter().GetResult(); + Assert.Contains(nameof(PairingResult.ReusedKey), store2.StatusMessage); + } + } - [Fact] - public void InvoiceFlowThroughDifferentStatesCorrectly() - { - using(var tester = ServerTester.Create()) - { - tester.Start(); - var user = tester.NewAccount(); - Assert.False(user.BitPay.TestAccess(Facade.Merchant)); - user.GrantAccess(); - Assert.True(user.BitPay.TestAccess(Facade.Merchant)); - var invoice = user.BitPay.CreateInvoice(new Invoice() - { - Price = 5000.0, - Currency = "USD", - PosData = "posData", - OrderId = "orderId", - //RedirectURL = redirect + "redirect", - //NotificationURL = CallbackUri + "/notification", - ItemDesc = "Some description", - FullNotifications = true - }, Facade.Merchant); + [Fact] + public void InvoiceFlowThroughDifferentStatesCorrectly() + { + using (var tester = ServerTester.Create()) + { + tester.Start(); + var user = tester.NewAccount(); + Assert.False(user.BitPay.TestAccess(Facade.Merchant)); + user.GrantAccess(); + Assert.True(user.BitPay.TestAccess(Facade.Merchant)); + var invoice = user.BitPay.CreateInvoice(new Invoice() + { + Price = 5000.0, + Currency = "USD", + PosData = "posData", + OrderId = "orderId", + //RedirectURL = redirect + "redirect", + //NotificationURL = CallbackUri + "/notification", + ItemDesc = "Some description", + FullNotifications = true + }, Facade.Merchant); - var textSearchResult = tester.PayTester.Runtime.InvoiceRepository.GetInvoices(new InvoiceQuery() - { - StoreId = user.StoreId, - TextSearch = invoice.OrderId - }).GetAwaiter().GetResult(); + var textSearchResult = tester.PayTester.Runtime.InvoiceRepository.GetInvoices(new InvoiceQuery() + { + StoreId = user.StoreId, + TextSearch = invoice.OrderId + }).GetAwaiter().GetResult(); - Assert.Equal(1, textSearchResult.Length); + Assert.Equal(1, textSearchResult.Length); - textSearchResult = tester.PayTester.Runtime.InvoiceRepository.GetInvoices(new InvoiceQuery() - { - StoreId = user.StoreId, - TextSearch = invoice.Id - }).GetAwaiter().GetResult(); + textSearchResult = tester.PayTester.Runtime.InvoiceRepository.GetInvoices(new InvoiceQuery() + { + StoreId = user.StoreId, + TextSearch = invoice.Id + }).GetAwaiter().GetResult(); - Assert.Equal(1, textSearchResult.Length); + Assert.Equal(1, textSearchResult.Length); - invoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant); - Assert.Equal(Money.Coins(0), invoice.BtcPaid); - Assert.Equal("new", invoice.Status); - Assert.Equal(false, (bool)((JValue)invoice.ExceptionStatus).Value); + invoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant); + Assert.Equal(Money.Coins(0), invoice.BtcPaid); + Assert.Equal("new", invoice.Status); + Assert.Equal(false, (bool)((JValue)invoice.ExceptionStatus).Value); - Assert.Equal(1, user.BitPay.GetInvoices(invoice.InvoiceTime.DateTime).Length); - Assert.Equal(0, user.BitPay.GetInvoices(invoice.InvoiceTime.DateTime + TimeSpan.FromDays(1)).Length); - Assert.Equal(1, user.BitPay.GetInvoices(invoice.InvoiceTime.DateTime - TimeSpan.FromDays(5)).Length); - Assert.Equal(1, user.BitPay.GetInvoices(invoice.InvoiceTime.DateTime - TimeSpan.FromDays(5), invoice.InvoiceTime.DateTime).Length); - Assert.Equal(0, user.BitPay.GetInvoices(invoice.InvoiceTime.DateTime - TimeSpan.FromDays(5), invoice.InvoiceTime.DateTime - TimeSpan.FromDays(1)).Length); + Assert.Equal(1, user.BitPay.GetInvoices(invoice.InvoiceTime.DateTime).Length); + Assert.Equal(0, user.BitPay.GetInvoices(invoice.InvoiceTime.DateTime + TimeSpan.FromDays(1)).Length); + Assert.Equal(1, user.BitPay.GetInvoices(invoice.InvoiceTime.DateTime - TimeSpan.FromDays(5)).Length); + Assert.Equal(1, user.BitPay.GetInvoices(invoice.InvoiceTime.DateTime - TimeSpan.FromDays(5), invoice.InvoiceTime.DateTime).Length); + Assert.Equal(0, user.BitPay.GetInvoices(invoice.InvoiceTime.DateTime - TimeSpan.FromDays(5), invoice.InvoiceTime.DateTime - TimeSpan.FromDays(1)).Length); - var firstPayment = Money.Coins(0.04m); + var firstPayment = Money.Coins(0.04m); - var txFee = Money.Zero; + var txFee = Money.Zero; - var rate = user.BitPay.GetRates(); + var rate = user.BitPay.GetRates(); - var cashCow = tester.ExplorerNode; - var invoiceAddress = BitcoinAddress.Create(invoice.BitcoinAddress, cashCow.Network); - cashCow.SendToAddress(invoiceAddress, firstPayment); + var cashCow = tester.ExplorerNode; + var invoiceAddress = BitcoinAddress.Create(invoice.BitcoinAddress, cashCow.Network); + cashCow.SendToAddress(invoiceAddress, firstPayment); - Money secondPayment = Money.Zero; + Money secondPayment = Money.Zero; - Eventually(() => - { - tester.SimulateCallback(invoiceAddress); - var localInvoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant); - Assert.Equal("paidPartial", localInvoice.Status); - Assert.Equal(firstPayment, localInvoice.BtcPaid); - txFee = localInvoice.BtcDue - invoice.BtcDue; - Assert.Equal("paidPartial", localInvoice.ExceptionStatus); - secondPayment = localInvoice.BtcDue; - }); + Eventually(() => + { + tester.SimulateCallback(invoiceAddress); + var localInvoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant); + Assert.Equal("paidPartial", localInvoice.Status); + Assert.Equal(firstPayment, localInvoice.BtcPaid); + txFee = localInvoice.BtcDue - invoice.BtcDue; + Assert.Equal("paidPartial", localInvoice.ExceptionStatus); + secondPayment = localInvoice.BtcDue; + }); - cashCow.SendToAddress(invoiceAddress, secondPayment); + cashCow.SendToAddress(invoiceAddress, secondPayment); - Eventually(() => - { - tester.SimulateCallback(invoiceAddress); - var localInvoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant); - Assert.Equal("paid", localInvoice.Status); - Assert.Equal(firstPayment + secondPayment, localInvoice.BtcPaid); - Assert.Equal(Money.Zero, localInvoice.BtcDue); - Assert.Equal(false, (bool)((JValue)localInvoice.ExceptionStatus).Value); - }); + Eventually(() => + { + tester.SimulateCallback(invoiceAddress); + var localInvoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant); + Assert.Equal("paid", localInvoice.Status); + Assert.Equal(firstPayment + secondPayment, localInvoice.BtcPaid); + Assert.Equal(Money.Zero, localInvoice.BtcDue); + Assert.Equal(false, (bool)((JValue)localInvoice.ExceptionStatus).Value); + }); - cashCow.Generate(1); //The user has medium speed settings, so 1 conf is enough to be confirmed + cashCow.Generate(1); //The user has medium speed settings, so 1 conf is enough to be confirmed - Eventually(() => - { - tester.SimulateCallback(); - var localInvoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant); - Assert.Equal("confirmed", localInvoice.Status); - }); + Eventually(() => + { + tester.SimulateCallback(); + var localInvoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant); + Assert.Equal("confirmed", localInvoice.Status); + }); - cashCow.Generate(5); //Now should be complete + cashCow.Generate(5); //Now should be complete - Eventually(() => - { - tester.SimulateCallback(); - var localInvoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant); - Assert.Equal("complete", localInvoice.Status); - }); + Eventually(() => + { + tester.SimulateCallback(); + var localInvoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant); + Assert.Equal("complete", localInvoice.Status); + }); - invoice = user.BitPay.CreateInvoice(new Invoice() - { - Price = 5000.0, - Currency = "USD", - PosData = "posData", - OrderId = "orderId", - //RedirectURL = redirect + "redirect", - //NotificationURL = CallbackUri + "/notification", - ItemDesc = "Some description", - FullNotifications = true - }, Facade.Merchant); - invoiceAddress = BitcoinAddress.Create(invoice.BitcoinAddress, cashCow.Network); + invoice = user.BitPay.CreateInvoice(new Invoice() + { + Price = 5000.0, + Currency = "USD", + PosData = "posData", + OrderId = "orderId", + //RedirectURL = redirect + "redirect", + //NotificationURL = CallbackUri + "/notification", + ItemDesc = "Some description", + FullNotifications = true + }, Facade.Merchant); + invoiceAddress = BitcoinAddress.Create(invoice.BitcoinAddress, cashCow.Network); - cashCow.SendToAddress(invoiceAddress, invoice.BtcDue + Money.Coins(1)); + cashCow.SendToAddress(invoiceAddress, invoice.BtcDue + Money.Coins(1)); - Eventually(() => - { - tester.SimulateCallback(invoiceAddress); - var localInvoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant); - Assert.Equal("paidOver", localInvoice.Status); - Assert.Equal(Money.Zero, localInvoice.BtcDue); - Assert.Equal("paidOver", (string)((JValue)localInvoice.ExceptionStatus).Value); - }); + Eventually(() => + { + tester.SimulateCallback(invoiceAddress); + var localInvoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant); + Assert.Equal("paidOver", localInvoice.Status); + Assert.Equal(Money.Zero, localInvoice.BtcDue); + Assert.Equal("paidOver", (string)((JValue)localInvoice.ExceptionStatus).Value); + }); - cashCow.Generate(1); + cashCow.Generate(1); - Eventually(() => - { - tester.SimulateCallback(); - var localInvoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant); - Assert.Equal("confirmed", localInvoice.Status); - Assert.Equal(Money.Zero, localInvoice.BtcDue); - Assert.Equal("paidOver", (string)((JValue)localInvoice.ExceptionStatus).Value); - }); - } - } + Eventually(() => + { + tester.SimulateCallback(); + var localInvoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant); + Assert.Equal("confirmed", localInvoice.Status); + Assert.Equal(Money.Zero, localInvoice.BtcDue); + Assert.Equal("paidOver", (string)((JValue)localInvoice.ExceptionStatus).Value); + }); + } + } - private void Eventually(Action act) - { - CancellationTokenSource cts = new CancellationTokenSource(10000); - while(true) - { - try - { - act(); - break; - } - catch(XunitException) when(!cts.Token.IsCancellationRequested) - { - cts.Token.WaitHandle.WaitOne(500); - } - } - } - } + private void Eventually(Action act) + { + CancellationTokenSource cts = new CancellationTokenSource(10000); + while (true) + { + try + { + act(); + break; + } + catch (XunitException) when (!cts.Token.IsCancellationRequested) + { + cts.Token.WaitHandle.WaitOne(500); + } + } + } + } } diff --git a/BTCPayServer.Tests/UnitTestPeusa.cs b/BTCPayServer.Tests/UnitTestPeusa.cs new file mode 100644 index 000000000..363f0a3d5 --- /dev/null +++ b/BTCPayServer.Tests/UnitTestPeusa.cs @@ -0,0 +1,50 @@ +using NBitcoin; +using NBitcoin.DataEncoders; +using NBitpayClient; +using System; +using System.Collections.Generic; +using System.Text; +using Xunit; + +namespace BTCPayServer.Tests +{ + // Helper class for testing functionality and generating data needed during coding/debuging + public class UnitTestPeusa + { + // Unit test that generates temorary checkout Bitpay page + // https://forkbitpay.slack.com/archives/C7M093Z55/p1508293682000217 + [Fact] + public void BitpayCheckout() + { + var key = new Key(Encoders.Hex.DecodeData("7b70a06f35562873e3dcb46005ed0fe78e1991ad906e56adaaafa40ba861e056")); + var url = new Uri("https://test.bitpay.com/"); + var btcpay = new Bitpay(key, url); + var invoice = btcpay.CreateInvoice(new Invoice() + { + + Price = 5.0, + Currency = "USD", + PosData = "posData", + OrderId = "cdfd8a5f-6928-4c3b-ba9b-ddf438029e73", + ItemDesc = "Hello from the otherside" + }, Facade.Merchant); + + // go to invoice.Url + Console.WriteLine(invoice.Url); + } + + // Generating Extended public key to use on http://localhost:14142/stores/{storeId} + [Fact] + public void GeneratePubkey() + { + var network = Network.RegTest; + + ExtKey masterKey = new ExtKey(); + Console.WriteLine("Master key : " + masterKey.ToString(network)); + ExtPubKey masterPubKey = masterKey.Neuter(); + + ExtPubKey pubkey = masterPubKey.Derive(0); + Console.WriteLine("PubKey " + 0 + " : " + pubkey.ToString(network)); + } + } +} diff --git a/BTCPayServer/Configuration/BTCPayServerRuntime.cs b/BTCPayServer/Configuration/BTCPayServerRuntime.cs index 568b266e2..7ef6b61af 100644 --- a/BTCPayServer/Configuration/BTCPayServerRuntime.cs +++ b/BTCPayServer/Configuration/BTCPayServerRuntime.cs @@ -13,7 +13,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; using BTCPayServer.Data; -using BTCPayServer.Servcices.Invoices; +using BTCPayServer.Services.Invoices; using BTCPayServer.Services.Wallets; namespace BTCPayServer.Configuration diff --git a/BTCPayServer/Controllers/CallbackController.cs b/BTCPayServer/Controllers/CallbackController.cs index f14697010..b3455b73c 100644 --- a/BTCPayServer/Controllers/CallbackController.cs +++ b/BTCPayServer/Controllers/CallbackController.cs @@ -1,5 +1,5 @@ using BTCPayServer.Logging; -using BTCPayServer.Servcices.Invoices; +using BTCPayServer.Services.Invoices; using BTCPayServer.Services; using BTCPayServer.Services.Wallets; using Microsoft.AspNetCore.Http; diff --git a/BTCPayServer/Controllers/InvoiceController.API.cs b/BTCPayServer/Controllers/InvoiceController.API.cs index 00d750e87..b5009f30b 100644 --- a/BTCPayServer/Controllers/InvoiceController.API.cs +++ b/BTCPayServer/Controllers/InvoiceController.API.cs @@ -10,7 +10,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using BTCPayServer.Data; -using BTCPayServer.Servcices.Invoices; +using BTCPayServer.Services.Invoices; using Microsoft.AspNetCore.Cors; using BTCPayServer.Services.Stores; diff --git a/BTCPayServer/Controllers/InvoiceController.UI.cs b/BTCPayServer/Controllers/InvoiceController.UI.cs index 8d6ab411b..34c57f70e 100644 --- a/BTCPayServer/Controllers/InvoiceController.UI.cs +++ b/BTCPayServer/Controllers/InvoiceController.UI.cs @@ -1,7 +1,7 @@ using BTCPayServer.Data; using BTCPayServer.Filters; using BTCPayServer.Models.InvoicingModels; -using BTCPayServer.Servcices.Invoices; +using BTCPayServer.Services.Invoices; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Cors; using Microsoft.AspNetCore.Mvc; @@ -268,7 +268,7 @@ namespace BTCPayServer.Controllers ItemDesc = model.ItemDesc, FullNotifications = true, BuyerEmail = model.BuyerEmail, - }, store, HttpContext.Request.GetAbsoluteRoot()); + }, store, HttpContext.Request.GetAbsoluteRoot(), 120); StatusMessage = $"Invoice {result.Data.Id} just created!"; return RedirectToAction(nameof(ListInvoices)); diff --git a/BTCPayServer/Controllers/InvoiceController.cs b/BTCPayServer/Controllers/InvoiceController.cs index 67abb5fec..69d4ac9c3 100644 --- a/BTCPayServer/Controllers/InvoiceController.cs +++ b/BTCPayServer/Controllers/InvoiceController.cs @@ -29,7 +29,7 @@ using BTCPayServer.Services; using System.ComponentModel.DataAnnotations; using System.Text.RegularExpressions; using BTCPayServer.Services.Stores; -using BTCPayServer.Servcices.Invoices; +using BTCPayServer.Services.Invoices; using BTCPayServer.Services.Rates; using BTCPayServer.Services.Wallets; using BTCPayServer.Validations; @@ -75,7 +75,7 @@ namespace BTCPayServer.Controllers _FeeProvider = feeProvider ?? throw new ArgumentNullException(nameof(feeProvider)); } - internal async Task> CreateInvoiceCore(Invoice invoice, StoreData store, string serverUrl) + internal async Task> CreateInvoiceCore(Invoice invoice, StoreData store, string serverUrl, double expiryMinutes = 15) { var derivationStrategy = store.DerivationStrategy; var entity = new InvoiceEntity @@ -87,7 +87,7 @@ namespace BTCPayServer.Controllers if(notificationUri == null || (notificationUri.Scheme != "http" && notificationUri.Scheme != "https")) //TODO: Filer non routable addresses ? notificationUri = null; EmailAddressAttribute emailValidator = new EmailAddressAttribute(); - entity.ExpirationTime = entity.InvoiceTime + TimeSpan.FromMinutes(15.0); + entity.ExpirationTime = entity.InvoiceTime.AddMinutes(expiryMinutes); entity.ServerUrl = serverUrl; entity.FullNotifications = invoice.FullNotifications; entity.NotificationURL = notificationUri?.AbsoluteUri; diff --git a/BTCPayServer/Data/StoreData.cs b/BTCPayServer/Data/StoreData.cs index f330a984c..8c3a6e401 100644 --- a/BTCPayServer/Data/StoreData.cs +++ b/BTCPayServer/Data/StoreData.cs @@ -1,5 +1,5 @@ using BTCPayServer.Models; -using BTCPayServer.Servcices.Invoices; +using BTCPayServer.Services.Invoices; using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations.Schema; diff --git a/BTCPayServer/Hosting/BTCPayServerServices.cs b/BTCPayServer/Hosting/BTCPayServerServices.cs index c8aaba0e0..d9dc7073e 100644 --- a/BTCPayServer/Hosting/BTCPayServerServices.cs +++ b/BTCPayServer/Hosting/BTCPayServerServices.cs @@ -16,7 +16,7 @@ using NBXplorer; using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.Hosting; using BTCPayServer.Services; -using BTCPayServer.Servcices.Invoices; +using BTCPayServer.Services.Invoices; using BTCPayServer.Services.Rates; using BTCPayServer.Services.Stores; using BTCPayServer.Services.Fees; diff --git a/BTCPayServer/Migrations/20170926073744_Settings.Designer.cs b/BTCPayServer/Migrations/20170926073744_Settings.Designer.cs index 8f27c3b37..400730f1c 100644 --- a/BTCPayServer/Migrations/20170926073744_Settings.Designer.cs +++ b/BTCPayServer/Migrations/20170926073744_Settings.Designer.cs @@ -1,6 +1,6 @@ // using BTCPayServer.Data; -using BTCPayServer.Servcices.Invoices; +using BTCPayServer.Services.Invoices; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; diff --git a/BTCPayServer/Migrations/20170926084408_RequiresEmailConfirmation.Designer.cs b/BTCPayServer/Migrations/20170926084408_RequiresEmailConfirmation.Designer.cs index c9c90ec1f..b5c9d23fd 100644 --- a/BTCPayServer/Migrations/20170926084408_RequiresEmailConfirmation.Designer.cs +++ b/BTCPayServer/Migrations/20170926084408_RequiresEmailConfirmation.Designer.cs @@ -1,6 +1,6 @@ // using BTCPayServer.Data; -using BTCPayServer.Servcices.Invoices; +using BTCPayServer.Services.Invoices; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; diff --git a/BTCPayServer/Migrations/20171006013443_AddressMapping.Designer.cs b/BTCPayServer/Migrations/20171006013443_AddressMapping.Designer.cs index c2b8f6bc6..ee5867766 100644 --- a/BTCPayServer/Migrations/20171006013443_AddressMapping.Designer.cs +++ b/BTCPayServer/Migrations/20171006013443_AddressMapping.Designer.cs @@ -1,6 +1,6 @@ // using BTCPayServer.Data; -using BTCPayServer.Servcices.Invoices; +using BTCPayServer.Services.Invoices; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; diff --git a/BTCPayServer/Migrations/20171010082424_Tokens.Designer.cs b/BTCPayServer/Migrations/20171010082424_Tokens.Designer.cs index af6f94745..c9cee961b 100644 --- a/BTCPayServer/Migrations/20171010082424_Tokens.Designer.cs +++ b/BTCPayServer/Migrations/20171010082424_Tokens.Designer.cs @@ -1,6 +1,6 @@ // using BTCPayServer.Data; -using BTCPayServer.Servcices.Invoices; +using BTCPayServer.Services.Invoices; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; diff --git a/BTCPayServer/Migrations/20171012020112_PendingInvoices.Designer.cs b/BTCPayServer/Migrations/20171012020112_PendingInvoices.Designer.cs index fe3429d46..8ac5e3cc0 100644 --- a/BTCPayServer/Migrations/20171012020112_PendingInvoices.Designer.cs +++ b/BTCPayServer/Migrations/20171012020112_PendingInvoices.Designer.cs @@ -1,6 +1,6 @@ // using BTCPayServer.Data; -using BTCPayServer.Servcices.Invoices; +using BTCPayServer.Services.Invoices; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; diff --git a/BTCPayServer/Migrations/ApplicationDbContextModelSnapshot.cs b/BTCPayServer/Migrations/ApplicationDbContextModelSnapshot.cs index b0ec6b352..65d4da025 100644 --- a/BTCPayServer/Migrations/ApplicationDbContextModelSnapshot.cs +++ b/BTCPayServer/Migrations/ApplicationDbContextModelSnapshot.cs @@ -1,6 +1,6 @@ // using BTCPayServer.Data; -using BTCPayServer.Servcices.Invoices; +using BTCPayServer.Services.Invoices; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; diff --git a/BTCPayServer/Models/InvoicingModels/InvoiceDetailsModel.cs b/BTCPayServer/Models/InvoicingModels/InvoiceDetailsModel.cs index 4c0e47790..320c4d4e9 100644 --- a/BTCPayServer/Models/InvoicingModels/InvoiceDetailsModel.cs +++ b/BTCPayServer/Models/InvoicingModels/InvoiceDetailsModel.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using BTCPayServer.Servcices.Invoices; +using BTCPayServer.Services.Invoices; using NBitcoin; namespace BTCPayServer.Models.InvoicingModels diff --git a/BTCPayServer/Models/StoreViewModels/StoreViewModel.cs b/BTCPayServer/Models/StoreViewModels/StoreViewModel.cs index 59f0aba51..e2cafc12d 100644 --- a/BTCPayServer/Models/StoreViewModels/StoreViewModel.cs +++ b/BTCPayServer/Models/StoreViewModels/StoreViewModel.cs @@ -1,4 +1,4 @@ -using BTCPayServer.Servcices.Invoices; +using BTCPayServer.Services.Invoices; using BTCPayServer.Validations; using System; using System.Collections.Generic; diff --git a/BTCPayServer/Services/Invoices/InvoiceEntity.cs b/BTCPayServer/Services/Invoices/InvoiceEntity.cs index 1b4daae16..2c690bdde 100644 --- a/BTCPayServer/Services/Invoices/InvoiceEntity.cs +++ b/BTCPayServer/Services/Invoices/InvoiceEntity.cs @@ -9,7 +9,7 @@ using NBitpayClient; using Newtonsoft.Json.Linq; using NBitcoin.DataEncoders; -namespace BTCPayServer.Servcices.Invoices +namespace BTCPayServer.Services.Invoices { public class BuyerInformation { diff --git a/BTCPayServer/Services/Invoices/InvoiceNotificationManager.cs b/BTCPayServer/Services/Invoices/InvoiceNotificationManager.cs index 0fae0c2bb..054c425d8 100644 --- a/BTCPayServer/Services/Invoices/InvoiceNotificationManager.cs +++ b/BTCPayServer/Services/Invoices/InvoiceNotificationManager.cs @@ -16,7 +16,7 @@ using Newtonsoft.Json.Linq; using Newtonsoft.Json; using System.Collections.Concurrent; -namespace BTCPayServer.Servcices.Invoices +namespace BTCPayServer.Services.Invoices { public class InvoiceNotificationManager { diff --git a/BTCPayServer/Services/Invoices/InvoiceRepository.cs b/BTCPayServer/Services/Invoices/InvoiceRepository.cs index b313d5ea7..7de919e39 100644 --- a/BTCPayServer/Services/Invoices/InvoiceRepository.cs +++ b/BTCPayServer/Services/Invoices/InvoiceRepository.cs @@ -17,7 +17,7 @@ using BTCPayServer.Data; using System.Globalization; using BTCPayServer.Models.InvoicingModels; -namespace BTCPayServer.Servcices.Invoices +namespace BTCPayServer.Services.Invoices { public class InvoiceRepository { diff --git a/BTCPayServer/Services/Invoices/InvoiceWatcher.cs b/BTCPayServer/Services/Invoices/InvoiceWatcher.cs index 9257b0bd3..98ab9f859 100644 --- a/BTCPayServer/Services/Invoices/InvoiceWatcher.cs +++ b/BTCPayServer/Services/Invoices/InvoiceWatcher.cs @@ -14,7 +14,7 @@ using System.Collections.Concurrent; using Hangfire; using BTCPayServer.Services.Wallets; -namespace BTCPayServer.Servcices.Invoices +namespace BTCPayServer.Services.Invoices { public class InvoiceWatcher : IHostedService { diff --git a/BTCPayServer/Views/Invoice/Checkout.cshtml b/BTCPayServer/Views/Invoice/Checkout.cshtml index 07993d88a..66a16f201 100644 --- a/BTCPayServer/Views/Invoice/Checkout.cshtml +++ b/BTCPayServer/Views/Invoice/Checkout.cshtml @@ -543,13 +543,13 @@ - + diff --git a/BTCPayServer/Views/Invoice/Invoice.cshtml b/BTCPayServer/Views/Invoice/Invoice.cshtml index 6e15aa2b4..6781d8803 100644 --- a/BTCPayServer/Views/Invoice/Invoice.cshtml +++ b/BTCPayServer/Views/Invoice/Invoice.cshtml @@ -3,6 +3,15 @@ ViewData["Title"] = "Invoice " + Model.Id; } + +
@@ -86,7 +95,7 @@ Payment Url - @Model.PaymentUrl + @Model.PaymentUrl