Refactor TorService (#2388)

* TorServices Refactor to make value passing easier

* Allow specifying Tor services through config

Format:

BTCPAY_TORSERVICES: "BTCPAYSERVER:URL.ONION:VIRTUALPORT;BTC-P2P:URL.ONION:VIRTUALPORT;BTC-RPC:URL.ONION:VIRTUALPORT;SOMEOTHERONIONSERVICE:URL.ONION:VIRTUALPORT"

* add tests

* Optimize Tor Services loader and ensure it is loaded as a hosted service

* Remove Task from Tor service loader

* Use options to parse Tor services

* Fix booboo

* Fix test after fixing booboo

* Adding timeout on long running CanEnumeratetorServices test

(cherry picked from commit 274b77e3175960158b803410037e2c7ff31984be)

* Renaming timeout variable to better name

* Only allow one of torrcfile or torservices

Co-authored-by: Kukks <evilkukka@gmail.com>
Co-authored-by: rockstardev <rockstardev@users.noreply.github.com>
This commit is contained in:
Jonathan Underwood
2021-04-18 11:26:06 +09:00
committed by GitHub
parent 475a68924e
commit ee0fa71605
8 changed files with 181 additions and 119 deletions

View File

@@ -131,5 +131,10 @@ namespace BTCPayServer
}
return network as T;
}
public bool TryGetNetwork<T>(string cryptoCode, out T network) where T : BTCPayNetworkBase
{
network = GetNetwork<T>(cryptoCode);
return network != null;
}
}
}

View File

