Refactor domain mapping (#2407)

This commit is contained in:
Nicolas Dorier
2021-03-30 11:41:44 +09:00
committed by nicolas.dorier
parent 17bdf55bcc
commit 14e6e492dd
4 changed files with 71 additions and 57 deletions

View File

@@ -57,8 +57,10 @@ namespace BTCPayServer.Controllers
} }
[HttpGet] [HttpGet]
[Route("/")]
[Route("/apps/{appId}/pos/{viewType?}")] [Route("/apps/{appId}/pos/{viewType?}")]
[XFrameOptionsAttribute(XFrameOptionsAttribute.XFrameOptions.AllowAll)] [XFrameOptionsAttribute(XFrameOptionsAttribute.XFrameOptions.AllowAll)]
[DomainMappingConstraint(AppType.PointOfSale)]
public async Task<IActionResult> ViewPointOfSale(string appId, PosViewType? viewType = null) public async Task<IActionResult> ViewPointOfSale(string appId, PosViewType? viewType = null)
{ {
var app = await _AppService.GetApp(appId, AppType.PointOfSale); var app = await _AppService.GetApp(appId, AppType.PointOfSale);
@@ -104,10 +106,12 @@ namespace BTCPayServer.Controllers
} }
[HttpPost] [HttpPost]
[Route("/")]
[Route("/apps/{appId}/pos/{viewType?}")] [Route("/apps/{appId}/pos/{viewType?}")]
[XFrameOptionsAttribute(XFrameOptionsAttribute.XFrameOptions.AllowAll)] [XFrameOptionsAttribute(XFrameOptionsAttribute.XFrameOptions.AllowAll)]
[IgnoreAntiforgeryToken] [IgnoreAntiforgeryToken]
[EnableCors(CorsPolicies.All)] [EnableCors(CorsPolicies.All)]
[DomainMappingConstraint(AppType.PointOfSale)]
public async Task<IActionResult> ViewPointOfSale(string appId, public async Task<IActionResult> ViewPointOfSale(string appId,
PosViewType viewType, PosViewType viewType,
[ModelBinder(typeof(InvariantDecimalModelBinder))] decimal amount, [ModelBinder(typeof(InvariantDecimalModelBinder))] decimal amount,
@@ -232,8 +236,10 @@ namespace BTCPayServer.Controllers
} }
[HttpGet] [HttpGet]
[Route("/")]
[Route("/apps/{appId}/crowdfund")] [Route("/apps/{appId}/crowdfund")]
[XFrameOptionsAttribute(XFrameOptionsAttribute.XFrameOptions.AllowAll)] [XFrameOptionsAttribute(XFrameOptionsAttribute.XFrameOptions.AllowAll)]
[DomainMappingConstraintAttribute(AppType.Crowdfund)]
public async Task<IActionResult> ViewCrowdfund(string appId, string statusMessage) public async Task<IActionResult> ViewCrowdfund(string appId, string statusMessage)
{ {
var app = await _AppService.GetApp(appId, AppType.Crowdfund, true); var app = await _AppService.GetApp(appId, AppType.Crowdfund, true);
@@ -263,10 +269,12 @@ namespace BTCPayServer.Controllers
} }
[HttpPost] [HttpPost]
[Route("/")]
[Route("/apps/{appId}/crowdfund")] [Route("/apps/{appId}/crowdfund")]
[XFrameOptionsAttribute(XFrameOptionsAttribute.XFrameOptions.AllowAll)] [XFrameOptionsAttribute(XFrameOptionsAttribute.XFrameOptions.AllowAll)]
[IgnoreAntiforgeryToken] [IgnoreAntiforgeryToken]
[EnableCors(CorsPolicies.All)] [EnableCors(CorsPolicies.All)]
[DomainMappingConstraintAttribute(AppType.Crowdfund)]
public async Task<IActionResult> ContributeToCrowdfund(string appId, ContributeToCrowdfund request, CancellationToken cancellationToken) public async Task<IActionResult> ContributeToCrowdfund(string appId, ContributeToCrowdfund request, CancellationToken cancellationToken)
{ {
if (request.Amount <= 0) if (request.Amount <= 0)

View File

@@ -7,6 +7,7 @@ using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
using BTCPayServer.Abstractions.Constants; using BTCPayServer.Abstractions.Constants;
using BTCPayServer.Data; using BTCPayServer.Data;
using BTCPayServer.Filters;
using BTCPayServer.HostedServices; using BTCPayServer.HostedServices;
using BTCPayServer.Models; using BTCPayServer.Models;
using BTCPayServer.Models.StoreViewModels; using BTCPayServer.Models.StoreViewModels;
@@ -48,71 +49,18 @@ namespace BTCPayServer.Controllers
SignInManager = signInManager; SignInManager = signInManager;
} }
private async Task<ViewResult> GoToApp(string appId, AppType? appType) [Route("")]
{ [DomainMappingConstraint()]
if (appType.HasValue && !string.IsNullOrEmpty(appId)) public IActionResult Index()
{
this.HttpContext.Response.Headers.Remove("Onion-Location");
switch (appType.Value)
{
case AppType.Crowdfund:
{
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
}
break;
}
case AppType.PointOfSale:
{
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
}
break;
}
}
}
return null;
}
public async Task<IActionResult> Index()
{ {
if (_cachedServerSettings.FirstRun) if (_cachedServerSettings.FirstRun)
{ {
return RedirectToAction(nameof(AccountController.Register), "Account"); return RedirectToAction(nameof(AccountController.Register), "Account");
} }
var matchedDomainMapping = _cachedServerSettings.DomainToAppMapping.FirstOrDefault(item =>
item.Domain.Equals(Request.Host.Host, StringComparison.InvariantCultureIgnoreCase));
if (matchedDomainMapping != null)
{
return await GoToApp(matchedDomainMapping.AppId, matchedDomainMapping.AppType) ?? GoToHome();
}
return await GoToApp(_cachedServerSettings.RootAppId, _cachedServerSettings.RootAppType) ?? GoToHome();
}
private IActionResult GoToHome()
{
if (SignInManager.IsSignedIn(User)) if (SignInManager.IsSignedIn(User))
return View("Home"); return View("Home");
else else
return RedirectToAction(nameof(AccountController.Login), "Account"); return Challenge();
} }
[Route("misc/lang")] [Route("misc/lang")]

