コード例 #1
0
        public void LoadArgs(IConfiguration conf)
        {
            NetworkType = DefaultConfiguration.GetNetworkType(conf);
            DataDir     = conf.GetDataDir(NetworkType);
            PluginDir   = conf.GetPluginDir(NetworkType);
            Logs.Configuration.LogInformation("Network: " + NetworkType.ToString());

            if (conf.GetOrDefault <bool>("launchsettings", false) && NetworkType != NetworkType.Regtest)
            {
                throw new ConfigException($"You need to run BTCPayServer with the run.sh or run.ps1 script");
            }

            var supportedChains = conf.GetOrDefault <string>("chains", "btc")
                                  .Split(',', StringSplitOptions.RemoveEmptyEntries)
                                  .Select(t => t.ToUpperInvariant()).ToHashSet();

            var networkProvider = new BTCPayNetworkProvider(NetworkType);
            var filtered        = networkProvider.Filter(supportedChains.ToArray());

#if ALTCOINS
            supportedChains.AddRange(filtered.GetAllElementsSubChains(networkProvider));
            supportedChains.AddRange(filtered.GetAllEthereumSubChains(networkProvider));
#endif
#if !ALTCOINS
            var onlyBTC = supportedChains.Count == 1 && supportedChains.First() == "BTC";
            if (!onlyBTC)
            {
                throw new ConfigException($"This build of BTCPay Server does not support altcoins");
            }
#endif
            NetworkProvider = networkProvider.Filter(supportedChains.ToArray());
            foreach (var chain in supportedChains)
            {
                if (NetworkProvider.GetNetwork <BTCPayNetworkBase>(chain) == null)
                {
                    throw new ConfigException($"Invalid chains \"{chain}\"");
                }
            }

            var validChains = new List <string>();
            foreach (var net in NetworkProvider.GetAll().OfType <BTCPayNetwork>())
            {
                NBXplorerConnectionSetting setting = new NBXplorerConnectionSetting();
                setting.CryptoCode  = net.CryptoCode;
                setting.ExplorerUri = conf.GetOrDefault <Uri>($"{net.CryptoCode}.explorer.url", net.NBXplorerNetwork.DefaultSettings.DefaultUrl);
                setting.CookieFile  = conf.GetOrDefault <string>($"{net.CryptoCode}.explorer.cookiefile", net.NBXplorerNetwork.DefaultSettings.DefaultCookieFile);
                NBXplorerConnectionSettings.Add(setting);

                {
                    var lightning = conf.GetOrDefault <string>($"{net.CryptoCode}.lightning", string.Empty);
                    if (lightning.Length != 0)
                    {
                        if (!LightningConnectionString.TryParse(lightning, true, out var connectionString, out var error))
                        {
                            Logs.Configuration.LogWarning($"Invalid setting {net.CryptoCode}.lightning, " + Environment.NewLine +
                                                          $"If you have a c-lightning server use: 'type=clightning;server=/root/.lightning/lightning-rpc', " + Environment.NewLine +
                                                          $"If you have a lightning charge server: 'type=charge;server=https://charge.example.com;api-token=yourapitoken'" + Environment.NewLine +
                                                          $"If you have a lnd server: 'type=lnd-rest;server=https://lnd:[email protected];macaroon=abf239...;certthumbprint=2abdf302...'" + Environment.NewLine +
                                                          $"              lnd server: 'type=lnd-rest;server=https://lnd:[email protected];macaroonfilepath=/root/.lnd/admin.macaroon;certthumbprint=2abdf302...'" + Environment.NewLine +
                                                          $"If you have an eclair server: 'type=eclair;server=http://eclair.com:4570;password=eclairpassword;bitcoin-host=bitcoind:37393;bitcoin-auth=bitcoinrpcuser:bitcoinrpcpassword" + Environment.NewLine +
                                                          $"               eclair server: 'type=eclair;server=http://eclair.com:4570;password=eclairpassword;bitcoin-host=bitcoind:37393" + Environment.NewLine +
                                                          $"Error: {error}" + Environment.NewLine +
                                                          "This service will not be exposed through BTCPay Server");
                        }
                        else
                        {
                            if (connectionString.IsLegacy)
                            {
                                Logs.Configuration.LogWarning($"Setting {net.CryptoCode}.lightning is a deprecated format, it will work now, but please replace it for future versions with '{connectionString.ToString()}'");
                            }
                            InternalLightningByCryptoCode.Add(net.CryptoCode, connectionString);
                        }
                    }
                }

                ExternalServices.Load(net.CryptoCode, conf);
            }
コード例 #2
0
        public void LoadArgs(IConfiguration conf)
        {
            NetworkType = DefaultConfiguration.GetNetworkType(conf);
            var defaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType);

            DataDir = conf.GetOrDefault <string>("datadir", defaultSettings.DefaultDataDirectory);
            Logs.Configuration.LogInformation("Network: " + NetworkType.ToString());

            var supportedChains = conf.GetOrDefault <string>("chains", "btc")
                                  .Split(',', StringSplitOptions.RemoveEmptyEntries)
                                  .Select(t => t.ToUpperInvariant());

            NetworkProvider = new BTCPayNetworkProvider(NetworkType).Filter(supportedChains.ToArray());
            foreach (var chain in supportedChains)
            {
                if (NetworkProvider.GetNetwork(chain) == null)
                {
                    throw new ConfigException($"Invalid chains \"{chain}\"");
                }
            }

            var validChains = new List <string>();

            foreach (var net in NetworkProvider.GetAll())
            {
                NBXplorerConnectionSetting setting = new NBXplorerConnectionSetting();
                setting.CryptoCode  = net.CryptoCode;
                setting.ExplorerUri = conf.GetOrDefault <Uri>($"{net.CryptoCode}.explorer.url", net.NBXplorerNetwork.DefaultSettings.DefaultUrl);
                setting.CookieFile  = conf.GetOrDefault <string>($"{net.CryptoCode}.explorer.cookiefile", net.NBXplorerNetwork.DefaultSettings.DefaultCookieFile);
                NBXplorerConnectionSettings.Add(setting);
                var lightning = conf.GetOrDefault <string>($"{net.CryptoCode}.lightning", string.Empty);
                if (lightning.Length != 0)
                {
                    if (!LightningConnectionString.TryParse(lightning, out var connectionString, out var error))
                    {
                        throw new ConfigException($"Invalid setting {net.CryptoCode}.lightning, you need to pass either " +
                                                  $"the absolute path to the unix socket of a running CLightning instance (eg. /root/.lightning/lightning-rpc), " +
                                                  $"or the url to a charge server with crendetials (eg. https://apitoken@API_TOKEN_SECRET:charge.example.com/)");
                    }
                    InternalLightningByCryptoCode.Add(net.CryptoCode, connectionString);
                }
            }

            Logs.Configuration.LogInformation("Supported chains: " + String.Join(',', supportedChains.ToArray()));

            PostgresConnectionString = conf.GetOrDefault <string>("postgres", null);
            BundleJsCss = conf.GetOrDefault <bool>("bundlejscss", true);
            ExternalUrl = conf.GetOrDefault <Uri>("externalurl", null);

            RootPath = conf.GetOrDefault <string>("rootpath", "/");
            if (!RootPath.StartsWith("/", StringComparison.InvariantCultureIgnoreCase))
            {
                RootPath = "/" + RootPath;
            }
            var old = conf.GetOrDefault <Uri>("internallightningnode", null);

            if (old != null)
            {
                throw new ConfigException($"internallightningnode should not be used anymore, use btclightning instead");
            }
        }
