mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2025-12-18 14:34:23 +01:00
Allow LN Address to customize invoice metadata, and various bug fixes on LNUrl (#4855)
* Allow LN Address to customize invoice metadata solves https://github.com/OpenSats/website/issues/8 * Refactor GetLNUrl * Fix lightningAddresssettings.Max being ignored * Fix: The payRequest generated by the callback wasn't the same as the original --------- Co-authored-by: nicolas.dorier <nicolas.dorier@gmail.com>
This commit is contained in:
@@ -4,7 +4,6 @@ using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Reflection.Metadata;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
@@ -17,7 +16,6 @@ using BTCPayServer.Lightning;
|
||||
using BTCPayServer.Payments;
|
||||
using BTCPayServer.Services;
|
||||
using BTCPayServer.Services.Invoices;
|
||||
using BTCPayServer.Services.Rates;
|
||||
using BTCPayServer.Services.Wallets;
|
||||
using BTCPayServer.Views.Manage;
|
||||
using BTCPayServer.Views.Server;
|
||||
@@ -29,6 +27,7 @@ using Microsoft.EntityFrameworkCore;
|
||||
using NBitcoin;
|
||||
using NBitcoin.DataEncoders;
|
||||
using NBitcoin.Payment;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using OpenQA.Selenium;
|
||||
using OpenQA.Selenium.Support.Extensions;
|
||||
@@ -2256,13 +2255,16 @@ namespace BTCPayServer.Tests
|
||||
s.FindAlertMessage(StatusMessageModel.StatusSeverity.Success);
|
||||
|
||||
s.Driver.ToggleCollapse("AddAddress");
|
||||
|
||||
var lnaddress2 = "EUR" + Guid.NewGuid().ToString();
|
||||
s.Driver.FindElement(By.Id("Add_Username")).SendKeys(lnaddress2);
|
||||
lnaddress2 = lnaddress2.ToLowerInvariant();
|
||||
|
||||
s.Driver.ToggleCollapse("AdvancedSettings");
|
||||
s.Driver.FindElement(By.Id("Add_CurrencyCode")).SendKeys("EUR");
|
||||
s.Driver.FindElement(By.Id("Add_Min")).SendKeys("2");
|
||||
s.Driver.FindElement(By.Id("Add_Max")).SendKeys("10");
|
||||
s.Driver.FindElement(By.Id("Add_InvoiceMetadata")).SendKeys("{\"test\":\"lol\"}");
|
||||
s.Driver.FindElement(By.CssSelector("button[value='add']")).Click();
|
||||
s.FindAlertMessage(StatusMessageModel.StatusSeverity.Success);
|
||||
|
||||
@@ -2278,20 +2280,100 @@ namespace BTCPayServer.Tests
|
||||
var lnurl = new Uri(LNURL.LNURL.ExtractUriFromInternetIdentifier(value).ToString()
|
||||
.Replace("https", "http"));
|
||||
var request = (LNURL.LNURLPayRequest)await LNURL.LNURL.FetchInformation(lnurl, new HttpClient());
|
||||
|
||||
var m = request.ParsedMetadata.ToDictionary(o => o.Key, o => o.Value);
|
||||
switch (value)
|
||||
{
|
||||
case { } v when v.StartsWith(lnaddress2):
|
||||
Assert.StartsWith(lnaddress2 + "@", m["text/identifier"]);
|
||||
lnaddress2 = m["text/identifier"];
|
||||
Assert.Equal(2, request.MinSendable.ToDecimal(LightMoneyUnit.Satoshi));
|
||||
Assert.Equal(10, request.MaxSendable.ToDecimal(LightMoneyUnit.Satoshi));
|
||||
break;
|
||||
|
||||
case { } v when v.StartsWith(lnaddress1):
|
||||
Assert.StartsWith(lnaddress1 + "@", m["text/identifier"]);
|
||||
lnaddress1 = m["text/identifier"];
|
||||
Assert.Equal(1, request.MinSendable.ToDecimal(LightMoneyUnit.Satoshi));
|
||||
Assert.Equal(6.12m, request.MaxSendable.ToDecimal(LightMoneyUnit.BTC));
|
||||
break;
|
||||
default:
|
||||
Assert.False(true, "Should have matched");
|
||||
break;
|
||||
}
|
||||
}
|
||||
var repo = s.Server.PayTester.GetService<InvoiceRepository>();
|
||||
var invoices = await repo.GetInvoices(new InvoiceQuery() { StoreId = new[] { s.StoreId } });
|
||||
Assert.Equal(2, invoices.Length);
|
||||
var emailSuffix = $"@{s.Server.PayTester.HostName}:{s.Server.PayTester.Port}";
|
||||
|
||||
foreach (var i in invoices)
|
||||
{
|
||||
var lightningPaymentMethod = i.GetPaymentMethod(new PaymentMethodId("BTC", PaymentTypes.LNURLPay));
|
||||
var paymentMethodDetails =
|
||||
lightningPaymentMethod.GetPaymentMethodDetails() as LNURLPayPaymentMethodDetails;
|
||||
Assert.Contains(
|
||||
paymentMethodDetails.ConsumedLightningAddress,
|
||||
new[] { lnaddress1, lnaddress2 });
|
||||
|
||||
if (paymentMethodDetails.ConsumedLightningAddress == lnaddress2)
|
||||
{
|
||||
Assert.Equal("lol", i.Metadata.AdditionalData["test"].Value<string>());
|
||||
}
|
||||
}
|
||||
|
||||
var lnUsername = lnaddress1.Split('@')[0];
|
||||
LNURLPayRequest req;
|
||||
using (var resp = await s.Server.PayTester.HttpClient.GetAsync($"/.well-known/lnurlp/{lnUsername}"))
|
||||
{
|
||||
var str = await resp.Content.ReadAsStringAsync();
|
||||
req = JsonConvert.DeserializeObject<LNURLPayRequest>(str);
|
||||
Assert.Contains(req.ParsedMetadata, m => m.Key == "text/identifier" && m.Value == lnaddress1);
|
||||
Assert.Contains(req.ParsedMetadata, m => m.Key == "text/plain" && m.Value.StartsWith("Paid to"));
|
||||
Assert.NotNull(req.Callback);
|
||||
Assert.Equal(new LightMoney(1000), req.MinSendable);
|
||||
Assert.Equal(LightMoney.FromUnit(6.12m, LightMoneyUnit.BTC), req.MaxSendable);
|
||||
}
|
||||
lnUsername = lnaddress2.Split('@')[0];
|
||||
using (var resp = await s.Server.PayTester.HttpClient.GetAsync($"/.well-known/lnurlp/{lnUsername}"))
|
||||
{
|
||||
var str = await resp.Content.ReadAsStringAsync();
|
||||
req = JsonConvert.DeserializeObject<LNURLPayRequest>(str);
|
||||
Assert.Equal(new LightMoney(2000), req.MinSendable);
|
||||
Assert.Equal(new LightMoney(10_000), req.MaxSendable);
|
||||
}
|
||||
// Check if we can get the same payrequest through the callback
|
||||
using (var resp = await s.Server.PayTester.HttpClient.GetAsync(req.Callback))
|
||||
{
|
||||
var str = await resp.Content.ReadAsStringAsync();
|
||||
req = JsonConvert.DeserializeObject<LNURLPayRequest>(str);
|
||||
Assert.Equal(new LightMoney(2000), req.MinSendable);
|
||||
Assert.Equal(new LightMoney(10_000), req.MaxSendable);
|
||||
}
|
||||
|
||||
// Can we ask for invoice? (Should fail, below minSpendable)
|
||||
using (var resp = await s.Server.PayTester.HttpClient.GetAsync(req.Callback + "?amount=1999"))
|
||||
{
|
||||
var str = await resp.Content.ReadAsStringAsync();
|
||||
var err = JsonConvert.DeserializeObject<LNUrlStatusResponse>(str);
|
||||
Assert.Equal("Amount is out of bounds.", err.Reason);
|
||||
}
|
||||
// Can we ask for invoice?
|
||||
using (var resp = await s.Server.PayTester.HttpClient.GetAsync(req.Callback + "?amount=2000"))
|
||||
{
|
||||
var str = await resp.Content.ReadAsStringAsync();
|
||||
var succ = JsonConvert.DeserializeObject<LNURLPayRequest.LNURLPayRequestCallbackResponse>(str);
|
||||
Assert.NotNull(succ.Pr);
|
||||
Assert.Equal(new LightMoney(2000), BOLT11PaymentRequest.Parse(succ.Pr, Network.RegTest).MinimumAmount);
|
||||
}
|
||||
|
||||
// Can we change comment?
|
||||
using (var resp = await s.Server.PayTester.HttpClient.GetAsync(req.Callback + "?amount=2001"))
|
||||
{
|
||||
var str = await resp.Content.ReadAsStringAsync();
|
||||
var succ = JsonConvert.DeserializeObject<LNURLPayRequest.LNURLPayRequestCallbackResponse>(str);
|
||||
Assert.NotNull(succ.Pr);
|
||||
Assert.Equal(new LightMoney(2001), BOLT11PaymentRequest.Parse(succ.Pr, Network.RegTest).MinimumAmount);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
||||
Reference in New Issue
Block a user