예제 #1
0
 private void SetExistingValues(StoreData store, LightningNodeViewModel vm)
 {
     if (GetExistingLightningSupportedPaymentMethod(vm.CryptoCode, store) is LightningSupportedPaymentMethod paymentMethod)
     {
         vm.ConnectionString = paymentMethod.GetDisplayableConnectionString();
     }
     vm.Enabled            = !store.GetStoreBlob().IsExcluded(new PaymentMethodId(vm.CryptoCode, PaymentTypes.LightningLike));
     vm.CanUseInternalNode = CanUseInternalLightning();
 }
예제 #2
0
        private void SetExistingValues(StoreData store, LightningNodeViewModel vm)
        {
            var lightning = GetExistingLightningSupportedPaymentMethod(vm.CryptoCode, store);

            if (lightning != null)
            {
                vm.LightningNodeType = lightning.IsInternalNode ? LightningNodeType.Internal : LightningNodeType.Custom;
                vm.ConnectionString  = lightning.GetDisplayableConnectionString();
            }
            vm.Enabled            = !store.GetStoreBlob().IsExcluded(new PaymentMethodId(vm.CryptoCode, PaymentTypes.LightningLike)) && lightning != null;
            vm.CanUseInternalNode = CanUseInternalLightning();
        }
예제 #3
0
        public async Task <IActionResult> AddLightningNode(string storeId, string selectedCrypto = null)
        {
            selectedCrypto = selectedCrypto ?? "BTC";
            var store = await _Repo.FindStore(storeId, GetUserId());

            if (store == null)
            {
                return(NotFound());
            }
            LightningNodeViewModel vm = new LightningNodeViewModel();

            vm.SetCryptoCurrencies(_NetworkProvider, selectedCrypto);
            return(View(vm));
        }
        public IActionResult AddLightningNode(string storeId, string cryptoCode)
        {
            var store = HttpContext.GetStoreData();

            if (store == null)
            {
                return(NotFound());
            }
            LightningNodeViewModel vm = new LightningNodeViewModel();

            vm.CryptoCode            = cryptoCode;
            vm.InternalLightningNode = GetInternalLighningNode(cryptoCode)?.ToUri(true)?.AbsoluteUri;
            SetExistingValues(store, vm);
            return(View(vm));
        }
        private void SetExistingValues(StoreData store, LightningNodeViewModel vm)
        {
            vm.CanUseInternalNode = CanUseInternalLightning();
            var lightning = GetExistingLightningSupportedPaymentMethod(vm.CryptoCode, store);

            if (lightning != null)
            {
                vm.LightningNodeType = lightning.IsInternalNode ? LightningNodeType.Internal : LightningNodeType.Custom;
                vm.ConnectionString  = lightning.GetDisplayableConnectionString();
            }
            else
            {
                vm.LightningNodeType = vm.CanUseInternalNode ? LightningNodeType.Internal : LightningNodeType.Custom;
            }
        }
        public async Task <IActionResult> AddLightningNode(string storeId, string cryptoCode)
        {
            var store = await _Repo.FindStore(storeId, GetUserId());

            if (store == null)
            {
                return(NotFound());
            }
            LightningNodeViewModel vm = new LightningNodeViewModel();

            vm.CryptoCode            = cryptoCode;
            vm.InternalLightningNode = GetInternalLighningNode(cryptoCode)?.ToUri(true)?.AbsoluteUri;
            SetExistingValues(store, vm);
            return(View(vm));
        }
예제 #7
0
        public IActionResult AddLightningNode(string storeId, string cryptoCode)
        {
            var store = HttpContext.GetStoreData();

            if (store == null)
            {
                return(NotFound());
            }
            LightningNodeViewModel vm = new LightningNodeViewModel
            {
                CryptoCode = cryptoCode,
                StoreId    = storeId
            };

            SetExistingValues(store, vm);
            return(View(vm));
        }
