diff --git a/BTCPayServer.Client/BTCPayServerClient.LightningNetworkPaymentMethods.cs b/BTCPayServer.Client/BTCPayServerClient.LightningNetworkPaymentMethods.cs index 8cec0b965..687ffca62 100644 --- a/BTCPayServer.Client/BTCPayServerClient.LightningNetworkPaymentMethods.cs +++ b/BTCPayServer.Client/BTCPayServerClient.LightningNetworkPaymentMethods.cs @@ -9,13 +9,19 @@ namespace BTCPayServer.Client public partial class BTCPayServerClient { public virtual async Task> - GetStoreLightningNetworkPaymentMethods(string storeId, bool enabledOnly = false, + GetStoreLightningNetworkPaymentMethods(string storeId, bool? enabled = null, CancellationToken token = default) { + var query = new Dictionary(); + if (enabled != null) + { + query.Add(nameof(enabled), enabled); + } + var response = await _httpClient.SendAsync( CreateHttpRequest($"api/v1/stores/{storeId}/payment-methods/LightningNetwork", - new Dictionary() {{nameof(enabledOnly), enabledOnly}}), token); + query), token); return await HandleResponse>(response); } diff --git a/BTCPayServer.Client/BTCPayServerClient.OnChainPaymentMethods.cs b/BTCPayServer.Client/BTCPayServerClient.OnChainPaymentMethods.cs index b21b54194..2afb3d502 100644 --- a/BTCPayServer.Client/BTCPayServerClient.OnChainPaymentMethods.cs +++ b/BTCPayServer.Client/BTCPayServerClient.OnChainPaymentMethods.cs @@ -9,13 +9,19 @@ namespace BTCPayServer.Client public partial class BTCPayServerClient { public virtual async Task> GetStoreOnChainPaymentMethods(string storeId, - bool enabledOnly = false, + bool? enabled = null, CancellationToken token = default) { + var query = new Dictionary(); + if (enabled != null) + { + query.Add(nameof(enabled), enabled); + } + var response = await _httpClient.SendAsync( CreateHttpRequest($"api/v1/stores/{storeId}/payment-methods/Onchain", - new Dictionary() {{nameof(enabledOnly), enabledOnly}}), token); + query), token); return await HandleResponse>(response); } diff --git a/BTCPayServer.Client/BTCPayServerClient.StorePaymentMethods.cs b/BTCPayServer.Client/BTCPayServerClient.StorePaymentMethods.cs index be05dd513..e5441f924 100644 --- a/BTCPayServer.Client/BTCPayServerClient.StorePaymentMethods.cs +++ b/BTCPayServer.Client/BTCPayServerClient.StorePaymentMethods.cs @@ -8,13 +8,19 @@ namespace BTCPayServer.Client public partial class BTCPayServerClient { public virtual async Task> GetStorePaymentMethods(string storeId, - bool enabledOnly = false, + bool? enabled = null, CancellationToken token = default) { + var query = new Dictionary(); + if (enabled != null) + { + query.Add(nameof(enabled), enabled); + } + var response = await _httpClient.SendAsync( CreateHttpRequest($"api/v1/stores/{storeId}/payment-methods", - new Dictionary() {{nameof(enabledOnly), enabledOnly}}), token); + query), token); return await HandleResponse>(response); } } diff --git a/BTCPayServer/Controllers/GreenField/StoreLightningNetworkPaymentMethodsController.cs b/BTCPayServer/Controllers/GreenField/StoreLightningNetworkPaymentMethodsController.cs index c10b374d4..e431dc415 100644 --- a/BTCPayServer/Controllers/GreenField/StoreLightningNetworkPaymentMethodsController.cs +++ b/BTCPayServer/Controllers/GreenField/StoreLightningNetworkPaymentMethodsController.cs @@ -42,7 +42,8 @@ namespace BTCPayServer.Controllers.GreenField _cssThemeManager = cssThemeManager; } - public static IEnumerable GetLightningPaymentMethods(StoreData store, BTCPayNetworkProvider networkProvider, bool enabledOnly = false) + public static IEnumerable GetLightningPaymentMethods(StoreData store, + BTCPayNetworkProvider networkProvider, bool? enabled) { var blob = store.GetStoreBlob(); var excludedPaymentMethods = blob.GetExcludedPaymentMethods(); @@ -53,20 +54,21 @@ namespace BTCPayServer.Controllers.GreenField .Select(paymentMethod => new LightningNetworkPaymentMethodData( paymentMethod.PaymentId.CryptoCode, - paymentMethod.GetExternalLightningUrl()?.ToString() ?? paymentMethod.GetDisplayableConnectionString(), + paymentMethod.GetExternalLightningUrl()?.ToString() ?? + paymentMethod.GetDisplayableConnectionString(), !excludedPaymentMethods.Match(paymentMethod.PaymentId) ) ) - .Where((result) => !enabledOnly || result.Enabled) + .Where((result) => enabled is null || enabled == result.Enabled) .ToList(); } [Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)] [HttpGet("~/api/v1/stores/{storeId}/payment-methods/LightningNetwork")] public ActionResult> GetLightningPaymentMethods( - [FromQuery] bool enabledOnly = false) + [FromQuery] bool? enabled) { - return Ok(GetLightningPaymentMethods(Store, _btcPayNetworkProvider, enabledOnly)); + return Ok(GetLightningPaymentMethods(Store, _btcPayNetworkProvider, enabled)); } [Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)] @@ -83,9 +85,10 @@ namespace BTCPayServer.Controllers.GreenField { return NotFound(); } + return Ok(method); } - + [Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)] [HttpDelete("~/api/v1/stores/{storeId}/payment-methods/LightningNetwork/{cryptoCode}")] public async Task RemoveLightningNetworkPaymentMethod( @@ -96,7 +99,7 @@ namespace BTCPayServer.Controllers.GreenField { return NotFound(); } - + var id = new PaymentMethodId(cryptoCode, PaymentTypes.LightningLike); var store = Store; store.SetSupportedPaymentMethod(id, null); @@ -132,9 +135,11 @@ namespace BTCPayServer.Controllers.GreenField { if (!await CanUseInternalLightning()) { - ModelState.AddModelError(nameof(paymentMethodData.ConnectionString), $"You are not authorized to use the internal lightning node"); + 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 @@ -149,17 +154,21 @@ namespace BTCPayServer.Controllers.GreenField 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 '.'."); + 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 @@ -177,7 +186,8 @@ namespace BTCPayServer.Controllers.GreenField return Ok(GetExistingLightningLikePaymentMethod(cryptoCode, store)); } - private LightningNetworkPaymentMethodData GetExistingLightningLikePaymentMethod(string cryptoCode, StoreData store = null) + private LightningNetworkPaymentMethodData GetExistingLightningLikePaymentMethod(string cryptoCode, + StoreData store = null) { store ??= Store; var storeBlob = store.GetStoreBlob(); @@ -200,16 +210,17 @@ namespace BTCPayServer.Controllers.GreenField network = network?.SupportLightning is true ? network : null; return network != null; } - + private async Task CanUseInternalLightning() { return _cssThemeManager.AllowLightningInternalNodeForAll || - (await _authorizationService.AuthorizeAsync(User, null, - new PolicyRequirement(Policies.CanUseInternalLightningNode))).Succeeded; + (await _authorizationService.AuthorizeAsync(User, null, + new PolicyRequirement(Policies.CanUseInternalLightningNode))).Succeeded; } + private async Task CanManageServer() { - return + return (await _authorizationService.AuthorizeAsync(User, null, new PolicyRequirement(Policies.CanModifyServerSettings))).Succeeded; } diff --git a/BTCPayServer/Controllers/GreenField/StoreOnChainPaymentMethodsController.cs b/BTCPayServer/Controllers/GreenField/StoreOnChainPaymentMethodsController.cs index 0bff45d9c..d080ac45b 100644 --- a/BTCPayServer/Controllers/GreenField/StoreOnChainPaymentMethodsController.cs +++ b/BTCPayServer/Controllers/GreenField/StoreOnChainPaymentMethodsController.cs @@ -35,7 +35,8 @@ namespace BTCPayServer.Controllers.GreenField _walletProvider = walletProvider; } - public static IEnumerable GetOnChainPaymentMethods(StoreData store, BTCPayNetworkProvider networkProvider, bool enabledOnly = false) + public static IEnumerable GetOnChainPaymentMethods(StoreData store, + BTCPayNetworkProvider networkProvider, bool? enabled) { var blob = store.GetStoreBlob(); var excludedPaymentMethods = blob.GetExcludedPaymentMethods(); @@ -46,16 +47,16 @@ namespace BTCPayServer.Controllers.GreenField .Select(strategy => new OnChainPaymentMethodData(strategy.PaymentId.CryptoCode, strategy.AccountDerivation.ToString(), !excludedPaymentMethods.Match(strategy.PaymentId))) - .Where((result) => !enabledOnly || result.Enabled) + .Where((result) => enabled is null || enabled == result.Enabled) .ToList(); } [Authorize(Policy = Policies.CanViewStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)] [HttpGet("~/api/v1/stores/{storeId}/payment-methods/onchain")] public ActionResult> GetOnChainPaymentMethods( - [FromQuery] bool enabledOnly = false) + [FromQuery] bool? enabled) { - return Ok(GetOnChainPaymentMethods(Store, _btcPayNetworkProvider, enabledOnly)); + return Ok(GetOnChainPaymentMethods(Store, _btcPayNetworkProvider, enabled)); } [Authorize(Policy = Policies.CanViewStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)] @@ -72,6 +73,7 @@ namespace BTCPayServer.Controllers.GreenField { return NotFound(); } + return Ok(method); } @@ -91,6 +93,7 @@ namespace BTCPayServer.Controllers.GreenField { return NotFound(); } + try { var strategy = DerivationSchemeSettings.Parse(paymentMethod.DerivationScheme, network); @@ -109,7 +112,7 @@ namespace BTCPayServer.Controllers.GreenField .ToString() }); } - + return Ok(result); } catch @@ -118,11 +121,10 @@ namespace BTCPayServer.Controllers.GreenField "Invalid Derivation Scheme"); return this.CreateValidationError(ModelState); } - } - - - [Authorize(Policy = Policies.CanViewStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)] + + + [Authorize(Policy = Policies.CanViewStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)] [HttpPost("~/api/v1/stores/{storeId}/payment-methods/onchain/{cryptoCode}/preview")] public IActionResult GetProposedOnChainPaymentMethodPreview(string cryptoCode, [FromBody] OnChainPaymentMethodData paymentMethodData, @@ -132,11 +134,13 @@ namespace BTCPayServer.Controllers.GreenField { return NotFound(); } + if (string.IsNullOrEmpty(paymentMethodData?.DerivationScheme)) { ModelState.AddModelError(nameof(OnChainPaymentMethodData.DerivationScheme), "Missing derivationScheme"); } + if (!ModelState.IsValid) return this.CreateValidationError(ModelState); DerivationSchemeSettings strategy; @@ -182,7 +186,7 @@ namespace BTCPayServer.Controllers.GreenField { return NotFound(); } - + var id = new PaymentMethodId(cryptoCode, PaymentTypes.BTCLike); var store = Store; store.SetSupportedPaymentMethod(id, null); @@ -207,6 +211,7 @@ namespace BTCPayServer.Controllers.GreenField ModelState.AddModelError(nameof(OnChainPaymentMethodData.DerivationScheme), "Missing derivationScheme"); } + if (!ModelState.IsValid) return this.CreateValidationError(ModelState); @@ -229,6 +234,7 @@ namespace BTCPayServer.Controllers.GreenField signing.AccountKeyPath = null; signing.RootFingerprint = null; } + store.SetSupportedPaymentMethod(id, strategy); storeBlob.SetExcluded(id, !paymentMethodData.Enabled); store.SetStoreBlob(storeBlob); diff --git a/BTCPayServer/Controllers/GreenField/StorePaymentMethodsController.cs b/BTCPayServer/Controllers/GreenField/StorePaymentMethodsController.cs index b2832d448..ebfb5c160 100644 --- a/BTCPayServer/Controllers/GreenField/StorePaymentMethodsController.cs +++ b/BTCPayServer/Controllers/GreenField/StorePaymentMethodsController.cs @@ -26,20 +26,20 @@ namespace BTCPayServer.Controllers.GreenField [Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)] [HttpGet("~/api/v1/stores/{storeId}/payment-methods")] public ActionResult> GetStorePaymentMethods( - [FromQuery] bool enabledOnly = false - ) + [FromQuery] bool? enabled) { var storeBlob = Store.GetStoreBlob(); var excludedPaymentMethods = storeBlob.GetExcludedPaymentMethods(); return Ok(Store.GetSupportedPaymentMethods(_btcPayNetworkProvider) - .Where(method => !enabledOnly || !excludedPaymentMethods.Match(method.PaymentId)) + .Where(method => + enabled is null || (enabled is false && excludedPaymentMethods.Match(method.PaymentId))) .ToDictionary( - method => method.PaymentId.ToStringNormalized(), - method => new GenericPaymentMethodData() - { - Enabled = enabledOnly || !excludedPaymentMethods.Match(method.PaymentId), - Data = method.PaymentId.PaymentType.GetGreenfieldData(method) - })); + method => method.PaymentId.ToStringNormalized(), + method => new GenericPaymentMethodData() + { + Enabled = enabled.GetValueOrDefault(!excludedPaymentMethods.Match(method.PaymentId)), + Data = method.PaymentId.PaymentType.GetGreenfieldData(method) + })); } } } diff --git a/BTCPayServer/wwwroot/swagger/v1/swagger.template.stores-payment-methods.json b/BTCPayServer/wwwroot/swagger/v1/swagger.template.stores-payment-methods.json index 63a723bdc..4a0e03f40 100644 --- a/BTCPayServer/wwwroot/swagger/v1/swagger.template.stores-payment-methods.json +++ b/BTCPayServer/wwwroot/swagger/v1/swagger.template.stores-payment-methods.json @@ -19,10 +19,10 @@ } }, { - "name": "enabledOnly", + "name": "enabled", "in": "query", "required": false, - "description": "Fetch payment methods that are enable only", + "description": "Fetch payment methods that are enabled/disabled only", "schema": { "type": "boolean" } diff --git a/BTCPayServer/wwwroot/swagger/v1/swagger.template.stores-payment-methods.lightning-network.json b/BTCPayServer/wwwroot/swagger/v1/swagger.template.stores-payment-methods.lightning-network.json index 03a2a37d2..c5a8368fe 100644 --- a/BTCPayServer/wwwroot/swagger/v1/swagger.template.stores-payment-methods.lightning-network.json +++ b/BTCPayServer/wwwroot/swagger/v1/swagger.template.stores-payment-methods.lightning-network.json @@ -15,6 +15,15 @@ "schema": { "type": "string" } + }, + { + "name": "enabled", + "in": "query", + "required": false, + "description": "Fetch payment methods that are enabled/disabled only", + "schema": { + "type": "boolean" + } } ], "description": "View information about the stores' configured Lightning Network payment methods", diff --git a/BTCPayServer/wwwroot/swagger/v1/swagger.template.stores-payment-methods.on-chain.json b/BTCPayServer/wwwroot/swagger/v1/swagger.template.stores-payment-methods.on-chain.json index 42eef3a47..aa30086f4 100644 --- a/BTCPayServer/wwwroot/swagger/v1/swagger.template.stores-payment-methods.on-chain.json +++ b/BTCPayServer/wwwroot/swagger/v1/swagger.template.stores-payment-methods.on-chain.json @@ -17,6 +17,15 @@ "schema": { "type": "string" } + }, + { + "name": "enabled", + "in": "query", + "required": false, + "description": "Fetch payment methods that are enabled/disabled only", + "schema": { + "type": "boolean" + } } ], "responses": {