Merge remote-tracking branch 'btcpayserver/master' into feature/coinswitch

This commit is contained in:
Kukks 2018-12-20 17:57:04 +01:00
commit fc9cd5bdf0
22 changed files with 382 additions and 80 deletions

View file

@ -355,7 +355,7 @@ namespace BTCPayServer.Tests
} }
} }
[Fact] [Fact(Timeout = 60 * 1000)]
[Trait("Integration", "Integration")] [Trait("Integration", "Integration")]
public async Task CanSetLightningServer() public async Task CanSetLightningServer()
{ {
@ -407,7 +407,7 @@ namespace BTCPayServer.Tests
await ProcessLightningPayment(LightningConnectionType.Charge); await ProcessLightningPayment(LightningConnectionType.Charge);
} }
[Fact] [Fact(Timeout = 60 * 1000)]
[Trait("Integration", "Integration")] [Trait("Integration", "Integration")]
public async Task CanSendLightningPaymentLnd() public async Task CanSendLightningPaymentLnd()
{ {
@ -1362,7 +1362,7 @@ namespace BTCPayServer.Tests
} }
} }
[Fact] [Fact(Timeout = 60 * 1000)]
[Trait("Integration", "Integration")] [Trait("Integration", "Integration")]
public async Task CanSetPaymentMethodLimits() public async Task CanSetPaymentMethodLimits()
{ {

View file

@ -93,12 +93,13 @@ services:
- bitcoind - bitcoind
- litecoind - litecoind
bitcoind: bitcoind:
restart: unless-stopped
image: btcpayserver/bitcoin:0.17.0 image: btcpayserver/bitcoin:0.17.0
environment: environment:
BITCOIN_NETWORK: regtest BITCOIN_NETWORK: regtest
BITCOIN_EXTRA_ARGS: | BITCOIN_EXTRA_ARGS: |-
deprecatedrpc=signrawtransaction
rpcuser=ceiwHEbqWI83 rpcuser=ceiwHEbqWI83
rpcpassword=DwubwWsoo3 rpcpassword=DwubwWsoo3
rpcport=43782 rpcport=43782
@ -106,9 +107,9 @@ services:
whitelist=0.0.0.0/0 whitelist=0.0.0.0/0
zmqpubrawblock=tcp://0.0.0.0:28332 zmqpubrawblock=tcp://0.0.0.0:28332
zmqpubrawtx=tcp://0.0.0.0:28333 zmqpubrawtx=tcp://0.0.0.0:28333
deprecatedrpc=signrawtransaction
ports: ports:
- "43782:43782" - "43782:43782"
- "28332:28332"
expose: expose:
- "43782" # RPC - "43782" # RPC
- "39388" # P2P - "39388" # P2P
@ -188,13 +189,13 @@ services:
- bitcoind - bitcoind
litecoind: litecoind:
restart: unless-stopped
image: nicolasdorier/docker-litecoin:0.16.3 image: nicolasdorier/docker-litecoin:0.16.3
environment: environment:
BITCOIN_EXTRA_ARGS: | BITCOIN_EXTRA_ARGS: |-
rpcuser=ceiwHEbqWI83 rpcuser=ceiwHEbqWI83
rpcpassword=DwubwWsoo3 rpcpassword=DwubwWsoo3
regtest=1 regtest=1
server=1
rpcport=43782 rpcport=43782
port=39388 port=39388
whitelist=0.0.0.0/0 whitelist=0.0.0.0/0
@ -221,13 +222,16 @@ services:
- MYSQL_ALLOW_EMPTY_PASSWORD=yes - MYSQL_ALLOW_EMPTY_PASSWORD=yes
merchant_lnd: merchant_lnd:
image: btcpayserver/lnd:0.5-beta-2 image: btcpayserver/lnd:v0.5.1-beta
restart: unless-stopped restart: unless-stopped
environment: environment:
LND_CHAIN: "btc" LND_CHAIN: "btc"
LND_ENVIRONMENT: "regtest" LND_ENVIRONMENT: "regtest"
LND_EXPLORERURL: "http://nbxplorer:32838/"
LND_EXTRA_ARGS: | LND_EXTRA_ARGS: |
restlisten=0.0.0.0:8080 restlisten=0.0.0.0:8080
rpclisten=127.0.0.1:10008
rpclisten=0.0.0.0:10009
bitcoin.node=bitcoind bitcoin.node=bitcoind
bitcoind.rpchost=bitcoind:43782 bitcoind.rpchost=bitcoind:43782
bitcoind.zmqpubrawblock=tcp://bitcoind:28332 bitcoind.zmqpubrawblock=tcp://bitcoind:28332
@ -248,13 +252,16 @@ services:
- bitcoind - bitcoind
customer_lnd: customer_lnd:
image: btcpayserver/lnd:0.5-beta-2 image: btcpayserver/lnd:v0.5.1-beta
restart: unless-stopped restart: unless-stopped
environment: environment:
LND_CHAIN: "btc" LND_CHAIN: "btc"
LND_ENVIRONMENT: "regtest" LND_ENVIRONMENT: "regtest"
LND_EXPLORERURL: "http://nbxplorer:32838/"
LND_EXTRA_ARGS: | LND_EXTRA_ARGS: |
restlisten=0.0.0.0:8080 restlisten=0.0.0.0:8080
rpclisten=127.0.0.1:10008
rpclisten=0.0.0.0:10009
bitcoin.node=bitcoind bitcoin.node=bitcoind
bitcoind.rpchost=bitcoind:43782 bitcoind.rpchost=bitcoind:43782
bitcoind.zmqpubrawblock=tcp://bitcoind:28332 bitcoind.zmqpubrawblock=tcp://bitcoind:28332

View file

@ -2,4 +2,4 @@
set -e set -e
dotnet test --filter Fast=Fast --no-build dotnet test --filter Fast=Fast --no-build
dotnet test --filter Integration=Integration --no-build dotnet test --filter Integration=Integration --no-build -v n

View file

@ -1,3 +1,5 @@
{ {
"parallelizeTestCollections": false "parallelizeTestCollections": false,
"longRunningTestSeconds": 60,
"diagnosticMessages": true
} }

View file

@ -26,7 +26,7 @@ namespace BTCPayServer
"GRS_BTC = bittrex(GRS_BTC)" "GRS_BTC = bittrex(GRS_BTC)"
}, },
CryptoImagePath = "imlegacy/groestlcoin.png", CryptoImagePath = "imlegacy/groestlcoin.png",
LightningImagePath = "imlegacy/groestlcoin-lightning.png", LightningImagePath = "imlegacy/groestlcoin-lightning.svg",
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType), DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
CoinType = NetworkType == NetworkType.Mainnet ? new KeyPath("17'") : new KeyPath("1'") CoinType = NetworkType == NetworkType.Mainnet ? new KeyPath("17'") : new KeyPath("1'")
}); });