コード例 #3
0
        public void LoadArgs(IConfiguration conf)
        {
            NetworkType = DefaultConfiguration.GetNetworkType(conf);
            var defaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType);

            DataDir = conf.GetOrDefault <string>("datadir", defaultSettings.DefaultDataDirectory);
            Logs.Configuration.LogInformation("Network: " + NetworkType.ToString());

            var supportedChains = conf.GetOrDefault <string>("chains", "btc")
                                  .Split(',', StringSplitOptions.RemoveEmptyEntries)
                                  .Select(t => t.ToUpperInvariant());

            NetworkProvider = new BTCPayNetworkProvider(NetworkType).Filter(supportedChains.ToArray());
            foreach (var chain in supportedChains)
            {
                if (NetworkProvider.GetNetwork(chain) == null)
                {
                    throw new ConfigException($"Invalid chains \"{chain}\"");
                }
            }

            var validChains = new List <string>();

            foreach (var net in NetworkProvider.GetAll())
            {
                NBXplorerConnectionSetting setting = new NBXplorerConnectionSetting();
                setting.CryptoCode  = net.CryptoCode;
                setting.ExplorerUri = conf.GetOrDefault <Uri>($"{net.CryptoCode}.explorer.url", net.NBXplorerNetwork.DefaultSettings.DefaultUrl);
                setting.CookieFile  = conf.GetOrDefault <string>($"{net.CryptoCode}.explorer.cookiefile", net.NBXplorerNetwork.DefaultSettings.DefaultCookieFile);
                NBXplorerConnectionSettings.Add(setting);
                {
                    var lightning = conf.GetOrDefault <string>($"{net.CryptoCode}.lightning", string.Empty);
                    if (lightning.Length != 0)
                    {
                        if (!LightningConnectionString.TryParse(lightning, true, out var connectionString, out var error))
                        {
                            throw new ConfigException($"Invalid setting {net.CryptoCode}.lightning, " + Environment.NewLine +
                                                      $"If you have a lightning server use: 'type=clightning;server=/root/.lightning/lightning-rpc', " + Environment.NewLine +
                                                      $"If you have a lightning charge server: 'type=charge;server=https://charge.example.com;api-token=yourapitoken'" + Environment.NewLine +
                                                      $"If you have a lnd server: 'type=lnd-rest;server=https://lnd:[email protected];macaroon=abf239...;certthumbprint=2abdf302...'" + Environment.NewLine +
                                                      $"              lnd server: 'type=lnd-rest;server=https://lnd:[email protected];macaroonfilepath=/root/.lnd/admin.macaroon;certthumbprint=2abdf302...'" + Environment.NewLine +
                                                      error);
                        }
                        if (connectionString.IsLegacy)
                        {
                            Logs.Configuration.LogWarning($"Setting {net.CryptoCode}.lightning will work but use an deprecated format, please replace it by '{connectionString.ToString()}'");
                        }
                        InternalLightningByCryptoCode.Add(net.CryptoCode, connectionString);
                    }
                }

                {
                    var lightning = conf.GetOrDefault <string>($"{net.CryptoCode}.external.lnd.grpc", string.Empty);
                    if (lightning.Length != 0)
                    {
                        if (!LightningConnectionString.TryParse(lightning, false, out var connectionString, out var error))
                        {
                            throw new ConfigException($"Invalid setting {net.CryptoCode}.external.lnd.grpc, " + Environment.NewLine +
                                                      $"lnd server: 'type=lnd-grpc;server=https://lnd.example.com;macaroon=abf239...;certthumbprint=2abdf302...'" + Environment.NewLine +
                                                      $"lnd server: 'type=lnd-grpc;server=https://lnd.example.com;macaroonfilepath=/root/.lnd/admin.macaroon;certthumbprint=2abdf302...'" + Environment.NewLine +
                                                      error);
                        }
                        ExternalServicesByCryptoCode.Add(net.CryptoCode, new ExternalLNDGRPC(connectionString));
                    }
                }
            }

            Logs.Configuration.LogInformation("Supported chains: " + String.Join(',', supportedChains.ToArray()));

            PostgresConnectionString = conf.GetOrDefault <string>("postgres", null);
            BundleJsCss = conf.GetOrDefault <bool>("bundlejscss", true);
            ExternalUrl = conf.GetOrDefault <Uri>("externalurl", null);

            RootPath = conf.GetOrDefault <string>("rootpath", "/");
            if (!RootPath.StartsWith("/", StringComparison.InvariantCultureIgnoreCase))
            {
                RootPath = "/" + RootPath;
            }
            var old = conf.GetOrDefault <Uri>("internallightningnode", null);

            if (old != null)
            {
                throw new ConfigException($"internallightningnode should not be used anymore, use btclightning instead");
            }
        }
