Merge branch 'master' into fix-1017

This commit is contained in:
Nicolas Dorier
2019-09-09 13:34:51 +09:00
committed by GitHub
16 changed files with 137 additions and 33 deletions

View File

@@ -91,10 +91,10 @@ namespace BTCPayServer.Data
builder.UseSqlite(_ConnectionString, o => o.MigrationsAssembly("BTCPayServer.Data"));
else if (_Type == DatabaseType.Postgres)
builder
.UseNpgsql(_ConnectionString, o => o.MigrationsAssembly("BTCPayServer.Data"))
.UseNpgsql(_ConnectionString, o => o.MigrationsAssembly("BTCPayServer.Data").EnableRetryOnFailure(10))
.ReplaceService<IMigrationsSqlGenerator, CustomNpgsqlMigrationsSqlGenerator>();
else if (_Type == DatabaseType.MySQL)
builder.UseMySql(_ConnectionString, o => o.MigrationsAssembly("BTCPayServer.Data"));
builder.UseMySql(_ConnectionString, o => o.MigrationsAssembly("BTCPayServer.Data").EnableRetryOnFailure(10));
}
}
}

View File

@@ -1,6 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;

View File

@@ -0,0 +1,36 @@
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using BTCPayServer.Rating;
using Newtonsoft.Json.Linq;
namespace BTCPayServer.Services.Rates
{
public class NdaxRateProvider : IRateProvider, IHasExchangeName
{
private readonly HttpClient _httpClient;
public NdaxRateProvider(HttpClient httpClient)
{
_httpClient = httpClient ?? new HttpClient();
}
public string ExchangeName => "ndax";
public async Task<ExchangeRates> GetRatesAsync(CancellationToken cancellationToken)
{
var response = await _httpClient.GetAsync("https://ndax.io/api/returnTicker", cancellationToken);
var jobj = await response.Content.ReadAsAsync<Dictionary<string, JObject>>(cancellationToken);
return new ExchangeRates(jobj.Select(pair => new ExchangeRate(ExchangeName, CurrencyPair.Parse(pair.Key),
new BidAsk(GetValue(pair.Value["highestBid"]), GetValue(pair.Value["lowestAsk"])))));
}
private static decimal GetValue(JToken jobj)
{
return string.IsNullOrEmpty(jobj.ToString()) ? 0 : jobj.Value<decimal>();
}
}
}

View File

@@ -113,6 +113,7 @@ namespace BTCPayServer.Services.Rates
Providers.Add(CoinAverageRateProvider.CoinAverageName, new CoinAverageRateProvider() { Exchange = CoinAverageRateProvider.CoinAverageName, HttpClient = _httpClientFactory?.CreateClient("EXCHANGE_COINAVERAGE"), Authenticator = _CoinAverageSettings });
Providers.Add("kraken", new KrakenExchangeRateProvider() { HttpClient = _httpClientFactory?.CreateClient("EXCHANGE_KRAKEN") });
Providers.Add("bylls", new ByllsRateProvider(_httpClientFactory?.CreateClient("EXCHANGE_BYLLS")));
Providers.Add("ndax", new NdaxRateProvider(_httpClientFactory?.CreateClient("EXCHANGE_NDAX")));
Providers.Add("bitbank", new BitbankRateProvider(_httpClientFactory?.CreateClient("EXCHANGE_BITBANK")));
Providers.Add("bitpay", new BitpayRateProvider(_httpClientFactory?.CreateClient("EXCHANGE_BITPAY")));
@@ -171,6 +172,7 @@ namespace BTCPayServer.Services.Rates
// Add other exchanges supported here
exchanges.Add(new CoinAverageExchange(CoinAverageRateProvider.CoinAverageName, "Coin Average", $"https://apiv2.bitcoinaverage.com/indices/global/ticker/short"));
exchanges.Add(new CoinAverageExchange("bylls", "Bylls", "https://bylls.com/api/price?from_currency=BTC&to_currency=CAD"));
exchanges.Add(new CoinAverageExchange("ndax", "NDAX", "https://ndax.io/api/returnTicker"));
exchanges.Add(new CoinAverageExchange("bitbank", "Bitbank", "https://public.bitbank.cc/prices"));
return exchanges;

