diff --git a/BTCPayServer.Tests/BTCPayServerTester.cs b/BTCPayServer.Tests/BTCPayServerTester.cs index 2c4984ac2..79bbc6538 100644 --- a/BTCPayServer.Tests/BTCPayServerTester.cs +++ b/BTCPayServer.Tests/BTCPayServerTester.cs @@ -118,6 +118,12 @@ namespace BTCPayServer.Tests config.AppendLine($"ltc.explorer.url={LTCNBXplorerUri.AbsoluteUri}"); config.AppendLine($"ltc.explorer.cookiefile=0"); config.AppendLine($"btc.lightning={IntegratedLightning.AbsoluteUri}"); + if (!string.IsNullOrEmpty(SSHPassword) && string.IsNullOrEmpty(SSHKeyFile)) + config.AppendLine($"sshpassword={SSHPassword}"); + if (!string.IsNullOrEmpty(SSHKeyFile)) + config.AppendLine($"sshkeyfile={SSHKeyFile}"); + if (!string.IsNullOrEmpty(SSHConnection)) + config.AppendLine($"sshconnection={SSHConnection}"); if (TestDatabase == TestDatabases.MySQL && !String.IsNullOrEmpty(MySQL)) config.AppendLine($"mysql=" + MySQL); @@ -280,8 +286,11 @@ namespace BTCPayServer.Tests return _Host.Services.GetRequiredService(); } - public IServiceProvider ServiceProvider => _Host.Services; + public IServiceProvider ServiceProvider => _Host.Services; + public string SSHPassword { get; internal set; } + public string SSHKeyFile { get; internal set; } + public string SSHConnection { get; set; } public T GetController(string userId = null, string storeId = null, Claim[] additionalClaims = null) where T : Controller { var context = new DefaultHttpContext(); diff --git a/BTCPayServer.Tests/SeleniumTests.cs b/BTCPayServer.Tests/SeleniumTests.cs index 03ff81652..98e94a6fe 100644 --- a/BTCPayServer.Tests/SeleniumTests.cs +++ b/BTCPayServer.Tests/SeleniumTests.cs @@ -7,6 +7,7 @@ using Xunit.Abstractions; using OpenQA.Selenium.Interactions; using System.Linq; using NBitcoin; +using System.Threading.Tasks; namespace BTCPayServer.Tests { @@ -94,6 +95,27 @@ namespace BTCPayServer.Tests s.Driver.FindElement(By.Id("LoginButton")).Click(); s.Driver.AssertNoError(); } + [Fact] + public async Task CanUseSSHService() + { + using (var s = SeleniumTester.Create()) + { + s.Start(); + var alice = s.RegisterNewUser(isAdmin: true); + s.Driver.Navigate().GoToUrl(s.Link("/server/services")); + Assert.Contains("server/services/ssh", s.Driver.PageSource); + using (var client = await s.Server.PayTester.GetService().SSHSettings.ConnectAsync()) + { + var result = await client.RunBash("echo hello"); + Assert.Equal(string.Empty, result.Error); + Assert.Equal("hello\n", result.Output); + Assert.Equal(0, result.ExitStatus); + } + s.Driver.Navigate().GoToUrl(s.Link("/server/services/ssh")); + s.Driver.AssertNoError(); + } + } + [Fact] public void CanUseDynamicDns() { diff --git a/BTCPayServer.Tests/ServerTester.cs b/BTCPayServer.Tests/ServerTester.cs index 433625dcb..f0c987133 100644 --- a/BTCPayServer.Tests/ServerTester.cs +++ b/BTCPayServer.Tests/ServerTester.cs @@ -71,6 +71,10 @@ namespace BTCPayServer.Tests PayTester.Port = int.Parse(GetEnvironment("TESTS_PORT", Utils.FreeTcpPort().ToString(CultureInfo.InvariantCulture)), CultureInfo.InvariantCulture); PayTester.HostName = GetEnvironment("TESTS_HOSTNAME", "127.0.0.1"); PayTester.InContainer = bool.Parse(GetEnvironment("TESTS_INCONTAINER", "false")); + + PayTester.SSHPassword = GetEnvironment("TESTS_SSHPASSWORD", "opD3i2282D"); + PayTester.SSHKeyFile = GetEnvironment("TESTS_SSHKEYFILE", ""); + PayTester.SSHConnection = GetEnvironment("TESTS_SSHCONNECTION", "root@127.0.0.1:21622"); } public bool Dockerized diff --git a/BTCPayServer.Tests/docker-compose.yml b/BTCPayServer.Tests/docker-compose.yml index 4aceda03d..b367f122d 100644 --- a/BTCPayServer.Tests/docker-compose.yml +++ b/BTCPayServer.Tests/docker-compose.yml @@ -25,6 +25,9 @@ services: TEST_MERCHANTCHARGE: "type=charge;server=http://lightning-charged:9112/;api-token=foiewnccewuify" TEST_MERCHANTLND: "https://lnd:lnd@merchant_lnd:8080/" TESTS_INCONTAINER: "true" + TESTS_SSHCONNECTION: "root@sshd:21622" + TESTS_SSHPASSWORD: "" + TESTS_SSHKEYFILE: "" expose: - "80" links: @@ -32,6 +35,7 @@ services: extra_hosts: - "tests:127.0.0.1" volumes: + - "sshd_datadir:/root/.ssh" - "customer_lightningd_datadir:/etc/customer_lightningd_datadir" - "merchant_lightningd_datadir:/etc/merchant_lightningd_datadir" @@ -46,6 +50,18 @@ services: - lightning-charged - customer_lnd - merchant_lnd + - sshd + + sshd: + build: + context: . + dockerfile: sshd.Dockerfile + ports: + - "21622:22" + expose: + - 22 + volumes: + - "sshd_datadir:/root/.ssh" devlnd: image: btcpayserver/bitcoin:0.18.0 @@ -270,6 +286,7 @@ services: - bitcoind volumes: + sshd_datadir: bitcoin_datadir: customer_lightningd_datadir: merchant_lightningd_datadir: diff --git a/BTCPayServer.Tests/sshd.Dockerfile b/BTCPayServer.Tests/sshd.Dockerfile new file mode 100644 index 000000000..9c672f52f --- /dev/null +++ b/BTCPayServer.Tests/sshd.Dockerfile @@ -0,0 +1,12 @@ +FROM alpine:3.8 + +RUN apk add --no-cache openssh sudo bash +RUN ssh-keygen -f /root/.ssh/id_rsa -t rsa -q -P "" -m PEM +RUN echo 'root:opD3i2282D' | chpasswd +RUN sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config +RUN ssh-keygen -f /etc/ssh/ssh_host_rsa_key -N '' -t rsa && \ + ssh-keygen -f /etc/ssh/ssh_host_dsa_key -N '' -t dsa && \ + ssh-keygen -f /etc/ssh/ssh_host_ecdsa_key -N '' -t ecdsa && \ + ssh-keygen -f /etc/ssh/ssh_host_ed25519_key -N '' -t ed25519 + +CMD ["/usr/sbin/sshd", "-D"] diff --git a/BTCPayServer/Properties/launchSettings.json b/BTCPayServer/Properties/launchSettings.json index ec1458aca..2f70b636b 100644 --- a/BTCPayServer/Properties/launchSettings.json +++ b/BTCPayServer/Properties/launchSettings.json @@ -41,7 +41,9 @@ "ASPNETCORE_ENVIRONMENT": "Development", "BTCPAY_CHAINS": "btc,ltc", "BTCPAY_POSTGRES": "User ID=postgres;Host=127.0.0.1;Port=39372;Database=btcpayserver", - "BTCPAY_EXTERNALSERVICES": "totoservice:totolink;" + "BTCPAY_EXTERNALSERVICES": "totoservice:totolink;", + "BTCPAY_SSHCONNECTION": "root@127.0.0.1:21622", + "BTCPAY_SSHPASSWORD": "opD3i2282D" }, "applicationUrl": "https://localhost:14142/" }