mirror of
https://github.com/tgstation/tgstation-server.git
synced 2026-08-30 08:33:19 +01:00
Add root routing to control panel
This commit is contained in:
@@ -5,7 +5,7 @@ namespace Tgstation.Server.Host.Configuration
|
||||
/// <summary>
|
||||
/// Configuration options for the web control panel
|
||||
/// </summary>
|
||||
sealed class ControlPanelConfiguration
|
||||
public sealed class ControlPanelConfiguration
|
||||
{
|
||||
/// <summary>
|
||||
/// The key for the <see cref="Microsoft.Extensions.Configuration.IConfigurationSection"/> the <see cref="ControlPanelConfiguration"/> resides in
|
||||
|
||||
@@ -51,6 +51,11 @@ namespace Tgstation.Server.Host.Controllers
|
||||
/// </summary>
|
||||
readonly bool requireInstance;
|
||||
|
||||
/// <summary>
|
||||
/// If <see cref="ApiHeaders"/> are required
|
||||
/// </summary>
|
||||
readonly bool requireHeaders;
|
||||
|
||||
/// <summary>
|
||||
/// Construct an <see cref="ApiController"/>
|
||||
/// </summary>
|
||||
@@ -58,7 +63,8 @@ namespace Tgstation.Server.Host.Controllers
|
||||
/// <param name="authenticationContextFactory">The <see cref="IAuthenticationContextFactory"/> for the <see cref="ApiController"/></param>
|
||||
/// <param name="logger">The value of <see cref="Logger"/></param>
|
||||
/// <param name="requireInstance">The value of <see cref="requireInstance"/></param>
|
||||
public ApiController(IDatabaseContext databaseContext, IAuthenticationContextFactory authenticationContextFactory, ILogger logger, bool requireInstance)
|
||||
/// <param name="requireHeaders">The value of <see cref="requireHeaders"/></param>
|
||||
public ApiController(IDatabaseContext databaseContext, IAuthenticationContextFactory authenticationContextFactory, ILogger logger, bool requireInstance, bool requireHeaders)
|
||||
{
|
||||
DatabaseContext = databaseContext ?? throw new ArgumentNullException(nameof(databaseContext));
|
||||
if (authenticationContextFactory == null)
|
||||
@@ -67,6 +73,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
AuthenticationContext = authenticationContextFactory.CurrentAuthenticationContext;
|
||||
Instance = AuthenticationContext?.InstanceUser?.Instance;
|
||||
this.requireInstance = requireInstance;
|
||||
this.requireHeaders = requireHeaders;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -113,8 +120,11 @@ namespace Tgstation.Server.Host.Controllers
|
||||
}
|
||||
catch (InvalidOperationException e)
|
||||
{
|
||||
await BadRequest(new ErrorMessage { Message = e.Message }).ExecuteResultAsync(context).ConfigureAwait(false);
|
||||
return;
|
||||
if (requireHeaders)
|
||||
{
|
||||
await BadRequest(new ErrorMessage { Message = e.Message }).ExecuteResultAsync(context).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (ModelState?.IsValid == false)
|
||||
@@ -138,7 +148,8 @@ namespace Tgstation.Server.Host.Controllers
|
||||
}
|
||||
}
|
||||
|
||||
Logger.LogDebug("Request made by User ID {0}. Api version: {1}. User-Agent: {2}. Type: {3}. Route {4}{5} to Instance {6}", AuthenticationContext?.User.Id.ToString(CultureInfo.InvariantCulture), ApiHeaders.ApiVersion, ApiHeaders.UserAgent, Request.Method, Request.Path, Request.QueryString, ApiHeaders.InstanceId);
|
||||
if (ApiHeaders != null)
|
||||
Logger.LogDebug("Request made by User ID {0}. Api version: {1}. User-Agent: {2}. Type: {3}. Route {4}{5} to Instance {6}", AuthenticationContext?.User.Id.ToString(CultureInfo.InvariantCulture), ApiHeaders.ApiVersion, ApiHeaders.UserAgent, Request.Method, Request.Path, Request.QueryString, ApiHeaders.InstanceId);
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Net.Mime;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Tgstation.Server.Api;
|
||||
using Tgstation.Server.Host.Configuration;
|
||||
using Tgstation.Server.Host.Core;
|
||||
using Tgstation.Server.Host.Models;
|
||||
using Tgstation.Server.Host.Security;
|
||||
using Wangkanai.Detection;
|
||||
|
||||
namespace Tgstation.Server.Host.Controllers
|
||||
{
|
||||
@@ -39,6 +44,16 @@ namespace Tgstation.Server.Host.Controllers
|
||||
/// </summary>
|
||||
readonly IIdentityCache identityCache;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="IBrowserResolver"/> for the <see cref="HomeController"/>
|
||||
/// </summary>
|
||||
readonly IBrowserResolver browserResolver;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="ControlPanelConfiguration"/> for the <see cref="HomeController"/>
|
||||
/// </summary>
|
||||
readonly ControlPanelConfiguration controlPanelConfiguration;
|
||||
|
||||
/// <summary>
|
||||
/// Construct a <see cref="HomeController"/>
|
||||
/// </summary>
|
||||
@@ -49,27 +64,45 @@ namespace Tgstation.Server.Host.Controllers
|
||||
/// <param name="cryptographySuite">The value of <see cref="cryptographySuite"/></param>
|
||||
/// <param name="application">The value of <see cref="application"/></param>
|
||||
/// <param name="identityCache">The value of <see cref="identityCache"/></param>
|
||||
/// <param name="browserResolver">The value of <see cref="browserResolver"/></param>
|
||||
/// <param name="controlPanelConfigurationOptions">The <see cref="IOptions{TOptions}"/> containing the value of <see cref="controlPanelConfiguration"/></param>
|
||||
/// <param name="logger">The <see cref="ILogger"/> for the <see cref="ApiController"/></param>
|
||||
public HomeController(IDatabaseContext databaseContext, IAuthenticationContextFactory authenticationContextFactory, ITokenFactory tokenFactory, ISystemIdentityFactory systemIdentityFactory, ICryptographySuite cryptographySuite, IApplication application, IIdentityCache identityCache, ILogger<HomeController> logger) : base(databaseContext, authenticationContextFactory, logger, false)
|
||||
public HomeController(IDatabaseContext databaseContext, IAuthenticationContextFactory authenticationContextFactory, ITokenFactory tokenFactory, ISystemIdentityFactory systemIdentityFactory, ICryptographySuite cryptographySuite, IApplication application, IIdentityCache identityCache, IBrowserResolver browserResolver, IOptions<ControlPanelConfiguration> controlPanelConfigurationOptions, ILogger<HomeController> logger) : base(databaseContext, authenticationContextFactory, logger, false, false)
|
||||
{
|
||||
this.tokenFactory = tokenFactory ?? throw new ArgumentNullException(nameof(tokenFactory));
|
||||
this.systemIdentityFactory = systemIdentityFactory ?? throw new ArgumentNullException(nameof(systemIdentityFactory));
|
||||
this.cryptographySuite = cryptographySuite ?? throw new ArgumentNullException(nameof(cryptographySuite));
|
||||
this.application = application ?? throw new ArgumentNullException(nameof(application));
|
||||
this.identityCache = identityCache ?? throw new ArgumentNullException(nameof(identityCache));
|
||||
this.browserResolver = browserResolver ?? throw new ArgumentNullException(nameof(browserResolver));
|
||||
controlPanelConfiguration = controlPanelConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(controlPanelConfigurationOptions));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the version of the <see cref="Application"/>
|
||||
/// Main page of the <see cref="Application"/>
|
||||
/// </summary>
|
||||
/// <returns><see cref="Application.Version"/></returns>
|
||||
/// <returns>The <see cref="Api.Models.ServerInformation"/> of the <see cref="Application"/> if a properly authenticated API request, the web control panel if on a browser and enabled, <see cref="UnauthorizedResult"/> otherwise</returns>
|
||||
[TgsAuthorize]
|
||||
[AllowAnonymous]
|
||||
[HttpGet]
|
||||
public JsonResult Home() => Json(new Api.Models.ServerInformation
|
||||
public IActionResult Home(CancellationToken cancellationToken)
|
||||
{
|
||||
Version = application.Version,
|
||||
ApiVersion = ApiHeaders.Version
|
||||
});
|
||||
if (AuthenticationContext != null)
|
||||
return Json(new Api.Models.ServerInformation
|
||||
{
|
||||
Version = application.Version,
|
||||
ApiVersion = ApiHeaders.Version
|
||||
});
|
||||
|
||||
//if we are using a browser and the control panel, soft redirect to the app page
|
||||
if (controlPanelConfiguration.Enable && browserResolver.Browser.Type != BrowserType.Generic)
|
||||
{
|
||||
Logger.LogDebug("Unauthorized browser request (User-Agent: \"{0}\"), loading control panel...", browserResolver.UserAgent);
|
||||
return File("~/index.html", MediaTypeNames.Text.Html);
|
||||
}
|
||||
|
||||
return Unauthorized();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempt to authenticate a <see cref="User"/> using <see cref="ApiController.ApiHeaders"/>
|
||||
@@ -79,6 +112,9 @@ namespace Tgstation.Server.Host.Controllers
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> CreateToken(CancellationToken cancellationToken)
|
||||
{
|
||||
if (ApiHeaders == null)
|
||||
return BadRequest(new Api.Models.ErrorMessage { Message = "Missing API headers!" });
|
||||
|
||||
if (ApiHeaders.IsTokenAuthentication)
|
||||
return BadRequest(new Api.Models.ErrorMessage { Message = "Cannot create a token using another token!" });
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
/// <param name="authenticationContextFactory">The <see cref="IAuthenticationContextFactory"/> for the <see cref="ApiController"/></param>
|
||||
/// <param name="logger">The <see cref="ILogger"/> for the <see cref="ApiController"/></param>
|
||||
/// <param name="requireInstance">If the <see cref="ModelController{TModel}"/> requires an <see cref="IAuthenticationContext.InstanceUser"/></param>
|
||||
public ModelController(IDatabaseContext databaseContext, IAuthenticationContextFactory authenticationContextFactory, ILogger logger, bool requireInstance) : base(databaseContext, authenticationContextFactory, logger, requireInstance) { }
|
||||
public ModelController(IDatabaseContext databaseContext, IAuthenticationContextFactory authenticationContextFactory, ILogger logger, bool requireInstance) : base(databaseContext, authenticationContextFactory, logger, requireInstance, true) { }
|
||||
|
||||
/// <summary>
|
||||
/// Attempt to create a <paramref name="model"/>
|
||||
|
||||
@@ -227,6 +227,9 @@ namespace Tgstation.Server.Host.Core
|
||||
options.SerializerSettings.Converters = new[] { new VersionConverter() };
|
||||
});
|
||||
|
||||
//enable browser detection
|
||||
services.AddDetectionCore().AddBrowser();
|
||||
|
||||
//enable CORS if necessary
|
||||
if (controlPanelConfiguration.AllowAnyOrigin || controlPanelConfiguration.AllowedOrigins?.Count > 0)
|
||||
services.AddCors();
|
||||
|
||||
@@ -26,9 +26,7 @@
|
||||
<NpmInstallStampFile>ClientApp/node_modules/.install-stamp</NpmInstallStampFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<Target Name="NpmInstall"
|
||||
Inputs="ClientApp/package-lock.json;ClientApp/package.json"
|
||||
Outputs="$(NpmInstallStampFile)">
|
||||
<Target Name="NpmInstall" Inputs="ClientApp/package-lock.json" Outputs="$(NpmInstallStampFile)">
|
||||
<Exec WorkingDirectory="ClientApp" Command="npm ci" />
|
||||
<Touch Files="$(NpmInstallStampFile)" AlwaysCreate="true" />
|
||||
</Target>
|
||||
@@ -38,17 +36,11 @@
|
||||
<Content Remove="ClientApp\package.json" />
|
||||
<Content Remove="ClientApp\public\manifest.json" />
|
||||
<Content Remove="ClientApp\tsconfig.json" />
|
||||
<Content Remove="ClientApp\tsconfig.prod.json" />
|
||||
<Content Remove="ClientApp\tsconfig.test.json" />
|
||||
<Content Remove="ClientApp\tslint.json" />
|
||||
<ClientApp Include="ClientApp\**\*" />
|
||||
<ClientApp Include="ClientApp\src;ClientApp\public;ClientApp\tsconfig.json;ClientApp\tslint.json;ClientApp\package-lock.json" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="NpmBuild"
|
||||
BeforeTargets="BeforeBuild"
|
||||
DependsOnTargets="NpmInstall"
|
||||
Inputs="@(ClientApp)"
|
||||
Outputs="wwwroot\index.html">
|
||||
<Target Name="NpmBuild" BeforeTargets="BeforeBuild" DependsOnTargets="NpmInstall" Inputs="@(ClientApp)" Outputs="wwwroot\index.html">
|
||||
<Exec WorkingDirectory="ClientApp" Command="npm run build" />
|
||||
</Target>
|
||||
|
||||
@@ -81,6 +73,7 @@
|
||||
<PackageReference Include="System.Diagnostics.PerformanceCounter" Version="4.5.0" />
|
||||
<PackageReference Include="System.DirectoryServices.AccountManagement" Version="4.5.0" />
|
||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="5.2.4" />
|
||||
<PackageReference Include="Wangkanai.Detection.Browser" Version="2.0.0-beta9" />
|
||||
<PackageReference Include="Z.EntityFramework.Plus.EFCore" Version="1.8.10" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -107,8 +100,6 @@
|
||||
<None Include="ClientApp\package.json" />
|
||||
<None Include="ClientApp\public\manifest.json" />
|
||||
<None Include="ClientApp\tsconfig.json" />
|
||||
<None Include="ClientApp\tsconfig.prod.json" />
|
||||
<None Include="ClientApp\tsconfig.test.json" />
|
||||
<None Include="ClientApp\tslint.json" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user