コード例 #4
0
        public void LoadArgs(IConfiguration conf)
        {
            NetworkType = DefaultConfiguration.GetNetworkType(conf);
            var defaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType);

            DataDir = conf.GetOrDefault <string>("datadir", defaultSettings.DefaultDataDirectory);
            Logs.Configuration.LogInformation("Network: " + NetworkType.ToString());

            var supportedChains = conf.GetOrDefault <string>("chains", "btc")
                                  .Split(',', StringSplitOptions.RemoveEmptyEntries)
                                  .Select(t => t.ToUpperInvariant());

            NetworkProvider = new BTCPayNetworkProvider(NetworkType).Filter(supportedChains.ToArray());
            foreach (var chain in supportedChains)
            {
                if (NetworkProvider.GetNetwork(chain) == null)
                {
                    throw new ConfigException($"Invalid chains \"{chain}\"");
                }
            }

            var validChains = new List <string>();

            foreach (var net in NetworkProvider.GetAll())
            {
                NBXplorerConnectionSetting setting = new NBXplorerConnectionSetting();
                setting.CryptoCode  = net.CryptoCode;
                setting.ExplorerUri = conf.GetOrDefault <Uri>($"{net.CryptoCode}.explorer.url", net.NBXplorerNetwork.DefaultSettings.DefaultUrl);
                setting.CookieFile  = conf.GetOrDefault <string>($"{net.CryptoCode}.explorer.cookiefile", net.NBXplorerNetwork.DefaultSettings.DefaultCookieFile);
                NBXplorerConnectionSettings.Add(setting);
                {
                    var lightning = conf.GetOrDefault <string>($"{net.CryptoCode}.lightning", string.Empty);
                    if (lightning.Length != 0)
                    {
                        if (!LightningConnectionString.TryParse(lightning, true, out var connectionString, out var error))
                        {
                            throw new ConfigException($"Invalid setting {net.CryptoCode}.lightning, " + Environment.NewLine +
                                                      $"If you have a lightning server use: 'type=clightning;server=/root/.lightning/lightning-rpc', " + Environment.NewLine +
                                                      $"If you have a lightning charge server: 'type=charge;server=https://charge.example.com;api-token=yourapitoken'" + Environment.NewLine +
                                                      $"If you have a lnd server: 'type=lnd-rest;server=https://lnd:[email protected];macaroon=abf239...;certthumbprint=2abdf302...'" + Environment.NewLine +
                                                      $"              lnd server: 'type=lnd-rest;server=https://lnd:[email protected];macaroonfilepath=/root/.lnd/admin.macaroon;certthumbprint=2abdf302...'" + Environment.NewLine +
                                                      error);
                        }
                        if (connectionString.IsLegacy)
                        {
                            Logs.Configuration.LogWarning($"Setting {net.CryptoCode}.lightning will work but use an deprecated format, please replace it by '{connectionString.ToString()}'");
                        }
                        InternalLightningByCryptoCode.Add(net.CryptoCode, connectionString);
                    }
                }

                {
                    var lightning = conf.GetOrDefault <string>($"{net.CryptoCode}.external.lnd.grpc", string.Empty);
                    if (lightning.Length != 0)
                    {
                        if (!LightningConnectionString.TryParse(lightning, false, out var connectionString, out var error))
                        {
                            throw new ConfigException($"Invalid setting {net.CryptoCode}.external.lnd.grpc, " + Environment.NewLine +
                                                      $"lnd server: 'type=lnd-grpc;server=https://lnd.example.com;macaroon=abf239...;certthumbprint=2abdf302...'" + Environment.NewLine +
                                                      $"lnd server: 'type=lnd-grpc;server=https://lnd.example.com;macaroonfilepath=/root/.lnd/admin.macaroon;certthumbprint=2abdf302...'" + Environment.NewLine +
                                                      error);
                        }
                        ExternalServicesByCryptoCode.Add(net.CryptoCode, new ExternalLNDGRPC(connectionString));
                    }
                }
            }

            Logs.Configuration.LogInformation("Supported chains: " + String.Join(',', supportedChains.ToArray()));

            PostgresConnectionString = conf.GetOrDefault <string>("postgres", null);
            BundleJsCss = conf.GetOrDefault <bool>("bundlejscss", true);
            ExternalUrl = conf.GetOrDefault <Uri>("externalurl", null);

            var sshSettings = ParseSSHConfiguration(conf);

            if ((!string.IsNullOrEmpty(sshSettings.Password) || !string.IsNullOrEmpty(sshSettings.KeyFile)) && !string.IsNullOrEmpty(sshSettings.Server))
            {
                int waitTime = 0;
                while (!string.IsNullOrEmpty(sshSettings.KeyFile) && !File.Exists(sshSettings.KeyFile))
                {
                    if (waitTime++ < 5)
                    {
                        System.Threading.Thread.Sleep(1000);
                    }
                    else
                    {
                        throw new ConfigException($"sshkeyfile does not exist");
                    }
                }

                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();
                }
                catch
                {
                    throw new ConfigException($"sshkeyfilepassword is invalid");
                }
                SSHSettings = sshSettings;
            }

            var fingerPrints = conf.GetOrDefault <string>("sshtrustedfingerprints", "");

            if (!string.IsNullOrEmpty(fingerPrints))
            {
                foreach (var fingerprint in fingerPrints.Split(';', StringSplitOptions.RemoveEmptyEntries))
                {
                    if (!SSHFingerprint.TryParse(fingerprint, out var f))
                    {
                        throw new ConfigException($"Invalid ssh fingerprint format {fingerprint}");
                    }
                    TrustedFingerprints.Add(f);
                }
            }

            RootPath = conf.GetOrDefault <string>("rootpath", "/");
            if (!RootPath.StartsWith("/", StringComparison.InvariantCultureIgnoreCase))
            {
                RootPath = "/" + RootPath;
            }
            var old = conf.GetOrDefault <Uri>("internallightningnode", null);

            if (old != null)
            {
                throw new ConfigException($"internallightningnode should not be used anymore, use btclightning instead");
            }
        }