@@ -23,7 +23,7 @@ namespace BTCPayServer.Tests
Logs.LogProvider = new XUnitLogProvider(helper);
}
[Fact(Timeout = TestTimeout)]
[Fact(Timeout = LongRunningTestTimeout)]
[Trait("Integration", "Integration")]
public async Task CanCreateAndDeleteCrowdfundApp()
{
@@ -63,7 +63,7 @@ namespace BTCPayServer.Tests
[Fact(Timeout = TestTimeout)]
[Fact(Timeout = LongRunningTestTimeout)]
[Trait("Integration", "Integration")]
public async Task CanContributeOnlyWhenAllowed()
{
@@ -155,7 +155,7 @@ namespace BTCPayServer.Tests
}
}
[Fact(Timeout = TestTimeout)]
[Fact(Timeout = LongRunningTestTimeout)]
[Trait("Integration", "Integration")]
public async Task CanComputeCrowdfundModel()
{

View File

@@ -47,7 +47,10 @@ using BTCPayServer.Validation;
using ExchangeSharp;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Configuration.Memory;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using NBitcoin;
using NBitcoin.DataEncoders;
using NBitcoin.Payment;
@@ -67,7 +70,7 @@ namespace BTCPayServer.Tests
{
public class UnitTest1
{
public const int TestTimeout = 60_000;
public const int LongRunningTestTimeout = 60_000; // 60s
public UnitTest1(ITestOutputHelper helper)
{
@@ -870,18 +873,55 @@ namespace BTCPayServer.Tests
}
}
[Fact]
[Fact(Timeout = LongRunningTestTimeout)]
[Trait("Fast", "Fast")]
public async Task CanEnumerateTorServices()
{
var tor = new TorServices(new BTCPayNetworkProvider(ChainName.Regtest),
new BTCPayServerOptions() { TorrcFile = TestUtils.GetTestDataFullPath("Tor/torrc") });
new OptionsWrapper<BTCPayServerOptions>(new BTCPayServerOptions()
{
TorrcFile = TestUtils.GetTestDataFullPath("Tor/torrc")
}));
await tor.Refresh();
Assert.Single(tor.Services.Where(t => t.ServiceType == TorServiceType.BTCPayServer));
Assert.Single(tor.Services.Where(t => t.ServiceType == TorServiceType.P2P));
Assert.Single(tor.Services.Where(t => t.ServiceType == TorServiceType.RPC));
Assert.True(tor.Services.Where(t => t.ServiceType == TorServiceType.Other).Count() > 1);
Assert.True(tor.Services.Count(t => t.ServiceType == TorServiceType.Other) > 1);
tor = new TorServices(new BTCPayNetworkProvider(ChainName.Regtest),
new OptionsWrapper<BTCPayServerOptions>(new BTCPayServerOptions()
{
TorrcFile = null,
TorServices = "btcpayserver:host.onion:80;btc-p2p:host2.onion:81,BTC-RPC:host3.onion:82,UNKNOWN:host4.onion:83,INVALID:ddd".Split(new[] {';', ','}, StringSplitOptions.RemoveEmptyEntries)
}));
await Task.WhenAll(tor.StartAsync(CancellationToken.None));
var btcpayS = Assert.Single(tor.Services.Where(t => t.ServiceType == TorServiceType.BTCPayServer));
Assert.Null(btcpayS.Network);
Assert.Equal("host.onion", btcpayS.OnionHost);
Assert.Equal(80, btcpayS.VirtualPort);
var p2p = Assert.Single(tor.Services.Where(t => t.ServiceType == TorServiceType.P2P));
Assert.NotNull(p2p.Network);
Assert.Equal("BTC", p2p.Network.CryptoCode);
Assert.Equal("host2.onion", p2p.OnionHost);
Assert.Equal(81, p2p.VirtualPort);
var rpc = Assert.Single(tor.Services.Where(t => t.ServiceType == TorServiceType.RPC));
Assert.NotNull(p2p.Network);
Assert.Equal("BTC", rpc.Network.CryptoCode);
Assert.Equal("host3.onion", rpc.OnionHost);
Assert.Equal(82, rpc.VirtualPort);
var unknown = Assert.Single(tor.Services.Where(t => t.ServiceType == TorServiceType.Other));
Assert.Null(unknown.Network);
Assert.Equal("host4.onion", unknown.OnionHost);
Assert.Equal(83, unknown.VirtualPort);
Assert.Equal("UNKNOWN", unknown.Name);
Assert.Equal(4, tor.Services.Length);
}
@@ -1046,7 +1086,7 @@ namespace BTCPayServer.Tests
});
}
[Fact(Timeout = TestTimeout)]
[Fact(Timeout = LongRunningTestTimeout)]
[Trait("Integration", "Integration")]
public async Task CanUseServerInitiatedPairingCode()
{
@@ -1073,7 +1113,7 @@ namespace BTCPayServer.Tests
}
}
[Fact(Timeout = TestTimeout)]
[Fact(Timeout = LongRunningTestTimeout)]
[Trait("Integration", "Integration")]
public async Task CanSendIPN()
{
@@ -1143,7 +1183,7 @@ namespace BTCPayServer.Tests
}
}
[Fact(Timeout = TestTimeout)]
[Fact(Timeout = LongRunningTestTimeout)]
[Trait("Integration", "Integration")]
public async Task CantPairTwiceWithSamePubkey()
{
@@ -1167,7 +1207,7 @@ namespace BTCPayServer.Tests
}
}
[Fact(Timeout = TestTimeout)]
[Fact(Timeout = LongRunningTestTimeout)]
[Trait("Integration", "Integration")]
public void CanSolveTheDogesRatesOnKraken()
{
@@ -1185,7 +1225,7 @@ namespace BTCPayServer.Tests
}
[Fact(Timeout = TestTimeout)]
[Fact(Timeout = LongRunningTestTimeout)]
[Trait("Integration", "Integration")]
public async Task CanUseTorClient()
{
@@ -1238,7 +1278,7 @@ namespace BTCPayServer.Tests
}
}
[Fact(Timeout = TestTimeout)]
[Fact(Timeout = LongRunningTestTimeout)]
[Trait("Integration", "Integration")]
public async Task CanRescanWallet()
{
@@ -1340,7 +1380,7 @@ namespace BTCPayServer.Tests
}
}
[Fact(Timeout = TestTimeout)]
[Fact(Timeout = LongRunningTestTimeout)]
[Trait("Integration", "Integration")]
public async Task CanListInvoices()
{
@@ -1391,7 +1431,7 @@ namespace BTCPayServer.Tests
}
}
[Fact(Timeout = TestTimeout)]
[Fact(Timeout = LongRunningTestTimeout)]
[Trait("Integration", "Integration")]
public async Task CanListNotifications()
{
@@ -1675,7 +1715,7 @@ namespace BTCPayServer.Tests
Assert.NotNull(paymentData.KeyPath);
}
[Fact(Timeout = TestTimeout)]
[Fact(Timeout = LongRunningTestTimeout)]
[Trait("Fast", "Fast")]
public void CanParseFilter()
{
@@ -1703,7 +1743,7 @@ namespace BTCPayServer.Tests
Assert.Equal("hekki", search.TextSearch);
}
[Fact(Timeout = TestTimeout)]
[Fact(Timeout = LongRunningTestTimeout)]
[Trait("Fast", "Fast")]
public void CanParseFingerprint()
{
@@ -1720,7 +1760,7 @@ namespace BTCPayServer.Tests
Assert.Equal(f1.ToString(), f2.ToString());
}
[Fact(Timeout = TestTimeout)]
[Fact(Timeout = LongRunningTestTimeout)]
[Trait("Integration", "Integration")]
public async void CheckCORSSetOnBitpayAPI()
{
@@ -1755,7 +1795,7 @@ namespace BTCPayServer.Tests
}
}
[Fact(Timeout = TestTimeout)]
[Fact(Timeout = LongRunningTestTimeout)]
[Trait("Integration", "Integration")]
public async Task TestAccessBitpayAPI()
{
@@ -1834,7 +1874,7 @@ namespace BTCPayServer.Tests
}
}
[Fact(Timeout = TestTimeout)]
[Fact(Timeout = LongRunningTestTimeout)]
[Trait("Integration", "Integration")]
public async Task CanUseExchangeSpecificRate()
{
@@ -1879,7 +1919,7 @@ namespace BTCPayServer.Tests
return invoice2.CryptoInfo[0].Rate;
}
[Fact(Timeout = TestTimeout)]
[Fact(Timeout = LongRunningTestTimeout)]
[Trait("Integration", "Integration")]
public async Task CanUseAnyoneCanCreateInvoice()
{
@@ -1931,7 +1971,7 @@ namespace BTCPayServer.Tests
}
}
[Fact(Timeout = TestTimeout)]
[Fact(Timeout = LongRunningTestTimeout)]
[Trait("Integration", "Integration")]
public async Task CanTweakRate()
{
@@ -1978,7 +2018,7 @@ namespace BTCPayServer.Tests
}
}
[Fact(Timeout = TestTimeout)]
[Fact(Timeout = LongRunningTestTimeout)]
[Trait("Integration", "Integration")]
public async Task CanModifyRates()
{
@@ -2307,7 +2347,7 @@ namespace BTCPayServer.Tests
Assert.True(client.WaitAllRunning(default).Wait(100));
}
[Fact(Timeout = TestTimeout)]
[Fact(Timeout = LongRunningTestTimeout)]
[Trait("Fast", "Fast")]
public void PosDataParser_ParsesCorrectly()
{
@@ -2333,7 +2373,7 @@ namespace BTCPayServer.Tests
});
}
[Fact(Timeout = TestTimeout)]
[Fact(Timeout = LongRunningTestTimeout)]
[Trait("Integration", "Integration")]
public async Task PosDataParser_ParsesCorrectly_Slower()
{
@@ -2383,7 +2423,7 @@ namespace BTCPayServer.Tests
}
}
[Fact(Timeout = TestTimeout)]
[Fact(Timeout = LongRunningTestTimeout)]
[Trait("Integration", "Integration")]
public async Task CanExportInvoicesJson()
{
@@ -2462,7 +2502,7 @@ namespace BTCPayServer.Tests
}
}
[Fact(Timeout = TestTimeout)]
[Fact(Timeout = LongRunningTestTimeout)]
[Trait("Integration", "Integration")]
public async Task CanChangeNetworkFeeMode()
{
@@ -2553,7 +2593,7 @@ namespace BTCPayServer.Tests
}
}
[Fact(Timeout = TestTimeout)]
[Fact(Timeout = LongRunningTestTimeout)]
[Trait("Integration", "Integration")]
public async Task CanExportInvoicesCsv()
{
@@ -2595,7 +2635,7 @@ namespace BTCPayServer.Tests
}
[Fact(Timeout = TestTimeout)]
[Fact(Timeout = LongRunningTestTimeout)]
[Trait("Integration", "Integration")]
public async Task CanCreateAndDeleteApps()
{
@@ -2633,7 +2673,7 @@ namespace BTCPayServer.Tests
}
}
[Fact(Timeout = TestTimeout)]
[Fact(Timeout = LongRunningTestTimeout)]
[Trait("Integration", "Integration")]
public async Task CanCreateStrangeInvoice()
{
@@ -2679,7 +2719,7 @@ namespace BTCPayServer.Tests
}
}
[Fact(Timeout = TestTimeout)]
[Fact(Timeout = LongRunningTestTimeout)]
[Trait("Integration", "Integration")]
public async Task InvoiceFlowThroughDifferentStatesCorrectly()
{
@@ -2869,7 +2909,7 @@ namespace BTCPayServer.Tests
}
}
[Fact(Timeout = TestTimeout)]
[Fact(Timeout = LongRunningTestTimeout)]
[Trait("Integration", "Integration")]
public void CanQueryDirectProviders()
{
@@ -2940,7 +2980,7 @@ namespace BTCPayServer.Tests
}
[Fact(Timeout = TestTimeout)]
[Fact(Timeout = LongRunningTestTimeout)]
[Trait("Integration", "Integration")]
public async Task CanExportBackgroundFetcherState()
{
@@ -2982,7 +3022,7 @@ namespace BTCPayServer.Tests
}
[Fact(Timeout = TestTimeout)]
[Fact(Timeout = LongRunningTestTimeout)]
[Trait("Integration", "Integration")]
public void CanGetRateCryptoCurrenciesByDefault()
{
@@ -3034,7 +3074,7 @@ namespace BTCPayServer.Tests
}
}
[Fact(Timeout = TestTimeout)]
[Fact(Timeout = LongRunningTestTimeout)]
[Trait("Integration", "Integration")]
public async Task CheckLogsRoute()
{
@@ -3117,7 +3157,7 @@ namespace BTCPayServer.Tests
return name;
}
[Fact(Timeout = TestTimeout)]
[Fact(Timeout = LongRunningTestTimeout)]
[Trait("Fast", "Fast")]
public void CanCheckFileNameValid()
{
@@ -3135,7 +3175,7 @@ namespace BTCPayServer.Tests
}
}
[Fact(Timeout = TestTimeout)]
[Fact(Timeout = LongRunningTestTimeout)]
[Trait("Fast", "Fast")]
public async Task CanCreateSqlitedb()
{
@@ -3147,7 +3187,7 @@ namespace BTCPayServer.Tests
await new ApplicationDbContext(builder.Options).Database.MigrateAsync();
}
[Fact(Timeout = TestTimeout)]
[Fact(Timeout = LongRunningTestTimeout)]
[Trait("Fast", "Fast")]
public void CanUsePermission()
{
@@ -3172,7 +3212,7 @@ namespace BTCPayServer.Tests
.Contains(Permission.Create(Policies.CanModifyStoreSettings)));
}
[Fact(Timeout = TestTimeout)]
[Fact(Timeout = LongRunningTestTimeout)]
[Trait("Fast", "Fast")]
public void CheckRatesProvider()
{
@@ -3260,7 +3300,7 @@ namespace BTCPayServer.Tests
}
[Fact(Timeout = TestTimeout)]
[Fact(Timeout = LongRunningTestTimeout)]
[Trait("Integration", "Integration")]
public async Task CanLoginWithNoSecondaryAuthSystemsOrRequestItWhenAdded()
{
@@ -3336,7 +3376,7 @@ namespace BTCPayServer.Tests
}
}
[Fact(Timeout = TestTimeout)]
[Fact(Timeout = LongRunningTestTimeout)]
[Trait("Integration", "Integration")]
public async void CheckOnionlocationForNonOnionHtmlRequests()
{
@@ -3382,7 +3422,7 @@ namespace BTCPayServer.Tests
}
}
[Fact(Timeout = TestTimeout)]
[Fact(Timeout = LongRunningTestTimeout)]
[Trait("Integration", "Integration")]
public async Task CanCheckForNewVersion()
{
@@ -3428,7 +3468,7 @@ namespace BTCPayServer.Tests
}
}
[Fact(Timeout = TestTimeout)]
[Fact(Timeout = LongRunningTestTimeout)]
[Trait("Integration", "Integration")]
public async Task CanDoLightningInternalNodeMigration()
{
@@ -3507,7 +3547,7 @@ namespace BTCPayServer.Tests
}
[Fact(Timeout = TestTimeout)]
[Fact(Timeout = LongRunningTestTimeout)]
[Trait("Integration", "Integration")]
public async Task CanDoInvoiceMigrations()
{
@@ -3588,7 +3628,7 @@ namespace BTCPayServer.Tests
await migrationStartupTask.ExecuteAsync();
}
[Fact(Timeout = TestTimeout)]
[Fact(Timeout = LongRunningTestTimeout)]
[Trait("Integration", "Integration")]
public async Task EmailSenderTests()
{

View File

@@ -69,7 +69,12 @@ namespace BTCPayServer.Configuration
BundleJsCss = conf.GetOrDefault<bool>("bundlejscss", true);
DockerDeployment = conf.GetOrDefault<bool>("dockerdeployment", true);
AllowAdminRegistration = conf.GetOrDefault<bool>("allow-admin-registration", false);
TorrcFile = conf.GetOrDefault<string>("torrcfile", null);
TorServices = conf.GetOrDefault<string>("torservices", null)
?.Split(new[] {';', ','}, StringSplitOptions.RemoveEmptyEntries);
if (!string.IsNullOrEmpty(TorrcFile) && TorServices != null)
throw new ConfigException($"torrcfile or torservices should be provided, but not both");
var socksEndpointString = conf.GetOrDefault<string>("socksendpoint", null);
if (!string.IsNullOrEmpty(socksEndpointString))
@@ -195,6 +200,7 @@ namespace BTCPayServer.Configuration
set;
}
public string TorrcFile { get; set; }
public string[] TorServices { get; set; }
public Uri UpdateUrl { get; set; }
}
}

