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(); }
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(); }
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)); }
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)); }
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)); } }
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)); } }
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)); } }