View File

@@ -0,0 +1,52 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using BTCPayServer.HostedServices;
using BTCPayServer.Services;
using BTCPayServer.Services.Apps;
using Microsoft.AspNetCore.Mvc.ActionConstraints;
using Microsoft.Extensions.DependencyInjection;
namespace BTCPayServer.Filters
{
public class DomainMappingConstraintAttribute : Attribute, IActionConstraint
{
public DomainMappingConstraintAttribute()
{
}
public DomainMappingConstraintAttribute(AppType appType)
{
AppType = appType;
}
public int Order => 100;
public AppType? AppType { get; set; }
public bool Accept(ActionConstraintContext context)
{
if (context.RouteContext.RouteData.Values.ContainsKey("appId"))
return true;
var css = context.RouteContext.HttpContext.RequestServices.GetService<CssThemeManager>();
if (css?.DomainToAppMapping is List<PoliciesSettings.DomainToAppMappingItem> mapping)
{
var matchedDomainMapping = css.DomainToAppMapping.FirstOrDefault(item =>
item.Domain.Equals(context.RouteContext.HttpContext.Request.Host.Host, StringComparison.InvariantCultureIgnoreCase));
if (matchedDomainMapping is PoliciesSettings.DomainToAppMappingItem)
{
if (!(AppType is AppType appType))
return false;
if (appType != matchedDomainMapping.AppType)
return false;
context.RouteContext.RouteData.Values.Add("appId", matchedDomainMapping.AppId);
return true;
}
return AppType is null;
}
else
{
return AppType is null;
}
}
}
}

View File

@@ -11,6 +11,7 @@ using BTCPayServer.Security;
using BTCPayServer.Services.Apps; using BTCPayServer.Services.Apps;
using BTCPayServer.Storage; using BTCPayServer.Storage;
using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
@@ -63,6 +64,11 @@ namespace BTCPayServer.Hosting
opts.DefaultSignInScheme = null; opts.DefaultSignInScheme = null;
opts.DefaultSignOutScheme = null; opts.DefaultSignOutScheme = null;
}); });
services.PostConfigure<CookieAuthenticationOptions>(IdentityConstants.ApplicationScheme, opt =>
{
opt.LoginPath = "/login";
});
services.Configure<SecurityStampValidatorOptions>(opts => services.Configure<SecurityStampValidatorOptions>(opts =>
{ {
opts.ValidationInterval = TimeSpan.FromMinutes(5.0); opts.ValidationInterval = TimeSpan.FromMinutes(5.0);