public async Task <IActionResult> UpdateLightningNetworkPaymentMethod(string cryptoCode, [FromBody] LightningNetworkPaymentMethodData paymentMethodData) { var paymentMethodId = new PaymentMethodId(cryptoCode, PaymentTypes.LightningLike); if (!GetNetwork(cryptoCode, out var network)) { return(NotFound()); } if (string.IsNullOrEmpty(paymentMethodData?.ConnectionString)) { ModelState.AddModelError(nameof(LightningNetworkPaymentMethodData.ConnectionString), "Missing connectionString"); } if (!ModelState.IsValid) { return(this.CreateValidationError(ModelState)); } LightningSupportedPaymentMethod paymentMethod = null; if (!string.IsNullOrEmpty(paymentMethodData.ConnectionString)) { if (paymentMethodData.ConnectionString == LightningSupportedPaymentMethod.InternalNode) { if (!await CanUseInternalLightning()) { ModelState.AddModelError(nameof(paymentMethodData.ConnectionString), $"You are not authorized to use the internal lightning node"); return(this.CreateValidationError(ModelState)); } paymentMethod = new Payments.Lightning.LightningSupportedPaymentMethod() { CryptoCode = paymentMethodId.CryptoCode }; paymentMethod.SetInternalNode(); } else { if (!LightningConnectionString.TryParse(paymentMethodData.ConnectionString, false, out var connectionString, out var error)) { ModelState.AddModelError(nameof(paymentMethodData.ConnectionString), $"Invalid URL ({error})"); return(this.CreateValidationError(ModelState)); } if (connectionString.ConnectionType == LightningConnectionType.LndGRPC) { ModelState.AddModelError(nameof(paymentMethodData.ConnectionString), $"BTCPay does not support gRPC connections"); return(this.CreateValidationError(ModelState)); } if (!await CanManageServer() && !connectionString.IsSafe()) { ModelState.AddModelError(nameof(paymentMethodData.ConnectionString), $"You do not have 'btcpay.server.canmodifyserversettings' rights, 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(this.CreateValidationError(ModelState)); } paymentMethod = new Payments.Lightning.LightningSupportedPaymentMethod() { CryptoCode = paymentMethodId.CryptoCode }; paymentMethod.SetLightningUrl(connectionString); } } var store = Store; var storeBlob = store.GetStoreBlob(); store.SetSupportedPaymentMethod(paymentMethodId, paymentMethod); storeBlob.SetExcluded(paymentMethodId, !paymentMethodData.Enabled); store.SetStoreBlob(storeBlob); await _storeRepository.UpdateStore(store); return(Ok(GetExistingLightningLikePaymentMethod(cryptoCode, store))); }
public async Task <IActionResult> UpdateLightningNetworkPaymentMethod(string storeId, string cryptoCode, [FromBody] UpdateLightningNetworkPaymentMethodRequest request) { var paymentMethodId = new PaymentMethodId(cryptoCode, PaymentTypes.LightningLike); AssertSupportLightning(cryptoCode); if (string.IsNullOrEmpty(request.ConnectionString)) { ModelState.AddModelError(nameof(LightningNetworkPaymentMethodData.ConnectionString), "Missing connectionString"); } if (!ModelState.IsValid) { return(this.CreateValidationError(ModelState)); } LightningSupportedPaymentMethod?paymentMethod = null; var store = Store; var storeBlob = store.GetStoreBlob(); var existing = GetExistingLightningLikePaymentMethod(_btcPayNetworkProvider, cryptoCode, store); if (existing == null || existing.ConnectionString != request.ConnectionString) { if (request.ConnectionString == LightningSupportedPaymentMethod.InternalNode) { if (!await CanUseInternalLightning()) { return(this.CreateAPIPermissionError(Policies.CanUseInternalLightningNode, $"You are not authorized to use the internal lightning node. Either add '{Policies.CanUseInternalLightningNode}' to an API Key, or allow non-admin users to use the internal lightning node in the server settings.")); } paymentMethod = new Payments.Lightning.LightningSupportedPaymentMethod() { CryptoCode = paymentMethodId.CryptoCode }; paymentMethod.SetInternalNode(); } else { if (!LightningConnectionString.TryParse(request.ConnectionString, false, out var connectionString, out var error)) { ModelState.AddModelError(nameof(request.ConnectionString), $"Invalid URL ({error})"); return(this.CreateValidationError(ModelState)); } if (connectionString.ConnectionType == LightningConnectionType.LndGRPC) { ModelState.AddModelError(nameof(request.ConnectionString), $"BTCPay does not support gRPC connections"); return(this.CreateValidationError(ModelState)); } if (!await CanManageServer() && !connectionString.IsSafe()) { ModelState.AddModelError(nameof(request.ConnectionString), $"You do not have 'btcpay.server.canmodifyserversettings' rights, 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(this.CreateValidationError(ModelState)); } paymentMethod = new Payments.Lightning.LightningSupportedPaymentMethod() { CryptoCode = paymentMethodId.CryptoCode }; paymentMethod.SetLightningUrl(connectionString); } } store.SetSupportedPaymentMethod(paymentMethodId, paymentMethod); storeBlob.SetExcluded(paymentMethodId, !request.Enabled); store.SetStoreBlob(storeBlob); await _storeRepository.UpdateStore(store); return(Ok(GetExistingLightningLikePaymentMethod(_btcPayNetworkProvider, cryptoCode, store))); }
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)); } }