Suppoort macaroonfilepath in connection string

This commit is contained in:
nicolas.dorier 2018-07-10 12:46:04 +09:00
parent 73cb3dc4ee
commit 1a1078782e
7 changed files with 162 additions and 32 deletions

View file

@ -59,6 +59,14 @@ namespace BTCPayServer.Tests.Lnd
Assert.Equal(createInvoice.BOLT11, getInvoice.BOLT11);
}
[Fact]
public void Play()
{
var seq = new System.Buffers.ReadOnlySequence<byte>(new ReadOnlyMemory<byte>(new byte[1000]));
var seq2 = seq.Slice(3);
var pos = seq2.GetPosition(0);
}
// integration tests
[Fact]
public async Task TestWaitListenInvoice()

View file

@ -97,6 +97,20 @@ namespace BTCPayServer.Controllers
}
}
if(connectionString.MacaroonFilePath != null)
{
if(!CanUseInternalLightning())
{
ModelState.AddModelError(nameof(vm.ConnectionString), "You are not authorized to use macaroonfilepath");
return View(vm);
}
if(!System.IO.File.Exists(connectionString.MacaroonFilePath))
{
ModelState.AddModelError(nameof(vm.ConnectionString), "The macaroonfilepath file does exist");
return View(vm);
}
}
if (isInternalNode && !CanUseInternalLightning())
{
ModelState.AddModelError(nameof(vm.ConnectionString), "Unauthorized url");

View file

@ -32,6 +32,7 @@ namespace BTCPayServer.Payments.Lightning
return new LndInvoiceClient(new LndSwaggerClient(new LndRestSettings(connString.BaseUri)
{
Macaroon = connString.Macaroon,
MacaroonFilePath = connString.MacaroonFilePath,
CertificateThumbprint = connString.CertificateThumbprint,
AllowInsecure = connString.AllowInsecure,
}));

View file

@ -196,6 +196,22 @@ namespace BTCPayServer.Payments.Lightning
}
}
var macaroonFilePath = Take(keyValues, "macaroonfilepath");
if (macaroonFilePath != null)
{
if(macaroon != null)
{
error = $"The key 'macaroon' is already specified";
return false;
}
if(!macaroonFilePath.EndsWith(".macaroon", StringComparison.OrdinalIgnoreCase))
{
error = $"The key 'macaroonfilepath' should point to a .macaroon file";
return false;
}
result.MacaroonFilePath = macaroonFilePath;
}
string securitySet = null;
var certthumbprint = Take(keyValues, "certthumbprint");
if (certthumbprint != null)
@ -223,12 +239,12 @@ namespace BTCPayServer.Payments.Lightning
if (allowinsecureStr != null)
{
var allowedValues = new[] { "true", "false" };
if(!allowedValues.Any(v=> v.Equals(allowinsecureStr, StringComparison.OrdinalIgnoreCase)))
if (!allowedValues.Any(v => v.Equals(allowinsecureStr, StringComparison.OrdinalIgnoreCase)))
{
error = $"The key 'allowinsecure' should be true or false";
return false;
}
bool allowInsecure = allowinsecureStr.Equals("true", StringComparison.OrdinalIgnoreCase);
if (securitySet != null && allowInsecure)
{
@ -238,7 +254,7 @@ namespace BTCPayServer.Payments.Lightning
result.AllowInsecure = allowInsecure;
}
if(!result.AllowInsecure && result.BaseUri.Scheme == "http")
if (!result.AllowInsecure && result.BaseUri.Scheme == "http")
{
error = $"The key 'allowinsecure' is false, but server's Uri is not using https";
return false;
@ -340,6 +356,7 @@ namespace BTCPayServer.Payments.Lightning
private set;
}
public byte[] Macaroon { get; set; }
public string MacaroonFilePath { get; set; }
public byte[] CertificateThumbprint { get; set; }
public bool AllowInsecure { get; set; }
@ -388,11 +405,15 @@ namespace BTCPayServer.Payments.Lightning
{
builder.Append($";macaroon={Encoder.EncodeData(Macaroon)}");
}
if (MacaroonFilePath != null)
{
builder.Append($";macaroonfilepath={MacaroonFilePath}");
}
if (CertificateThumbprint != null)
{
builder.Append($";certthumbprint={Encoders.Hex.EncodeData(CertificateThumbprint)}");
}
if(AllowInsecure)
if (AllowInsecure)
{
builder.Append($";allowinsecure=true");
}

View file

@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using NBitcoin.DataEncoders;
namespace BTCPayServer.Payments.Lightning.Lnd
{
public abstract class LndAuthentication
{
public class FixedMacaroonAuthentication : LndAuthentication
{
public FixedMacaroonAuthentication(byte[] macaroon)
{
if (macaroon == null)
throw new ArgumentNullException(nameof(macaroon));
Macaroon = macaroon;
}
public byte[] Macaroon { get; set; }
public override void AddAuthentication(HttpRequestMessage httpRequest)
{
httpRequest.Headers.Add("Grpc-Metadata-macaroon", Encoders.Hex.EncodeData(Macaroon));
}
}
public class NullAuthentication : LndAuthentication
{
public static NullAuthentication Instance { get; } = new NullAuthentication();
private NullAuthentication()
{
}
public override void AddAuthentication(HttpRequestMessage httpRequest)
{
}
}
public class MacaroonFileAuthentication : LndAuthentication
{
public MacaroonFileAuthentication(string filePath)
{
if (filePath == null)
throw new ArgumentNullException(nameof(filePath));
// Because this dump the whole file, let's make sure it is indeed the macaroon
if (!filePath.EndsWith(".macaroon", StringComparison.OrdinalIgnoreCase))
throw new ArgumentException(message: "filePath is not a macaroon file", paramName: nameof(filePath));
FilePath = filePath;
}
public string FilePath { get; set; }
public override void AddAuthentication(HttpRequestMessage httpRequest)
{
try
{
var bytes = File.ReadAllBytes(FilePath);
httpRequest.Headers.Add("Grpc-Metadata-macaroon", Encoders.Hex.EncodeData(bytes));
}
catch
{
}
}
}
public abstract void AddAuthentication(HttpRequestMessage httpRequest);
}
}

View file

@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace BTCPayServer.Payments.Lightning.Lnd
{
public class LndRestSettings
{
public LndRestSettings()
{
}
public LndRestSettings(Uri uri)
{
Uri = uri;
}
public Uri Uri { get; set; }
/// <summary>
/// The SHA256 of the PEM certificate
/// </summary>
public byte[] CertificateThumbprint { get; set; }
public byte[] Macaroon { get; set; }
public bool AllowInsecure { get; set; }
public string MacaroonFilePath { get; set; }
public LndAuthentication CreateLndAuthentication()
{
if (Macaroon != null)
return new LndAuthentication.FixedMacaroonAuthentication(Macaroon);
if (!string.IsNullOrEmpty(MacaroonFilePath))
return new LndAuthentication.MacaroonFileAuthentication(MacaroonFilePath);
return LndAuthentication.NullAuthentication.Instance;
}
}
}

View file

@ -10,38 +10,28 @@ using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using NBitcoin.DataEncoders;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace BTCPayServer.Payments.Lightning.Lnd
{
public class LndRestSettings
{
public LndRestSettings()
{
}
public LndRestSettings(Uri uri)
{
Uri = uri;
}
public Uri Uri { get; set; }
/// <summary>
/// The SHA256 of the PEM certificate
/// </summary>
public byte[] CertificateThumbprint { get; set; }
public byte[] Macaroon { get; set; }
public bool AllowInsecure { get; set; }
}
public partial class LndSwaggerClient
{
public LndSwaggerClient(LndRestSettings settings)
: this(settings.Uri.AbsoluteUri.TrimEnd('/'), CreateHttpClient(settings))
{
_Settings = settings;
_Authentication = settings.CreateLndAuthentication();
}
LndRestSettings _Settings;
LndAuthentication _Authentication;
partial void PrepareRequest(HttpClient client, HttpRequestMessage request, string url)
{
_Authentication.AddAuthentication(request);
}
internal static HttpClient CreateHttpClient(LndRestSettings settings)
{
var handler = new HttpClientHandler
@ -60,7 +50,7 @@ namespace BTCPayServer.Payments.Lightning.Lnd
};
}
if(settings.AllowInsecure)
if (settings.AllowInsecure)
{
handler.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
}
@ -69,14 +59,7 @@ namespace BTCPayServer.Payments.Lightning.Lnd
if (settings.Uri.Scheme == "http")
throw new InvalidOperationException("AllowInsecure is set to false, but the URI is not using https");
}
var httpClient = new HttpClient(handler);
if (settings.Macaroon != null)
{
var macaroonHex = BitConverter.ToString(settings.Macaroon).Replace("-", "", StringComparison.InvariantCulture);
httpClient.DefaultRequestHeaders.Add("Grpc-Metadata-macaroon", macaroonHex);
}
return httpClient;
return new HttpClient(handler);
}
internal HttpClient CreateHttpClient()