예제 #8
0
        public IActionResult AddLightningNode(string storeId, string bitcoinCode)
        {
            var store = HttpContext.GetStoreData();

            if (store == null)
            {
                return(NotFound());
            }
            LightningNodeViewModel vm = new LightningNodeViewModel
            {
                bitcoinCode           = bitcoinCode,
                InternalLightningNode = GetInternalLighningNode(bitcoinCode)?.ToString(),
                StoreId = storeId
            };

            SetExistingValues(store, vm);
            return(View(vm));
        }
        public async Task <IActionResult> AddLightningNode(string storeId, LightningNodeViewModel vm, string command, string cryptoCode)
        {
            vm.CryptoCode = cryptoCode;
            var store = HttpContext.GetStoreData();

            if (store == null)
            {
                return(NotFound());
            }
            var network = vm.CryptoCode == null ? null : _ExplorerProvider.GetNetwork(vm.CryptoCode);

            var internalLightning = GetInternalLighningNode(network.CryptoCode);

            vm.InternalLightningNode = internalLightning?.ToString();
            if (network == null)
            {
                ModelState.AddModelError(nameof(vm.CryptoCode), "Invalid network");
                return(View(vm));
            }

            PaymentMethodId paymentMethodId = new PaymentMethodId(network.CryptoCode, PaymentTypes.LightningLike);

            Payments.Lightning.LightningSupportedPaymentMethod paymentMethod = null;
            if (!string.IsNullOrEmpty(vm.ConnectionString))
            {
                if (!LightningConnectionString.TryParse(vm.ConnectionString, false, out var connectionString, out var error))
                {
                    ModelState.AddModelError(nameof(vm.ConnectionString), $"Invalid URL ({error})");
                    return(View(vm));
                }

                if (connectionString.ConnectionType == LightningConnectionType.LndGRPC)
                {
                    ModelState.AddModelError(nameof(vm.ConnectionString), $"BTCPay does not support gRPC connections");
                    return(View(vm));
                }

                bool isInternalNode = connectionString.IsInternalNode(internalLightning);

                if (connectionString.BaseUri.Scheme == "http")
                {
                    if (!isInternalNode)
                    {
                        ModelState.AddModelError(nameof(vm.ConnectionString), "The url must be HTTPS");
                        return(View(vm));
                    }
                }

                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 not exist");
                        return(View(vm));
                    }
                    if (!System.IO.Path.IsPathRooted(connectionString.MacaroonFilePath))
                    {
                        ModelState.AddModelError(nameof(vm.ConnectionString), "The macaroonfilepath should be fully rooted");
                        return(View(vm));
                    }
                }

                if (isInternalNode && !CanUseInternalLightning())
                {
                    ModelState.AddModelError(nameof(vm.ConnectionString), "Unauthorized url");
                    return(View(vm));
                }

                paymentMethod = new Payments.Lightning.LightningSupportedPaymentMethod()
                {
                    CryptoCode = paymentMethodId.CryptoCode
                };
                paymentMethod.SetLightningUrl(connectionString);
            }

            switch (command)
            {
            case "save":
                var storeBlob = store.GetStoreBlob();
                storeBlob.SetExcluded(paymentMethodId, !vm.Enabled);
                store.SetStoreBlob(storeBlob);
                store.SetSupportedPaymentMethod(paymentMethodId, paymentMethod);
                await _Repo.UpdateStore(store);

                TempData[WellKnownTempData.SuccessMessage] = $"Lightning node modified ({network.CryptoCode})";
                return(RedirectToAction(nameof(UpdateStore), new { storeId = storeId }));

            case "test" when paymentMethod == null:
                ModelState.AddModelError(nameof(vm.ConnectionString), "Missing url parameter");
                return(View(vm));

            case "test":
                var handler = _ServiceProvider.GetRequiredService <LightningLikePaymentHandler>();
                try
                {
                    var info = await handler.GetNodeInfo(this.Request.IsOnion(), paymentMethod, network);

                    if (!vm.SkipPortTest)
                    {
                        using (CancellationTokenSource cts = new CancellationTokenSource(TimeSpan.FromSeconds(20)))
                        {
                            await handler.TestConnection(info, cts.Token);
                        }
                    }
                    TempData[WellKnownTempData.SuccessMessage] = $"Connection to the lightning node succeeded ({info})";
                }
                catch (Exception ex)
                {
                    TempData[WellKnownTempData.ErrorMessage] = ex.Message;
                    return(View(vm));
                }
                return(View(vm));

            default:
                return(View(vm));
            }
        }
 private void SetExistingValues(StoreData store, LightningNodeViewModel vm)
 {
     vm.ConnectionString = GetExistingLightningSupportedPaymentMethod(vm.CryptoCode, store)?.GetLightningUrl()?.ToString();
     vm.Enabled          = !store.GetStoreBlob().IsExcluded(new PaymentMethodId(vm.CryptoCode, PaymentTypes.LightningLike));
 }
        public async Task <IActionResult> AddLightningNode(string storeId, LightningNodeViewModel vm, string command, string cryptoCode)
        {
            vm.CryptoCode = cryptoCode;
            var store = HttpContext.GetStoreData();

            if (store == null)
            {
                return(NotFound());
            }
            var network = vm.CryptoCode == null ? null : _ExplorerProvider.GetNetwork(vm.CryptoCode);

            var internalLightning = GetInternalLighningNode(network.CryptoCode);

            vm.InternalLightningNode = internalLightning?.ToUri(true)?.AbsoluteUri;
            if (network == null)
            {
                ModelState.AddModelError(nameof(vm.CryptoCode), "Invalid network");
                return(View(vm));
            }

            PaymentMethodId paymentMethodId = new PaymentMethodId(network.CryptoCode, PaymentTypes.LightningLike);

            Payments.Lightning.LightningSupportedPaymentMethod paymentMethod = null;
            if (!string.IsNullOrEmpty(vm.Url))
            {
                if (!LightningConnectionString.TryParse(vm.Url, out var connectionString, out var error))
                {
                    ModelState.AddModelError(nameof(vm.Url), $"Invalid URL ({error})");
                    return(View(vm));
                }

                var  internalDomain = internalLightning?.ToUri(false)?.DnsSafeHost;
                bool isLocal        = (internalDomain == "127.0.0.1" || internalDomain == "localhost");

                bool isInternalNode = connectionString.ConnectionType == LightningConnectionType.CLightning ||
                                      connectionString.BaseUri.DnsSafeHost == internalDomain ||
                                      isLocal;

                if (connectionString.BaseUri.Scheme == "http" && !isLocal)
                {
                    if (!isInternalNode || (isInternalNode && !CanUseInternalLightning()))
                    {
                        ModelState.AddModelError(nameof(vm.Url), "The url must be HTTPS");
                        return(View(vm));
                    }
                }

                if (isInternalNode && !CanUseInternalLightning())
                {
                    ModelState.AddModelError(nameof(vm.Url), "Unauthorized url");
                    return(View(vm));
                }

                paymentMethod = new Payments.Lightning.LightningSupportedPaymentMethod()
                {
                    CryptoCode = paymentMethodId.CryptoCode
                };
                paymentMethod.SetLightningUrl(connectionString);
            }
            if (command == "save")
            {
                store.SetSupportedPaymentMethod(paymentMethodId, paymentMethod);
                await _Repo.UpdateStore(store);

                StatusMessage = $"Lightning node modified ({network.CryptoCode})";
                return(RedirectToAction(nameof(UpdateStore), new { storeId = storeId }));
            }
            else // if(command == "test")
            {
                if (paymentMethod == null)
                {
                    ModelState.AddModelError(nameof(vm.Url), "Missing url parameter");
                    return(View(vm));
                }
                var handler = (LightningLikePaymentHandler)_ServiceProvider.GetRequiredService <IPaymentMethodHandler <Payments.Lightning.LightningSupportedPaymentMethod> >();
                try
                {
                    var info = await handler.Test(paymentMethod, network);

                    if (!vm.SkipPortTest)
                    {
                        using (CancellationTokenSource cts = new CancellationTokenSource(TimeSpan.FromSeconds(20)))
                        {
                            await handler.TestConnection(info, cts.Token);
                        }
                    }
                    vm.StatusMessage = $"Connection to the lightning node succeed ({info})";
                }
                catch (Exception ex)
                {
                    vm.StatusMessage = $"Error: {ex.Message}";
                    return(View(vm));
                }
                return(View(vm));
            }
        }
 private void SetExistingValues(StoreData store, LightningNodeViewModel vm)
 {
     vm.Url = GetExistingLightningSupportedPaymentMethod(vm.CryptoCode, store)?.GetLightningUrl()?.ToString();
 }
        public async Task <IActionResult> SetupLightningNode(string storeId, LightningNodeViewModel vm, string command, string cryptoCode)
        {
            vm.CryptoCode = cryptoCode;
            var store = HttpContext.GetStoreData();

            if (store == null)
            {
                return(NotFound());
            }

            vm.CanUseInternalNode = CanUseInternalLightning();

            if (vm.CryptoCode == null)
            {
                ModelState.AddModelError(nameof(vm.CryptoCode), "Invalid network");
                return(View(vm));
            }

            var network         = _ExplorerProvider.GetNetwork(vm.CryptoCode);
            var paymentMethodId = new PaymentMethodId(network.CryptoCode, PaymentTypes.LightningLike);

            LightningSupportedPaymentMethod?paymentMethod = null;

            if (vm.LightningNodeType == LightningNodeType.Internal)
            {
                if (!CanUseInternalLightning())
                {
                    ModelState.AddModelError(nameof(vm.ConnectionString), "You are not authorized to use the internal lightning node");
                    return(View(vm));
                }
                paymentMethod = new LightningSupportedPaymentMethod
                {
                    CryptoCode = paymentMethodId.CryptoCode
                };
                paymentMethod.SetInternalNode();
            }
            else
            {
                if (string.IsNullOrEmpty(vm.ConnectionString))
                {
                    ModelState.AddModelError(nameof(vm.ConnectionString), "Please provide a connection string");
                    return(View(vm));
                }
                if (!LightningConnectionString.TryParse(vm.ConnectionString, false, out var connectionString, out var error))
                {
                    ModelState.AddModelError(nameof(vm.ConnectionString), $"Invalid URL ({error})");
                    return(View(vm));
                }
                if (connectionString.ConnectionType == LightningConnectionType.LndGRPC)
                {
                    ModelState.AddModelError(nameof(vm.ConnectionString), $"BTCPay does not support gRPC connections");
                    return(View(vm));
                }
                if (!User.IsInRole(Roles.ServerAdmin) && !connectionString.IsSafe())
                {
                    ModelState.AddModelError(nameof(vm.ConnectionString), "You are not a server admin, so the connection string should not contain 'cookiefilepath', 'macaroondirectorypath', 'macaroonfilepath', and should not point to a local ip or to a dns name ending with '.internal', '.local', '.lan' or '.'.");
                    return(View(vm));
                }

                paymentMethod = new LightningSupportedPaymentMethod
                {
                    CryptoCode = paymentMethodId.CryptoCode
                };
                paymentMethod.SetLightningUrl(connectionString);
            }

            switch (command)
            {
            case "save":
                var lnurl = new PaymentMethodId(vm.CryptoCode, PaymentTypes.LNURLPay);
                store.SetSupportedPaymentMethod(paymentMethodId, paymentMethod);
                store.SetSupportedPaymentMethod(lnurl, new LNURLPaySupportedPaymentMethod()
                {
                    CryptoCode                = vm.CryptoCode,
                    UseBech32Scheme           = true,
                    EnableForStandardInvoices = false,
                    LUD12Enabled              = false
                });

                await _Repo.UpdateStore(store);

                TempData[WellKnownTempData.SuccessMessage] = $"{network.CryptoCode} Lightning node updated.";
                return(RedirectToAction(nameof(LightningSettings), new { storeId, cryptoCode }));

            case "test":
                var handler = _ServiceProvider.GetRequiredService <LightningLikePaymentHandler>();
                try
                {
                    var info = await handler.GetNodeInfo(paymentMethod, network, new InvoiceLogs(), Request.IsOnion(), true);

                    if (!vm.SkipPortTest)
                    {
                        using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(20));
                        await handler.TestConnection(info.First(), cts.Token);
                    }
                    TempData[WellKnownTempData.SuccessMessage] = $"Connection to the Lightning node successful. Your node address: {info.First()}";
                }
                catch (Exception ex)
                {
                    TempData[WellKnownTempData.ErrorMessage] = ex.Message;
                    return(View(vm));
                }
                return(View(vm));

            default:
                return(View(vm));
            }
        }
        public async Task <IActionResult> AddLightningNode(string storeId, LightningNodeViewModel vm, string command)
        {
            var store = await _Repo.FindStore(storeId, GetUserId());

            if (store == null)
            {
                return(NotFound());
            }
            var network = vm.CryptoCurrency == null ? null : _ExplorerProvider.GetNetwork(vm.CryptoCurrency);

            vm.SetCryptoCurrencies(_NetworkProvider, vm.CryptoCurrency);
            vm.InternalLightningNode = GetInternalLightningNodeIfAuthorized();
            if (network == null || network.CLightningNetworkName == null)
            {
                ModelState.AddModelError(nameof(vm.CryptoCurrency), "Invalid network");
                return(View(vm));
            }

            PaymentMethodId paymentMethodId = new PaymentMethodId(network.CryptoCode, PaymentTypes.LightningLike);

            Payments.Lightning.LightningSupportedPaymentMethod paymentMethod = null;
            if (!string.IsNullOrEmpty(vm.Url))
            {
                Uri uri;
                if (!Uri.TryCreate(vm.Url, UriKind.Absolute, out uri))
                {
                    ModelState.AddModelError(nameof(vm.Url), "Invalid URL");
                    return(View(vm));
                }

                if (uri.Scheme != "https")
                {
                    var internalNode = GetInternalLightningNodeIfAuthorized();
                    if (internalNode == null || GetDomain(internalNode) != GetDomain(uri.AbsoluteUri))
                    {
                        ModelState.AddModelError(nameof(vm.Url), "The url must be HTTPS");
                        return(View(vm));
                    }
                }

                if (!CanUseInternalLightning() && GetDomain(_BtcpayServerOptions.InternalLightningNode.AbsoluteUri) == GetDomain(uri.AbsoluteUri))
                {
                    ModelState.AddModelError(nameof(vm.Url), "Unauthorized url");
                    return(View(vm));
                }

                if (string.IsNullOrEmpty(uri.UserInfo) || uri.UserInfo.Split(':').Length != 2)
                {
                    ModelState.AddModelError(nameof(vm.Url), "The url is missing user and password");
                    return(View(vm));
                }

                paymentMethod = new Payments.Lightning.LightningSupportedPaymentMethod()
                {
                    CryptoCode = paymentMethodId.CryptoCode
                };
                paymentMethod.SetLightningChargeUrl(uri);
            }
            if (command == "save")
            {
                store.SetSupportedPaymentMethod(paymentMethodId, paymentMethod);
                await _Repo.UpdateStore(store);

                StatusMessage = $"Lightning node modified ({network.CryptoCode})";
                return(RedirectToAction(nameof(UpdateStore), new { storeId = storeId }));
            }
            else // if(command == "test")
            {
                if (paymentMethod == null)
                {
                    ModelState.AddModelError(nameof(vm.Url), "Missing url parameter");
                    return(View(vm));
                }
                var handler = (LightningLikePaymentHandler)_ServiceProvider.GetRequiredService <IPaymentMethodHandler <Payments.Lightning.LightningSupportedPaymentMethod> >();
                try
                {
                    await handler.Test(paymentMethod, network);
                }
                catch (Exception ex)
                {
                    vm.StatusMessage = $"Error: {ex.Message}";
                    return(View(vm));
                }
                vm.StatusMessage = "Connection to the lightning node succeed";
                return(View(vm));
            }
        }