View File

@@ -39,6 +39,7 @@ namespace BTCPayServer.Configuration
app.Option("--sshauthorizedkeys", "Path to a authorized_keys file that BTCPayServer can modify from the website (default: empty)", CommandOptionType.SingleValue);
app.Option("--sshtrustedfingerprints", "SSH Host public key fingerprint or sha256 (default: empty, it will allow untrusted connections)", CommandOptionType.SingleValue);
app.Option("--torrcfile", "Path to torrc file containing hidden services directories (default: empty)", CommandOptionType.SingleValue);
app.Option("--torservices", "Tor hostnames of available services added to Server Settings (and sets onion header for btcpay). Format: btcpayserver:host.onion:80;btc-p2p:host2.onion:81,BTC-RPC:host3.onion:82,UNKNOWN:host4.onion:83. (default: empty)", CommandOptionType.SingleValue);
app.Option("--socksendpoint", "Socks endpoint to connect to onion urls (default: empty)", CommandOptionType.SingleValue);
app.Option("--updateurl", $"Url used for once a day new release version check. Check performed only if value is not empty (default: empty)", CommandOptionType.SingleValue);
app.Option("--debuglog", "A rolling log file for debug messages.", CommandOptionType.SingleValue);

View File

@@ -1,30 +0,0 @@
using System;
using System.Threading.Tasks;
using BTCPayServer.Configuration;
using BTCPayServer.Services;
namespace BTCPayServer.HostedServices
{
public class TorServicesHostedService : BaseAsyncService
{
private readonly BTCPayServerOptions _options;
private readonly TorServices _torServices;
public TorServicesHostedService(BTCPayServerOptions options, TorServices torServices)
{
_options = options;
_torServices = torServices;
}
internal override Task[] InitializeTasks()
{
return new Task[] { CreateLoopTask(RefreshTorServices) };
}
async Task RefreshTorServices()
{
await _torServices.Refresh();
await Task.Delay(TimeSpan.FromSeconds(120), Cancellation);
}
}
}