コード例 #5
0
        public void LoadArgs(IConfiguration conf)
        {
            NetworkType = DefaultConfiguration.GetNetworkType(conf);
            var defaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType);

            DataDir = conf.GetOrDefault <string>("datadir", defaultSettings.DefaultDataDirectory);
            Logs.Configuration.LogInformation("Network: " + NetworkType.ToString());

            var supportedChains = conf.GetOrDefault <string>("chains", "btc")
                                  .Split(',', StringSplitOptions.RemoveEmptyEntries)
                                  .Select(t => t.ToUpperInvariant());

            NetworkProvider = new BTCPayNetworkProvider(NetworkType).Filter(supportedChains.ToArray());
            foreach (var chain in supportedChains)
            {
                if (NetworkProvider.GetNetwork(chain) == null)
                {
                    throw new ConfigException($"Invalid chains \"{chain}\"");
                }
            }

            var validChains = new List <string>();

            foreach (var net in NetworkProvider.GetAll())
            {
                NBXplorerConnectionSetting setting = new NBXplorerConnectionSetting();
                setting.CryptoCode  = net.CryptoCode;
                setting.ExplorerUri = conf.GetOrDefault <Uri>($"{net.CryptoCode}.explorer.url", net.NBXplorerNetwork.DefaultSettings.DefaultUrl);
                setting.CookieFile  = conf.GetOrDefault <string>($"{net.CryptoCode}.explorer.cookiefile", net.NBXplorerNetwork.DefaultSettings.DefaultCookieFile);
                NBXplorerConnectionSettings.Add(setting);

                {
                    var lightning = conf.GetOrDefault <string>($"{net.CryptoCode}.lightning", string.Empty);
                    if (lightning.Length != 0)
                    {
                        if (!LightningConnectionString.TryParse(lightning, true, out var connectionString, out var error))
                        {
                            throw new ConfigException($"Invalid setting {net.CryptoCode}.lightning, " + Environment.NewLine +
                                                      $"If you have a c-lightning server use: 'type=clightning;server=/root/.lightning/lightning-rpc', " + Environment.NewLine +
                                                      $"If you have a lightning charge server: 'type=charge;server=https://charge.example.com;api-token=yourapitoken'" + Environment.NewLine +
                                                      $"If you have a lnd server: 'type=lnd-rest;server=https://lnd:[email protected];macaroon=abf239...;certthumbprint=2abdf302...'" + Environment.NewLine +
                                                      $"              lnd server: 'type=lnd-rest;server=https://lnd:[email protected];macaroonfilepath=/root/.lnd/admin.macaroon;certthumbprint=2abdf302...'" + Environment.NewLine +
                                                      error);
                        }
                        if (connectionString.IsLegacy)
                        {
                            Logs.Configuration.LogWarning($"Setting {net.CryptoCode}.lightning is a deprecated format, it will work now, but please replace it for future versions with '{connectionString.ToString()}'");
                        }
                        InternalLightningByCryptoCode.Add(net.CryptoCode, connectionString);
                    }
                }

                void externalLnd <T>(string code, string lndType)
                {
                    var lightning = conf.GetOrDefault <string>(code, string.Empty);

                    if (lightning.Length != 0)
                    {
                        if (!LightningConnectionString.TryParse(lightning, false, out var connectionString, out var error))
                        {
                            throw new ConfigException($"Invalid setting {code}, " + Environment.NewLine +
                                                      $"lnd server: 'type={lndType};server=https://lnd.example.com;macaroon=abf239...;certthumbprint=2abdf302...'" + Environment.NewLine +
                                                      $"lnd server: 'type={lndType};server=https://lnd.example.com;macaroonfilepath=/root/.lnd/admin.macaroon;certthumbprint=2abdf302...'" + Environment.NewLine +
                                                      error);
                        }
                        var instanceType = typeof(T);
                        ExternalServicesByCryptoCode.Add(net.CryptoCode, (ExternalService)Activator.CreateInstance(instanceType, connectionString));
                    }
                };

                externalLnd <ExternalLndGrpc>($"{net.CryptoCode}.external.lnd.grpc", "lnd-grpc");
                externalLnd <ExternalLndRest>($"{net.CryptoCode}.external.lnd.rest", "lnd-rest");

                var spark = conf.GetOrDefault <string>($"{net.CryptoCode}.external.spark", string.Empty);
                if (spark.Length != 0)
                {
                    if (!SparkConnectionString.TryParse(spark, out var connectionString))
                    {
                        throw new ConfigException($"Invalid setting {net.CryptoCode}.external.spark, " + Environment.NewLine +
                                                  $"Valid example: 'server=https://btcpay.example.com/spark/btc/;cookiefile=/etc/clightning_bitcoin_spark/.cookie'");
                    }
                    ExternalServicesByCryptoCode.Add(net.CryptoCode, new ExternalSpark(connectionString));
                }

                var charge = conf.GetOrDefault <string>($"{net.CryptoCode}.external.charge", string.Empty);
                if (charge.Length != 0)
                {
                    if (!LightningConnectionString.TryParse(charge, false, out var chargeConnectionString, out var chargeError))
                    {
                        LightningConnectionString.TryParse("type=charge;" + charge, false, out chargeConnectionString, out chargeError);
                    }

                    if (chargeConnectionString == null || chargeConnectionString.ConnectionType != LightningConnectionType.Charge)
                    {
                        throw new ConfigException($"Invalid setting {net.CryptoCode}.external.charge, " + Environment.NewLine +
                                                  $"lightning charge server: 'type=charge;server=https://charge.example.com;api-token=2abdf302...'" + Environment.NewLine +
                                                  $"lightning charge server: 'type=charge;server=https://charge.example.com;cookiefilepath=/root/.charge/.cookie'" + Environment.NewLine +
                                                  chargeError ?? string.Empty);
                    }
                    ExternalServicesByCryptoCode.Add(net.CryptoCode, new ExternalCharge(chargeConnectionString));
                }
            }

            Logs.Configuration.LogInformation("Supported chains: " + String.Join(',', supportedChains.ToArray()));

            var services = conf.GetOrDefault <string>("externalservices", null);

            if (services != null)
            {
                foreach (var service in services.Split(new[] { ';', ',' })
                         .Select(p => p.Split(':'))
                         .Where(p => p.Length == 2)
                         .Select(p => (Name: p[0], Link: p[1])))
                {
                    ExternalServices.AddOrReplace(service.Name, service.Link);
                }
            }

            PostgresConnectionString = conf.GetOrDefault <string>("postgres", null);
            MySQLConnectionString    = conf.GetOrDefault <string>("mysql", null);
            BundleJsCss = conf.GetOrDefault <bool>("bundlejscss", true);
            ExternalUrl = conf.GetOrDefault <Uri>("externalurl", null);

            var sshSettings = ParseSSHConfiguration(conf);

            if ((!string.IsNullOrEmpty(sshSettings.Password) || !string.IsNullOrEmpty(sshSettings.KeyFile)) && !string.IsNullOrEmpty(sshSettings.Server))
            {
                int waitTime = 0;
                while (!string.IsNullOrEmpty(sshSettings.KeyFile) && !File.Exists(sshSettings.KeyFile))
                {
                    if (waitTime++ < 5)
                    {
                        System.Threading.Thread.Sleep(1000);
                    }
                    else
                    {
                        throw new ConfigException($"sshkeyfile does not exist");
                    }
                }

                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();
                }
                catch
                {
                    throw new ConfigException($"sshkeyfilepassword is invalid");
                }
                SSHSettings = sshSettings;
            }

            var fingerPrints = conf.GetOrDefault <string>("sshtrustedfingerprints", "");

            if (!string.IsNullOrEmpty(fingerPrints))
            {
                foreach (var fingerprint in fingerPrints.Split(';', StringSplitOptions.RemoveEmptyEntries))
                {
                    if (!SSHFingerprint.TryParse(fingerprint, out var f))
                    {
                        throw new ConfigException($"Invalid ssh fingerprint format {fingerprint}");
                    }
                    TrustedFingerprints.Add(f);
                }
            }

            RootPath = conf.GetOrDefault <string>("rootpath", "/");
            if (!RootPath.StartsWith("/", StringComparison.InvariantCultureIgnoreCase))
            {
                RootPath = "/" + RootPath;
            }
            var old = conf.GetOrDefault <Uri>("internallightningnode", null);

            if (old != null)
            {
                throw new ConfigException($"internallightningnode is deprecated and should not be used anymore, use btclightning instead");
            }

            LogFile = GetDebugLog(conf);
            if (!string.IsNullOrEmpty(LogFile))
            {
                Logs.Configuration.LogInformation("LogFile: " + LogFile);
                Logs.Configuration.LogInformation("Log Level: " + GetDebugLogLevel(conf));
            }

            DisableRegistration = conf.GetOrDefault <bool>("disable-registration", true);
        }