diff --git a/BTCPayServer/BTCPayServer.csproj b/BTCPayServer/BTCPayServer.csproj index 29d8e2039..8a891cac5 100644 --- a/BTCPayServer/BTCPayServer.csproj +++ b/BTCPayServer/BTCPayServer.csproj @@ -127,6 +127,9 @@ PreserveNewest $(IncludeRazorContentInPack) + + $(IncludeRazorContentInPack) + $(IncludeRazorContentInPack) @@ -139,7 +142,7 @@ $(IncludeRazorContentInPack) - + $(IncludeRazorContentInPack) diff --git a/BTCPayServer/Configuration/BTCPayServerOptions.cs b/BTCPayServer/Configuration/BTCPayServerOptions.cs index f425e2653..c000e83e2 100644 --- a/BTCPayServer/Configuration/BTCPayServerOptions.cs +++ b/BTCPayServer/Configuration/BTCPayServerOptions.cs @@ -15,6 +15,7 @@ using Renci.SshNet; using NBitcoin.DataEncoders; using BTCPayServer.SSH; using BTCPayServer.Lightning; +using BTCPayServer.Configuration.External; namespace BTCPayServer.Configuration { @@ -78,6 +79,7 @@ namespace BTCPayServer.Configuration setting.ExplorerUri = conf.GetOrDefault($"{net.CryptoCode}.explorer.url", net.NBXplorerNetwork.DefaultSettings.DefaultUrl); setting.CookieFile = conf.GetOrDefault($"{net.CryptoCode}.explorer.cookiefile", net.NBXplorerNetwork.DefaultSettings.DefaultCookieFile); NBXplorerConnectionSettings.Add(setting); + { var lightning = conf.GetOrDefault($"{net.CryptoCode}.lightning", string.Empty); if (lightning.Length != 0) @@ -99,20 +101,25 @@ namespace BTCPayServer.Configuration } } + void externalLnd(string code, string lndType) { - var lightning = conf.GetOrDefault($"{net.CryptoCode}.external.lnd.grpc", string.Empty); + var lightning = conf.GetOrDefault(code, string.Empty); if (lightning.Length != 0) { if (!LightningConnectionString.TryParse(lightning, false, out var connectionString, out var error)) { - throw new ConfigException($"Invalid setting {net.CryptoCode}.external.lnd.grpc, " + Environment.NewLine + - $"lnd server: 'type=lnd-grpc;server=https://lnd.example.com;macaroon=abf239...;certthumbprint=2abdf302...'" + Environment.NewLine + - $"lnd server: 'type=lnd-grpc;server=https://lnd.example.com;macaroonfilepath=/root/.lnd/admin.macaroon;certthumbprint=2abdf302...'" + Environment.NewLine + + throw new ConfigException($"Invalid setting {code}, " + Environment.NewLine + + $"lnd server: 'type={lndType};server=https://lnd.example.com;macaroon=abf239...;certthumbprint=2abdf302...'" + Environment.NewLine + + $"lnd server: 'type={lndType};server=https://lnd.example.com;macaroonfilepath=/root/.lnd/admin.macaroon;certthumbprint=2abdf302...'" + Environment.NewLine + error); } - ExternalServicesByCryptoCode.Add(net.CryptoCode, new ExternalLNDGRPC(connectionString)); + var instanceType = typeof(T); + ExternalServicesByCryptoCode.Add(net.CryptoCode, (ExternalService)Activator.CreateInstance(instanceType, connectionString)); } - } + }; + + externalLnd($"{net.CryptoCode}.external.lnd.grpc", "lnd-grpc"); + externalLnd($"{net.CryptoCode}.external.lnd.rest", "lnd-rest"); } Logs.Configuration.LogInformation("Supported chains: " + String.Join(',', supportedChains.ToArray())); @@ -127,12 +134,12 @@ namespace BTCPayServer.Configuration int waitTime = 0; while (!string.IsNullOrEmpty(sshSettings.KeyFile) && !File.Exists(sshSettings.KeyFile)) { - if(waitTime++ < 5) + if (waitTime++ < 5) System.Threading.Thread.Sleep(1000); else throw new ConfigException($"sshkeyfile does not exist"); } - + if (sshSettings.Port > ushort.MaxValue || sshSettings.Port < ushort.MinValue) throw new ConfigException($"ssh port is invalid"); @@ -250,29 +257,4 @@ namespace BTCPayServer.Configuration return builder.ToString(); } } - - public class ExternalServices : MultiValueDictionary - { - public IEnumerable GetServices(string cryptoCode) where T : ExternalService - { - if (!this.TryGetValue(cryptoCode.ToUpperInvariant(), out var services)) - return Array.Empty(); - return services.OfType(); - } - } - - public class ExternalService - { - - } - - public class ExternalLNDGRPC : ExternalService - { - public ExternalLNDGRPC(LightningConnectionString connectionString) - { - ConnectionString = connectionString; - } - - public LightningConnectionString ConnectionString { get; set; } - } } diff --git a/BTCPayServer/Configuration/External/ExternalLnd.cs b/BTCPayServer/Configuration/External/ExternalLnd.cs new file mode 100644 index 000000000..af072ab9e --- /dev/null +++ b/BTCPayServer/Configuration/External/ExternalLnd.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using BTCPayServer.Lightning; + +namespace BTCPayServer.Configuration.External +{ + public abstract class ExternalLnd : ExternalService + { + public ExternalLnd(LightningConnectionString connectionString, LndTypes type) + { + ConnectionString = connectionString; + Type = type; + } + + public LndTypes Type { get; set; } + public LightningConnectionString ConnectionString { get; set; } + } + + public enum LndTypes + { + gRPC, Rest + } + + public class ExternalLndGrpc : ExternalLnd + { + public ExternalLndGrpc(LightningConnectionString connectionString) : base(connectionString, LndTypes.gRPC) { } + } + + public class ExternalLndRest : ExternalLnd + { + public ExternalLndRest(LightningConnectionString connectionString) : base(connectionString, LndTypes.Rest) { } + } +} diff --git a/BTCPayServer/Configuration/External/ExternalService.cs b/BTCPayServer/Configuration/External/ExternalService.cs new file mode 100644 index 000000000..c43a709b0 --- /dev/null +++ b/BTCPayServer/Configuration/External/ExternalService.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using BTCPayServer.Lightning; + +namespace BTCPayServer.Configuration.External +{ + public class ExternalServices : MultiValueDictionary + { + public IEnumerable GetServices(string cryptoCode) where T : ExternalService + { + if (!this.TryGetValue(cryptoCode.ToUpperInvariant(), out var services)) + return Array.Empty(); + return services.OfType(); + } + } + + public class ExternalService + { + } +} diff --git a/BTCPayServer/Controllers/ServerController.cs b/BTCPayServer/Controllers/ServerController.cs index 4028d04c2..d10317ae3 100644 --- a/BTCPayServer/Controllers/ServerController.cs +++ b/BTCPayServer/Controllers/ServerController.cs @@ -25,6 +25,7 @@ using System.Threading.Tasks; using Renci.SshNet; using BTCPayServer.Logging; using BTCPayServer.Lightning; +using BTCPayServer.Configuration.External; namespace BTCPayServer.Controllers { @@ -277,7 +278,7 @@ namespace BTCPayServer.Controllers else { e.CanTrust = _Options.IsTrustedFingerprint(e.FingerPrint, e.HostKey); - if(!e.CanTrust) + if (!e.CanTrust) Logs.Configuration.LogError($"SSH host fingerprint for {e.HostKeyName} is untrusted, start BTCPay with -sshtrustedfingerprints \"{Encoders.Hex.EncodeData(e.FingerPrint)}\""); } }; @@ -421,17 +422,15 @@ namespace BTCPayServer.Controllers var result = new ServicesViewModel(); foreach (var cryptoCode in _Options.ExternalServicesByCryptoCode.Keys) { + int i = 0; + foreach (var grpcService in _Options.ExternalServicesByCryptoCode.GetServices(cryptoCode)) { - int i = 0; - foreach (var grpcService in _Options.ExternalServicesByCryptoCode.GetServices(cryptoCode)) + result.LNDServices.Add(new ServicesViewModel.LNDServiceViewModel() { - result.LNDServices.Add(new ServicesViewModel.LNDServiceViewModel() - { - Crypto = cryptoCode, - Type = "gRPC", - Index = i++, - }); - } + Crypto = cryptoCode, + Type = grpcService.Type, + Index = i++, + }); } } result.HasSSH = _Options.SSHSettings != null; @@ -439,17 +438,17 @@ namespace BTCPayServer.Controllers } [Route("server/services/lnd-grpc/{cryptoCode}/{index}")] - public IActionResult LNDGRPCServices(string cryptoCode, int index, uint? nonce) + public IActionResult LndGrpcServices(string cryptoCode, int index, uint? nonce) { if (!_dashBoard.IsFullySynched(cryptoCode, out var unusud)) { StatusMessage = $"Error: {cryptoCode} is not fully synched"; return RedirectToAction(nameof(Services)); } - var external = GetExternalLNDConnectionString(cryptoCode, index); + var external = GetExternalLndConnectionString(cryptoCode, index); if (external == null) return NotFound(); - var model = new LNDGRPCServicesViewModel(); + var model = new LndGrpcServicesViewModel(); model.Host = $"{external.BaseUri.DnsSafeHost}:{external.BaseUri.Port}"; model.SSL = external.BaseUri.Scheme == "https"; @@ -493,9 +492,9 @@ namespace BTCPayServer.Controllers [Route("server/services/lnd-grpc/{cryptoCode}/{index}")] [HttpPost] - public IActionResult LNDGRPCServicesPOST(string cryptoCode, int index) + public IActionResult LndGrpcServicesPost(string cryptoCode, int index) { - var external = GetExternalLNDConnectionString(cryptoCode, index); + var external = GetExternalLndConnectionString(cryptoCode, index); if (external == null) return NotFound(); LightningConfigurations confs = new LightningConfigurations(); @@ -513,12 +512,12 @@ namespace BTCPayServer.Controllers var nonce = RandomUtils.GetUInt32(); var configKey = GetConfigKey("lnd-grpc", cryptoCode, index, nonce); _LnConfigProvider.KeepConfig(configKey, confs); - return RedirectToAction(nameof(LNDGRPCServices), new { cryptoCode = cryptoCode, nonce = nonce }); + return RedirectToAction(nameof(LndGrpcServices), new { cryptoCode = cryptoCode, nonce = nonce }); } - private LightningConnectionString GetExternalLNDConnectionString(string cryptoCode, int index) + private LightningConnectionString GetExternalLndConnectionString(string cryptoCode, int index) { - var connectionString = _Options.ExternalServicesByCryptoCode.GetServices(cryptoCode).Skip(index).Select(c => c.ConnectionString).FirstOrDefault(); + var connectionString = _Options.ExternalServicesByCryptoCode.GetServices(cryptoCode).Skip(index).Select(c => c.ConnectionString).FirstOrDefault(); if (connectionString == null) return null; connectionString = connectionString.Clone(); @@ -531,13 +530,35 @@ namespace BTCPayServer.Controllers } catch { - Logging.Logs.Configuration.LogWarning($"{cryptoCode}: The macaroon file path of the external LND grpc config was not found ({connectionString.MacaroonFilePath})"); + Logs.Configuration.LogWarning($"{cryptoCode}: The macaroon file path of the external LND grpc config was not found ({connectionString.MacaroonFilePath})"); return null; } } return connectionString; } + [Route("server/services/lnd-rest/{cryptoCode}/{index}")] + public IActionResult LndRestServices(string cryptoCode, int index, uint? nonce) + { + if (!_dashBoard.IsFullySynched(cryptoCode, out var unusud)) + { + StatusMessage = $"Error: {cryptoCode} is not fully synched"; + return RedirectToAction(nameof(Services)); + } + var external = GetExternalLndConnectionString(cryptoCode, index); + if (external == null) + return NotFound(); + var model = new LndRestServicesViewModel(); + + model.BaseApiUrl = external.BaseUri.ToString(); + if (external.CertificateThumbprint != null) + model.CertificateThumbprint = Encoders.Hex.EncodeData(external.CertificateThumbprint); + if (external.Macaroon != null) + model.Macaroon = Encoders.Hex.EncodeData(external.Macaroon); + + return View(model); + } + [Route("server/services/ssh")] public IActionResult SSHService(bool downloadKeyFile = false) { diff --git a/BTCPayServer/Controllers/StoresController.LightningLike.cs b/BTCPayServer/Controllers/StoresController.LightningLike.cs index 747b63d0a..60c05d028 100644 --- a/BTCPayServer/Controllers/StoresController.LightningLike.cs +++ b/BTCPayServer/Controllers/StoresController.LightningLike.cs @@ -114,7 +114,7 @@ namespace BTCPayServer.Controllers } if(!System.IO.File.Exists(connectionString.MacaroonFilePath)) { - ModelState.AddModelError(nameof(vm.ConnectionString), "The macaroonfilepath file does exist"); + ModelState.AddModelError(nameof(vm.ConnectionString), "The macaroonfilepath file does not exist"); return View(vm); } if(!System.IO.Path.IsPathRooted(connectionString.MacaroonFilePath)) diff --git a/BTCPayServer/Models/ServerViewModels/LNDGRPCServicesViewModel.cs b/BTCPayServer/Models/ServerViewModels/LndGrpcServicesViewModel.cs similarity index 91% rename from BTCPayServer/Models/ServerViewModels/LNDGRPCServicesViewModel.cs rename to BTCPayServer/Models/ServerViewModels/LndGrpcServicesViewModel.cs index 01f78bd3b..1636b94f1 100644 --- a/BTCPayServer/Models/ServerViewModels/LNDGRPCServicesViewModel.cs +++ b/BTCPayServer/Models/ServerViewModels/LndGrpcServicesViewModel.cs @@ -5,7 +5,7 @@ using System.Threading.Tasks; namespace BTCPayServer.Models.ServerViewModels { - public class LNDGRPCServicesViewModel + public class LndGrpcServicesViewModel { public string Host { get; set; } public bool SSL { get; set; } diff --git a/BTCPayServer/Models/ServerViewModels/LndRestServicesViewModel.cs b/BTCPayServer/Models/ServerViewModels/LndRestServicesViewModel.cs new file mode 100644 index 000000000..1d4efc5bc --- /dev/null +++ b/BTCPayServer/Models/ServerViewModels/LndRestServicesViewModel.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace BTCPayServer.Models.ServerViewModels +{ + public class LndRestServicesViewModel + { + public string BaseApiUrl { get; set; } + public string Macaroon { get; set; } + public string CertificateThumbprint { get; set; } + } +} diff --git a/BTCPayServer/Models/ServerViewModels/ServicesViewModel.cs b/BTCPayServer/Models/ServerViewModels/ServicesViewModel.cs index 15d8dda41..23e9b2911 100644 --- a/BTCPayServer/Models/ServerViewModels/ServicesViewModel.cs +++ b/BTCPayServer/Models/ServerViewModels/ServicesViewModel.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using BTCPayServer.Configuration.External; namespace BTCPayServer.Models.ServerViewModels { @@ -10,7 +11,7 @@ namespace BTCPayServer.Models.ServerViewModels public class LNDServiceViewModel { public string Crypto { get; set; } - public string Type { get; set; } + public LndTypes Type { get; set; } public int Index { get; set; } } public List LNDServices { get; set; } = new List(); diff --git a/BTCPayServer/Properties/launchSettings.json b/BTCPayServer/Properties/launchSettings.json index 6555e2c8e..e398044a6 100644 --- a/BTCPayServer/Properties/launchSettings.json +++ b/BTCPayServer/Properties/launchSettings.json @@ -4,17 +4,18 @@ "commandName": "Project", "commandLineArgs": "--debuglog debug.log", "launchBrowser": true, - "environmentVariables": { - "BTCPAY_NETWORK": "regtest", - "BTCPAY_BUNDLEJSCSS": "true", - "BTCPAY_LTCEXPLORERURL": "http://127.0.0.1:32838/", - "BTCPAY_BTCLIGHTNING": "type=charge;server=http://127.0.0.1:54938/;api-token=foiewnccewuify", - "BTCPAY_BTCEXTERNALLNDGRPC": "type=lnd-grpc;server=https://lnd:lnd@127.0.0.1:53280/;allowinsecure=true", - "BTCPAY_BTCEXPLORERURL": "http://127.0.0.1:32838/", - "ASPNETCORE_ENVIRONMENT": "Development", - "BTCPAY_CHAINS": "btc,ltc", - "BTCPAY_POSTGRES": "User ID=postgres;Host=127.0.0.1;Port=39372;Database=btcpayserver" - }, + "environmentVariables": { + "BTCPAY_NETWORK": "regtest", + "BTCPAY_BUNDLEJSCSS": "true", + "BTCPAY_LTCEXPLORERURL": "http://127.0.0.1:32838/", + "BTCPAY_BTCLIGHTNING": "type=charge;server=http://127.0.0.1:54938/;api-token=foiewnccewuify", + "BTCPAY_BTCEXTERNALLNDGRPC": "type=lnd-grpc;server=https://lnd:lnd@127.0.0.1:53280/;allowinsecure=true", + "BTCPAY_BTCEXTERNALLNDREST": "type=lnd-rest;server=https://lnd:lnd@127.0.0.1:53280/lnd-rest/btc/;allowinsecure=true;macaroonfilepath=D:\\admin.macaroon", + "BTCPAY_BTCEXPLORERURL": "http://127.0.0.1:32838/", + "ASPNETCORE_ENVIRONMENT": "Development", + "BTCPAY_CHAINS": "btc,ltc", + "BTCPAY_POSTGRES": "User ID=postgres;Host=127.0.0.1;Port=39372;Database=btcpayserver" + }, "applicationUrl": "http://127.0.0.1:14142/" } } diff --git a/BTCPayServer/Views/Server/LNDGRPCServices.cshtml b/BTCPayServer/Views/Server/LndGrpcServices.cshtml similarity index 97% rename from BTCPayServer/Views/Server/LNDGRPCServices.cshtml rename to BTCPayServer/Views/Server/LndGrpcServices.cshtml index bcf2f2262..a23b68e5a 100644 --- a/BTCPayServer/Views/Server/LNDGRPCServices.cshtml +++ b/BTCPayServer/Views/Server/LndGrpcServices.cshtml @@ -1,10 +1,10 @@ -@model BTCPayServer.Models.ServerViewModels.LNDGRPCServicesViewModel +@model LndGrpcServicesViewModel @{ ViewData.SetActivePageAndTitle(ServerNavPages.Services); } -

GRPC settings

+

LND GRPC

diff --git a/BTCPayServer/Views/Server/LndRestServices.cshtml b/BTCPayServer/Views/Server/LndRestServices.cshtml new file mode 100644 index 000000000..0b0b01523 --- /dev/null +++ b/BTCPayServer/Views/Server/LndRestServices.cshtml @@ -0,0 +1,41 @@ +@model LndRestServicesViewModel +@{ + ViewData.SetActivePageAndTitle(ServerNavPages.Services); +} + + +

LND REST

+ +
+
+
+
+
+ +
+ +
+
+

BTCPay exposes LND Rest services for outside consumption. See connection information below

+
+ +
+ + +
+ @if (Model.Macaroon != null) + { +
+ + +
+ } + @if (Model.CertificateThumbprint != null) + { +
+ + +
+ } +
+
diff --git a/BTCPayServer/Views/Server/Services.cshtml b/BTCPayServer/Views/Server/Services.cshtml index f487a1075..7451fb2d5 100644 --- a/BTCPayServer/Views/Server/Services.cshtml +++ b/BTCPayServer/Views/Server/Services.cshtml @@ -16,7 +16,7 @@
- You can get access here to LND-gRPC or SSH services exposed by your server + You can get access here to LND (gRPC, Rest) or SSH services exposed by your server
@@ -29,17 +29,24 @@ - @foreach(var lnd in Model.LNDServices) + @foreach (var lnd in Model.LNDServices) { @lnd.Crypto - @lnd.Type + LND @lnd.Type.ToString() - See information + @if (lnd.Type == BTCPayServer.Configuration.External.LndTypes.gRPC) + { + See information + } + else if (lnd.Type == BTCPayServer.Configuration.External.LndTypes.Rest) + { + See information + } } - @if(Model.HasSSH) + @if (Model.HasSSH) { None