View File

@@ -93,6 +93,7 @@ namespace BTCPayServer.Hosting
services.TryAddSingleton<ISettingsRepository>(provider => provider.GetService<SettingsRepository>());
services.TryAddSingleton<LabelFactory>();
services.TryAddSingleton<TorServices>();
services.AddSingleton<IHostedService>(provider => provider.GetRequiredService<TorServices>());
services.TryAddSingleton<SocketFactory>();
services.TryAddSingleton<LightningClientFactoryService>();
services.TryAddSingleton<InvoicePaymentNotification>();
@@ -346,7 +347,6 @@ namespace BTCPayServer.Hosting
services.AddSingleton<IHostedService, TransactionLabelMarkerHostedService>();
services.AddSingleton<IHostedService, UserEventHostedService>();
services.AddSingleton<IHostedService, DynamicDnsHostedService>();
services.AddSingleton<IHostedService, TorServicesHostedService>();
services.AddSingleton<IHostedService, PaymentRequestStreamer>();
services.AddSingleton<IBackgroundJobClient, BackgroundJobClient>();
services.AddScoped<IAuthorizationHandler, CookieAuthorizationHandler>();

View File

@@ -2,74 +2,77 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using BTCPayServer.Configuration;
using BTCPayServer.HostedServices;
using BTCPayServer.Logging;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace BTCPayServer.Services
{
public class TorServices
public class TorServices : BaseAsyncService
{
private readonly BTCPayNetworkProvider _networks;
readonly BTCPayServerOptions _Options;
public TorServices(BTCPayServer.BTCPayNetworkProvider networks, BTCPayServerOptions options)
private readonly BTCPayNetworkProvider _btcPayNetworkProvider;
private readonly IOptions<BTCPayServerOptions> _options;
public TorServices(BTCPayNetworkProvider btcPayNetworkProvider, IOptions<BTCPayServerOptions> options)
{
_networks = networks;
_Options = options;
_btcPayNetworkProvider = btcPayNetworkProvider;
_options = options;
}
public TorService[] Services { get; internal set; } = Array.Empty<TorService>();
private bool firstRun = true;
internal async Task Refresh()
{
if (string.IsNullOrEmpty(_Options.TorrcFile) || !File.Exists(_Options.TorrcFile))
if (firstRun)
{
if (!string.IsNullOrEmpty(_Options.TorrcFile))
Logs.PayServer.LogWarning("Torrc file is not found");
Services = Array.Empty<TorService>();
return;
firstRun = false;
}
else
{
await Task.Delay(TimeSpan.FromSeconds(120), Cancellation);
}
List<TorService> result = new List<TorService>();
try
{
var torrcContent = await File.ReadAllTextAsync(_Options.TorrcFile);
if (!File.Exists(_options.Value.TorrcFile))
{
Logs.PayServer.LogWarning("Torrc file is not found");
Services = Array.Empty<TorService>();
return;
}
var torrcContent = await File.ReadAllTextAsync(_options.Value.TorrcFile);
if (!Torrc.TryParse(torrcContent, out var torrc))
{
Logs.PayServer.LogWarning("Torrc file could not be parsed");
Services = Array.Empty<TorService>();
return;
}
var torrcDir = Path.GetDirectoryName(_Options.TorrcFile);
var services = torrc.ServiceDirectories.SelectMany(d => d.ServicePorts.Select(p => (Directory: GetDirectory(d, torrcDir), VirtualPort: p.VirtualPort)))
.Select(d => (ServiceName: d.Directory.Name,
ReadingLines: System.IO.File.ReadAllLinesAsync(Path.Combine(d.Directory.FullName, "hostname")),
VirtualPort: d.VirtualPort))
.ToArray();
var torrcDir = Path.GetDirectoryName(_options.Value.TorrcFile);
var services = torrc.ServiceDirectories.SelectMany(d =>
d.ServicePorts.Select(p => (Directory: GetDirectory(d, torrcDir), VirtualPort: p.VirtualPort)))
.Select(d => (ServiceName: d.Directory.Name,
ReadingLines: System.IO.File.ReadAllLinesAsync(Path.Combine(d.Directory.FullName, "hostname")),
VirtualPort: d.VirtualPort))
.ToArray();
foreach (var service in services)
{
try
{
var onionHost = (await service.ReadingLines)[0].Trim();
var torService = new TorService()
{
Name = service.ServiceName,
OnionHost = onionHost,
VirtualPort = service.VirtualPort
};
if (service.ServiceName.Equals("BTCPayServer", StringComparison.OrdinalIgnoreCase))
torService.ServiceType = TorServiceType.BTCPayServer;
else if (TryParseP2PService(service.ServiceName, out var network, out var serviceType))
{
torService.ServiceType = serviceType;
torService.Network = network;
}
var torService = ParseService(service.ServiceName, onionHost, service.VirtualPort);
result.Add(torService);
}
catch (Exception ex)
{
Logs.PayServer.LogWarning(ex, $"Error while reading hidden service {service.ServiceName} configuration");
Logs.PayServer.LogWarning(ex,
$"Error while reading hidden service {service.ServiceName} configuration");
}
}
}
@@ -77,9 +80,29 @@ namespace BTCPayServer.Services
{
Logs.PayServer.LogWarning(ex, $"Error while reading torrc file");
}
Services = result.ToArray();
}
private TorService ParseService(string serviceName, string onionHost, int virtualPort)
{
var torService = new TorService() {Name = serviceName, OnionHost = onionHost, VirtualPort = virtualPort};
if (Enum.TryParse<TorServiceType>(serviceName, true, out var serviceType))
torService.ServiceType = serviceType;
else if (TryParseCryptoSpecificService(serviceName, out var network, out serviceType))
{
torService.ServiceType = serviceType;
torService.Network = network;
}
else
{
torService.ServiceType = TorServiceType.Other;
}
return torService;
}
private static DirectoryInfo GetDirectory(HiddenServiceDir hs, string relativeTo)
{
if (Path.IsPathRooted(hs.DirectoryPath))
@@ -87,25 +110,42 @@ namespace BTCPayServer.Services
return new DirectoryInfo(Path.Combine(relativeTo, hs.DirectoryPath));
}
private bool TryParseP2PService(string name, out BTCPayNetworkBase network, out TorServiceType serviceType)
private bool TryParseCryptoSpecificService(string name, out BTCPayNetworkBase network,
out TorServiceType serviceType)
{
network = null;
serviceType = TorServiceType.Other;
var splitted = name.Trim().Split('-');
if (splitted.Length == 2 && splitted[1] == "P2P")
return splitted.Length == 2 && Enum.TryParse(splitted[1], true, out serviceType) &&
_btcPayNetworkProvider.TryGetNetwork(splitted[0], out network);
}
public override async Task StartAsync(CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(_options.Value.TorrcFile))
{
serviceType = TorServiceType.P2P;
}
else if (splitted.Length == 2 && splitted[1] == "RPC")
{
serviceType = TorServiceType.RPC;
LoadFromConfig();
}
else
{
return false;
await Refresh();
await base.StartAsync(cancellationToken);
}
network = _networks.GetNetwork<BTCPayNetworkBase>(splitted[0]);
return network != null;
}
internal override Task[] InitializeTasks()
{
return new[] {CreateLoopTask(Refresh)};
}
private void LoadFromConfig()
{
Services = _options.Value.TorServices.Select(p => p.Split(":", StringSplitOptions.RemoveEmptyEntries))
.Where(p => p.Length == 3)
.Select(strings =>
int.TryParse(strings[2], out var port) ? ParseService(strings[0], strings[1], port) : null)
.Where(p => p != null)
.ToArray();
}
}