diff --git a/BTCPayServer/Configuration/BTCPayServerOptions.cs b/BTCPayServer/Configuration/BTCPayServerOptions.cs index c1d0e75b3..ed5b61ee6 100644 --- a/BTCPayServer/Configuration/BTCPayServerOptions.cs +++ b/BTCPayServer/Configuration/BTCPayServerOptions.cs @@ -149,6 +149,7 @@ namespace BTCPayServer.Configuration PostgresConnectionString = conf.GetOrDefault("postgres", null); MySQLConnectionString = conf.GetOrDefault("mysql", null); BundleJsCss = conf.GetOrDefault("bundlejscss", true); + TorHiddenServicesDirectory = conf.GetOrDefault("torservices", null); var sshSettings = ParseSSHConfiguration(conf); if ((!string.IsNullOrEmpty(sshSettings.Password) || !string.IsNullOrEmpty(sshSettings.KeyFile)) && !string.IsNullOrEmpty(sshSettings.Server)) @@ -273,5 +274,6 @@ namespace BTCPayServer.Configuration get; set; } + public string TorHiddenServicesDirectory { get; set; } } } diff --git a/BTCPayServer/Configuration/DefaultConfiguration.cs b/BTCPayServer/Configuration/DefaultConfiguration.cs index efca1e956..243ef7ae7 100644 --- a/BTCPayServer/Configuration/DefaultConfiguration.cs +++ b/BTCPayServer/Configuration/DefaultConfiguration.cs @@ -40,6 +40,7 @@ namespace BTCPayServer.Configuration app.Option("--sshkeyfile", "SSH private key file to manage BTCPay (default: empty)", CommandOptionType.SingleValue); app.Option("--sshkeyfilepassword", "Password of the SSH keyfile (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("--torservices", "Path to folder containing hidden services directories (default: empty)", CommandOptionType.SingleValue); app.Option("--debuglog", "A rolling log file for debug messages.", CommandOptionType.SingleValue); app.Option("--debugloglevel", "The severity you log (default:information)", CommandOptionType.SingleValue); app.Option("--disable-registration", "Disables new user registrations (default:true)", CommandOptionType.SingleValue); diff --git a/BTCPayServer/Controllers/ServerController.cs b/BTCPayServer/Controllers/ServerController.cs index 062fbb82d..6663bd84d 100644 --- a/BTCPayServer/Controllers/ServerController.cs +++ b/BTCPayServer/Controllers/ServerController.cs @@ -39,6 +39,7 @@ namespace BTCPayServer.Controllers private RateFetcher _RateProviderFactory; private StoreRepository _StoreRepository; LightningConfigurationProvider _LnConfigProvider; + private readonly TorServices _torServices; BTCPayServerOptions _Options; public ServerController(UserManager userManager, @@ -48,6 +49,7 @@ namespace BTCPayServer.Controllers NBXplorerDashboard dashBoard, IHttpClientFactory httpClientFactory, LightningConfigurationProvider lnConfigProvider, + TorServices torServices, Services.Stores.StoreRepository storeRepository) { _Options = options; @@ -58,6 +60,7 @@ namespace BTCPayServer.Controllers _RateProviderFactory = rateProviderFactory; _StoreRepository = storeRepository; _LnConfigProvider = lnConfigProvider; + _torServices = torServices; } [Route("server/rates")] @@ -443,7 +446,7 @@ namespace BTCPayServer.Controllers } [Route("server/services")] - public IActionResult Services() + public async Task Services() { var result = new ServicesViewModel(); result.ExternalServices = _Options.ExternalServices; @@ -463,6 +466,7 @@ namespace BTCPayServer.Controllers Link = this.Url.Action(nameof(SSHService)) }); } + result.TorServices = await _torServices.GetServices(); return View(result); } diff --git a/BTCPayServer/Hosting/BTCPayServerServices.cs b/BTCPayServer/Hosting/BTCPayServerServices.cs index 5ab519a8e..3d8b82e2d 100644 --- a/BTCPayServer/Hosting/BTCPayServerServices.cs +++ b/BTCPayServer/Hosting/BTCPayServerServices.cs @@ -62,6 +62,7 @@ namespace BTCPayServer.Hosting }); services.AddHttpClient(); services.TryAddSingleton(); + services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddSingleton(o => o.GetRequiredService>().Value); services.TryAddSingleton(o => diff --git a/BTCPayServer/Models/ServerViewModels/ServicesViewModel.cs b/BTCPayServer/Models/ServerViewModels/ServicesViewModel.cs index 1cad93f1f..8b83e221f 100644 --- a/BTCPayServer/Models/ServerViewModels/ServicesViewModel.cs +++ b/BTCPayServer/Models/ServerViewModels/ServicesViewModel.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using BTCPayServer.Configuration; +using BTCPayServer.Services; namespace BTCPayServer.Models.ServerViewModels { @@ -17,5 +18,6 @@ namespace BTCPayServer.Models.ServerViewModels public List ExternalServices { get; set; } = new List(); public List OtherExternalServices { get; set; } = new List(); + public TorService[] TorServices { get; set; } = Array.Empty(); } } diff --git a/BTCPayServer/Services/TorServices.cs b/BTCPayServer/Services/TorServices.cs new file mode 100644 index 000000000..89a3cf2cd --- /dev/null +++ b/BTCPayServer/Services/TorServices.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using BTCPayServer.Configuration; + +namespace BTCPayServer.Services +{ + public class TorServices + { + BTCPayServerOptions _Options; + public TorServices(BTCPayServerOptions options) + { + _Options = options; + } + + public async Task GetServices() + { + if (string.IsNullOrEmpty(_Options.TorHiddenServicesDirectory) || !Directory.Exists(_Options.TorHiddenServicesDirectory)) + return Array.Empty(); + List result = new List(); + var servicesDirs = Directory.GetDirectories(_Options.TorHiddenServicesDirectory); + var services = servicesDirs + .Select(d => new DirectoryInfo(d)) + .Select(d => (ServiceName: d.Name, ReadingLines: System.IO.File.ReadAllLinesAsync(Path.Combine(d.FullName, "hostname")))) + .ToArray(); + foreach (var service in services) + { + try + { + var onionUrl = (await service.ReadingLines)[0].Trim(); + result.Add(new TorService() { Name = service.ServiceName, OnionUrl = onionUrl }); + } + catch + { + + } + } + return result.ToArray(); + } + } + + public class TorService + { + public string Name { get; set; } + public string OnionUrl { get; set; } + } +} diff --git a/BTCPayServer/Views/Server/Services.cshtml b/BTCPayServer/Views/Server/Services.cshtml index 52000fec2..42d17c4dc 100644 --- a/BTCPayServer/Views/Server/Services.cshtml +++ b/BTCPayServer/Views/Server/Services.cshtml @@ -48,35 +48,68 @@ @if (Model.OtherExternalServices.Count != 0) { -
-
-

Other services

-
- Other external services -
-
- - - - - - - - - @foreach (var s in Model.OtherExternalServices) - { +
+
+

Other services

+
+ Other external services +
+
+
NameActions
+ - - + + - } - -
@s.Name - See information - NameActions
+ + + @foreach (var s in Model.OtherExternalServices) + { + + @s.Name + + See information + + + } + + +
+
+
+} + +@if (Model.TorServices.Length != 0) +{ +
+
+

TOR hidden services

+
+ TOR services hosted on this server +
+
+ + + + + + + + + @foreach (var s in Model.TorServices) + { + + + + + } + +
NameActions
@s.Name + See information +
+
- } @section Scripts {