예제 #15
0
        public async Task <IActionResult> AddLightningNode(string storeId, LightningNodeViewModel vm, string command, string cryptoCode)
        {
            vm.CryptoCode = cryptoCode;
            var store = HttpContext.GetStoreData();

            if (store == null)
            {
                return(NotFound());
            }
            var network = vm.CryptoCode == null ? null : _ExplorerProvider.GetNetwork(vm.CryptoCode);

            if (network == null)
            {
                ModelState.AddModelError(nameof(vm.CryptoCode), "Invalid network");
                return(View(vm));
            }

            PaymentMethodId paymentMethodId = new PaymentMethodId(network.CryptoCode, PaymentTypes.LightningLike);

            Payments.Lightning.LightningSupportedPaymentMethod paymentMethod = null;
            if (vm.ConnectionString == LightningSupportedPaymentMethod.InternalNode)
            {
                if (!CanUseInternalLightning())
                {
                    ModelState.AddModelError(nameof(vm.ConnectionString), $"You are not authorized to use the internal lightning node");
                    return(View(vm));
                }
                paymentMethod = new Payments.Lightning.LightningSupportedPaymentMethod()
                {
                    CryptoCode = paymentMethodId.CryptoCode
                };
                paymentMethod.SetInternalNode();
            }
            else if (!string.IsNullOrEmpty(vm.ConnectionString))
            {
                if (!LightningConnectionString.TryParse(vm.ConnectionString, false, out var connectionString, out var error))
                {
                    ModelState.AddModelError(nameof(vm.ConnectionString), $"Invalid URL ({error})");
                    return(View(vm));
                }

                if (connectionString.ConnectionType == LightningConnectionType.LndGRPC)
                {
                    ModelState.AddModelError(nameof(vm.ConnectionString), $"BTCPay does not support gRPC connections");
                    return(View(vm));
                }
                if (!User.IsInRole(Roles.ServerAdmin) && !connectionString.IsSafe())
                {
                    ModelState.AddModelError(nameof(vm.ConnectionString), $"You are not a server admin, so the connection string should not contain 'cookiefilepath', 'macaroondirectorypath', 'macaroonfilepath', and should not point to a local ip or to a dns name ending with '.internal', '.local', '.lan' or '.'.");
                    return(View(vm));
                }

                paymentMethod = new Payments.Lightning.LightningSupportedPaymentMethod()
                {
                    CryptoCode = paymentMethodId.CryptoCode
                };
                paymentMethod.SetLightningUrl(connectionString);
            }

            switch (command)
            {
            case "save":
                var storeBlob = store.GetStoreBlob();
                storeBlob.SetExcluded(paymentMethodId, !vm.Enabled);
                storeBlob.Hints.Lightning = false;
                store.SetStoreBlob(storeBlob);
                store.SetSupportedPaymentMethod(paymentMethodId, paymentMethod);
                await _Repo.UpdateStore(store);

                TempData[WellKnownTempData.SuccessMessage] = $"Lightning node modified ({network.CryptoCode})";
                return(RedirectToAction(nameof(UpdateStore), new { storeId = storeId }));

            case "test" when paymentMethod == null:
                ModelState.AddModelError(nameof(vm.ConnectionString), "Missing url parameter");
                return(View(vm));

            case "test":
                var handler = _ServiceProvider.GetRequiredService <LightningLikePaymentHandler>();
                try
                {
                    var info = await handler.GetNodeInfo(this.Request.IsOnion(), paymentMethod, network);

                    if (!vm.SkipPortTest)
                    {
                        using (CancellationTokenSource cts = new CancellationTokenSource(TimeSpan.FromSeconds(20)))
                        {
                            await handler.TestConnection(info, cts.Token);
                        }
                    }
                    TempData[WellKnownTempData.SuccessMessage] = $"Connection to the lightning node succeeded. Your node address: {info}";
                }
                catch (Exception ex)
                {
                    TempData[WellKnownTempData.ErrorMessage] = ex.Message;
                    return(View(vm));
                }
                return(View(vm));

            default:
                return(View(vm));
            }
        }
