Plugins: Add hook for resolving Lightning Address (#5322)

This commit is contained in:
d11n
2023-09-14 12:53:48 +02:00
committed by GitHub
parent 492512f527
commit 163f805f3b
3 changed files with 71 additions and 42 deletions

View File

@@ -48,7 +48,7 @@ public class LightningAddressService
{ {
return await _memoryCache.GetOrCreateAsync(GetKey(username), async entry => return await _memoryCache.GetOrCreateAsync(GetKey(username), async entry =>
{ {
var result = await Get(new LightningAddressQuery() { Usernames = new[] { username } }); var result = await Get(new LightningAddressQuery { Usernames = new[] { username } });
return result.FirstOrDefault(); return result.FirstOrDefault();
}); });
} }
@@ -62,7 +62,7 @@ public class LightningAddressService
{ {
data.Username = NormalizeUsername(data.Username); data.Username = NormalizeUsername(data.Username);
await using var context = _applicationDbContextFactory.CreateContext(); await using var context = _applicationDbContextFactory.CreateContext();
var result = (await GetCore(context, new LightningAddressQuery() { Usernames = new[] { data.Username } })) var result = (await GetCore(context, new LightningAddressQuery { Usernames = new[] { data.Username } }))
.FirstOrDefault(); .FirstOrDefault();
if (result is not null) if (result is not null)
{ {
@@ -84,7 +84,7 @@ public class LightningAddressService
{ {
username = NormalizeUsername(username); username = NormalizeUsername(username);
await using var context = _applicationDbContextFactory.CreateContext(); await using var context = _applicationDbContextFactory.CreateContext();
var x = (await GetCore(context, new LightningAddressQuery() { Usernames = new[] { username } })).FirstOrDefault(); var x = (await GetCore(context, new LightningAddressQuery { Usernames = new[] { username } })).FirstOrDefault();
if (x is null) if (x is null)
return true; return true;
if (storeId is not null && x.StoreDataId != storeId) if (storeId is not null && x.StoreDataId != storeId)
@@ -100,7 +100,7 @@ public class LightningAddressService
public async Task Set(LightningAddressData data, ApplicationDbContext context) public async Task Set(LightningAddressData data, ApplicationDbContext context)
{ {
var result = (await GetCore(context, new LightningAddressQuery() { Usernames = new[] { data.Username } })) var result = (await GetCore(context, new LightningAddressQuery { Usernames = new[] { data.Username } }))
.FirstOrDefault(); .FirstOrDefault();
if (result is not null) if (result is not null)
{ {

View File

@@ -3,7 +3,6 @@ using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.Linq; using System.Linq;
using System.Net.Http;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using BTCPayServer.Abstractions.Constants; using BTCPayServer.Abstractions.Constants;
@@ -18,9 +17,9 @@ using BTCPayServer.Data.Payouts.LightningLike;
using BTCPayServer.Events; using BTCPayServer.Events;
using BTCPayServer.HostedServices; using BTCPayServer.HostedServices;
using BTCPayServer.Lightning; using BTCPayServer.Lightning;
using BTCPayServer.Logging;
using BTCPayServer.Payments; using BTCPayServer.Payments;
using BTCPayServer.Payments.Lightning; using BTCPayServer.Payments.Lightning;
using BTCPayServer.Plugins;
using BTCPayServer.Plugins.Crowdfund; using BTCPayServer.Plugins.Crowdfund;
using BTCPayServer.Plugins.PointOfSale; using BTCPayServer.Plugins.PointOfSale;
using BTCPayServer.Plugins.PointOfSale.Models; using BTCPayServer.Plugins.PointOfSale.Models;
@@ -32,7 +31,6 @@ using BTCPayServer.Services.Stores;
using LNURL; using LNURL;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Cors; using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Routing;
using NBitcoin; using NBitcoin;
@@ -368,41 +366,56 @@ namespace BTCPayServer
[IgnoreAntiforgeryToken] [IgnoreAntiforgeryToken]
public async Task<IActionResult> ResolveLightningAddress(string username) public async Task<IActionResult> ResolveLightningAddress(string username)
{ {
if (string.IsNullOrEmpty(username))
return NotFound("Unknown username");
LNURLPayRequest lnurlRequest = null;
// Check core and fall back to lookup Lightning Address via plugins
var lightningAddressSettings = await _lightningAddressService.ResolveByAddress(username); var lightningAddressSettings = await _lightningAddressService.ResolveByAddress(username);
if (lightningAddressSettings is null || username is null) if (lightningAddressSettings is null)
return NotFound("Unknown username");
var store = await _storeRepository.FindStore(lightningAddressSettings.StoreDataId);
var cryptoCode = "BTC";
if (store is null)
return NotFound("Unknown username");
if (GetLNUrlPaymentMethodId(cryptoCode, store, out var lnUrlMethod) is null)
return NotFound("LNUrl not available for store");
var blob = lightningAddressSettings.GetBlob();
var lnurlRequest = new LNURLPayRequest()
{ {
Tag = "payRequest", var resolver = (LightningAddressResolver)await _pluginHookService.ApplyFilter("resolve-lnurlp-request-for-lightning-address",
MinSendable = blob?.Min is decimal min ? new LightMoney(min, LightMoneyUnit.Satoshi) : null, new LightningAddressResolver(username));
MaxSendable = blob?.Max is decimal max ? new LightMoney(max, LightMoneyUnit.Satoshi) : null,
CommentAllowed = lnUrlMethod.LUD12Enabled ? 2000 : 0 lnurlRequest = resolver.LNURLPayRequest;
}; if (lnurlRequest is null)
return NotFound("Unknown username");
}
else
{
var store = await _storeRepository.FindStore(lightningAddressSettings.StoreDataId);
if (store is null)
return NotFound("Unknown username");
var cryptoCode = "BTC";
if (GetLNUrlPaymentMethodId(cryptoCode, store, out var lnUrlMethod) is null)
return NotFound("LNURL not available for store");
var blob = lightningAddressSettings.GetBlob();
lnurlRequest = new LNURLPayRequest
{
Tag = "payRequest",
MinSendable = blob?.Min is decimal min ? new LightMoney(min, LightMoneyUnit.Satoshi) : null,
MaxSendable = blob?.Max is decimal max ? new LightMoney(max, LightMoneyUnit.Satoshi) : null,
CommentAllowed = lnUrlMethod.LUD12Enabled ? 2000 : 0
};
var lnUrlMetadata = new Dictionary<string, string>
{
["text/identifier"] = $"{username}@{Request.Host}"
};
SetLNUrlDescriptionMetadata(lnUrlMetadata, store, store.GetStoreBlob(), null);
lnurlRequest.Metadata =
JsonConvert.SerializeObject(lnUrlMetadata.Select(kv => new[] { kv.Key, kv.Value }));
lnurlRequest.Callback = new Uri(_linkGenerator.GetUriByAction(
action: nameof(GetLNURLForLightningAddress),
controller: "UILNURL",
values: new { cryptoCode, username }, Request.Scheme, Request.Host, Request.PathBase));
}
NormalizeSendable(lnurlRequest); NormalizeSendable(lnurlRequest);
var lnUrlMetadata = new Dictionary<string, string>()
{
["text/identifier"] = $"{username}@{Request.Host}"
};
SetLNUrlDescriptionMetadata(lnUrlMetadata, store, store.GetStoreBlob(), null);
lnurlRequest.Metadata =
JsonConvert.SerializeObject(lnUrlMetadata.Select(kv => new[] { kv.Key, kv.Value }));
lnurlRequest.Callback = new Uri(_linkGenerator.GetUriByAction(
action: nameof(GetLNURLForLightningAddress),
controller: "UILNURL",
values: new { cryptoCode, username }, Request.Scheme, Request.Host, Request.PathBase));
lnurlRequest = await _pluginHookService.ApplyFilter("modify-lnurlp-request", lnurlRequest) as LNURLPayRequest; lnurlRequest = await _pluginHookService.ApplyFilter("modify-lnurlp-request", lnurlRequest) as LNURLPayRequest;
return Ok(lnurlRequest); return Ok(lnurlRequest);
} }
@@ -417,21 +430,23 @@ namespace BTCPayServer
return NotFound("Unknown username"); return NotFound("Unknown username");
var blob = lightningAddressSettings.GetBlob(); var blob = lightningAddressSettings.GetBlob();
var store = await _storeRepository.FindStore(lightningAddressSettings.StoreDataId); var store = await _storeRepository.FindStore(lightningAddressSettings.StoreDataId);
if (store is null)
return NotFound("Unknown username");
var result = await GetLNURLRequest( var result = await GetLNURLRequest(
cryptoCode, cryptoCode,
store, store,
store.GetStoreBlob(), store.GetStoreBlob(),
new CreateInvoiceRequest() new CreateInvoiceRequest
{ {
Currency = blob?.CurrencyCode, Currency = blob?.CurrencyCode,
Metadata = blob?.InvoiceMetadata Metadata = blob?.InvoiceMetadata
}, },
new LNURLPayRequest() new LNURLPayRequest
{ {
MinSendable = blob?.Min is decimal min ? new LightMoney(min, LightMoneyUnit.Satoshi) : null, MinSendable = blob?.Min is decimal min ? new LightMoney(min, LightMoneyUnit.Satoshi) : null,
MaxSendable = blob?.Max is decimal max ? new LightMoney(max, LightMoneyUnit.Satoshi) : null, MaxSendable = blob?.Max is decimal max ? new LightMoney(max, LightMoneyUnit.Satoshi) : null,
}, },
new Dictionary<string, string>() new Dictionary<string, string>
{ {
{ "text/identifier", $"{username}@{Request.Host}" } { "text/identifier", $"{username}@{Request.Host}" }
}); });

View File

@@ -0,0 +1,14 @@
using LNURL;
namespace BTCPayServer.Plugins;
public class LightningAddressResolver
{
public string Username { get; set; }
public LNURLPayRequest LNURLPayRequest { get; set; }
public LightningAddressResolver(string username)
{
Username = username;
}
}