2017-09-13 08:47:34 +02:00
|
|
|
|
using System;
|
|
|
|
|
using System.Diagnostics;
|
2020-06-28 10:55:27 +02:00
|
|
|
|
using System.IO;
|
2019-06-25 20:41:32 +02:00
|
|
|
|
using System.Linq;
|
2020-06-28 10:55:27 +02:00
|
|
|
|
using System.Net.Http;
|
2017-09-13 08:47:34 +02:00
|
|
|
|
using System.Threading.Tasks;
|
2020-06-28 10:55:27 +02:00
|
|
|
|
using BTCPayServer.Data;
|
|
|
|
|
using BTCPayServer.HostedServices;
|
2017-09-13 08:47:34 +02:00
|
|
|
|
using BTCPayServer.Models;
|
2020-06-28 10:55:27 +02:00
|
|
|
|
using BTCPayServer.Security;
|
2019-04-11 23:30:23 +02:00
|
|
|
|
using BTCPayServer.Services;
|
2019-06-25 20:41:32 +02:00
|
|
|
|
using BTCPayServer.Services.Apps;
|
2020-06-28 10:55:27 +02:00
|
|
|
|
using Microsoft.AspNetCore.Authorization;
|
|
|
|
|
using Microsoft.AspNetCore.Hosting;
|
2019-11-06 06:31:45 +01:00
|
|
|
|
using Microsoft.AspNetCore.Identity;
|
2020-06-28 10:55:27 +02:00
|
|
|
|
using Microsoft.AspNetCore.Mvc;
|
2020-03-18 12:08:09 +01:00
|
|
|
|
using Microsoft.Extensions.FileProviders;
|
2020-06-28 10:55:27 +02:00
|
|
|
|
using NBitcoin;
|
|
|
|
|
using NBitcoin.Payment;
|
|
|
|
|
using Newtonsoft.Json;
|
|
|
|
|
using Newtonsoft.Json.Linq;
|
2017-09-13 08:47:34 +02:00
|
|
|
|
|
|
|
|
|
namespace BTCPayServer.Controllers
|
|
|
|
|
{
|
|
|
|
|
public class HomeController : Controller
|
|
|
|
|
{
|
2019-04-11 23:30:23 +02:00
|
|
|
|
private readonly CssThemeManager _cachedServerSettings;
|
2020-03-18 12:08:09 +01:00
|
|
|
|
private readonly IFileProvider _fileProvider;
|
2019-04-11 23:30:23 +02:00
|
|
|
|
|
2018-12-03 15:57:43 +01:00
|
|
|
|
public IHttpClientFactory HttpClientFactory { get; }
|
2020-06-28 10:55:27 +02:00
|
|
|
|
SignInManager<ApplicationUser> SignInManager { get; }
|
2018-12-03 15:57:43 +01:00
|
|
|
|
|
2020-06-28 10:55:27 +02:00
|
|
|
|
public HomeController(IHttpClientFactory httpClientFactory,
|
2019-11-06 06:31:45 +01:00
|
|
|
|
CssThemeManager cachedServerSettings,
|
2020-03-18 12:08:09 +01:00
|
|
|
|
IWebHostEnvironment webHostEnvironment,
|
2019-11-06 06:31:45 +01:00
|
|
|
|
SignInManager<ApplicationUser> signInManager)
|
2018-12-03 15:57:43 +01:00
|
|
|
|
{
|
|
|
|
|
HttpClientFactory = httpClientFactory;
|
2019-04-11 23:30:23 +02:00
|
|
|
|
_cachedServerSettings = cachedServerSettings;
|
2020-03-18 12:08:09 +01:00
|
|
|
|
_fileProvider = webHostEnvironment.WebRootFileProvider;
|
2019-11-06 06:31:45 +01:00
|
|
|
|
SignInManager = signInManager;
|
2018-12-03 15:57:43 +01:00
|
|
|
|
}
|
2019-05-24 08:07:09 +02:00
|
|
|
|
|
2019-06-25 20:41:32 +02:00
|
|
|
|
private async Task<ViewResult> GoToApp(string appId, AppType? appType)
|
2017-09-13 08:47:34 +02:00
|
|
|
|
{
|
2019-06-25 20:41:32 +02:00
|
|
|
|
if (appType.HasValue && !string.IsNullOrEmpty(appId))
|
2019-04-11 23:30:23 +02:00
|
|
|
|
{
|
2020-06-27 08:39:02 +02:00
|
|
|
|
this.HttpContext.Response.Headers.Remove("Onion-Location");
|
2019-06-25 20:41:32 +02:00
|
|
|
|
switch (appType.Value)
|
2019-04-11 23:30:23 +02:00
|
|
|
|
{
|
2019-06-25 20:41:32 +02:00
|
|
|
|
case AppType.Crowdfund:
|
|
|
|
|
{
|
2020-06-28 10:55:27 +02:00
|
|
|
|
var serviceProvider = HttpContext.RequestServices;
|
|
|
|
|
var controller = (AppsPublicController)serviceProvider.GetService(typeof(AppsPublicController));
|
|
|
|
|
controller.Url = Url;
|
|
|
|
|
controller.ControllerContext = ControllerContext;
|
|
|
|
|
var res = await controller.ViewCrowdfund(appId, null) as ViewResult;
|
|
|
|
|
if (res != null)
|
|
|
|
|
{
|
|
|
|
|
res.ViewName = $"/Views/AppsPublic/ViewCrowdfund.cshtml";
|
|
|
|
|
return res; // return
|
|
|
|
|
}
|
2019-06-25 20:41:32 +02:00
|
|
|
|
|
2020-06-28 10:55:27 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
2019-06-25 20:41:32 +02:00
|
|
|
|
|
|
|
|
|
case AppType.PointOfSale:
|
|
|
|
|
{
|
2020-06-28 10:55:27 +02:00
|
|
|
|
var serviceProvider = HttpContext.RequestServices;
|
|
|
|
|
var controller = (AppsPublicController)serviceProvider.GetService(typeof(AppsPublicController));
|
|
|
|
|
controller.Url = Url;
|
|
|
|
|
controller.ControllerContext = ControllerContext;
|
|
|
|
|
var res = await controller.ViewPointOfSale(appId) as ViewResult;
|
|
|
|
|
if (res != null)
|
|
|
|
|
{
|
|
|
|
|
res.ViewName = $"/Views/AppsPublic/{res.ViewName}.cshtml";
|
|
|
|
|
return res; // return
|
|
|
|
|
}
|
2019-06-25 20:41:32 +02:00
|
|
|
|
|
2020-06-28 10:55:27 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
2019-04-11 23:30:23 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2019-06-25 20:41:32 +02:00
|
|
|
|
return null;
|
|
|
|
|
}
|
2019-05-24 08:07:09 +02:00
|
|
|
|
|
2019-06-25 20:41:32 +02:00
|
|
|
|
public async Task<IActionResult> Index()
|
|
|
|
|
{
|
2019-11-06 06:31:45 +01:00
|
|
|
|
if (_cachedServerSettings.FirstRun)
|
|
|
|
|
{
|
|
|
|
|
return RedirectToAction(nameof(AccountController.Register), "Account");
|
|
|
|
|
}
|
2019-06-25 20:41:32 +02:00
|
|
|
|
var matchedDomainMapping = _cachedServerSettings.DomainToAppMapping.FirstOrDefault(item =>
|
|
|
|
|
item.Domain.Equals(Request.Host.Host, StringComparison.InvariantCultureIgnoreCase));
|
|
|
|
|
if (matchedDomainMapping != null)
|
|
|
|
|
{
|
2020-06-28 10:55:27 +02:00
|
|
|
|
return await GoToApp(matchedDomainMapping.AppId, matchedDomainMapping.AppType) ?? GoToHome();
|
2019-05-24 08:07:09 +02:00
|
|
|
|
}
|
2019-04-11 23:30:23 +02:00
|
|
|
|
|
2020-06-28 10:55:27 +02:00
|
|
|
|
return await GoToApp(_cachedServerSettings.RootAppId, _cachedServerSettings.RootAppType) ?? GoToHome();
|
2019-11-06 06:31:45 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private IActionResult GoToHome()
|
|
|
|
|
{
|
|
|
|
|
if (SignInManager.IsSignedIn(User))
|
|
|
|
|
return View("Home");
|
|
|
|
|
else
|
|
|
|
|
return RedirectToAction(nameof(AccountController.Login), "Account");
|
2017-09-13 08:47:34 +02:00
|
|
|
|
}
|
2018-05-21 13:44:03 +02:00
|
|
|
|
|
2018-12-03 15:57:43 +01:00
|
|
|
|
[Route("translate")]
|
|
|
|
|
public IActionResult BitpayTranslator()
|
|
|
|
|
{
|
|
|
|
|
return View(new BitpayTranslatorViewModel());
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-18 12:08:09 +01:00
|
|
|
|
[Route("swagger/v1/swagger.json")]
|
2020-06-28 10:55:27 +02:00
|
|
|
|
[Authorize(AuthenticationSchemes = AuthenticationSchemes.Cookie + "," + AuthenticationSchemes.Greenfield)]
|
2020-03-18 12:08:09 +01:00
|
|
|
|
public async Task<IActionResult> Swagger()
|
|
|
|
|
{
|
2020-04-01 15:48:39 +02:00
|
|
|
|
JObject json = new JObject();
|
|
|
|
|
var directoryContents = _fileProvider.GetDirectoryContents("swagger/v1");
|
|
|
|
|
foreach (IFileInfo fi in directoryContents)
|
|
|
|
|
{
|
|
|
|
|
await using var stream = fi.CreateReadStream();
|
|
|
|
|
using var reader = new StreamReader(fi.CreateReadStream());
|
|
|
|
|
json.Merge(JObject.Parse(await reader.ReadToEndAsync()));
|
|
|
|
|
}
|
2020-03-18 12:08:09 +01:00
|
|
|
|
var servers = new JArray();
|
|
|
|
|
servers.Add(new JObject(new JProperty("url", HttpContext.Request.GetAbsoluteRoot())));
|
|
|
|
|
json["servers"] = servers;
|
|
|
|
|
return Json(json);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Route("docs")]
|
2020-05-23 21:18:51 +02:00
|
|
|
|
[Authorize(AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
2020-03-18 12:08:09 +01:00
|
|
|
|
public IActionResult SwaggerDocs()
|
|
|
|
|
{
|
|
|
|
|
return View();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2018-12-03 15:57:43 +01:00
|
|
|
|
[HttpPost]
|
|
|
|
|
[Route("translate")]
|
|
|
|
|
public async Task<IActionResult> BitpayTranslator(BitpayTranslatorViewModel vm)
|
|
|
|
|
{
|
|
|
|
|
if (!ModelState.IsValid)
|
|
|
|
|
return View(vm);
|
|
|
|
|
vm.BitpayLink = vm.BitpayLink ?? string.Empty;
|
|
|
|
|
vm.BitpayLink = vm.BitpayLink.Trim();
|
|
|
|
|
if (!vm.BitpayLink.StartsWith("bitcoin:", StringComparison.OrdinalIgnoreCase))
|
|
|
|
|
{
|
|
|
|
|
var invoiceId = vm.BitpayLink.Substring(vm.BitpayLink.LastIndexOf("=", StringComparison.OrdinalIgnoreCase) + 1);
|
|
|
|
|
vm.BitpayLink = $"bitcoin:?r=https://bitpay.com/i/{invoiceId}";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
2019-11-13 05:07:41 +01:00
|
|
|
|
BitcoinUrlBuilder urlBuilder = new BitcoinUrlBuilder(vm.BitpayLink, Network.Main);
|
2018-12-10 09:34:27 +01:00
|
|
|
|
#pragma warning disable CS0618 // Type or member is obsolete
|
2018-12-04 03:53:25 +01:00
|
|
|
|
if (!urlBuilder.PaymentRequestUrl.DnsSafeHost.EndsWith("bitpay.com", StringComparison.OrdinalIgnoreCase))
|
2018-12-03 15:57:43 +01:00
|
|
|
|
{
|
|
|
|
|
throw new Exception("This tool only work with bitpay");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var client = HttpClientFactory.CreateClient();
|
|
|
|
|
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, urlBuilder.PaymentRequestUrl);
|
2018-12-10 09:34:27 +01:00
|
|
|
|
#pragma warning restore CS0618 // Type or member is obsolete
|
2018-12-03 15:57:43 +01:00
|
|
|
|
request.Headers.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/payment-request"));
|
|
|
|
|
var result = await client.SendAsync(request);
|
|
|
|
|
// {"network":"main","currency":"BTC","requiredFeeRate":29.834,"outputs":[{"amount":255900,"address":"1PgPo5d4swD6pKfCgoXtoW61zqTfX9H7tj"}],"time":"2018-12-03T14:39:47.162Z","expires":"2018-12-03T14:54:47.162Z","memo":"Payment request for BitPay invoice HHfG8cprRMzZG6MErCqbjv for merchant VULTR Holdings LLC","paymentUrl":"https://bitpay.com/i/HHfG8cprRMzZG6MErCqbjv","paymentId":"HHfG8cprRMzZG6MErCqbjv"}
|
|
|
|
|
var str = await result.Content.ReadAsStringAsync();
|
2018-12-04 03:53:25 +01:00
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var jobj = JObject.Parse(str);
|
|
|
|
|
vm.Address = ((JArray)jobj["outputs"])[0]["address"].Value<string>();
|
|
|
|
|
var amount = Money.Satoshis(((JArray)jobj["outputs"])[0]["amount"].Value<long>());
|
|
|
|
|
vm.Amount = amount.ToString();
|
|
|
|
|
vm.BitcoinUri = $"bitcoin:{vm.Address}?amount={amount.ToString()}";
|
|
|
|
|
}
|
|
|
|
|
catch (JsonReaderException)
|
|
|
|
|
{
|
|
|
|
|
ModelState.AddModelError(nameof(vm.BitpayLink), $"Invalid or expired bitpay invoice");
|
|
|
|
|
return View(vm);
|
|
|
|
|
}
|
2018-12-03 15:57:43 +01:00
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
ModelState.AddModelError(nameof(vm.BitpayLink), $"Error while requesting {ex.Message}");
|
|
|
|
|
return View(vm);
|
|
|
|
|
}
|
|
|
|
|
return View(vm);
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-21 13:44:03 +02:00
|
|
|
|
public IActionResult Error()
|
|
|
|
|
{
|
|
|
|
|
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
|
|
|
|
|
}
|
2017-09-13 08:47:34 +02:00
|
|
|
|
}
|
|
|
|
|
}
|