2020-06-29 04:44:35 +02:00
using System ;
2017-09-13 08:47:34 +02:00
using System.IO ;
2020-06-28 10:55:27 +02:00
using System.Linq ;
2017-09-13 08:47:34 +02:00
using System.Net ;
2021-12-31 08:59:02 +01:00
using BTCPayServer.Configuration ;
2020-06-28 10:55:27 +02:00
using BTCPayServer.Logging ;
using BTCPayServer.SSH ;
using Microsoft.Extensions.Configuration ;
using Microsoft.Extensions.Logging ;
using NBitcoin ;
2018-11-07 14:29:35 +01:00
using Serilog.Events ;
2017-09-13 08:47:34 +02:00
namespace BTCPayServer.Configuration
{
2017-10-27 10:53:04 +02:00
public class BTCPayServerOptions
{
2021-01-27 06:39:38 +01:00
public ChainName NetworkType
2017-10-27 10:53:04 +02:00
{
get ; set ;
}
public string ConfigurationFile
2018-11-07 14:29:35 +01:00
{
get ;
private set ;
2018-12-20 14:40:32 +01:00
}
2018-11-07 14:29:35 +01:00
public string LogFile
2017-10-27 10:53:04 +02:00
{
get ;
private set ;
}
2019-03-17 16:03:02 +01:00
public EndPoint SocksEndpoint { get ; set ; }
2020-06-28 10:55:27 +02:00
2018-01-12 08:00:31 +01:00
2019-01-06 16:43:55 +01:00
public bool DisableRegistration
{
get ;
private set ;
}
2018-11-07 14:29:35 +01:00
public static string GetDebugLog ( IConfiguration configuration )
{
2019-11-14 10:49:04 +01:00
var logfile = configuration . GetValue < string > ( "debuglog" , null ) ;
if ( ! string . IsNullOrEmpty ( logfile ) )
{
if ( ! Path . IsPathRooted ( logfile ) )
{
2021-01-06 15:51:13 +01:00
logfile = Path . Combine ( new DataDirectories ( ) . Configure ( configuration ) . DataDir , logfile ) ;
2019-11-14 10:49:04 +01:00
}
}
return logfile ;
2018-11-07 14:29:35 +01:00
}
public static LogEventLevel GetDebugLogLevel ( IConfiguration configuration )
{
var raw = configuration . GetValue ( "debugloglevel" , nameof ( LogEventLevel . Debug ) ) ;
2018-12-20 14:40:32 +01:00
return ( LogEventLevel ) Enum . Parse ( typeof ( LogEventLevel ) , raw , true ) ;
2018-11-07 14:29:35 +01:00
}
2021-11-22 09:16:08 +01:00
public void LoadArgs ( IConfiguration conf , Logs Logs )
2017-10-27 10:53:04 +02:00
{
2018-04-19 09:54:25 +02:00
NetworkType = DefaultConfiguration . GetNetworkType ( conf ) ;
2021-12-31 08:59:02 +01:00
2018-04-19 09:54:25 +02:00
Logs . Configuration . LogInformation ( "Network: " + NetworkType . ToString ( ) ) ;
2017-09-13 08:47:34 +02:00
2021-01-27 06:39:38 +01:00
if ( conf . GetOrDefault < bool > ( "launchsettings" , false ) & & NetworkType ! = ChainName . Regtest )
2019-05-14 17:55:15 +02:00
throw new ConfigException ( $"You need to run BTCPayServer with the run.sh or run.ps1 script" ) ;
2023-02-10 03:43:46 +01:00
if ( conf . GetOrDefault < string > ( "POSTGRES" , null ) = = null )
{
if ( conf . GetOrDefault < string > ( "SQLITEFILE" , null ) ! = null )
Logs . Configuration . LogWarning ( "SQLITE backend support is out of support. Please migrate to Postgres by following the following instructions https://github.com/btcpayserver/btcpayserver/blob/master/docs/db-migration.md" ) ;
if ( conf . GetOrDefault < string > ( "MYSQL" , null ) ! = null )
Logs . Configuration . LogWarning ( "MYSQL backend support is out of support. Please migrate to Postgres by following the following instructions (https://github.com/btcpayserver/btcpayserver/blob/master/docs/db-migration.md)" ) ;
}
2020-10-15 14:28:09 +02:00
DockerDeployment = conf . GetOrDefault < bool > ( "dockerdeployment" , true ) ;
2019-03-17 12:49:26 +01:00
TorrcFile = conf . GetOrDefault < string > ( "torrcfile" , null ) ;
2021-04-18 04:26:06 +02:00
TorServices = conf . GetOrDefault < string > ( "torservices" , null )
2021-12-31 08:59:02 +01:00
? . Split ( new [ ] { ';' , ',' } , StringSplitOptions . RemoveEmptyEntries ) ;
2021-04-18 04:26:06 +02:00
if ( ! string . IsNullOrEmpty ( TorrcFile ) & & TorServices ! = null )
throw new ConfigException ( $"torrcfile or torservices should be provided, but not both" ) ;
2019-03-31 06:16:05 +02:00
var socksEndpointString = conf . GetOrDefault < string > ( "socksendpoint" , null ) ;
2020-06-28 10:55:27 +02:00
if ( ! string . IsNullOrEmpty ( socksEndpointString ) )
2019-03-31 06:16:05 +02:00
{
if ( ! Utils . TryParseEndpoint ( socksEndpointString , 9050 , out var endpoint ) )
throw new ConfigException ( "Invalid value for socksendpoint" ) ;
SocksEndpoint = endpoint ;
}
2020-06-28 10:55:27 +02:00
2020-08-03 10:16:29 +02:00
UpdateUrl = conf . GetOrDefault < Uri > ( "updateurl" , null ) ;
2018-04-05 08:50:23 +02:00
2018-08-13 02:43:59 +02:00
var sshSettings = ParseSSHConfiguration ( conf ) ;
2018-08-12 16:23:26 +02:00
if ( ( ! string . IsNullOrEmpty ( sshSettings . Password ) | | ! string . IsNullOrEmpty ( sshSettings . KeyFile ) ) & & ! string . IsNullOrEmpty ( sshSettings . Server ) )
2018-08-12 14:38:45 +02:00
{
2018-08-13 02:43:59 +02:00
int waitTime = 0 ;
while ( ! string . IsNullOrEmpty ( sshSettings . KeyFile ) & & ! File . Exists ( sshSettings . KeyFile ) )
{
2018-10-27 15:49:39 +02:00
if ( waitTime + + < 5 )
2018-08-13 02:43:59 +02:00
System . Threading . Thread . Sleep ( 1000 ) ;
else
throw new ConfigException ( $"sshkeyfile does not exist" ) ;
}
2018-10-27 15:49:39 +02:00
2018-08-12 14:38:45 +02:00
if ( sshSettings . Port > ushort . MaxValue | |
sshSettings . Port < ushort . MinValue )
throw new ConfigException ( $"ssh port is invalid" ) ;
if ( ! string . IsNullOrEmpty ( sshSettings . Password ) & & ! string . IsNullOrEmpty ( sshSettings . KeyFile ) )
throw new ConfigException ( $"sshpassword or sshkeyfile should be provided, but not both" ) ;
try
{
sshSettings . CreateConnectionInfo ( ) ;
2019-08-25 05:25:42 +02:00
SSHSettings = sshSettings ;
}
catch ( NotSupportedException ex )
{
Logs . Configuration . LogWarning ( $"The SSH key is not supported ({ex.Message}), try to generate the key with ssh-keygen using \" - m PEM \ ". Skipping SSH configuration..." ) ;
2018-08-12 14:38:45 +02:00
}
2022-10-14 07:51:05 +02:00
catch ( Exception ex )
2018-08-12 14:38:45 +02:00
{
2022-10-14 07:51:05 +02:00
Logs . Configuration . LogWarning ( ex , "Error while loading SSH settings" ) ;
2018-08-12 14:38:45 +02:00
}
}
2018-08-12 16:23:26 +02:00
var fingerPrints = conf . GetOrDefault < string > ( "sshtrustedfingerprints" , "" ) ;
if ( ! string . IsNullOrEmpty ( fingerPrints ) )
{
2018-08-13 02:43:59 +02:00
foreach ( var fingerprint in fingerPrints . Split ( ';' , StringSplitOptions . RemoveEmptyEntries ) )
2018-08-12 16:23:26 +02:00
{
2018-08-13 02:43:59 +02:00
if ( ! SSHFingerprint . TryParse ( fingerprint , out var f ) )
throw new ConfigException ( $"Invalid ssh fingerprint format {fingerprint}" ) ;
2019-08-27 16:30:25 +02:00
SSHSettings ? . TrustedFingerprints . Add ( f ) ;
2018-08-12 16:23:26 +02:00
}
}
2018-04-05 08:50:23 +02:00
RootPath = conf . GetOrDefault < string > ( "rootpath" , "/" ) ;
2018-04-09 07:31:39 +02:00
if ( ! RootPath . StartsWith ( "/" , StringComparison . InvariantCultureIgnoreCase ) )
RootPath = "/" + RootPath ;
2018-03-20 18:09:25 +01:00
var old = conf . GetOrDefault < Uri > ( "internallightningnode" , null ) ;
2018-07-23 04:53:39 +02:00
if ( old ! = null )
2019-01-18 15:23:47 +01:00
throw new ConfigException ( $"internallightningnode is deprecated and should not be used anymore, use btclightning instead" ) ;
2018-11-07 14:29:35 +01:00
LogFile = GetDebugLog ( conf ) ;
if ( ! string . IsNullOrEmpty ( LogFile ) )
{
Logs . Configuration . LogInformation ( "LogFile: " + LogFile ) ;
Logs . Configuration . LogInformation ( "Log Level: " + GetDebugLogLevel ( conf ) ) ;
}
2019-01-06 16:43:55 +01:00
DisableRegistration = conf . GetOrDefault < bool > ( "disable-registration" , true ) ;
2021-12-31 08:59:02 +01:00
RecommendedPlugins = conf . GetOrDefault ( "recommended-plugins" , "" ) . ToLowerInvariant ( ) . Split ( '\r' , '\n' , '\t' , ' ' ) . Where ( s = > ! string . IsNullOrEmpty ( s ) ) . Distinct ( ) . ToArray ( ) ;
2021-10-11 05:32:09 +02:00
CheatMode = conf . GetOrDefault ( "cheatmode" , false ) ;
if ( CheatMode & & this . NetworkType = = ChainName . Mainnet )
throw new ConfigException ( $"cheatmode can't be used on mainnet" ) ;
2017-10-27 10:53:04 +02:00
}
2018-08-12 16:23:26 +02:00
2020-11-05 10:21:09 +01:00
public string [ ] RecommendedPlugins { get ; set ; }
2021-10-11 05:32:09 +02:00
public bool CheatMode { get ; set ; }
2020-10-15 14:28:09 +02:00
2018-08-13 02:43:59 +02:00
private SSHSettings ParseSSHConfiguration ( IConfiguration conf )
2018-08-12 16:23:26 +02:00
{
2018-08-13 02:43:59 +02:00
var settings = new SSHSettings ( ) ;
settings . Server = conf . GetOrDefault < string > ( "sshconnection" , null ) ;
if ( settings . Server ! = null )
2018-08-12 16:23:26 +02:00
{
2018-08-13 02:43:59 +02:00
var parts = settings . Server . Split ( ':' ) ;
if ( parts . Length = = 2 & & int . TryParse ( parts [ 1 ] , out int port ) )
{
settings . Port = port ;
settings . Server = parts [ 0 ] ;
}
else
{
settings . Port = 22 ;
}
2018-08-12 16:23:26 +02:00
2018-08-13 02:43:59 +02:00
parts = settings . Server . Split ( '@' ) ;
if ( parts . Length = = 2 )
{
settings . Username = parts [ 0 ] ;
settings . Server = parts [ 1 ] ;
}
else
{
settings . Username = "root" ;
}
2018-08-12 16:23:26 +02:00
}
2018-08-13 02:43:59 +02:00
settings . Password = conf . GetOrDefault < string > ( "sshpassword" , "" ) ;
settings . KeyFile = conf . GetOrDefault < string > ( "sshkeyfile" , "" ) ;
2019-09-20 11:51:14 +02:00
settings . AuthorizedKeysFile = conf . GetOrDefault < string > ( "sshauthorizedkeys" , "" ) ;
2018-08-13 02:43:59 +02:00
settings . KeyFilePassword = conf . GetOrDefault < string > ( "sshkeyfilepassword" , "" ) ;
return settings ;
2018-08-12 16:23:26 +02:00
}
2018-04-05 08:50:23 +02:00
public string RootPath { get ; set ; }
2020-10-15 14:28:09 +02:00
public bool DockerDeployment { get ; set ; }
2022-10-21 02:17:06 +02:00
public SSHSettings SSHSettings { get ; set ; }
2019-03-17 12:49:26 +01:00
public string TorrcFile { get ; set ; }
2021-04-18 04:26:06 +02:00
public string [ ] TorServices { get ; set ; }
2020-08-01 16:10:05 +02:00
public Uri UpdateUrl { get ; set ; }
2017-10-27 10:53:04 +02:00
}
2017-09-13 08:47:34 +02:00
}