mirror of
https://github.com/btcpayserver/btcpayserver.git
synced 2024-11-19 18:11:36 +01:00
193 lines
8.2 KiB
C#
193 lines
8.2 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using BTCPayServer.Controllers;
|
|
|
|
namespace BTCPayServer.Configuration
|
|
{
|
|
public class ExternalConnectionString
|
|
{
|
|
public Uri Server { get; set; }
|
|
public byte[] Macaroon { get; set; }
|
|
public Macaroons Macaroons { get; set; }
|
|
public string MacaroonFilePath { get; set; }
|
|
public string CertificateThumbprint { get; set; }
|
|
public string MacaroonDirectoryPath { get; set; }
|
|
public string APIToken { get; set; }
|
|
public string CookieFilePath { get; set; }
|
|
public string AccessKey { get; set; }
|
|
|
|
/// <summary>
|
|
/// Return a connectionString which does not depends on external resources or information like relative path or file path
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public async Task<ExternalConnectionString> Expand(Uri absoluteUrlBase, ExternalServiceTypes serviceType)
|
|
{
|
|
var connectionString = this.Clone();
|
|
// Transform relative URI into absolute URI
|
|
var serviceUri = connectionString.Server.IsAbsoluteUri ? connectionString.Server : ToRelative(absoluteUrlBase, connectionString.Server.ToString());
|
|
if (!serviceUri.Scheme.Equals("https", StringComparison.OrdinalIgnoreCase) &&
|
|
!serviceUri.DnsSafeHost.EndsWith(".onion", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
throw new System.Security.SecurityException($"Insecure transport protocol to access this service, please use HTTPS or TOR");
|
|
}
|
|
connectionString.Server = serviceUri;
|
|
|
|
if (serviceType == ExternalServiceTypes.LNDGRPC || serviceType == ExternalServiceTypes.LNDRest)
|
|
{
|
|
// Read the MacaroonDirectory
|
|
if (connectionString.MacaroonDirectoryPath != null)
|
|
{
|
|
try
|
|
{
|
|
connectionString.Macaroons = await Macaroons.GetFromDirectoryAsync(connectionString.MacaroonDirectoryPath);
|
|
connectionString.MacaroonDirectoryPath = null;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
throw new System.IO.DirectoryNotFoundException("Macaroon directory path not found", ex);
|
|
}
|
|
}
|
|
|
|
// Read the MacaroonFilePath
|
|
if (connectionString.MacaroonFilePath != null)
|
|
{
|
|
try
|
|
{
|
|
connectionString.Macaroon = await System.IO.File.ReadAllBytesAsync(connectionString.MacaroonFilePath);
|
|
connectionString.MacaroonFilePath = null;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
throw new System.IO.FileNotFoundException("Macaroon not found", ex);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (serviceType == ExternalServiceTypes.Charge || serviceType == ExternalServiceTypes.RTL || serviceType == ExternalServiceTypes.Spark)
|
|
{
|
|
// Read access key from cookie file
|
|
if (connectionString.CookieFilePath != null)
|
|
{
|
|
string cookieFileContent = null;
|
|
bool isFake = false;
|
|
try
|
|
{
|
|
cookieFileContent = await System.IO.File.ReadAllTextAsync(connectionString.CookieFilePath);
|
|
isFake = connectionString.CookieFilePath == "fake";
|
|
connectionString.CookieFilePath = null;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
throw new System.IO.FileNotFoundException("Cookie file path not found", ex);
|
|
}
|
|
if (serviceType == ExternalServiceTypes.RTL)
|
|
{
|
|
connectionString.AccessKey = cookieFileContent;
|
|
}
|
|
else if (serviceType == ExternalServiceTypes.Spark)
|
|
{
|
|
var cookie = (isFake ? "fake:fake:fake" // Hacks for testing
|
|
: cookieFileContent).Split(':');
|
|
if (cookie.Length >= 3)
|
|
{
|
|
connectionString.AccessKey = cookie[2];
|
|
}
|
|
else
|
|
{
|
|
throw new FormatException("Invalid cookiefile format");
|
|
}
|
|
}
|
|
else if (serviceType == ExternalServiceTypes.Charge)
|
|
{
|
|
connectionString.APIToken = isFake ? "fake" : cookieFileContent;
|
|
}
|
|
}
|
|
}
|
|
return connectionString;
|
|
}
|
|
|
|
private Uri ToRelative(Uri absoluteUrlBase, string path)
|
|
{
|
|
if (path.StartsWith('/'))
|
|
path = path.Substring(1);
|
|
return new Uri($"{absoluteUrlBase.AbsoluteUri.WithTrailingSlash()}{path}", UriKind.Absolute);
|
|
}
|
|
|
|
public ExternalConnectionString Clone()
|
|
{
|
|
return new ExternalConnectionString()
|
|
{
|
|
MacaroonFilePath = MacaroonFilePath,
|
|
CertificateThumbprint = CertificateThumbprint,
|
|
Macaroon = Macaroon,
|
|
MacaroonDirectoryPath = MacaroonDirectoryPath,
|
|
Server = Server,
|
|
APIToken = APIToken,
|
|
CookieFilePath = CookieFilePath,
|
|
AccessKey = AccessKey,
|
|
Macaroons = Macaroons?.Clone()
|
|
};
|
|
}
|
|
public static bool TryParse(string str, out ExternalConnectionString result, out string error)
|
|
{
|
|
if (str == null)
|
|
throw new ArgumentNullException(nameof(str));
|
|
error = null;
|
|
result = null;
|
|
var resultTemp = new ExternalConnectionString();
|
|
foreach(var kv in str.Split(';')
|
|
.Select(part => part.Split('='))
|
|
.Where(kv => kv.Length == 2))
|
|
{
|
|
switch (kv[0].ToLowerInvariant())
|
|
{
|
|
case "server":
|
|
if (resultTemp.Server != null)
|
|
{
|
|
error = "Duplicated server attribute";
|
|
return false;
|
|
}
|
|
if (!Uri.IsWellFormedUriString(kv[1], UriKind.RelativeOrAbsolute))
|
|
{
|
|
error = "Invalid URI";
|
|
return false;
|
|
}
|
|
resultTemp.Server = new Uri(kv[1], UriKind.RelativeOrAbsolute);
|
|
if (!resultTemp.Server.IsAbsoluteUri && (kv[1].Length == 0 || kv[1][0] != '/'))
|
|
resultTemp.Server = new Uri($"/{kv[1]}", UriKind.RelativeOrAbsolute);
|
|
break;
|
|
case "cookiefile":
|
|
case "cookiefilepath":
|
|
if (resultTemp.CookieFilePath != null)
|
|
{
|
|
error = "Duplicated cookiefile attribute";
|
|
return false;
|
|
}
|
|
|
|
resultTemp.CookieFilePath = kv[1];
|
|
break;
|
|
case "macaroondirectorypath":
|
|
resultTemp.MacaroonDirectoryPath = kv[1];
|
|
break;
|
|
case "certthumbprint":
|
|
resultTemp.CertificateThumbprint = kv[1];
|
|
break;
|
|
case "macaroonfilepath":
|
|
resultTemp.MacaroonFilePath = kv[1];
|
|
break;
|
|
case "api-token":
|
|
resultTemp.APIToken = kv[1];
|
|
break;
|
|
case "access-key":
|
|
resultTemp.AccessKey = kv[1];
|
|
break;
|
|
}
|
|
}
|
|
result = resultTemp;
|
|
return true;
|
|
}
|
|
}
|
|
}
|