mirror of
https://github.com/btcpayserver/btcpayserver.git
synced 2025-03-12 19:02:01 +01:00
Allow passing LNURLW to register boltcard
This commit is contained in:
parent
18fe420b74
commit
b9ef41b8c3
3 changed files with 71 additions and 2 deletions
|
@ -15,6 +15,8 @@ namespace BTCPayServer.Client.Models
|
|||
}
|
||||
public class RegisterBoltcardRequest
|
||||
{
|
||||
[JsonProperty("LNURLW")]
|
||||
public string LNURLW { get; set; }
|
||||
[JsonConverter(typeof(HexJsonConverter))]
|
||||
[JsonProperty("UID")]
|
||||
public byte[] UID { get; set; }
|
||||
|
|
|
@ -13,6 +13,7 @@ using BTCPayServer.Controllers;
|
|||
using BTCPayServer.Events;
|
||||
using BTCPayServer.Lightning;
|
||||
using BTCPayServer.Models.InvoicingModels;
|
||||
using BTCPayServer.NTag424;
|
||||
using BTCPayServer.Payments;
|
||||
using BTCPayServer.Payments.Lightning;
|
||||
using BTCPayServer.PayoutProcessors;
|
||||
|
@ -24,6 +25,7 @@ using BTCPayServer.Services.Stores;
|
|||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NBitcoin;
|
||||
using NBitcoin.DataEncoders;
|
||||
using NBitpayClient;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
@ -1115,6 +1117,35 @@ namespace BTCPayServer.Tests
|
|||
OnExisting = OnExistingBehavior.KeepVersion
|
||||
});
|
||||
Assert.Equal(card2.Version, card3.Version);
|
||||
var p = new byte[] { 0xc7 }.Concat(uid).Concat(new byte[8]).ToArray();
|
||||
var card4 = await client.RegisterBoltcard(test4.Id, new RegisterBoltcardRequest()
|
||||
{
|
||||
OnExisting = OnExistingBehavior.KeepVersion,
|
||||
LNURLW = card2.LNURLW + $"?p={Encoders.Hex.EncodeData(AESKey.Parse(card2.K1).Encrypt(p))}"
|
||||
});
|
||||
Assert.Equal(card2.Version, card4.Version);
|
||||
Assert.Equal(card2.K4, card4.K4);
|
||||
// Can't define both properties
|
||||
await AssertValidationError(["LNURLW"], () => client.RegisterBoltcard(test4.Id, new RegisterBoltcardRequest()
|
||||
{
|
||||
OnExisting = OnExistingBehavior.KeepVersion,
|
||||
UID = uid,
|
||||
LNURLW = card2.LNURLW + $"?p={Encoders.Hex.EncodeData(AESKey.Parse(card2.K1).Encrypt(p))}"
|
||||
}));
|
||||
// p is malformed
|
||||
await AssertValidationError(["LNURLW"], () => client.RegisterBoltcard(test4.Id, new RegisterBoltcardRequest()
|
||||
{
|
||||
OnExisting = OnExistingBehavior.KeepVersion,
|
||||
UID = uid,
|
||||
LNURLW = card2.LNURLW + $"?p=lol"
|
||||
}));
|
||||
// p is invalid
|
||||
p[0] = 0;
|
||||
await AssertValidationError(["LNURLW"], () => client.RegisterBoltcard(test4.Id, new RegisterBoltcardRequest()
|
||||
{
|
||||
OnExisting = OnExistingBehavior.KeepVersion,
|
||||
LNURLW = card2.LNURLW + $"?p={Encoders.Hex.EncodeData(AESKey.Parse(card2.K1).Encrypt(p))}"
|
||||
}));
|
||||
// Test with SATS denomination values
|
||||
var testSats = await client.CreatePullPayment(storeId, new Client.Models.CreatePullPaymentRequest()
|
||||
{
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO.IsolatedStorage;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
|
@ -215,7 +216,29 @@ namespace BTCPayServer.Controllers.Greenfield
|
|||
var pp = await _pullPaymentService.GetPullPayment(pullPaymentId, false);
|
||||
if (pp is null)
|
||||
return PullPaymentNotFound();
|
||||
_logs.PayServer.LogInformation(JsonConvert.SerializeObject(request, Formatting.Indented));
|
||||
var issuerKey = await _settingsRepository.GetIssuerKey(_env);
|
||||
// LNURLW is used by deeplinks
|
||||
if (request?.LNURLW is not null)
|
||||
{
|
||||
if (request.UID is not null)
|
||||
{
|
||||
ModelState.AddModelError(nameof(request.LNURLW), "You should pass either LNURLW or UID but not both");
|
||||
return this.CreateValidationError(ModelState);
|
||||
}
|
||||
var p = ExtractP(request.LNURLW);
|
||||
if (p is null)
|
||||
{
|
||||
ModelState.AddModelError(nameof(request.LNURLW), "The LNURLW should contains a 'p=' parameter");
|
||||
return this.CreateValidationError(ModelState);
|
||||
}
|
||||
if (issuerKey.TryDecrypt(p) is not BoltcardPICCData picc)
|
||||
{
|
||||
ModelState.AddModelError(nameof(request.LNURLW), "The LNURLW 'p=' parameter cannot be decrypted");
|
||||
return this.CreateValidationError(ModelState);
|
||||
}
|
||||
request.UID = picc.Uid;
|
||||
}
|
||||
|
||||
if (request?.UID is null || request.UID.Length != 7)
|
||||
{
|
||||
ModelState.AddModelError(nameof(request.UID), "The UID is required and should be 7 bytes");
|
||||
|
@ -234,7 +257,6 @@ namespace BTCPayServer.Controllers.Greenfield
|
|||
_ => request.OnExisting
|
||||
};
|
||||
|
||||
var issuerKey = await _settingsRepository.GetIssuerKey(_env);
|
||||
var version = await _dbContextFactory.LinkBoltcardToPullPayment(pullPaymentId, issuerKey, request.UID, request.OnExisting);
|
||||
var keys = issuerKey.CreatePullPaymentCardKey(request.UID, version, pullPaymentId).DeriveBoltcardKeys(issuerKey);
|
||||
|
||||
|
@ -254,6 +276,20 @@ namespace BTCPayServer.Controllers.Greenfield
|
|||
});
|
||||
}
|
||||
|
||||
private string? ExtractP(string? url)
|
||||
{
|
||||
if (url is null || !Uri.TryCreate(url, UriKind.Absolute, out var uri))
|
||||
return null;
|
||||
int num = uri.AbsoluteUri.IndexOf('?');
|
||||
if (num == -1)
|
||||
return null;
|
||||
string input = uri.AbsoluteUri.Substring(num);
|
||||
Match match = Regex.Match(input, "p=([a-f0-9A-F]{32})");
|
||||
if (!match.Success)
|
||||
return null;
|
||||
return match.Groups[1].Value;
|
||||
}
|
||||
|
||||
[HttpGet("~/api/v1/pull-payments/{pullPaymentId}")]
|
||||
[AllowAnonymous]
|
||||
public async Task<IActionResult> GetPullPayment(string pullPaymentId)
|
||||
|
|
Loading…
Add table
Reference in a new issue