View file

@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework> <TargetFramework>netcoreapp2.1</TargetFramework>
<Version>1.0.3.31</Version> <Version>1.0.3.33</Version>
<NoWarn>NU1701,CA1816,CA1308,CA1810,CA2208</NoWarn> <NoWarn>NU1701,CA1816,CA1308,CA1810,CA2208</NoWarn>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
@ -33,7 +33,7 @@
<EmbeddedResource Include="Currencies.txt" /> <EmbeddedResource Include="Currencies.txt" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="BTCPayServer.Lightning.All" Version="1.1.0.3" /> <PackageReference Include="BTCPayServer.Lightning.All" Version="1.1.0.4" />
<PackageReference Include="BuildBundlerMinifier" Version="2.7.385" /> <PackageReference Include="BuildBundlerMinifier" Version="2.7.385" />
<PackageReference Include="DigitalRuby.ExchangeSharp" Version="0.5.3" /> <PackageReference Include="DigitalRuby.ExchangeSharp" Version="0.5.3" />
<PackageReference Include="Hangfire" Version="1.6.20" /> <PackageReference Include="Hangfire" Version="1.6.20" />
@ -136,6 +136,9 @@
<Content Update="Views\Home\BitpayTranslator.cshtml"> <Content Update="Views\Home\BitpayTranslator.cshtml">
<Pack>$(IncludeRazorContentInPack)</Pack> <Pack>$(IncludeRazorContentInPack)</Pack>
</Content> </Content>
<Content Update="Views\Server\LightningChargeServices.cshtml">
<Pack>$(IncludeRazorContentInPack)</Pack>
</Content>
<Content Update="Views\Server\SparkServices.cshtml"> <Content Update="Views\Server\SparkServices.cshtml">
<Pack>$(IncludeRazorContentInPack)</Pack> <Pack>$(IncludeRazorContentInPack)</Pack>
</Content> </Content>

View file

@ -139,7 +139,7 @@ namespace BTCPayServer.Configuration
externalLnd<ExternalLndRest>($"{net.CryptoCode}.external.lnd.rest", "lnd-rest"); externalLnd<ExternalLndRest>($"{net.CryptoCode}.external.lnd.rest", "lnd-rest");
var spark = conf.GetOrDefault<string>($"{net.CryptoCode}.external.spark", string.Empty); var spark = conf.GetOrDefault<string>($"{net.CryptoCode}.external.spark", string.Empty);
if(spark.Length != 0) if (spark.Length != 0)
{ {
if (!SparkConnectionString.TryParse(spark, out var connectionString)) if (!SparkConnectionString.TryParse(spark, out var connectionString))
{ {
@ -148,14 +148,30 @@ namespace BTCPayServer.Configuration
} }
ExternalServicesByCryptoCode.Add(net.CryptoCode, new ExternalSpark(connectionString)); 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())); Logs.Configuration.LogInformation("Supported chains: " + String.Join(',', supportedChains.ToArray()));
var services = conf.GetOrDefault<string>("externalservices", null); var services = conf.GetOrDefault<string>("externalservices", null);
if(services != null) if (services != null)
{ {
foreach(var service in services.Split(new[] { ';', ',' }) foreach (var service in services.Split(new[] { ';', ',' })
.Select(p => p.Split(':')) .Select(p => p.Split(':'))
.Where(p => p.Length == 2) .Where(p => p.Length == 2)
.Select(p => (Name: p[0], Link: p[1]))) .Select(p => (Name: p[0], Link: p[1])))

View file

@ -50,7 +50,8 @@ namespace BTCPayServer.Configuration
app.Option($"--{crypto}explorercookiefile", $"Path to the cookie file (default: {network.NBXplorerNetwork.DefaultSettings.DefaultCookieFile})", CommandOptionType.SingleValue); app.Option($"--{crypto}explorercookiefile", $"Path to the cookie file (default: {network.NBXplorerNetwork.DefaultSettings.DefaultCookieFile})", CommandOptionType.SingleValue);
app.Option($"--{crypto}lightning", $"Easy configuration of lightning for the server administrator: Must be a UNIX socket of c-lightning (lightning-rpc) or URL to a charge server (default: empty)", CommandOptionType.SingleValue); app.Option($"--{crypto}lightning", $"Easy configuration of lightning for the server administrator: Must be a UNIX socket of c-lightning (lightning-rpc) or URL to a charge server (default: empty)", CommandOptionType.SingleValue);
app.Option($"--{crypto}externallndgrpc", $"The LND gRPC configuration BTCPay will expose to easily connect to the internal lnd wallet from Zap wallet (default: empty)", CommandOptionType.SingleValue); app.Option($"--{crypto}externallndgrpc", $"The LND gRPC configuration BTCPay will expose to easily connect to the internal lnd wallet from Zap wallet (default: empty)", CommandOptionType.SingleValue);
app.Option($"--{crypto}externalspark", $"The connection string to spark server (default: empty)", CommandOptionType.SingleValue); app.Option($"--{crypto}externalspark", $"Show spark information in Server settings / Server. The connection string to spark server (default: empty)", CommandOptionType.SingleValue);
app.Option($"--{crypto}externalcharge", $"Show lightning charge information in Server settings/Server. The connection string to charge server (default: empty)", CommandOptionType.SingleValue);
} }
return app; return app;
} }

