diff --git a/BTCPayServer.Tests/GreenfieldAPITests.cs b/BTCPayServer.Tests/GreenfieldAPITests.cs index 3c6bdcc29..2dc9252a2 100644 --- a/BTCPayServer.Tests/GreenfieldAPITests.cs +++ b/BTCPayServer.Tests/GreenfieldAPITests.cs @@ -1795,14 +1795,11 @@ namespace BTCPayServer.Tests { await nonAdminUserClient.GetStoreLightningNetworkPaymentMethod(nonAdminUser.StoreId, "BTC"); }); - await Assert.ThrowsAsync(async () => - { - await nonAdminUserClient.UpdateStoreLightningNetworkPaymentMethod(nonAdminUser.StoreId, "BTC", new UpdateLightningNetworkPaymentMethodRequest() + await AssertPermissionError("btcpay.server.canuseinternallightningnode", () => nonAdminUserClient.UpdateStoreLightningNetworkPaymentMethod(nonAdminUser.StoreId, "BTC", new UpdateLightningNetworkPaymentMethodRequest() { Enabled = method.Enabled, ConnectionString = method.ConnectionString - }); - }); + })); settings = await tester.PayTester.GetService().GetSettingAsync(); settings.AllowLightningInternalNodeForAll = true; @@ -1813,6 +1810,36 @@ namespace BTCPayServer.Tests Enabled = method.Enabled, ConnectionString = method.ConnectionString }); + + // NonAdmin can't set to internal node in AllowLightningInternalNodeForAll is false, but can do other connection string + settings = (await tester.PayTester.GetService().GetSettingAsync()) ?? new PoliciesSettings(); + settings.AllowLightningInternalNodeForAll = false; + await tester.PayTester.GetService().UpdateSetting(settings); + await nonAdminUserClient.UpdateStoreLightningNetworkPaymentMethod(nonAdminUser.StoreId, "BTC", new UpdateLightningNetworkPaymentMethodRequest() + { + Enabled = true, + ConnectionString = "type=clightning;server=tcp://8.8.8.8" + }); + await AssertPermissionError("btcpay.server.canuseinternallightningnode", () => nonAdminUserClient.UpdateStoreLightningNetworkPaymentMethod(nonAdminUser.StoreId, "BTC", new UpdateLightningNetworkPaymentMethodRequest() + { + Enabled = true, + ConnectionString = "Internal Node" + })); + // NonAdmin add admin as owner of the store + await nonAdminUser.AddOwner(admin.UserId); + // Admin turn on Internal node + adminClient = await admin.CreateClient(Policies.CanModifyStoreSettings, Policies.CanUseInternalLightningNode); + var data = await adminClient.UpdateStoreLightningNetworkPaymentMethod(nonAdminUser.StoreId, "BTC", new UpdateLightningNetworkPaymentMethodRequest() + { + Enabled = method.Enabled, + ConnectionString = "Internal Node" + }); + // Make sure that the nonAdmin can toggle enabled, ConnectionString unchanged. + await nonAdminUserClient.UpdateStoreLightningNetworkPaymentMethod(nonAdminUser.StoreId, "BTC", new UpdateLightningNetworkPaymentMethodRequest() + { + Enabled = !data.Enabled, + ConnectionString = "Internal Node" + }); } [Fact(Timeout = 60 * 2 * 1000)] diff --git a/BTCPayServer.Tests/TestAccount.cs b/BTCPayServer.Tests/TestAccount.cs index 6e3846056..0abe095b5 100644 --- a/BTCPayServer.Tests/TestAccount.cs +++ b/BTCPayServer.Tests/TestAccount.cs @@ -526,5 +526,10 @@ retry: var repo = this.parent.PayTester.GetService(); await repo.AddStoreUser(StoreId, userId, "Guest"); } + public async Task AddOwner(string userId) + { + var repo = this.parent.PayTester.GetService(); + await repo.AddStoreUser(StoreId, userId, "Owner"); + } } } diff --git a/BTCPayServer/Controllers/GreenField/StoreLightningNetworkPaymentMethodsController.cs b/BTCPayServer/Controllers/GreenField/StoreLightningNetworkPaymentMethodsController.cs index 92e55366f..fc1f78e77 100644 --- a/BTCPayServer/Controllers/GreenField/StoreLightningNetworkPaymentMethodsController.cs +++ b/BTCPayServer/Controllers/GreenField/StoreLightningNetworkPaymentMethodsController.cs @@ -129,15 +129,16 @@ namespace BTCPayServer.Controllers.GreenField return this.CreateValidationError(ModelState); LightningSupportedPaymentMethod? paymentMethod = null; - if (!string.IsNullOrEmpty(request!.ConnectionString)) + 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()) { - ModelState.AddModelError(nameof(request.ConnectionString), - $"You are not authorized to use the internal lightning node"); - return this.CreateValidationError(ModelState); + 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() @@ -176,9 +177,6 @@ namespace BTCPayServer.Controllers.GreenField paymentMethod.SetLightningUrl(connectionString); } } - - var store = Store; - var storeBlob = store.GetStoreBlob(); store.SetSupportedPaymentMethod(paymentMethodId, paymentMethod); storeBlob.SetExcluded(paymentMethodId, !request.Enabled); store.SetStoreBlob(storeBlob);