예제 #16
0
        public async Task <IActionResult> AddLightningNode(string storeId, LightningNodeViewModel vm, string command, string cryptoCode)
        {
            vm.CryptoCode = cryptoCode;
            var store = HttpContext.GetStoreData();

            if (store == null)
            {
                return(NotFound());
            }
            var network = vm.CryptoCode == null ? null : _ExplorerProvider.GetNetwork(vm.CryptoCode);

            var internalLightning = GetInternalLighningNode(network.CryptoCode);

            vm.InternalLightningNode = internalLightning?.ToString();
            if (network == null)
            {
                ModelState.AddModelError(nameof(vm.CryptoCode), "Red inválida");
                return(View(vm));
            }

            PaymentMethodId paymentMethodId = new PaymentMethodId(network.CryptoCode, PaymentTypes.LightningLike);

            Payments.Lightning.LightningSupportedPaymentMethod paymentMethod = null;
            if (!string.IsNullOrEmpty(vm.ConnectionString))
            {
                if (!LightningConnectionString.TryParse(vm.ConnectionString, false, out var connectionString, out var error))
                {
                    ModelState.AddModelError(nameof(vm.ConnectionString), $"URL invalida ({error})");
                    return(View(vm));
                }

                if (connectionString.ConnectionType == LightningConnectionType.LndGRPC)
                {
                    ModelState.AddModelError(nameof(vm.ConnectionString), $"BTCPay no admite conexiones gRPC");
                    return(View(vm));
                }

                var internalDomain = internalLightning?.BaseUri?.DnsSafeHost;

                bool isInternalNode = connectionString.ConnectionType == LightningConnectionType.CLightning ||
                                      connectionString.BaseUri.DnsSafeHost == internalDomain ||
                                      (internalDomain == "127.0.0.1" || internalDomain == "localhost");

                if (connectionString.BaseUri.Scheme == "http")
                {
                    if (!isInternalNode)
                    {
                        ModelState.AddModelError(nameof(vm.ConnectionString), "La url debe ser HTTPS");
                        return(View(vm));
                    }
                }

                if (connectionString.MacaroonFilePath != null)
                {
                    if (!CanUseInternalLightning())
                    {
                        ModelState.AddModelError(nameof(vm.ConnectionString), "Usted no está autorizado para usar Macaroonfilepath");
                        return(View(vm));
                    }
                    if (!System.IO.File.Exists(connectionString.MacaroonFilePath))
                    {
                        ModelState.AddModelError(nameof(vm.ConnectionString), "El archivo macaroonfilepath no existe");
                        return(View(vm));
                    }
                    if (!System.IO.Path.IsPathRooted(connectionString.MacaroonFilePath))
                    {
                        ModelState.AddModelError(nameof(vm.ConnectionString), "El macaroonfilepath debe estar completamente enraizado.");
                        return(View(vm));
                    }
                }

                if (isInternalNode && !CanUseInternalLightning())
                {
                    ModelState.AddModelError(nameof(vm.ConnectionString), "URL no autorizada");
                    return(View(vm));
                }

                paymentMethod = new Payments.Lightning.LightningSupportedPaymentMethod()
                {
                    CryptoCode = paymentMethodId.CryptoCode
                };
                paymentMethod.SetLightningUrl(connectionString);
            }

            switch (command)
            {
            case "save":
                var storeBlob = store.GetStoreBlob();
                storeBlob.SetExcluded(paymentMethodId, !vm.Enabled);
                store.SetStoreBlob(storeBlob);
                store.SetSupportedPaymentMethod(paymentMethodId, paymentMethod);
                await _Repo.UpdateStore(store);

                StatusMessage = $"Lightning nodo modificado ({network.CryptoCode})";
                return(RedirectToAction(nameof(UpdateStore), new { storeId = storeId }));

            case "test" when paymentMethod == null:
                ModelState.AddModelError(nameof(vm.ConnectionString), "Falta el parámetro url");
                return(View(vm));

            case "test":
                var handler = (LightningLikePaymentHandler)_ServiceProvider.GetRequiredService <IPaymentMethodHandler <Payments.Lightning.LightningSupportedPaymentMethod> >();
                try
                {
                    var info = await handler.GetNodeInfo(this.Request.IsOnion(), paymentMethod, network);

                    if (!vm.SkipPortTest)
                    {
                        using (CancellationTokenSource cts = new CancellationTokenSource(TimeSpan.FromSeconds(20)))
                        {
                            await handler.TestConnection(info, cts.Token);
                        }
                    }
                    vm.StatusMessage = $"La conexión al nodo del Lightning tuvo éxito ({info})";
                }
                catch (Exception ex)
                {
                    vm.StatusMessage = $"Error: {ex.Message}";
                    return(View(vm));
                }
                return(View(vm));

            default:
                return(View(vm));
            }
        }