View file

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using BTCPayServer.Lightning;
namespace BTCPayServer.Configuration.External
{
public class ExternalCharge : ExternalService
{
public ExternalCharge(LightningConnectionString connectionString)
{
if (connectionString == null)
throw new ArgumentNullException(nameof(connectionString));
ConnectionString = connectionString;
}
public LightningConnectionString ConnectionString { get; }
}
}

View file

@ -31,6 +31,7 @@ namespace BTCPayServer.Configuration
resultTemp.Server = new Uri(kv[1], UriKind.Absolute); resultTemp.Server = new Uri(kv[1], UriKind.Absolute);
break; break;
case "cookiefile": case "cookiefile":
case "cookiefilepath":
if (resultTemp.CookeFile != null) if (resultTemp.CookeFile != null)
return false; return false;
resultTemp.CookeFile = kv[1]; resultTemp.CookeFile = kv[1];

View file

@ -0,0 +1,57 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
namespace BTCPayServer.Controllers
{
public class Macaroons
{
public class Macaroon
{
public Macaroon(byte[] bytes)
{
Bytes = bytes;
Hex = NBitcoin.DataEncoders.Encoders.Hex.EncodeData(bytes);
}
public string Hex { get; set; }
public byte[] Bytes { get; set; }
}
public static async Task<Macaroons> GetFromDirectoryAsync(string directoryPath)
{
if (directoryPath == null)
throw new ArgumentNullException(nameof(directoryPath));
Macaroons macaroons = new Macaroons();
if (!Directory.Exists(directoryPath))
return macaroons;
foreach(var file in Directory.GetFiles(directoryPath, "*.macaroon"))
{
try
{
switch (Path.GetFileName(file))
{
case "admin.macaroon":
macaroons.AdminMacaroon = new Macaroon(await File.ReadAllBytesAsync(file));
break;
case "readonly.macaroon":
macaroons.ReadonlyMacaroon = new Macaroon(await File.ReadAllBytesAsync(file));
break;
case "invoice.macaroon":
macaroons.InvoiceMacaroon = new Macaroon(await File.ReadAllBytesAsync(file));
break;
default:
break;
}
}
catch { }
}
return macaroons;
}
public Macaroon ReadonlyMacaroon { get; set; }
public Macaroon InvoiceMacaroon { get; set; }
public Macaroon AdminMacaroon { get; set; }
}
}

View file

