2021-06-14 11:19:52 +02:00
#nullable enable
2021-02-26 03:58:51 +01:00
using System.Collections.Generic ;
2021-07-29 13:29:34 +02:00
using System.Diagnostics.CodeAnalysis ;
2021-02-26 03:58:51 +01:00
using System.Linq ;
using System.Threading.Tasks ;
using BTCPayServer.Abstractions.Constants ;
2021-07-27 14:08:54 +02:00
using BTCPayServer.Abstractions.Contracts ;
2021-02-26 03:58:51 +01:00
using BTCPayServer.Client ;
using BTCPayServer.Client.Models ;
using BTCPayServer.Configuration ;
using BTCPayServer.Data ;
using BTCPayServer.HostedServices ;
using BTCPayServer.Lightning ;
using BTCPayServer.Payments ;
using BTCPayServer.Payments.Lightning ;
using BTCPayServer.Security ;
using BTCPayServer.Services.Stores ;
using Microsoft.AspNetCore.Authorization ;
using Microsoft.AspNetCore.Mvc ;
using Microsoft.Extensions.Options ;
using StoreData = BTCPayServer . Data . StoreData ;
namespace BTCPayServer.Controllers.GreenField
{
[ApiController]
[Authorize(AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
public class StoreLightningNetworkPaymentMethodsController : ControllerBase
{
private StoreData Store = > HttpContext . GetStoreData ( ) ;
private readonly StoreRepository _storeRepository ;
private readonly BTCPayNetworkProvider _btcPayNetworkProvider ;
private readonly IAuthorizationService _authorizationService ;
2021-07-27 14:08:54 +02:00
private readonly ISettingsRepository _settingsRepository ;
2021-02-26 03:58:51 +01:00
public StoreLightningNetworkPaymentMethodsController (
StoreRepository storeRepository ,
BTCPayNetworkProvider btcPayNetworkProvider ,
IAuthorizationService authorizationService ,
2021-07-27 14:08:54 +02:00
ISettingsRepository settingsRepository )
2021-02-26 03:58:51 +01:00
{
_storeRepository = storeRepository ;
_btcPayNetworkProvider = btcPayNetworkProvider ;
_authorizationService = authorizationService ;
2021-07-27 14:08:54 +02:00
_settingsRepository = settingsRepository ;
2021-02-26 03:58:51 +01:00
}
2021-07-26 11:12:44 +02:00
public static IEnumerable < LightningNetworkPaymentMethodData > GetLightningPaymentMethods ( StoreData store ,
BTCPayNetworkProvider networkProvider , bool? enabled )
2021-02-26 03:58:51 +01:00
{
2021-06-02 05:49:58 +02:00
var blob = store . GetStoreBlob ( ) ;
2021-02-26 03:58:51 +01:00
var excludedPaymentMethods = blob . GetExcludedPaymentMethods ( ) ;
2021-06-02 05:49:58 +02:00
return store . GetSupportedPaymentMethods ( networkProvider )
2021-02-26 03:58:51 +01:00
. Where ( ( method ) = > method . PaymentId . PaymentType = = PaymentTypes . LightningLike )
. OfType < LightningSupportedPaymentMethod > ( )
. Select ( paymentMethod = >
2021-06-14 11:19:52 +02:00
new LightningNetworkPaymentMethodData (
paymentMethod . PaymentId . CryptoCode ,
2021-07-26 11:12:44 +02:00
paymentMethod . GetExternalLightningUrl ( ) ? . ToString ( ) ? ?
paymentMethod . GetDisplayableConnectionString ( ) ,
2021-09-25 07:04:34 +02:00
! excludedPaymentMethods . Match ( paymentMethod . PaymentId ) ,
paymentMethod . PaymentId . ToStringNormalized ( )
2021-06-14 11:19:52 +02:00
)
)
2021-07-26 11:12:44 +02:00
. Where ( ( result ) = > enabled is null | | enabled = = result . Enabled )
2021-06-02 05:49:58 +02:00
. ToList ( ) ;
}
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
[HttpGet("~/api/v1/stores/{storeId}/payment-methods/LightningNetwork")]
public ActionResult < IEnumerable < LightningNetworkPaymentMethodData > > GetLightningPaymentMethods (
2021-07-27 14:11:47 +02:00
string storeId ,
2021-07-26 11:12:44 +02:00
[FromQuery] bool? enabled )
2021-06-02 05:49:58 +02:00
{
2021-07-26 11:12:44 +02:00
return Ok ( GetLightningPaymentMethods ( Store , _btcPayNetworkProvider , enabled ) ) ;
2021-02-26 03:58:51 +01:00
}
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
[HttpGet("~/api/v1/stores/{storeId}/payment-methods/LightningNetwork/{cryptoCode}")]
2021-07-27 14:11:47 +02:00
public ActionResult < LightningNetworkPaymentMethodData > GetLightningNetworkPaymentMethod ( string storeId , string cryptoCode )
2021-02-26 03:58:51 +01:00
{
if ( ! GetNetwork ( cryptoCode , out BTCPayNetwork _ ) )
{
return NotFound ( ) ;
}
var method = GetExistingLightningLikePaymentMethod ( cryptoCode ) ;
if ( method is null )
{
return NotFound ( ) ;
}
2021-07-26 11:12:44 +02:00
2021-02-26 03:58:51 +01:00
return Ok ( method ) ;
}
2021-07-26 11:12:44 +02:00
2021-02-26 03:58:51 +01:00
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
[HttpDelete("~/api/v1/stores/{storeId}/payment-methods/LightningNetwork/{cryptoCode}")]
public async Task < IActionResult > RemoveLightningNetworkPaymentMethod (
2021-07-27 14:11:47 +02:00
string storeId ,
2021-02-26 03:58:51 +01:00
string cryptoCode ,
int offset = 0 , int amount = 10 )
{
if ( ! GetNetwork ( cryptoCode , out BTCPayNetwork _ ) )
{
return NotFound ( ) ;
}
2021-07-26 11:12:44 +02:00
2021-02-26 03:58:51 +01:00
var id = new PaymentMethodId ( cryptoCode , PaymentTypes . LightningLike ) ;
var store = Store ;
store . SetSupportedPaymentMethod ( id , null ) ;
await _storeRepository . UpdateStore ( store ) ;
return Ok ( ) ;
}
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
[HttpPut("~/api/v1/stores/{storeId}/payment-methods/LightningNetwork/{cryptoCode}")]
2021-07-27 14:11:47 +02:00
public async Task < IActionResult > UpdateLightningNetworkPaymentMethod ( string storeId , string cryptoCode ,
2021-08-30 06:38:57 +02:00
[FromBody] UpdateLightningNetworkPaymentMethodRequest request )
2021-02-26 03:58:51 +01:00
{
var paymentMethodId = new PaymentMethodId ( cryptoCode , PaymentTypes . LightningLike ) ;
if ( ! GetNetwork ( cryptoCode , out var network ) )
{
return NotFound ( ) ;
}
2021-08-30 06:38:57 +02:00
if ( string . IsNullOrEmpty ( request . ConnectionString ) )
2021-02-26 03:58:51 +01:00
{
ModelState . AddModelError ( nameof ( LightningNetworkPaymentMethodData . ConnectionString ) ,
"Missing connectionString" ) ;
}
if ( ! ModelState . IsValid )
return this . CreateValidationError ( ModelState ) ;
2021-07-29 13:29:34 +02:00
LightningSupportedPaymentMethod ? paymentMethod = null ;
2021-08-30 06:38:57 +02:00
if ( ! string . IsNullOrEmpty ( request ! . ConnectionString ) )
2021-02-26 03:58:51 +01:00
{
2021-08-30 06:38:57 +02:00
if ( request . ConnectionString = = LightningSupportedPaymentMethod . InternalNode )
2021-02-26 03:58:51 +01:00
{
2021-03-02 03:11:58 +01:00
if ( ! await CanUseInternalLightning ( ) )
2021-02-26 03:58:51 +01:00
{
2021-08-30 06:38:57 +02:00
ModelState . AddModelError ( nameof ( request . ConnectionString ) ,
2021-07-26 11:12:44 +02:00
$"You are not authorized to use the internal lightning node" ) ;
2021-02-26 03:58:51 +01:00
return this . CreateValidationError ( ModelState ) ;
}
2021-07-26 11:12:44 +02:00
2021-03-02 03:11:58 +01:00
paymentMethod = new Payments . Lightning . LightningSupportedPaymentMethod ( )
{
CryptoCode = paymentMethodId . CryptoCode
} ;
paymentMethod . SetInternalNode ( ) ;
2021-02-26 03:58:51 +01:00
}
2021-03-02 03:11:58 +01:00
else
2021-02-26 03:58:51 +01:00
{
2021-08-30 06:38:57 +02:00
if ( ! LightningConnectionString . TryParse ( request . ConnectionString , false ,
2021-03-02 03:11:58 +01:00
out var connectionString , out var error ) )
2021-02-26 03:58:51 +01:00
{
2021-08-30 06:38:57 +02:00
ModelState . AddModelError ( nameof ( request . ConnectionString ) , $"Invalid URL ({error})" ) ;
2021-02-26 03:58:51 +01:00
return this . CreateValidationError ( ModelState ) ;
}
2021-07-26 11:12:44 +02:00
2021-03-02 03:11:58 +01:00
if ( connectionString . ConnectionType = = LightningConnectionType . LndGRPC )
2021-02-26 03:58:51 +01:00
{
2021-08-30 06:38:57 +02:00
ModelState . AddModelError ( nameof ( request . ConnectionString ) ,
2021-03-02 03:11:58 +01:00
$"BTCPay does not support gRPC connections" ) ;
2021-02-26 03:58:51 +01:00
return this . CreateValidationError ( ModelState ) ;
}
2021-07-26 11:12:44 +02:00
2021-03-02 03:11:58 +01:00
if ( ! await CanManageServer ( ) & & ! connectionString . IsSafe ( ) )
2021-02-26 03:58:51 +01:00
{
2021-08-30 06:38:57 +02:00
ModelState . AddModelError ( nameof ( request . ConnectionString ) ,
2021-07-26 11:12:44 +02:00
$"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 '.'." ) ;
2021-02-26 03:58:51 +01:00
return this . CreateValidationError ( ModelState ) ;
}
2021-07-26 11:12:44 +02:00
2021-03-02 03:11:58 +01:00
paymentMethod = new Payments . Lightning . LightningSupportedPaymentMethod ( )
{
CryptoCode = paymentMethodId . CryptoCode
} ;
paymentMethod . SetLightningUrl ( connectionString ) ;
2021-02-26 03:58:51 +01:00
}
}
var store = Store ;
var storeBlob = store . GetStoreBlob ( ) ;
store . SetSupportedPaymentMethod ( paymentMethodId , paymentMethod ) ;
2021-08-30 06:38:57 +02:00
storeBlob . SetExcluded ( paymentMethodId , ! request . Enabled ) ;
2021-02-26 03:58:51 +01:00
store . SetStoreBlob ( storeBlob ) ;
await _storeRepository . UpdateStore ( store ) ;
return Ok ( GetExistingLightningLikePaymentMethod ( cryptoCode , store ) ) ;
}
2021-07-29 13:29:34 +02:00
private LightningNetworkPaymentMethodData ? GetExistingLightningLikePaymentMethod ( string cryptoCode ,
StoreData ? store = null )
2021-02-26 03:58:51 +01:00
{
store ? ? = Store ;
var storeBlob = store . GetStoreBlob ( ) ;
var id = new PaymentMethodId ( cryptoCode , PaymentTypes . LightningLike ) ;
var paymentMethod = store
. GetSupportedPaymentMethods ( _btcPayNetworkProvider )
. OfType < LightningSupportedPaymentMethod > ( )
. FirstOrDefault ( method = > method . PaymentId = = id ) ;
var excluded = storeBlob . IsExcluded ( id ) ;
2021-07-29 13:29:34 +02:00
return paymentMethod is null
2021-02-26 03:58:51 +01:00
? null
: new LightningNetworkPaymentMethodData ( paymentMethod . PaymentId . CryptoCode ,
2021-09-25 07:04:34 +02:00
paymentMethod . GetDisplayableConnectionString ( ) , ! excluded ,
paymentMethod . PaymentId . ToStringNormalized ( ) ) ;
2021-02-26 03:58:51 +01:00
}
2021-07-29 13:29:34 +02:00
private bool GetNetwork ( string cryptoCode , [ MaybeNullWhen ( false ) ] out BTCPayNetwork network )
2021-02-26 03:58:51 +01:00
{
network = _btcPayNetworkProvider . GetNetwork < BTCPayNetwork > ( cryptoCode ) ;
network = network ? . SupportLightning is true ? network : null ;
return network ! = null ;
}
2021-07-26 11:12:44 +02:00
2021-02-26 03:58:51 +01:00
private async Task < bool > CanUseInternalLightning ( )
{
2021-07-27 14:08:54 +02:00
return ( await _settingsRepository . GetPolicies ( ) ) . AllowLightningInternalNodeForAll | |
2021-07-26 11:12:44 +02:00
( await _authorizationService . AuthorizeAsync ( User , null ,
new PolicyRequirement ( Policies . CanUseInternalLightningNode ) ) ) . Succeeded ;
2021-02-26 03:58:51 +01:00
}
2021-07-26 11:12:44 +02:00
2021-03-02 03:11:58 +01:00
private async Task < bool > CanManageServer ( )
{
2021-07-26 11:12:44 +02:00
return
2021-03-02 03:11:58 +01:00
( await _authorizationService . AuthorizeAsync ( User , null ,
new PolicyRequirement ( Policies . CanModifyServerSettings ) ) ) . Succeeded ;
}
2021-02-26 03:58:51 +01:00
}
}