View File

@@ -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<T>();
}
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<T>(string userId = null, string storeId = null, Claim[] additionalClaims = null) where T : Controller
{
var context = new DefaultHttpContext();

View File

@@ -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<BTCPayServer.Configuration.BTCPayServerOptions>().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()
{
@@ -269,7 +291,7 @@ namespace BTCPayServer.Tests
s.Driver.FindElement(By.CssSelector("div.note-editable.card-block")).SendKeys("1BTC = 1BTC");
s.Driver.FindElement(By.Id("TargetCurrency")).SendKeys("JPY");
s.Driver.FindElement(By.Id("TargetAmount")).SendKeys("700");
s.Driver.FindElement(By.Id("SaveSettings")).Submit();
s.Driver.FindElement(By.Id("SaveSettings")).ForceClick();
s.Driver.FindElement(By.Id("ViewApp")).ForceClick();
s.Driver.SwitchTo().Window(s.Driver.WindowHandles.Last());
Assert.True(s.Driver.PageSource.Contains("Currently Active!"), "Unable to create CF");
@@ -292,7 +314,7 @@ namespace BTCPayServer.Tests
s.Driver.FindElement(By.Id("Title")).SendKeys("Pay123");
s.Driver.FindElement(By.Id("Amount")).SendKeys("700");
s.Driver.FindElement(By.Id("Currency")).SendKeys("BTC");
s.Driver.FindElement(By.Id("SaveButton")).Submit();
s.Driver.FindElement(By.Id("SaveButton")).ForceClick();
s.Driver.FindElement(By.Name("ViewAppButton")).SendKeys(Keys.Return);
s.Driver.SwitchTo().Window(s.Driver.WindowHandles.Last());
Assert.True(s.Driver.PageSource.Contains("Amount due"), "Unable to create Payment Request");

View File

@@ -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

View File

@@ -16,7 +16,6 @@ services:
TESTS_LTCNBXPLORERURL: http://nbxplorer:32838/
TESTS_DB: "Postgres"
TESTS_POSTGRES: User ID=postgres;Host=postgres;Port=5432;Database=btcpayserver
TESTS_MYSQL: User ID=root;Host=mysql;Port=3306;Database=btcpayserver
TESTS_PORT: 80
TESTS_HOSTNAME: tests
TESTS_RUN_EXTERNAL_INTEGRATION: ${TESTS_RUN_EXTERNAL_INTEGRATION:-false}
@@ -26,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:22"
TESTS_SSHPASSWORD: ""
TESTS_SSHKEYFILE: ""
expose:
- "80"
links:
@@ -33,26 +35,33 @@ 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"
# The dev container is not actually used, it is just handy to run `docker-compose up dev` to start all services
dev:
image: btcpayserver/bitcoin:0.18.0
environment:
BITCOIN_NETWORK: regtest
BITCOIN_EXTRA_ARGS: |
deprecatedrpc=signrawtransaction
connect=bitcoind:39388
image: coscale/docker-sleep
links:
- nbxplorer
- postgres
- mysql
- customer_lightningd
- merchant_lightningd
- 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
@@ -64,7 +73,6 @@ services:
links:
- nbxplorer
- postgres
- mysql
- customer_lnd
- merchant_lnd
nbxplorer:
@@ -213,15 +221,6 @@ services:
- "39372:5432"
expose:
- "5432"
mysql:
image: mysql:8.0.12
expose:
- "3306"
ports:
- "33036:3306"
environment:
- MYSQL_ALLOW_EMPTY_PASSWORD=yes
merchant_lnd:
image: btcpayserver/lnd:v0.7.0-beta
@@ -287,6 +286,7 @@ services:
- bitcoind
volumes:
sshd_datadir:
bitcoin_datadir:
customer_lightningd_datadir:
merchant_lightningd_datadir:

View File

@@ -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"]

View File

@@ -531,7 +531,7 @@ namespace BTCPayServer.Controllers
var balanceChange = psbt.GetBalance(settings.AccountDerivation, signingKey, rootedKeyPath);
if (balanceChange == Money.Zero)
{
ModelState.AddModelError(nameof(viewModel.SeedOrKey), "This seed does not seem to be able to sign this transaction. Either this is the wrong key, or Wallet Settings have not the correct account path in the wallet settings.");
ModelState.AddModelError(nameof(viewModel.SeedOrKey), "This seed is unable to sign this transaction. Either the seed is incorrect, or the account path has not been properly configured in the Wallet Settings.");
return View(viewModel);
}
psbt.SignAll(settings.AccountDerivation, signingKey, rootedKeyPath);

View File

@@ -266,4 +266,5 @@ CFP Franc XPF 0
Moroccan Dirham MAD 2
Yemeni Rial YER 2
Zambian Kwacha ZMW 2
Zimbabwe Dollar ZWL 2
Zimbabwe Dollar ZWL 2
Indonesian Rupiah RP 2

View File

@@ -106,12 +106,14 @@ namespace BTCPayServer.Hosting
else if(!String.IsNullOrEmpty(opts.MySQLConnectionString))
{
Logs.Configuration.LogInformation($"MySQL DB used ({opts.MySQLConnectionString})");
Logs.Configuration.LogWarning("MySQL is not widely tested and should be considered experimental, we advise you to use postgres instead.");
dbContext = new ApplicationDbContextFactory(DatabaseType.MySQL, opts.MySQLConnectionString);
}
else
{
var connStr = "Data Source=" + Path.Combine(opts.DataDir, "sqllite.db");
Logs.Configuration.LogInformation($"SQLite DB used ({connStr})");
Logs.Configuration.LogWarning("MySQL is not widely tested and should be considered experimental, we advise you to use postgres instead.");
dbContext = new ApplicationDbContextFactory(DatabaseType.Sqlite, connStr);
}

View File

@@ -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/"
}

View File

@@ -16,6 +16,10 @@ namespace BTCPayServer.Services
public class DynamicDnsSettings
{
public List<DynamicDnsService> Services { get; set; } = new List<DynamicDnsService>();
public override string ToString()
{
return String.Empty;
}
}
public class DynamicDnsService
{

View File

@@ -151,9 +151,9 @@
<div class="col-lg-5">
<br />
These parameters allow you to influence process after purchase. <i>Server IPN</i> is location we'll query with details.
We can also deliver email notification to specified addres.
We can also deliver email notification to specified address.
<br /><br />
Finally <i>Browser Redirect</i> defines where BtcPayServer will redirect customer after puchase is completed.
Finally <i>Browser Redirect</i> defines where BTCPayServer will redirect customer after purchase is completed.
</div>
</div>
<h3>Advanced</h3>

View File

@@ -5,8 +5,6 @@
ViewData.SetActivePageAndTitle(WalletsNavPages.Transactions);
}
<style type="text/css">
.smMaxWidth {
max-width: 200px;
}
@@ -29,6 +27,10 @@
white-space: nowrap;
text-overflow: ellipsis;
}
.transactionLabel:not(:last-child) {
margin-bottom: 4px;
}
</style>
@if (TempData.ContainsKey("TempDataProperty-StatusMessage"))
{
@@ -73,7 +75,17 @@
<td style="text-align:left">
@foreach (var label in transaction.Labels)
{
<a asp-route-labelFilter="@label.Value"><span class="badge" style="display:block;background-color:@label.Color;color:white;">@label.Value</span></a>
<a
asp-route-labelFilter="@label.Value"
class="badge transactionLabel"
style="
background-color: @label.Color;
color: white;
display: block;
"
>
@label.Value
</a>
}
</td>
<td class="smMaxWidth text-truncate @(transaction.IsConfirmed ? "" : "unconf")">