2020-06-28 21:44:35 -05:00
using System ;
2017-09-13 15:47:34 +09:00
using System.IO ;
2020-06-28 17:55:27 +09:00
using System.Linq ;
2017-09-13 15:47:34 +09:00
using System.Net ;
2021-12-31 16:59:02 +09:00
using BTCPayServer.Configuration ;
2020-06-28 17:55:27 +09: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 15:47:34 +09:00
namespace BTCPayServer.Configuration
{
2017-10-27 17:53:04 +09:00
public class BTCPayServerOptions
{
2021-01-27 14:39:38 +09:00
public ChainName NetworkType
2017-10-27 17:53:04 +09:00
{
get ; set ;
}
public string ConfigurationFile
2018-11-07 14:29:35 +01:00
{
get ;
private set ;
2018-12-20 22:40:32 +09:00
}
2018-11-07 14:29:35 +01:00
public string LogFile
2017-10-27 17:53:04 +09:00
{
get ;
private set ;
}
2019-03-18 00:03:02 +09:00
public EndPoint SocksEndpoint { get ; set ; }
2020-06-28 17:55:27 +09:00
2018-01-12 16:00:31 +09: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 18:49:04 +09: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 18:49:04 +09: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 22:40:32 +09:00
return ( LogEventLevel ) Enum . Parse ( typeof ( LogEventLevel ) , raw , true ) ;
2018-11-07 14:29:35 +01:00
}
2021-11-22 17:16:08 +09:00
public void LoadArgs ( IConfiguration conf , Logs Logs )
2017-10-27 17:53:04 +09:00
{
2018-04-19 16:54:25 +09:00
NetworkType = DefaultConfiguration . GetNetworkType ( conf ) ;
2021-12-31 16:59:02 +09:00
2018-04-19 16:54:25 +09:00
Logs . Configuration . LogInformation ( "Network: " + NetworkType . ToString ( ) ) ;
2017-09-13 15:47:34 +09:00
2021-01-27 14:39:38 +09:00
if ( conf . GetOrDefault < bool > ( "launchsettings" , false ) & & NetworkType ! = ChainName . Regtest )
2019-05-15 00:55:15 +09:00
throw new ConfigException ( $"You need to run BTCPayServer with the run.sh or run.ps1 script" ) ;
2023-02-10 11:43:46 +09:00
if ( conf . GetOrDefault < string > ( "POSTGRES" , null ) = = null )
{
2023-03-20 10:40:48 +09:00
var allowDeprecated = conf . GetOrDefault < bool > ( "DEPRECATED" , false ) ;
if ( allowDeprecated )
{
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)" ) ;
}
else
{
if ( conf . GetOrDefault < string > ( "SQLITEFILE" , null ) ! = null )
throw new ConfigException ( "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 you don't want to update, you can try to start this instance by using the command line argument --deprecated" ) ;
if ( conf . GetOrDefault < string > ( "MYSQL" , null ) ! = null )
throw new ConfigException ( "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). If you don't want to update, you can try to start this instance by using the command line argument --deprecated" ) ;
}
2023-02-10 11:43:46 +09:00
}
2020-10-15 14:28:09 +02:00
DockerDeployment = conf . GetOrDefault < bool > ( "dockerdeployment" , true ) ;
2019-03-17 20:49:26 +09:00
TorrcFile = conf . GetOrDefault < string > ( "torrcfile" , null ) ;
2021-04-18 11:26:06 +09:00
TorServices = conf . GetOrDefault < string > ( "torservices" , null )
2021-12-31 16:59:02 +09:00
? . Split ( new [ ] { ';' , ',' } , StringSplitOptions . RemoveEmptyEntries ) ;
2021-04-18 11:26:06 +09:00
if ( ! string . IsNullOrEmpty ( TorrcFile ) & & TorServices ! = null )
throw new ConfigException ( $"torrcfile or torservices should be provided, but not both" ) ;
2019-03-31 13:16:05 +09:00
var socksEndpointString = conf . GetOrDefault < string > ( "socksendpoint" , null ) ;
2020-06-28 17:55:27 +09:00
if ( ! string . IsNullOrEmpty ( socksEndpointString ) )
2019-03-31 13:16:05 +09:00
{
if ( ! Utils . TryParseEndpoint ( socksEndpointString , 9050 , out var endpoint ) )
throw new ConfigException ( "Invalid value for socksendpoint" ) ;
SocksEndpoint = endpoint ;
}
2020-06-28 17:55:27 +09:00
2020-08-03 03:16:29 -05:00
UpdateUrl = conf . GetOrDefault < Uri > ( "updateurl" , null ) ;
2018-04-05 15:50:23 +09:00
2018-08-13 09:43:59 +09:00
var sshSettings = ParseSSHConfiguration ( conf ) ;
2018-08-12 23:23:26 +09:00
if ( ( ! string . IsNullOrEmpty ( sshSettings . Password ) | | ! string . IsNullOrEmpty ( sshSettings . KeyFile ) ) & & ! string . IsNullOrEmpty ( sshSettings . Server ) )
2018-08-12 21:38:45 +09:00
{
2018-08-13 09:43:59 +09:00
int waitTime = 0 ;
while ( ! string . IsNullOrEmpty ( sshSettings . KeyFile ) & & ! File . Exists ( sshSettings . KeyFile ) )
{
2018-10-27 08:49:39 -05:00
if ( waitTime + + < 5 )
2018-08-13 09:43:59 +09:00
System . Threading . Thread . Sleep ( 1000 ) ;
else
throw new ConfigException ( $"sshkeyfile does not exist" ) ;
}
2018-10-27 08:49:39 -05:00
2018-08-12 21:38:45 +09: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 12:25:42 +09: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 21:38:45 +09:00
}
2022-10-14 14:51:05 +09:00
catch ( Exception ex )
2018-08-12 21:38:45 +09:00
{
2022-10-14 14:51:05 +09:00
Logs . Configuration . LogWarning ( ex , "Error while loading SSH settings" ) ;
2018-08-12 21:38:45 +09:00
}
}
2018-08-12 23:23:26 +09:00
var fingerPrints = conf . GetOrDefault < string > ( "sshtrustedfingerprints" , "" ) ;
if ( ! string . IsNullOrEmpty ( fingerPrints ) )
{
2018-08-13 09:43:59 +09:00
foreach ( var fingerprint in fingerPrints . Split ( ';' , StringSplitOptions . RemoveEmptyEntries ) )
2018-08-12 23:23:26 +09:00
{
2018-08-13 09:43:59 +09:00
if ( ! SSHFingerprint . TryParse ( fingerprint , out var f ) )
throw new ConfigException ( $"Invalid ssh fingerprint format {fingerprint}" ) ;
2019-08-27 23:30:25 +09:00
SSHSettings ? . TrustedFingerprints . Add ( f ) ;
2018-08-12 23:23:26 +09:00
}
}
2018-04-05 15:50:23 +09:00
RootPath = conf . GetOrDefault < string > ( "rootpath" , "/" ) ;
2018-04-09 14:31:39 +09:00
if ( ! RootPath . StartsWith ( "/" , StringComparison . InvariantCultureIgnoreCase ) )
RootPath = "/" + RootPath ;
2018-03-21 02:09:25 +09:00
var old = conf . GetOrDefault < Uri > ( "internallightningnode" , null ) ;
2018-07-23 11:53:39 +09:00
if ( old ! = null )
2019-01-18 10:23:47 -04: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 16:59:02 +09:00
RecommendedPlugins = conf . GetOrDefault ( "recommended-plugins" , "" ) . ToLowerInvariant ( ) . Split ( '\r' , '\n' , '\t' , ' ' ) . Where ( s = > ! string . IsNullOrEmpty ( s ) ) . Distinct ( ) . ToArray ( ) ;
2021-10-11 12:32:09 +09: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 17:53:04 +09:00
}
2018-08-12 23:23:26 +09:00
2020-11-05 10:21:09 +01:00
public string [ ] RecommendedPlugins { get ; set ; }
2021-10-11 12:32:09 +09:00
public bool CheatMode { get ; set ; }
2020-10-15 14:28:09 +02:00
2018-08-13 09:43:59 +09:00
private SSHSettings ParseSSHConfiguration ( IConfiguration conf )
2018-08-12 23:23:26 +09:00
{
2018-08-13 09:43:59 +09:00
var settings = new SSHSettings ( ) ;
settings . Server = conf . GetOrDefault < string > ( "sshconnection" , null ) ;
if ( settings . Server ! = null )
2018-08-12 23:23:26 +09:00
{
2018-08-13 09:43:59 +09: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 23:23:26 +09:00
2018-08-13 09:43:59 +09:00
parts = settings . Server . Split ( '@' ) ;
if ( parts . Length = = 2 )
{
settings . Username = parts [ 0 ] ;
settings . Server = parts [ 1 ] ;
}
else
{
settings . Username = "root" ;
}
2018-08-12 23:23:26 +09:00
}
2018-08-13 09:43:59 +09:00
settings . Password = conf . GetOrDefault < string > ( "sshpassword" , "" ) ;
settings . KeyFile = conf . GetOrDefault < string > ( "sshkeyfile" , "" ) ;
2019-09-20 18:51:14 +09:00
settings . AuthorizedKeysFile = conf . GetOrDefault < string > ( "sshauthorizedkeys" , "" ) ;
2018-08-13 09:43:59 +09:00
settings . KeyFilePassword = conf . GetOrDefault < string > ( "sshkeyfilepassword" , "" ) ;
return settings ;
2018-08-12 23:23:26 +09:00
}
2018-04-05 15:50:23 +09: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 20:49:26 +09:00
public string TorrcFile { get ; set ; }
2021-04-18 11:26:06 +09:00
public string [ ] TorServices { get ; set ; }
2020-08-01 09:10:05 -05:00
public Uri UpdateUrl { get ; set ; }
2017-10-27 17:53:04 +09:00
}
2017-09-13 15:47:34 +09:00
}