diff --git a/BTCPayServer.Tests/TestAccount.cs b/BTCPayServer.Tests/TestAccount.cs index 085d68349..b45d364f5 100644 --- a/BTCPayServer.Tests/TestAccount.cs +++ b/BTCPayServer.Tests/TestAccount.cs @@ -128,7 +128,7 @@ namespace BTCPayServer.Tests var storeController = this.GetController(); await storeController.AddLightningNode(StoreId, new LightningNodeViewModel() { - Url = connectionType == LightningConnectionType.Charge ? parent.MerchantCharge.Client.Uri.AbsoluteUri : + ConnectionString = connectionType == LightningConnectionType.Charge ? parent.MerchantCharge.Client.Uri.AbsoluteUri : connectionType == LightningConnectionType.CLightning ? parent.MerchantLightningD.Address.AbsoluteUri : throw new NotSupportedException(connectionType.ToString()), SkipPortTest = true diff --git a/BTCPayServer.Tests/UnitTest1.cs b/BTCPayServer.Tests/UnitTest1.cs index f048289a4..8e59c0600 100644 --- a/BTCPayServer.Tests/UnitTest1.cs +++ b/BTCPayServer.Tests/UnitTest1.cs @@ -409,14 +409,14 @@ namespace BTCPayServer.Tests var testResult = storeController.AddLightningNode(user.StoreId, new LightningNodeViewModel() { - Url = tester.MerchantCharge.Client.Uri.AbsoluteUri + ConnectionString = tester.MerchantCharge.Client.Uri.AbsoluteUri }, "test", "BTC").GetAwaiter().GetResult(); Assert.DoesNotContain("Error", ((LightningNodeViewModel)Assert.IsType(testResult).Model).StatusMessage, StringComparison.OrdinalIgnoreCase); Assert.True(storeController.ModelState.IsValid); Assert.IsType(storeController.AddLightningNode(user.StoreId, new LightningNodeViewModel() { - Url = tester.MerchantCharge.Client.Uri.AbsoluteUri + ConnectionString = tester.MerchantCharge.Client.Uri.AbsoluteUri }, "save", "BTC").GetAwaiter().GetResult()); var storeVm = Assert.IsType(Assert.IsType(storeController.UpdateStore()).Model); @@ -428,41 +428,84 @@ namespace BTCPayServer.Tests public void CanParseLightningURL() { LightningConnectionString conn = null; - Assert.True(LightningConnectionString.TryParse("/test/a", out conn)); - Assert.Equal("unix://test/a", conn.ToString()); - Assert.Equal("unix://test/a", conn.ToUri(true).AbsoluteUri); - Assert.Equal("unix://test/a", conn.ToUri(false).AbsoluteUri); - Assert.Equal(LightningConnectionType.CLightning, conn.ConnectionType); + Assert.True(LightningConnectionString.TryParse("/test/a", true, out conn)); + for (int i = 0; i < 2; i++) + { + if (i == 1) + Assert.True(LightningConnectionString.TryParse(conn.ToString(), false, out conn)); + Assert.Equal(i == 0, conn.IsLegacy); + Assert.Equal("type=clightning;server=unix://test/a", conn.ToString()); + Assert.Equal("unix://test/a", conn.ToUri(true).AbsoluteUri); + Assert.Equal("unix://test/a", conn.ToUri(false).AbsoluteUri); + Assert.Equal(LightningConnectionType.CLightning, conn.ConnectionType); + } - Assert.True(LightningConnectionString.TryParse("unix://test/a", out conn)); - Assert.Equal("unix://test/a", conn.ToString()); - Assert.Equal("unix://test/a", conn.ToUri(true).AbsoluteUri); - Assert.Equal("unix://test/a", conn.ToUri(false).AbsoluteUri); - Assert.Equal(LightningConnectionType.CLightning, conn.ConnectionType); + Assert.True(LightningConnectionString.TryParse("unix://test/a", true, out conn)); + for (int i = 0; i < 2; i++) + { + if (i == 1) + Assert.True(LightningConnectionString.TryParse(conn.ToString(), false, out conn)); + Assert.Equal("type=clightning;server=unix://test/a", conn.ToString()); + Assert.Equal("unix://test/a", conn.ToUri(true).AbsoluteUri); + Assert.Equal("unix://test/a", conn.ToUri(false).AbsoluteUri); + Assert.Equal(LightningConnectionType.CLightning, conn.ConnectionType); + } - Assert.True(LightningConnectionString.TryParse("unix://test/a", out conn)); - Assert.Equal("unix://test/a", conn.ToString()); - Assert.Equal("unix://test/a", conn.ToUri(true).AbsoluteUri); - Assert.Equal("unix://test/a", conn.ToUri(false).AbsoluteUri); - Assert.Equal(LightningConnectionType.CLightning, conn.ConnectionType); + Assert.True(LightningConnectionString.TryParse("unix://test/a", true, out conn)); + for (int i = 0; i < 2; i++) + { + if (i == 1) + Assert.True(LightningConnectionString.TryParse(conn.ToString(), false, out conn)); + Assert.Equal("type=clightning;server=unix://test/a", conn.ToString()); + Assert.Equal("unix://test/a", conn.ToUri(true).AbsoluteUri); + Assert.Equal("unix://test/a", conn.ToUri(false).AbsoluteUri); + Assert.Equal(LightningConnectionType.CLightning, conn.ConnectionType); + } - Assert.True(LightningConnectionString.TryParse("tcp://test/a", out conn)); - Assert.Equal("tcp://test/a", conn.ToString()); - Assert.Equal("tcp://test/a", conn.ToUri(true).AbsoluteUri); - Assert.Equal("tcp://test/a", conn.ToUri(false).AbsoluteUri); - Assert.Equal(LightningConnectionType.CLightning, conn.ConnectionType); + Assert.True(LightningConnectionString.TryParse("tcp://test/a", true, out conn)); + for (int i = 0; i < 2; i++) + { + if (i == 1) + Assert.True(LightningConnectionString.TryParse(conn.ToString(), false, out conn)); + Assert.Equal("type=clightning;server=tcp://test/a", conn.ToString()); + Assert.Equal("tcp://test/a", conn.ToUri(true).AbsoluteUri); + Assert.Equal("tcp://test/a", conn.ToUri(false).AbsoluteUri); + Assert.Equal(LightningConnectionType.CLightning, conn.ConnectionType); + } - Assert.True(LightningConnectionString.TryParse("http://aaa:bbb@test/a", out conn)); - Assert.Equal("http://aaa:bbb@test/a", conn.ToString()); - Assert.Equal("http://aaa:bbb@test/a", conn.ToUri(true).AbsoluteUri); - Assert.Equal("http://test/a", conn.ToUri(false).AbsoluteUri); - Assert.Equal(LightningConnectionType.Charge, conn.ConnectionType); - Assert.Equal("aaa", conn.Username); - Assert.Equal("bbb", conn.Password); + Assert.True(LightningConnectionString.TryParse("http://aaa:bbb@test/a", true, out conn)); + for (int i = 0; i < 2; i++) + { + if (i == 1) + Assert.True(LightningConnectionString.TryParse(conn.ToString(), false, out conn)); + Assert.Equal("type=charge;server=http://aaa:bbb@test/a", conn.ToString()); + Assert.Equal("http://aaa:bbb@test/a", conn.ToUri(true).AbsoluteUri); + Assert.Equal("http://test/a", conn.ToUri(false).AbsoluteUri); + Assert.Equal(LightningConnectionType.Charge, conn.ConnectionType); + Assert.Equal("aaa", conn.Username); + Assert.Equal("bbb", conn.Password); + } - Assert.False(LightningConnectionString.TryParse("lol://aaa:bbb@test/a", out conn)); - Assert.False(LightningConnectionString.TryParse("https://test/a", out conn)); - Assert.False(LightningConnectionString.TryParse("unix://dwewoi:dwdwqd@test/a", out conn)); + Assert.True(LightningConnectionString.TryParse("http://api-token:bbb@test/a", true, out conn)); + for (int i = 0; i < 2; i++) + { + if (i == 1) + Assert.True(LightningConnectionString.TryParse(conn.ToString(), false, out conn)); + Assert.Equal("type=charge;server=http://test/a;api-token=bbb", conn.ToString()); + } + + Assert.False(LightningConnectionString.TryParse("lol://aaa:bbb@test/a", true, out conn)); + Assert.False(LightningConnectionString.TryParse("https://test/a", true, out conn)); + Assert.False(LightningConnectionString.TryParse("unix://dwewoi:dwdwqd@test/a", true, out conn)); + Assert.False(LightningConnectionString.TryParse("tcp://test/a", false, out conn)); + Assert.False(LightningConnectionString.TryParse("type=charge;server=http://aaa:bbb@test/a;unk=lol", false, out conn)); + Assert.False(LightningConnectionString.TryParse("type=charge;server=tcp://aaa:bbb@test/a", false, out conn)); + Assert.False(LightningConnectionString.TryParse("type=charge", false, out conn)); + Assert.False(LightningConnectionString.TryParse("type=clightning", false, out conn)); + Assert.True(LightningConnectionString.TryParse("type=clightning;server=tcp://aaa:bbb@test/a", false, out conn)); + Assert.True(LightningConnectionString.TryParse("type=clightning;server=/aaa:bbb@test/a", false, out conn)); + Assert.True(LightningConnectionString.TryParse("type=clightning;server=unix://aaa:bbb@test/a", false, out conn)); + Assert.False(LightningConnectionString.TryParse("type=clightning;server=wtf://aaa:bbb@test/a", false, out conn)); } [Fact] diff --git a/BTCPayServer/Configuration/BTCPayServerOptions.cs b/BTCPayServer/Configuration/BTCPayServerOptions.cs index 2ed2e665d..db9760412 100644 --- a/BTCPayServer/Configuration/BTCPayServerOptions.cs +++ b/BTCPayServer/Configuration/BTCPayServerOptions.cs @@ -77,11 +77,15 @@ namespace BTCPayServer.Configuration var lightning = conf.GetOrDefault($"{net.CryptoCode}.lightning", string.Empty); if(lightning.Length != 0) { - if(!LightningConnectionString.TryParse(lightning, out var connectionString, out var error)) + if(!LightningConnectionString.TryParse(lightning, true, out var connectionString, out var error)) { - throw new ConfigException($"Invalid setting {net.CryptoCode}.lightning, you need to pass either " + - $"the absolute path to the unix socket of a running CLightning instance (eg. /root/.lightning/lightning-rpc), " + - $"or the url to a charge server with crendetials (eg. https://apitoken@API_TOKEN_SECRET:charge.example.com/)"); + throw new ConfigException($"Invalid setting {net.CryptoCode}.lightning, " + Environment.NewLine + + $"If you have a lightning server use: 'type=clightning;server=/root/.lightning/lightning-rpc', " + Environment.NewLine + + $"If you have a lightning charge server: 'type=charge;server=https://charge.example.com;api-token=yourapitoken'"); + } + if(connectionString.IsLegacy) + { + Logs.Configuration.LogWarning($"Setting {net.CryptoCode}.lightning will work but use an deprecated format, please replace it by '{connectionString.ToString()}'"); } InternalLightningByCryptoCode.Add(net.CryptoCode, connectionString); } diff --git a/BTCPayServer/Controllers/InvoiceController.cs b/BTCPayServer/Controllers/InvoiceController.cs index 7a02ebb24..cd148bfd7 100644 --- a/BTCPayServer/Controllers/InvoiceController.cs +++ b/BTCPayServer/Controllers/InvoiceController.cs @@ -115,10 +115,11 @@ namespace BTCPayServer.Controllers entity.Status = "new"; entity.SpeedPolicy = ParseSpeedPolicy(invoice.TransactionSpeed, store.SpeedPolicy); - HashSet currencyPairsToFetch = new HashSet(); var rules = storeBlob.GetRateRules(_NetworkProvider); + await UpdateCLightningConnectionStringIfNeeded(store); + foreach (var network in store.GetSupportedPaymentMethods(_NetworkProvider) .Select(c => _NetworkProvider.GetNetwork(c.PaymentId.CryptoCode)) .Where(c => c != null)) @@ -208,6 +209,22 @@ namespace BTCPayServer.Controllers return new DataWrapper(resp) { Facade = "pos/invoice" }; } + private async Task UpdateCLightningConnectionStringIfNeeded(StoreData store) + { + bool needUpdate = false; + foreach (var method in store.GetSupportedPaymentMethods(_NetworkProvider).OfType()) + { + var lightning = method.GetLightningUrl(); + if (lightning.IsLegacy) + { + method.SetLightningUrl(lightning); + needUpdate = true; + } + } + if(needUpdate) + await _StoreRepository.UpdateStore(store); + } + private async Task CreatePaymentMethodAsync(Dictionary> fetchingByCurrencyPair, IPaymentMethodHandler handler, ISupportedPaymentMethod supportedPaymentMethod, BTCPayNetwork network, InvoiceEntity entity, StoreData store) { var storeBlob = store.GetStoreBlob(); diff --git a/BTCPayServer/Controllers/StoresController.LightningLike.cs b/BTCPayServer/Controllers/StoresController.LightningLike.cs index 1b51b51b4..eb2859277 100644 --- a/BTCPayServer/Controllers/StoresController.LightningLike.cs +++ b/BTCPayServer/Controllers/StoresController.LightningLike.cs @@ -26,14 +26,14 @@ namespace BTCPayServer.Controllers return NotFound(); LightningNodeViewModel vm = new LightningNodeViewModel(); vm.CryptoCode = cryptoCode; - vm.InternalLightningNode = GetInternalLighningNode(cryptoCode)?.ToUri(true)?.AbsoluteUri; + vm.InternalLightningNode = GetInternalLighningNode(cryptoCode)?.ToString(); SetExistingValues(store, vm); return View(vm); } private void SetExistingValues(StoreData store, LightningNodeViewModel vm) { - vm.Url = GetExistingLightningSupportedPaymentMethod(vm.CryptoCode, store)?.GetLightningUrl()?.ToString(); + vm.ConnectionString = GetExistingLightningSupportedPaymentMethod(vm.CryptoCode, store)?.GetLightningUrl()?.ToString(); } private LightningSupportedPaymentMethod GetExistingLightningSupportedPaymentMethod(string cryptoCode, StoreData store) @@ -65,7 +65,7 @@ namespace BTCPayServer.Controllers var network = vm.CryptoCode == null ? null : _ExplorerProvider.GetNetwork(vm.CryptoCode); var internalLightning = GetInternalLighningNode(network.CryptoCode); - vm.InternalLightningNode = internalLightning?.ToUri(true)?.AbsoluteUri; + vm.InternalLightningNode = internalLightning?.ToString(); if (network == null) { ModelState.AddModelError(nameof(vm.CryptoCode), "Invalid network"); @@ -74,11 +74,11 @@ namespace BTCPayServer.Controllers PaymentMethodId paymentMethodId = new PaymentMethodId(network.CryptoCode, PaymentTypes.LightningLike); Payments.Lightning.LightningSupportedPaymentMethod paymentMethod = null; - if (!string.IsNullOrEmpty(vm.Url)) + if (!string.IsNullOrEmpty(vm.ConnectionString)) { - if (!LightningConnectionString.TryParse(vm.Url, out var connectionString, out var error)) + if (!LightningConnectionString.TryParse(vm.ConnectionString, false, out var connectionString, out var error)) { - ModelState.AddModelError(nameof(vm.Url), $"Invalid URL ({error})"); + ModelState.AddModelError(nameof(vm.ConnectionString), $"Invalid URL ({error})"); return View(vm); } @@ -93,14 +93,14 @@ namespace BTCPayServer.Controllers { if (!isInternalNode || (isInternalNode && !CanUseInternalLightning())) { - ModelState.AddModelError(nameof(vm.Url), "The url must be HTTPS"); + ModelState.AddModelError(nameof(vm.ConnectionString), "The url must be HTTPS"); return View(vm); } } if (isInternalNode && !CanUseInternalLightning()) { - ModelState.AddModelError(nameof(vm.Url), "Unauthorized url"); + ModelState.AddModelError(nameof(vm.ConnectionString), "Unauthorized url"); return View(vm); } @@ -121,7 +121,7 @@ namespace BTCPayServer.Controllers { if (paymentMethod == null) { - ModelState.AddModelError(nameof(vm.Url), "Missing url parameter"); + ModelState.AddModelError(nameof(vm.ConnectionString), "Missing url parameter"); return View(vm); } var handler = (LightningLikePaymentHandler)_ServiceProvider.GetRequiredService>(); diff --git a/BTCPayServer/Models/StoreViewModels/LightningNodeViewModel.cs b/BTCPayServer/Models/StoreViewModels/LightningNodeViewModel.cs index 1de9f6dc0..d9ba80caf 100644 --- a/BTCPayServer/Models/StoreViewModels/LightningNodeViewModel.cs +++ b/BTCPayServer/Models/StoreViewModels/LightningNodeViewModel.cs @@ -9,8 +9,8 @@ namespace BTCPayServer.Models.StoreViewModels { public class LightningNodeViewModel { - [Display(Name = "Lightning charge url")] - public string Url + [Display(Name = "Connection string")] + public string ConnectionString { get; set; diff --git a/BTCPayServer/Payments/Lightning/LightningConnectionString.cs b/BTCPayServer/Payments/Lightning/LightningConnectionString.cs index fe7fc8a6a..82871c7f5 100644 --- a/BTCPayServer/Payments/Lightning/LightningConnectionString.cs +++ b/BTCPayServer/Payments/Lightning/LightningConnectionString.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Text; using System.Threading.Tasks; namespace BTCPayServer.Payments.Lightning @@ -12,14 +13,168 @@ namespace BTCPayServer.Payments.Lightning } public class LightningConnectionString { - public static bool TryParse(string str, out LightningConnectionString connectionString) + static Dictionary typeMapping; + static Dictionary typeMappingReverse; + static LightningConnectionString() { - return TryParse(str, out connectionString, out var error); + typeMapping = new Dictionary(); + typeMapping.Add("clightning", LightningConnectionType.CLightning); + typeMapping.Add("charge", LightningConnectionType.Charge); + typeMappingReverse = new Dictionary(); + foreach (var kv in typeMapping) + { + typeMappingReverse.Add(kv.Value, kv.Key); + } } - public static bool TryParse(string str, out LightningConnectionString connectionString, out string error) + public static bool TryParse(string str, bool supportLegacy, out LightningConnectionString connectionString) + { + return TryParse(str, supportLegacy, out connectionString, out var error); + } + public static bool TryParse(string str, bool supportLegacy, out LightningConnectionString connectionString, out string error) { if (str == null) throw new ArgumentNullException(nameof(str)); + + if (supportLegacy) + { + var parsed = TryParseLegacy(str, out connectionString, out error); + if (!parsed) + { + parsed = TryParseNewFormat(str, out connectionString, out error); + } + return parsed; + } + else + { + return TryParseNewFormat(str, out connectionString, out error); + } + } + + private static bool TryParseNewFormat(string str, out LightningConnectionString connectionString, out string error) + { + connectionString = null; + error = null; + var parts = str.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries); + Dictionary keyValues = new Dictionary(); + foreach (var part in parts.Select(p => p.Trim())) + { + var idx = part.IndexOf('=', StringComparison.OrdinalIgnoreCase); + if (idx == -1) + { + error = "The format of the connectionString should a list of key=value delimited by semicolon"; + return false; + } + var key = part.Substring(0, idx).Trim().ToLowerInvariant(); + var value = part.Substring(idx + 1).Trim(); + if (keyValues.ContainsKey(key)) + { + error = $"Duplicate key {key}"; + return false; + } + keyValues.Add(key, value); + } + + var possibleTypes = String.Join(", ", typeMapping.Select(k => k.Key).ToArray()); + + LightningConnectionString result = new LightningConnectionString(); + var type = Take(keyValues, "type"); + if (type == null) + { + error = $"The key 'type' is mandatory, possible values are {possibleTypes}"; + return false; + } + + if (!typeMapping.TryGetValue(type.ToLowerInvariant(), out var connectionType)) + { + error = $"The key 'type' is invalid, possible values are {possibleTypes}"; + return false; + } + + result.ConnectionType = connectionType; + + switch (connectionType) + { + case LightningConnectionType.Charge: + { + var server = Take(keyValues, "server"); + if (server == null) + { + error = $"The key 'server' is mandatory for charge connection strings"; + return false; + } + + if (!Uri.TryCreate(server, UriKind.Absolute, out var uri) + || (uri.Scheme != "http" && uri.Scheme != "https")) + { + error = $"The key 'server' should be an URI starting by http:// or https://"; + return false; + } + + parts = uri.UserInfo.Split(':'); + if (!string.IsNullOrEmpty(uri.UserInfo) && parts.Length == 2) + { + result.Username = parts[0]; + result.Password = parts[1]; + } + else + { + var apiToken = Take(keyValues, "api-token"); + if (apiToken == null) + { + error = "The key 'api-token' is not found"; + return false; + } + result.Username = "api-token"; + result.Password = apiToken; + } + result.BaseUri = new UriBuilder(uri) { UserName = "", Password = "" }.Uri; + } + break; + case LightningConnectionType.CLightning: + { + var server = Take(keyValues, "server"); + if (server == null) + { + error = $"The key 'server' is mandatory for charge connection strings"; + return false; + } + + if (server.StartsWith("//", StringComparison.OrdinalIgnoreCase)) + server = "unix:" + str; + else if (server.StartsWith("/", StringComparison.OrdinalIgnoreCase)) + server = "unix:/" + str; + + if (!Uri.TryCreate(server, UriKind.Absolute, out var uri) + || (uri.Scheme != "tcp" && uri.Scheme != "unix")) + { + error = $"The key 'server' should be an URI starting by tcp:// or unix:// or a path to the 'lightning-rpc' unix socket"; + return false; + } + result.BaseUri = uri; + } + break; + default: + throw new NotSupportedException(connectionType.ToString()); + } + + if (keyValues.Count != 0) + { + error = $"Unknown keys ({String.Join(", ", keyValues.Select(k => k.Key).ToArray())})"; + return false; + } + + connectionString = result; + return true; + } + private static string Take(Dictionary keyValues, string key) + { + if (keyValues.TryGetValue(key, out var v)) + keyValues.Remove(key); + return v; + } + + private static bool TryParseLegacy(string str, out LightningConnectionString connectionString, out string error) + { if (str.StartsWith('/')) str = "unix:" + str; var result = new LightningConnectionString(); @@ -49,8 +204,12 @@ namespace BTCPayServer.Payments.Lightning str = str.Substring(1); } uri = new Uri("unix://" + str, UriKind.Absolute); + result.ConnectionType = LightningConnectionType.CLightning; } + if (uri.Scheme == "tcp") + result.ConnectionType = LightningConnectionType.CLightning; + if (uri.Scheme == "http" || uri.Scheme == "https") { var parts = uri.UserInfo.Split(':'); @@ -61,6 +220,7 @@ namespace BTCPayServer.Payments.Lightning } result.Username = parts[0]; result.Password = parts[1]; + result.ConnectionType = LightningConnectionType.Charge; } else if (!string.IsNullOrEmpty(uri.UserInfo)) { @@ -68,6 +228,7 @@ namespace BTCPayServer.Payments.Lightning return false; } result.BaseUri = new UriBuilder(uri) { UserName = "", Password = "" }.Uri; + result.IsLegacy = true; connectionString = result; return true; } @@ -80,14 +241,12 @@ namespace BTCPayServer.Payments.Lightning public string Username { get; set; } public string Password { get; set; } public Uri BaseUri { get; set; } + public bool IsLegacy { get; private set; } public LightningConnectionType ConnectionType { - get - { - return BaseUri.Scheme == "http" || BaseUri.Scheme == "https" ? LightningConnectionType.Charge - : LightningConnectionType.CLightning; - } + get; + private set; } public Uri ToUri(bool withCredentials) @@ -104,7 +263,28 @@ namespace BTCPayServer.Payments.Lightning public override string ToString() { - return ToUri(true).AbsoluteUri; + var type = typeMappingReverse[ConnectionType]; + StringBuilder builder = new StringBuilder(); + builder.Append($"type={type}"); + switch (ConnectionType) + { + case LightningConnectionType.Charge: + if(Username == null || Username == "api-token") + { + builder.Append($";server={BaseUri};api-token={Password}"); + } + else + { + builder.Append($";server={ToUri(true)}"); + } + break; + case LightningConnectionType.CLightning: + builder.Append($";server={BaseUri}"); + break; + default: + throw new NotSupportedException(type); + } + return builder.ToString(); } } } diff --git a/BTCPayServer/Payments/Lightning/LightningSupportedPaymentMethod.cs b/BTCPayServer/Payments/Lightning/LightningSupportedPaymentMethod.cs index e1b100e9e..4c7e8a2ab 100644 --- a/BTCPayServer/Payments/Lightning/LightningSupportedPaymentMethod.cs +++ b/BTCPayServer/Payments/Lightning/LightningSupportedPaymentMethod.cs @@ -11,15 +11,29 @@ namespace BTCPayServer.Payments.Lightning [Obsolete("Use Get/SetLightningUrl")] public string LightningChargeUrl { get; set; } + [Obsolete("Use Get/SetLightningUrl")] + public string LightningConnectionString { get; set; } + public LightningConnectionString GetLightningUrl() { #pragma warning disable CS0618 // Type or member is obsolete - var fullUri = new UriBuilder(LightningChargeUrl) { UserName = Username, Password = Password }.Uri.AbsoluteUri; - if(!LightningConnectionString.TryParse(fullUri, out var connectionString, out var error)) + if (!string.IsNullOrEmpty(LightningConnectionString)) { - throw new FormatException(error); + if (!BTCPayServer.Payments.Lightning.LightningConnectionString.TryParse(LightningConnectionString, false, out var connectionString, out var error)) + { + throw new FormatException(error); + } + return connectionString; + } + else + { + var fullUri = new UriBuilder(LightningChargeUrl) { UserName = Username, Password = Password }.Uri.AbsoluteUri; + if (!BTCPayServer.Payments.Lightning.LightningConnectionString.TryParse(fullUri, true, out var connectionString, out var error)) + { + throw new FormatException(error); + } + return connectionString; } - return connectionString; #pragma warning restore CS0618 // Type or member is obsolete } @@ -29,9 +43,10 @@ namespace BTCPayServer.Payments.Lightning throw new ArgumentNullException(nameof(connectionString)); #pragma warning disable CS0618 // Type or member is obsolete - Username = connectionString.Username; - Password = connectionString.Password; - LightningChargeUrl = connectionString.BaseUri.AbsoluteUri; + LightningConnectionString = connectionString.ToString(); + Username = null; + Password = null; + LightningChargeUrl = null; #pragma warning restore CS0618 // Type or member is obsolete } diff --git a/BTCPayServer/Views/Stores/AddLightningNode.cshtml b/BTCPayServer/Views/Stores/AddLightningNode.cshtml index 5a1d49355..bc861bf04 100644 --- a/BTCPayServer/Views/Stores/AddLightningNode.cshtml +++ b/BTCPayServer/Views/Stores/AddLightningNode.cshtml @@ -36,9 +36,9 @@ This URL should point to an installed lightning charge server for @Model.CryptoCode
- - - + + + @if(Model.InternalLightningNode != null) {