@ -449,6 +449,16 @@ namespace BTCPayServer.Controllers
Index = i++, Index = i++,
}); });
} }
foreach (var chargeService in _Options.ExternalServicesByCryptoCode.GetServices<ExternalCharge>(cryptoCode))
{
result.LNDServices.Add(new ServicesViewModel.LNDServiceViewModel()
{
Crypto = cryptoCode,
Type = "Lightning charge server",
Action = nameof(LightningChargeServices),
Index = i++,
});
}
} }
foreach(var externalService in _Options.ExternalServices) foreach(var externalService in _Options.ExternalServices)
{ {
@ -469,6 +479,45 @@ namespace BTCPayServer.Controllers
return View(result); return View(result);
} }
[Route("server/services/lightning-charge/{cryptoCode}/{index}")]
public async Task<IActionResult> LightningChargeServices(string cryptoCode, int index, bool showQR = false)
{
if (!_dashBoard.IsFullySynched(cryptoCode, out var unusud))
{
StatusMessage = $"Error: {cryptoCode} is not fully synched";
return RedirectToAction(nameof(Services));
}
var lightningCharge = _Options.ExternalServicesByCryptoCode.GetServices<ExternalCharge>(cryptoCode).Select(c => c.ConnectionString).FirstOrDefault();
if (lightningCharge == null)
{
return NotFound();
}
ChargeServiceViewModel vm = new ChargeServiceViewModel();
vm.Uri = lightningCharge.ToUri(false).AbsoluteUri;
vm.APIToken = lightningCharge.Password;
try
{
if (string.IsNullOrEmpty(vm.APIToken) && lightningCharge.CookieFilePath != null)
{
if (lightningCharge.CookieFilePath != "fake")
vm.APIToken = await System.IO.File.ReadAllTextAsync(lightningCharge.CookieFilePath);
else
vm.APIToken = "fake";
}
var builder = new UriBuilder(lightningCharge.ToUri(false));
builder.UserName = "api-token";
builder.Password = vm.APIToken;
vm.AuthenticatedUri = builder.ToString();
}
catch (Exception ex)
{
StatusMessage = $"Error: {ex.Message}";
return RedirectToAction(nameof(Services));
}
return View(vm);
}
[Route("server/services/spark/{cryptoCode}/{index}")] [Route("server/services/spark/{cryptoCode}/{index}")]
public async Task<IActionResult> SparkServices(string cryptoCode, int index, bool showQR = false) public async Task<IActionResult> SparkServices(string cryptoCode, int index, bool showQR = false)
{ {
@ -477,7 +526,7 @@ namespace BTCPayServer.Controllers
StatusMessage = $"Error: {cryptoCode} is not fully synched"; StatusMessage = $"Error: {cryptoCode} is not fully synched";
return RedirectToAction(nameof(Services)); return RedirectToAction(nameof(Services));
} }
var spark = _Options.ExternalServicesByCryptoCode.GetServices<ExternalSpark>(cryptoCode).Skip(index).Select(c => c.ConnectionString).FirstOrDefault(); var spark = _Options.ExternalServicesByCryptoCode.GetServices<ExternalSpark>(cryptoCode).Select(c => c.ConnectionString).FirstOrDefault();
if(spark == null) if(spark == null)
{ {
return NotFound(); return NotFound();
@ -504,7 +553,7 @@ namespace BTCPayServer.Controllers
} }
[Route("server/services/lnd/{cryptoCode}/{index}")] [Route("server/services/lnd/{cryptoCode}/{index}")]
public IActionResult LndServices(string cryptoCode, int index, uint? nonce) public async Task<IActionResult> LndServices(string cryptoCode, int index, uint? nonce)
{ {
if (!_dashBoard.IsFullySynched(cryptoCode, out var unusud)) if (!_dashBoard.IsFullySynched(cryptoCode, out var unusud))
{ {
@ -520,6 +569,7 @@ namespace BTCPayServer.Controllers
model.Host = $"{external.BaseUri.DnsSafeHost}:{external.BaseUri.Port}"; model.Host = $"{external.BaseUri.DnsSafeHost}:{external.BaseUri.Port}";
model.SSL = external.BaseUri.Scheme == "https"; model.SSL = external.BaseUri.Scheme == "https";
model.ConnectionType = "GRPC"; model.ConnectionType = "GRPC";
model.GRPCSSLCipherSuites = "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256";
} }
else if(external.ConnectionType == LightningConnectionType.LndREST) else if(external.ConnectionType == LightningConnectionType.LndREST)
{ {
@ -535,10 +585,10 @@ namespace BTCPayServer.Controllers
{ {
model.Macaroon = Encoders.Hex.EncodeData(external.Macaroon); model.Macaroon = Encoders.Hex.EncodeData(external.Macaroon);
} }
if (external.RestrictedMacaroon != null) var macaroons = external.MacaroonDirectoryPath == null ? null : await Macaroons.GetFromDirectoryAsync(external.MacaroonDirectoryPath);
{ model.AdminMacaroon = macaroons?.AdminMacaroon?.Hex;
model.RestrictedMacaroon = Encoders.Hex.EncodeData(external.RestrictedMacaroon); model.InvoiceMacaroon = macaroons?.InvoiceMacaroon?.Hex;
} model.ReadonlyMacaroon = macaroons?.ReadonlyMacaroon?.Hex;
if (nonce != null) if (nonce != null)
{ {
@ -571,38 +621,40 @@ namespace BTCPayServer.Controllers
[Route("server/services/lnd/{cryptoCode}/{index}")] [Route("server/services/lnd/{cryptoCode}/{index}")]
[HttpPost] [HttpPost]
public IActionResult LndServicesPost(string cryptoCode, int index) public async Task<IActionResult> LndServicesPost(string cryptoCode, int index)
{ {
var external = GetExternalLndConnectionString(cryptoCode, index); var external = GetExternalLndConnectionString(cryptoCode, index);
if (external == null) if (external == null)
return NotFound(); return NotFound();
LightningConfigurations confs = new LightningConfigurations(); LightningConfigurations confs = new LightningConfigurations();
var macaroons = external.MacaroonDirectoryPath == null ? null : await Macaroons.GetFromDirectoryAsync(external.MacaroonDirectoryPath);
if (external.ConnectionType == LightningConnectionType.LndGRPC) if (external.ConnectionType == LightningConnectionType.LndGRPC)
{ {
LightningConfiguration conf = new LightningConfiguration(); LightningConfiguration grpcConf = new LightningConfiguration();
conf.Type = "grpc"; grpcConf.Type = "grpc";
conf.ChainType = _Options.NetworkType.ToString(); grpcConf.Host = external.BaseUri.DnsSafeHost;
conf.CryptoCode = cryptoCode; grpcConf.Port = external.BaseUri.Port;
conf.Host = external.BaseUri.DnsSafeHost; grpcConf.SSL = external.BaseUri.Scheme == "https";
conf.Port = external.BaseUri.Port; confs.Configurations.Add(grpcConf);
conf.SSL = external.BaseUri.Scheme == "https";
conf.Macaroon = external.Macaroon == null ? null : Encoders.Hex.EncodeData(external.Macaroon);
conf.RestrictedMacaroon = external.RestrictedMacaroon == null ? null : Encoders.Hex.EncodeData(external.RestrictedMacaroon);
conf.CertificateThumbprint = external.CertificateThumbprint == null ? null : Encoders.Hex.EncodeData(external.CertificateThumbprint);
confs.Configurations.Add(conf);
} }
else if (external.ConnectionType == LightningConnectionType.LndREST) else if (external.ConnectionType == LightningConnectionType.LndREST)
{ {
var restconf = new LNDRestConfiguration(); var restconf = new LNDRestConfiguration();
restconf.Type = "lnd-rest"; restconf.Type = "lnd-rest";
restconf.ChainType = _Options.NetworkType.ToString();
restconf.CryptoCode = cryptoCode;
restconf.Uri = external.BaseUri.AbsoluteUri; restconf.Uri = external.BaseUri.AbsoluteUri;
restconf.Macaroon = external.Macaroon == null ? null : Encoders.Hex.EncodeData(external.Macaroon);
restconf.RestrictedMacaroon = external.RestrictedMacaroon == null ? null : Encoders.Hex.EncodeData(external.RestrictedMacaroon);
restconf.CertificateThumbprint = external.CertificateThumbprint == null ? null : Encoders.Hex.EncodeData(external.CertificateThumbprint);
confs.Configurations.Add(restconf); confs.Configurations.Add(restconf);
} }
else
throw new NotSupportedException(external.ConnectionType.ToString());
var commonConf = (LNDConfiguration)confs.Configurations[confs.Configurations.Count - 1];
commonConf.ChainType = _Options.NetworkType.ToString();
commonConf.CryptoCode = cryptoCode;
commonConf.Macaroon = external.Macaroon == null ? null : Encoders.Hex.EncodeData(external.Macaroon);
commonConf.CertificateThumbprint = external.CertificateThumbprint == null ? null : Encoders.Hex.EncodeData(external.CertificateThumbprint);
commonConf.AdminMacaroon = macaroons?.AdminMacaroon?.Hex;
commonConf.ReadonlyMacaroon = macaroons?.ReadonlyMacaroon?.Hex;
commonConf.InvoiceMacaroon = macaroons?.InvoiceMacaroon?.Hex;
var nonce = RandomUtils.GetUInt32(); var nonce = RandomUtils.GetUInt32();
var configKey = GetConfigKey("lnd", cryptoCode, index, nonce); var configKey = GetConfigKey("lnd", cryptoCode, index, nonce);
_LnConfigProvider.KeepConfig(configKey, confs); _LnConfigProvider.KeepConfig(configKey, confs);
@ -628,18 +680,6 @@ namespace BTCPayServer.Controllers
return null; return null;
} }
} }
if (connectionString.RestrictedMacaroonFilePath != null)
{
try
{
connectionString.RestrictedMacaroon = System.IO.File.ReadAllBytes(connectionString.RestrictedMacaroonFilePath);
}
catch
{
Logs.Configuration.LogWarning($"{cryptoCode}: The restrictedmacaroon file path of the external LND grpc config was not found ({connectionString.RestrictedMacaroonFilePath})");
}
connectionString.RestrictedMacaroonFilePath = null;
}
return connectionString; return connectionString;
} }

View file

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace BTCPayServer.Models.ServerViewModels
{
public class ChargeServiceViewModel
{
public string Uri { get; set; }
public string APIToken { get; set; }
public string AuthenticatedUri { get; set; }
}
}

View file

@ -11,8 +11,12 @@ namespace BTCPayServer.Models.ServerViewModels
public string Host { get; set; } public string Host { get; set; }
public bool SSL { get; set; } public bool SSL { get; set; }
public string Macaroon { get; set; } public string Macaroon { get; set; }
public string RestrictedMacaroon { get; set; } public string AdminMacaroon { get; set; }
public string ReadonlyMacaroon { get; set; }
public string InvoiceMacaroon { get; set; }
public string CertificateThumbprint { get; set; } public string CertificateThumbprint { get; set; }
[Display(Name = "GRPC SSL Cipher suite (GRPC_SSL_CIPHER_SUITES)")]
public string GRPCSSLCipherSuites { get; set; }
public string QRCode { get; set; } public string QRCode { get; set; }
public string QRCodeLink { get; set; } public string QRCodeLink { get; set; }
[Display(Name = "REST Uri")] [Display(Name = "REST Uri")]

View file

@ -156,7 +156,8 @@ namespace BTCPayServer.Payments.Lightning
if (notification.Id == listenedInvoice.PaymentMethodDetails.InvoiceId && if (notification.Id == listenedInvoice.PaymentMethodDetails.InvoiceId &&
notification.BOLT11 == listenedInvoice.PaymentMethodDetails.BOLT11) notification.BOLT11 == listenedInvoice.PaymentMethodDetails.BOLT11)
{ {
if (notification.Status == LightningInvoiceStatus.Paid && notification.PaidAt.HasValue) if (notification.Status == LightningInvoiceStatus.Paid &&
notification.PaidAt.HasValue && notification.Amount != null)
{ {
await AddPayment(network, notification, listenedInvoice); await AddPayment(network, notification, listenedInvoice);
if (DoneListening(listenedInvoice)) if (DoneListening(listenedInvoice))

View file

@ -30,6 +30,7 @@
"BTCPAY_BTCEXTERNALLNDGRPC": "type=lnd-grpc;server=https://lnd:lnd@127.0.0.1:53280/;allowinsecure=true", "BTCPAY_BTCEXTERNALLNDGRPC": "type=lnd-grpc;server=https://lnd:lnd@127.0.0.1:53280/;allowinsecure=true",
"BTCPAY_BTCEXTERNALLNDREST": "type=lnd-rest;server=https://lnd:lnd@127.0.0.1:53280/lnd-rest/btc/;allowinsecure=true", "BTCPAY_BTCEXTERNALLNDREST": "type=lnd-rest;server=https://lnd:lnd@127.0.0.1:53280/lnd-rest/btc/;allowinsecure=true",
"BTCPAY_BTCEXTERNALSPARK": "server=https://127.0.0.1:53280/spark/btc/;cookiefile=fake", "BTCPAY_BTCEXTERNALSPARK": "server=https://127.0.0.1:53280/spark/btc/;cookiefile=fake",
"BTCPAY_BTCEXTERNALCHARGE": "server=https://127.0.0.1:53280/spark/btc/;cookiefilepath=fake",
"BTCPAY_BTCEXPLORERURL": "http://127.0.0.1:32838/", "BTCPAY_BTCEXPLORERURL": "http://127.0.0.1:32838/",
"ASPNETCORE_ENVIRONMENT": "Development", "ASPNETCORE_ENVIRONMENT": "Development",
"BTCPAY_CHAINS": "btc,ltc", "BTCPAY_CHAINS": "btc,ltc",

View file

@ -4,6 +4,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using NBitcoin; using NBitcoin;
using NBitcoin.DataEncoders;
namespace BTCPayServer.Services namespace BTCPayServer.Services
{ {
@ -27,9 +28,9 @@ namespace BTCPayServer.Services
private void CleanExpired() private void CleanExpired()
{ {
foreach(var item in _Map) foreach (var item in _Map)
{ {
if(item.Value.expiration < DateTimeOffset.UtcNow) if (item.Value.expiration < DateTimeOffset.UtcNow)
{ {
_Map.TryRemove(item.Key, out var unused); _Map.TryRemove(item.Key, out var unused);
} }
@ -41,26 +42,26 @@ namespace BTCPayServer.Services
{ {
public List<object> Configurations { get; set; } = new List<object>(); public List<object> Configurations { get; set; } = new List<object>();
} }
public class LightningConfiguration
public class LNDConfiguration
{ {
public string ChainType { get; set; } public string ChainType { get; set; }
public string Type { get; set; } public string Type { get; set; }
public string CryptoCode { get; set; } public string CryptoCode { get; set; }
public string CertificateThumbprint { get; set; }
public string Macaroon { get; set; }
public string AdminMacaroon { get; set; }
public string ReadonlyMacaroon { get; set; }
public string InvoiceMacaroon { get; set; }
}
public class LightningConfiguration : LNDConfiguration
{
public string Host { get; set; } public string Host { get; set; }
public int Port { get; set; } public int Port { get; set; }
public bool SSL { get; set; } public bool SSL { get; set; }
public string CertificateThumbprint { get; set; }
public string Macaroon { get; set; }
public string RestrictedMacaroon { get; set; }
} }
public class LNDRestConfiguration public class LNDRestConfiguration : LNDConfiguration
{ {
public string ChainType { get; set; }
public string Type { get; set; }
public string CryptoCode { get; set; }
public string Uri { get; set; } public string Uri { get; set; }
public string Macaroon { get; set; }
public string CertificateThumbprint { get; set; }
public string RestrictedMacaroon { get; set; }
} }
} }

View file

@ -0,0 +1,60 @@
@model ChargeServiceViewModel
@{
ViewData.SetActivePageAndTitle(ServerNavPages.Services);
}
<h4>Lightning charge service</h4>
<partial name="_StatusMessage" for="@TempData["StatusMessage"]" />
<div class="row">
<div class="col-md-6">
<div asp-validation-summary="All" class="text-danger"></div>
</div>
</div>
<div class="row">
<div class="col-md-8">
<div class="form-group">
<p>
<span>Lightning charge is a simple API for invoicing on lightning network, you can use it with several plugins:</span>
<ul>
<li><a href="https://github.com/ElementsProject/woocommerce-gateway-lightning" target="_blank">WooCommerce Lightning Gateway</a>: A comprehensive e-commerce application that integrates with stock-management and order-tracking systems</li>
<li><a href="https://github.com/ElementsProject/nanopos" target="_blank">Nanopos</a>: A simple point-of-sale system for fixed-price goods</li>
<li><a href="https://github.com/ElementsProject/filebazaar" target="_blank">FileBazaar</a>: A system for selling files such as documents, images, and videos</li>
<li><a href="https://github.com/ElementsProject/wordpress-lightning-publisher" target="_blank">Lightning Publisher for WordPress</a>: A patronage model for unlocking WordPress blog entries</li>
<li><a href="https://github.com/ElementsProject/paypercall" target="_blank">Paypercall</a>: A programmers toolkit for Lightning that enables micropayments for individual API calls</li>
<li><a href="https://github.com/ElementsProject/ifpaytt" target="_blank">Ifpaytt</a>: An extension of paypercall that allows web developers using IFTTT to request payments for service usage</li>
<li><a href="https://github.com/ElementsProject/lightning-jukebox" target="_blank">Lightning Jukebox</a>: A fun demo that reimagines a classic technology for the Lightning Network</li>
<li><a href="https://github.com/ElementsProject/nanotip" target="_blank">Nanotip</a>: The simple tip jar, rebuilt to issue Lightning Network invoices</li>
</ul>
</p>
</div>
</div>
</div>
<div class="row">
<div class="col-md-8">
<h4>Credentials</h4>
@if (Model.Uri != null)
{
<div class="form-group">
<label asp-for="Uri"></label>
<input asp-for="Uri" readonly class="form-control" />
</div>
}
@if (Model.APIToken != null)
{
<div class="form-group">
<label asp-for="APIToken"></label>
<input asp-for="APIToken" readonly class="form-control" />
</div>
}
@if (Model.AuthenticatedUri != null)
{
<div class="form-group">
<label asp-for="AuthenticatedUri"></label>
<input asp-for="AuthenticatedUri" readonly class="form-control" />
</div>
}
</div>
</div>

View file

@ -86,12 +86,33 @@
<input asp-for="Macaroon" readonly class="form-control" /> <input asp-for="Macaroon" readonly class="form-control" />
</div> </div>
} }
@if (Model.RestrictedMacaroon != null) @if (Model.AdminMacaroon != null)
{ {
@*<div class="form-group"> <div class="form-group">
<label asp-for="RestrictedMacaroon"></label> <label asp-for="AdminMacaroon"></label>
<input asp-for="RestrictedMacaroon" readonly class="form-control" /> <input asp-for="AdminMacaroon" readonly class="form-control" />
</div>*@ </div>
}
@if (Model.InvoiceMacaroon != null)
{
<div class="form-group">
<label asp-for="InvoiceMacaroon"></label>
<input asp-for="InvoiceMacaroon" readonly class="form-control" />
</div>
}
@if (Model.ReadonlyMacaroon != null)
{
<div class="form-group">
<label asp-for="ReadonlyMacaroon"></label>
<input asp-for="ReadonlyMacaroon" readonly class="form-control" />
</div>
}
@if (Model.GRPCSSLCipherSuites != null)
{
<div class="form-group">
<label asp-for="GRPCSSLCipherSuites"></label>
<input asp-for="GRPCSSLCipherSuites" readonly class="form-control" />
</div>
} }
@if (Model.CertificateThumbprint != null) @if (Model.CertificateThumbprint != null)
{ {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 93 KiB

View file

@ -0,0 +1,54 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="1000px" height="1000px" viewBox="0 0 1000 1000" enable-background="new 0 0 1000 1000" xml:space="preserve">
<g id="Groestlcoin_LN">
<g>
<path fill="#FFFFFF" d="M286.425,653.96"/>
<g>
<polygon fill="#FFFFFF" points="603.786,724.791 601.652,728.634 601.652,728.634 "/>
<path fill="#FFFFFF" d="M502.935,79.215c-46.6,0-91.46,7.565-133.443,21.495L243.38,13.165l-14.07,17.69l96.15,87.27
C179.64,185.465,78.2,333.075,78.2,503.95c0,234.2,190.535,424.733,424.733,424.733c50.125,0,98.24-8.755,142.927-24.77
l-32.592-22.73c-35.02,10.262-72.038,15.79-110.335,15.79c-216.714,0-393.023-176.31-393.023-393.023
c0-162.935,99.665-303.02,241.229-362.515c3.025-1.27,3.025-1.27,0,0l244.506,221.93L460.67,634.56l148.255,132.08l-5.14-41.903
l-2.135,3.845l2.135-3.845l-13.28-108.262l134.37-269.043l-322.04-223.565c31.97-8.425,65.521-12.935,100.101-12.935
c216.716,0,393.024,176.31,393.024,393.025c0,160.175-96.325,298.26-234.085,359.415l25.775,23.005
c141.925-68.83,240.02-214.38,240.02-382.42C927.67,269.75,737.135,79.215,502.935,79.215z"/>
</g>
<path fill="#FFFFFF" d="M687.65,886.375l-25.775-23.005c-3.925,1.74-3.925,1.74,0,0L409.78,638.36l135.08-271.985L396.12,232.45
l-0.555,1.19L418.38,391.2l0,0L288.575,654.75l324.688,226.435l32.592,22.73l126.01,87.88l14.02-17.74L687.65,886.375z"/>
</g>
<g>
<path fill="#FFFFFF" d="M286.425,653.96"/>
<g>
<polygon fill="#FFFFFF" points="603.786,724.791 601.652,728.634 601.652,728.634 "/>
<path fill="#FFFFFF" d="M502.935,79.215c-46.6,0-91.46,7.565-133.443,21.495L243.38,13.165l-14.07,17.69l96.15,87.27
C179.64,185.465,78.2,333.075,78.2,503.95c0,234.2,190.535,424.733,424.733,424.733c50.125,0,98.24-8.755,142.927-24.77
l-32.592-22.73c-35.02,10.262-72.038,15.79-110.335,15.79c-216.714,0-393.023-176.31-393.023-393.023
c0-162.935,99.665-303.02,241.229-362.515c3.025-1.27,3.025-1.27,0,0l244.506,221.93L460.67,634.56l148.255,132.08l-5.14-41.903
l-2.135,3.845l2.135-3.845l-13.28-108.262l134.37-269.043l-322.04-223.565c31.97-8.425,65.521-12.935,100.101-12.935
c216.716,0,393.024,176.31,393.024,393.025c0,160.175-96.325,298.26-234.085,359.415l25.775,23.005
c141.925-68.83,240.02-214.38,240.02-382.42C927.67,269.75,737.135,79.215,502.935,79.215z"/>
</g>
<path fill="#FFFFFF" d="M687.65,886.375l-25.775-23.005c-3.925,1.74-3.925,1.74,0,0L409.78,638.36l135.08-271.985L396.12,232.45
l-0.555,1.19L418.38,391.2l0,0L288.575,654.75l324.688,226.435l32.592,22.73l126.01,87.88l14.02-17.74L687.65,886.375z"/>
</g>
<g>
<path fill="#FFFFFF" d="M286.425,653.96"/>
<g>
<circle fill="#FFFFFF" cx="510" cy="500" r="408.335"/>
<polygon fill="#FFFFFF" points="603.786,724.791 601.652,728.634 601.652,728.634 "/>
<path fill="#009CCD" d="M502.935,79.215c-46.6,0-91.46,7.565-133.443,21.495L243.38,13.165l-14.07,17.69l96.15,87.27
C179.64,185.465,78.2,333.075,78.2,503.95c0,234.2,190.535,424.733,424.733,424.733c50.125,0,98.24-8.755,142.927-24.77
l-32.592-22.73c-35.02,10.262-72.038,15.79-110.335,15.79c-216.714,0-393.023-176.31-393.023-393.023
c0-162.935,99.665-303.02,241.229-362.515c3.025-1.27,3.025-1.27,0,0l244.506,221.93L460.67,634.56l148.255,132.08l-5.14-41.903
l-2.135,3.845l2.135-3.845l-13.28-108.262l134.37-269.043l-322.04-223.565c31.97-8.425,65.521-12.935,100.101-12.935
c216.716,0,393.024,176.31,393.024,393.025c0,160.175-96.325,298.26-234.085,359.415l25.775,23.005
c141.925-68.83,240.02-214.38,240.02-382.42C927.67,269.75,737.135,79.215,502.935,79.215z"/>
</g>
<path fill="#006694" d="M687.65,886.375l-25.775-23.005c-3.925,1.74-3.925,1.74,0,0L409.78,638.36l135.08-271.985L396.12,232.45
l-0.555,1.19L418.38,391.2l0,0L288.575,654.75l324.688,226.435l32.592,22.73l126.01,87.88l14.02-17.74L687.65,886.375z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4 KiB

View file

@ -22,12 +22,12 @@
"Amount": "Cantidad", "Amount": "Cantidad",
"Address": "Dirección", "Address": "Dirección",
"Copied": "Copiado", "Copied": "Copiado",
"ConversionTab_BodyTop": "Puedes pagar {{btcDue}} {{cryptoCode}} usando Altcoins que este comercio no soporta directamente.", "ConversionTab_BodyTop": "Puedes pagar {{btcDue}} {{cryptoCode}} usando altcoins que este comercio no soporta directamente.",
"ConversionTab_BodyDesc": "Este servicio es provisto por terceros. Ten en cuenta que no tenemos control sobre cómo estos terceros envían los fondos. La factura solo se marcará como pagada una vez se reciban los fondos en la cadena de bloques de {{cryptoCode}} .", "ConversionTab_BodyDesc": "Este servicio es provisto por terceros. Ten en cuenta que no tenemos control sobre cómo estos terceros envían los fondos. La factura solo se marcará como pagada una vez se reciban los fondos en la cadena de bloques de {{cryptoCode}} .",
"ConversionTab_CalculateAmount_Error": "Reintentar", "ConversionTab_CalculateAmount_Error": "Reintentar",
"ConversionTab_LoadCurrencies_Error": "Reintentar", "ConversionTab_LoadCurrencies_Error": "Reintentar",
"ConversionTab_Lightning": "No hay proveedores de conversión disponibles para los pagos de Lightning Network.", "ConversionTab_Lightning": "No hay proveedores de conversión disponibles para los pagos de Lightning Network.",
"ConversionTab_CurrencyList_Select_Option": "Por favor selecciona el tipo de moneda que de desea cambiar", "ConversionTab_CurrencyList_Select_Option": "Selecciona la moneda a convertir",
"Invoice expiring soon...": "La factura expira pronto...", "Invoice expiring soon...": "La factura expira pronto...",
"Invoice expired": "La factura expiró", "Invoice expired": "La factura expiró",
"What happened?": "¿Qué sucedió?", "What happened?": "¿Qué sucedió?",