mirror of
https://github.com/tgstation/tgstation-server.git
synced 2026-08-27 15:07:03 +01:00
More GraphQL development
- Setup query structure for the potential for `RemoteGateway`s. - Add new `ErrorCode` indicating they are not implemented. - Rename `ServerInformationBase` to `GatewayInformationBase`. - Fix `TgsRestAuthorizeAttribute` lacking an `IAuthorizationFilter`.
This commit is contained in:
+3
-3
@@ -5,10 +5,10 @@
|
||||
<PropertyGroup>
|
||||
<TgsCoreVersion>6.10.0</TgsCoreVersion>
|
||||
<TgsConfigVersion>5.2.0</TgsConfigVersion>
|
||||
<TgsApiVersion>10.9.0</TgsApiVersion>
|
||||
<TgsApiVersion>10.10.0</TgsApiVersion>
|
||||
<TgsCommonLibraryVersion>7.0.0</TgsCommonLibraryVersion>
|
||||
<TgsApiLibraryVersion>15.0.0</TgsApiLibraryVersion>
|
||||
<TgsClientVersion>18.0.0</TgsClientVersion>
|
||||
<TgsApiLibraryVersion>16.0.0</TgsApiLibraryVersion>
|
||||
<TgsClientVersion>19.0.0</TgsClientVersion>
|
||||
<TgsDmapiVersion>7.3.0</TgsDmapiVersion>
|
||||
<TgsInteropVersion>5.10.0</TgsInteropVersion>
|
||||
<TgsHostWatchdogVersion>1.5.0</TgsHostWatchdogVersion>
|
||||
|
||||
@@ -461,7 +461,7 @@ namespace Tgstation.Server.Api.Models
|
||||
RepoTestMergeConflict,
|
||||
|
||||
/// <summary>
|
||||
/// Attempted to create an instance outside of the <see cref="Internal.ServerInformationBase.ValidInstancePaths"/>.
|
||||
/// Attempted to create an instance outside of the <see cref="Internal.GatewayInformationBase.ValidInstancePaths"/>.
|
||||
/// </summary>
|
||||
[Description("The new instance's path is not under a white-listed path.")]
|
||||
InstanceNotAtWhitelistedPath,
|
||||
@@ -663,5 +663,11 @@ namespace Tgstation.Server.Api.Models
|
||||
/// </summary>
|
||||
[Description("Provided repository username doesn't match the user of the corresponding access token!")]
|
||||
RepoTokenUsernameMismatch,
|
||||
|
||||
/// <summary>
|
||||
/// Attempted to make a cross swarm server request using the GraphQL API.
|
||||
/// </summary>
|
||||
[Description("GraphQL swarm remote gateways not implemented!")]
|
||||
RemoteGatewaysNotImplemented,
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ namespace Tgstation.Server.Api.Models.Internal
|
||||
/// <summary>
|
||||
/// Information about the local tgstation-server.
|
||||
/// </summary>
|
||||
public class LocalServerInformation : ServerInformationBase
|
||||
public class GatewayInformation : GatewayInformationBase
|
||||
{
|
||||
/// <summary>
|
||||
/// If the server is running on a windows operating system.
|
||||
+1
-1
@@ -5,7 +5,7 @@ namespace Tgstation.Server.Api.Models.Internal
|
||||
/// <summary>
|
||||
/// Base class for <see cref="Response.ServerInformationResponse"/>.
|
||||
/// </summary>
|
||||
public abstract class ServerInformationBase
|
||||
public abstract class GatewayInformationBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Minimum length of database user passwords.
|
||||
@@ -6,7 +6,7 @@ namespace Tgstation.Server.Api.Models.Internal
|
||||
/// <summary>
|
||||
/// Information about a server in the swarm.
|
||||
/// </summary>
|
||||
public abstract class SwarmServer : IEquatable<SwarmServer>
|
||||
public abstract class SwarmServer
|
||||
{
|
||||
/// <summary>
|
||||
/// The public address of the server.
|
||||
@@ -47,12 +47,5 @@ namespace Tgstation.Server.Api.Models.Internal
|
||||
PublicAddress = copy.PublicAddress;
|
||||
Identifier = copy.Identifier;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Equals(SwarmServer other)
|
||||
=> other != null
|
||||
&& other.Identifier == Identifier
|
||||
&& other.PublicAddress == PublicAddress
|
||||
&& other.Address == Address;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
using System;
|
||||
|
||||
using Tgstation.Server.Api.Models.Response;
|
||||
using Tgstation.Server.Api.Models.Response;
|
||||
|
||||
namespace Tgstation.Server.Api.Models.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents information about a running <see cref="SwarmServer"/>.
|
||||
/// </summary>
|
||||
public class SwarmServerInformation : SwarmServer, IEquatable<SwarmServerInformation>
|
||||
public class SwarmServerInformation : SwarmServer
|
||||
{
|
||||
/// <summary>
|
||||
/// If the <see cref="SwarmServerResponse"/> is the controller.
|
||||
@@ -30,10 +28,5 @@ namespace Tgstation.Server.Api.Models.Internal
|
||||
{
|
||||
Controller = copy.Controller;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Equals(SwarmServerInformation other)
|
||||
=> base.Equals(other)
|
||||
&& other.Controller == Controller;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace Tgstation.Server.Api.Models.Response
|
||||
/// <summary>
|
||||
/// Represents basic server information.
|
||||
/// </summary>
|
||||
public sealed class ServerInformationResponse : Internal.LocalServerInformation
|
||||
public sealed class ServerInformationResponse : Internal.GatewayInformation
|
||||
{
|
||||
/// <summary>
|
||||
/// The version of the host.
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
query ServerInformation {
|
||||
swarm {
|
||||
metadata {
|
||||
apiVersion
|
||||
dmApiVersion
|
||||
updateInProgress
|
||||
version
|
||||
}
|
||||
currentNode {
|
||||
gateway {
|
||||
information {
|
||||
instanceLimit
|
||||
minimumPasswordLength
|
||||
userGroupLimit
|
||||
userLimit
|
||||
validInstancePaths
|
||||
windowsHost
|
||||
oAuthProviderInfos {
|
||||
value {
|
||||
clientId
|
||||
redirectUri
|
||||
serverUrl
|
||||
}
|
||||
key
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
nodes {
|
||||
info {
|
||||
address
|
||||
controller
|
||||
identifier
|
||||
publicAddress
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
query ServerInformationQuery {
|
||||
swarm {
|
||||
metadata {
|
||||
apiVersion
|
||||
dmApiVersion
|
||||
updateInProgress
|
||||
version
|
||||
}
|
||||
localServer {
|
||||
information {
|
||||
instanceLimit
|
||||
minimumPasswordLength
|
||||
userGroupLimit
|
||||
userLimit
|
||||
validInstancePaths
|
||||
windowsHost
|
||||
oAuthProviderInfos {
|
||||
key
|
||||
value {
|
||||
clientId
|
||||
redirectUri
|
||||
serverUrl
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
servers {
|
||||
address
|
||||
controller
|
||||
identifier
|
||||
publicAddress
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@ namespace Tgstation.Server.Host.Configuration
|
||||
/// <summary>
|
||||
/// General configuration options.
|
||||
/// </summary>
|
||||
public sealed class GeneralConfiguration : ServerInformationBase
|
||||
public sealed class GeneralConfiguration : GatewayInformationBase
|
||||
{
|
||||
/// <summary>
|
||||
/// The key for the <see cref="Microsoft.Extensions.Configuration.IConfigurationSection"/> the <see cref="GeneralConfiguration"/> resides in.
|
||||
@@ -29,22 +29,22 @@ namespace Tgstation.Server.Host.Configuration
|
||||
public const ushort DefaultApiPort = 5000;
|
||||
|
||||
/// <summary>
|
||||
/// The default value for <see cref="ServerInformationBase.MinimumPasswordLength"/>.
|
||||
/// The default value for <see cref="GatewayInformationBase.MinimumPasswordLength"/>.
|
||||
/// </summary>
|
||||
const uint DefaultMinimumPasswordLength = 15;
|
||||
|
||||
/// <summary>
|
||||
/// The default value for <see cref="ServerInformationBase.InstanceLimit"/>.
|
||||
/// The default value for <see cref="GatewayInformationBase.InstanceLimit"/>.
|
||||
/// </summary>
|
||||
const uint DefaultInstanceLimit = 10;
|
||||
|
||||
/// <summary>
|
||||
/// The default value for <see cref="ServerInformationBase.UserLimit"/>.
|
||||
/// The default value for <see cref="GatewayInformationBase.UserLimit"/>.
|
||||
/// </summary>
|
||||
const uint DefaultUserLimit = 100;
|
||||
|
||||
/// <summary>
|
||||
/// The default value for <see cref="ServerInformationBase.UserGroupLimit"/>.
|
||||
/// The default value for <see cref="GatewayInformationBase.UserGroupLimit"/>.
|
||||
/// </summary>
|
||||
const uint DefaultUserGroupLimit = 25;
|
||||
|
||||
|
||||
@@ -56,6 +56,7 @@ using Tgstation.Server.Host.Controllers.Results;
|
||||
using Tgstation.Server.Host.Database;
|
||||
using Tgstation.Server.Host.Extensions;
|
||||
using Tgstation.Server.Host.GraphQL;
|
||||
using Tgstation.Server.Host.GraphQL.Types;
|
||||
using Tgstation.Server.Host.GraphQL.Types.Scalars;
|
||||
using Tgstation.Server.Host.IO;
|
||||
using Tgstation.Server.Host.Jobs;
|
||||
@@ -297,6 +298,8 @@ namespace Tgstation.Server.Host.Core
|
||||
.AddAuthorization()
|
||||
.AddMutationConventions()
|
||||
.AddErrorFilter<ErrorMessageFilter>()
|
||||
.AddType<LocalGateway>()
|
||||
.AddType<RemoteGateway>()
|
||||
.AddType<UnsignedIntType>()
|
||||
.BindRuntimeType<Version, SemverType>()
|
||||
.AddQueryType<Query>()
|
||||
|
||||
@@ -33,5 +33,14 @@ namespace Tgstation.Server.Host.GraphQL
|
||||
ErrorCode = errorMessage.ErrorCode != default ? errorMessage.ErrorCode : null;
|
||||
AdditionalData = errorMessage.AdditionalData;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ErrorMessageException"/> class.
|
||||
/// </summary>
|
||||
/// <param name="errorCode">The <see cref="ErrorCode"/>.</param>
|
||||
public ErrorMessageException(ErrorCode errorCode)
|
||||
: this(new ErrorMessageResponse(errorCode), String.Empty)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#pragma warning disable CA1724
|
||||
|
||||
using Tgstation.Server.Host.GraphQL.Types;
|
||||
|
||||
namespace Tgstation.Server.Host.GraphQL
|
||||
{
|
||||
/// <summary>
|
||||
@@ -10,9 +8,9 @@ namespace Tgstation.Server.Host.GraphQL
|
||||
public sealed class Query
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the <see cref="ServerSwarm"/>.
|
||||
/// Gets the <see cref="Types.Swarm"/>.
|
||||
/// </summary>
|
||||
/// <returns>A new <see cref="ServerSwarm"/>.</returns>
|
||||
public ServerSwarm Swarm() => new();
|
||||
/// <returns>A new <see cref="Types.Swarm"/>.</returns>
|
||||
public Types.Swarm Swarm() => new();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
using HotChocolate;
|
||||
using HotChocolate.Authorization;
|
||||
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
using Tgstation.Server.Api.Models.Internal;
|
||||
using Tgstation.Server.Host.Configuration;
|
||||
using Tgstation.Server.Host.Security.OAuth;
|
||||
using Tgstation.Server.Host.System;
|
||||
|
||||
namespace Tgstation.Server.Host.GraphQL.Types
|
||||
{
|
||||
/// <summary>
|
||||
/// Management interface for the parent <see cref="Node"/>.
|
||||
/// </summary>
|
||||
public interface IGateway
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets <see cref="GatewayInformation"/>.
|
||||
/// </summary>
|
||||
/// <param name="oAuthProviders">The <see cref="IOAuthProviders"/> to use.</param>
|
||||
/// <param name="platformIdentifier">The <see cref="IPlatformIdentifier"/> to use.</param>
|
||||
/// <param name="generalConfigurationOptions">The <see cref="IOptionsSnapshot{TOptions}"/> containing the <see cref="GeneralConfiguration"/> to use.</param>
|
||||
/// <returns>A new <see cref="GatewayInformation"/>.</returns>
|
||||
[AllowAnonymous]
|
||||
GatewayInformation Information(
|
||||
[Service] IOAuthProviders oAuthProviders,
|
||||
[Service] IPlatformIdentifier platformIdentifier,
|
||||
[Service] IOptionsSnapshot<GeneralConfiguration> generalConfigurationOptions);
|
||||
}
|
||||
}
|
||||
+6
-13
@@ -1,9 +1,9 @@
|
||||
using System;
|
||||
|
||||
using HotChocolate;
|
||||
using HotChocolate.Authorization;
|
||||
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
using Tgstation.Server.Api.Models.Internal;
|
||||
using Tgstation.Server.Host.Configuration;
|
||||
using Tgstation.Server.Host.Security.OAuth;
|
||||
@@ -12,19 +12,12 @@ using Tgstation.Server.Host.System;
|
||||
namespace Tgstation.Server.Host.GraphQL.Types
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the local tgstation-server.
|
||||
/// <see cref="IGateway"/> for the <see cref="Node"/> this query is executing on.
|
||||
/// </summary>
|
||||
public sealed class LocalServer
|
||||
public sealed class LocalGateway : IGateway
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets <see cref="LocalServerInformation"/>.
|
||||
/// </summary>
|
||||
/// <param name="oAuthProviders">The <see cref="IOAuthProviders"/> to use.</param>
|
||||
/// <param name="platformIdentifier">The <see cref="IPlatformIdentifier"/> to use.</param>
|
||||
/// <param name="generalConfigurationOptions">The <see cref="IOptionsSnapshot{TOptions}"/> containing the <see cref="GeneralConfiguration"/> to use.</param>
|
||||
/// <returns>A new <see cref="LocalServerInformation"/>.</returns>
|
||||
[AllowAnonymous]
|
||||
public LocalServerInformation Information(
|
||||
/// <inheritdoc />
|
||||
public GatewayInformation Information(
|
||||
[Service] IOAuthProviders oAuthProviders,
|
||||
[Service] IPlatformIdentifier platformIdentifier,
|
||||
[Service] IOptionsSnapshot<GeneralConfiguration> generalConfigurationOptions)
|
||||
@@ -34,7 +27,7 @@ namespace Tgstation.Server.Host.GraphQL.Types
|
||||
ArgumentNullException.ThrowIfNull(generalConfigurationOptions);
|
||||
|
||||
var generalConfiguration = generalConfigurationOptions.Value;
|
||||
return new LocalServerInformation
|
||||
return new GatewayInformation
|
||||
{
|
||||
MinimumPasswordLength = generalConfiguration.MinimumPasswordLength,
|
||||
InstanceLimit = generalConfiguration.InstanceLimit,
|
||||
@@ -0,0 +1,47 @@
|
||||
using System;
|
||||
|
||||
using HotChocolate;
|
||||
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
using Tgstation.Server.Host.Configuration;
|
||||
|
||||
namespace Tgstation.Server.Host.GraphQL.Types
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a node server in a swarm.
|
||||
/// </summary>
|
||||
public sealed class Node
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the <see cref="NodeInformation"/>.
|
||||
/// </summary>
|
||||
public NodeInformation? Info { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Node"/> class.
|
||||
/// </summary>
|
||||
/// <param name="info">The value of <see cref="Info"/>.</param>
|
||||
public Node(NodeInformation? info)
|
||||
{
|
||||
Info = info;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="Node"/>'s <see cref="IGateway"/>.
|
||||
/// </summary>
|
||||
/// <param name="swarmConfigurationOptions">The <see cref="IOptionsSnapshot{TOptions}"/> containing the current <see cref="SwarmConfiguration"/>.</param>
|
||||
/// <returns>A new <see cref="IGateway"/>.</returns>
|
||||
/// <remarks>The <see cref="Node"/>'s <see cref="IGateway"/>.</remarks>
|
||||
public IGateway? Gateway([Service] IOptionsSnapshot<SwarmConfiguration> swarmConfigurationOptions)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(swarmConfigurationOptions);
|
||||
|
||||
bool local = Info == null || Info.Identifier == swarmConfigurationOptions.Value.Identifier;
|
||||
if (local)
|
||||
return new LocalGateway();
|
||||
|
||||
return new RemoteGateway();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
using System;
|
||||
|
||||
using HotChocolate.Types.Relay;
|
||||
|
||||
namespace Tgstation.Server.Host.GraphQL.Types
|
||||
{
|
||||
/// <summary>
|
||||
/// Represent a server in the TGS server swarm.
|
||||
/// </summary>
|
||||
public sealed class NodeInformation
|
||||
{
|
||||
/// <summary>
|
||||
/// The swarm server ID.
|
||||
/// </summary>
|
||||
[ID]
|
||||
public string Identifier { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The swarm server's internal <see cref="Uri"/>.
|
||||
/// </summary>
|
||||
public Uri Address { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The swarm server's optional public address.
|
||||
/// </summary>
|
||||
public Uri? PublicAddress { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not the server is the swarm's controller.
|
||||
/// </summary>
|
||||
public bool Controller { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="NodeInformation"/> class.
|
||||
/// </summary>
|
||||
/// <param name="swarmServerInformation">The <see cref="Api.Models.Internal.SwarmServerInformation"/> to build from.</param>
|
||||
public NodeInformation(Api.Models.Internal.SwarmServerInformation swarmServerInformation)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(swarmServerInformation);
|
||||
|
||||
Identifier = swarmServerInformation.Identifier!;
|
||||
Address = swarmServerInformation.Address!;
|
||||
PublicAddress = swarmServerInformation.PublicAddress;
|
||||
Controller = swarmServerInformation.Controller;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
|
||||
using HotChocolate;
|
||||
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
using Tgstation.Server.Api.Models;
|
||||
using Tgstation.Server.Api.Models.Internal;
|
||||
using Tgstation.Server.Host.Configuration;
|
||||
using Tgstation.Server.Host.Security.OAuth;
|
||||
using Tgstation.Server.Host.System;
|
||||
|
||||
namespace Tgstation.Server.Host.GraphQL.Types
|
||||
{
|
||||
/// <summary>
|
||||
/// <see cref="IGateway"/> for accessing remote <see cref="Node"/>s.
|
||||
/// </summary>
|
||||
/// <remarks>This is currently unimplemented.</remarks>
|
||||
public sealed class RemoteGateway : IGateway
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public GatewayInformation Information(
|
||||
[Service] IOAuthProviders oAuthProviders,
|
||||
[Service] IPlatformIdentifier platformIdentifier,
|
||||
[Service] IOptionsSnapshot<GeneralConfiguration> generalConfigurationOptions)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(oAuthProviders);
|
||||
ArgumentNullException.ThrowIfNull(platformIdentifier);
|
||||
ArgumentNullException.ThrowIfNull(generalConfigurationOptions);
|
||||
|
||||
throw new ErrorMessageException(ErrorCode.RemoteGatewaysNotImplemented);
|
||||
}
|
||||
}
|
||||
}
|
||||
+29
-12
@@ -1,9 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using HotChocolate;
|
||||
|
||||
using Tgstation.Server.Api.Models.Internal;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
using Tgstation.Server.Host.Configuration;
|
||||
using Tgstation.Server.Host.Core;
|
||||
using Tgstation.Server.Host.Swarm;
|
||||
using Tgstation.Server.Host.System;
|
||||
@@ -13,7 +16,7 @@ namespace Tgstation.Server.Host.GraphQL.Types
|
||||
/// <summary>
|
||||
/// Represents a tgstation-server swarm.
|
||||
/// </summary>
|
||||
public sealed class ServerSwarm
|
||||
public sealed class Swarm
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the <see cref="SwarmMetadata"/> for the swarm.
|
||||
@@ -30,12 +33,6 @@ namespace Tgstation.Server.Host.GraphQL.Types
|
||||
return new SwarmMetadata(assemblyInformationProvider, serverControl.UpdateInProgress);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the local <see cref="Types.LocalServer"/>.
|
||||
/// </summary>
|
||||
/// <returns>A new <see cref="Types.LocalServer"/>.</returns>
|
||||
public LocalServer LocalServer() => new();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the swarm's <see cref="Types.Users"/>.
|
||||
/// </summary>
|
||||
@@ -43,15 +40,35 @@ namespace Tgstation.Server.Host.GraphQL.Types
|
||||
public Users Users() => new();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="SwarmServerInformation"/> for all servers in a swarm.
|
||||
/// Gets the connected <see cref="Node"/> server.
|
||||
/// </summary>
|
||||
/// <param name="swarmService">The <see cref="ISwarmService"/> to use.</param>
|
||||
/// <returns>A <see cref="List{T}"/> of <see cref="SwarmServerInformation"/>s if the local server is part of a swarm, <see langword="null"/> otherwise.</returns>
|
||||
public List<SwarmServerInformation>? Servers(
|
||||
/// <param name="swarmConfigurationOptions">The <see cref="IOptionsSnapshot{TOptions}"/> containing the current <see cref="SwarmConfiguration"/>.</param>
|
||||
/// <returns>A new <see cref="Node"/>.</returns>
|
||||
public Node CurrentNode(
|
||||
[Service] ISwarmService swarmService,
|
||||
[Service] IOptionsSnapshot<SwarmConfiguration> swarmConfigurationOptions)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(swarmService);
|
||||
ArgumentNullException.ThrowIfNull(swarmConfigurationOptions);
|
||||
|
||||
var nodeInfos = Nodes(swarmService);
|
||||
if (nodeInfos != null)
|
||||
return nodeInfos.First(x => x.Info!.Identifier == swarmConfigurationOptions.Value.Identifier);
|
||||
|
||||
return new Node(null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all <see cref="Node"/> servers in the swarm.
|
||||
/// </summary>
|
||||
/// <param name="swarmService">The <see cref="ISwarmService"/> to use.</param>
|
||||
/// <returns>A <see cref="List{T}"/> of <see cref="Node"/>s if the local server is part of a swarm, <see langword="null"/> otherwise.</returns>
|
||||
public List<Node>? Nodes(
|
||||
[Service] ISwarmService swarmService)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(swarmService);
|
||||
return swarmService.GetSwarmServers();
|
||||
return swarmService.GetSwarmServers()?.Select(x => new Node(new NodeInformation(x))).ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ using Tgstation.Server.Host.System;
|
||||
namespace Tgstation.Server.Host.GraphQL.Types
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents information that is constant across all servers in a <see cref="ServerSwarm"/>.
|
||||
/// Represents information that is constant across all servers in a <see cref="Swarm"/>.
|
||||
/// </summary>
|
||||
public sealed class SwarmMetadata
|
||||
{
|
||||
|
||||
@@ -23,6 +23,32 @@ namespace Tgstation.Server.Host.Security
|
||||
/// </summary>
|
||||
public RightsType? RightsType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Implementation of <see cref="IAuthorizationFilter.OnAuthorization(AuthorizationFilterContext)"/>.
|
||||
/// </summary>
|
||||
/// <param name="context">The <see cref="AuthorizationFilterContext"/>.</param>
|
||||
public static void OnAuthorizationHelper(AuthorizationFilterContext context)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(context);
|
||||
|
||||
var services = context.HttpContext.RequestServices;
|
||||
var authenticationContext = services.GetRequiredService<IAuthenticationContext>();
|
||||
var logger = services.GetRequiredService<ILogger<TgsAuthorizeAttribute>>();
|
||||
|
||||
if (!authenticationContext.Valid)
|
||||
{
|
||||
logger.LogTrace("authenticationContext is invalid!");
|
||||
context.Result = new UnauthorizedResult();
|
||||
return;
|
||||
}
|
||||
|
||||
if (authenticationContext.User.Require(x => x.Enabled))
|
||||
return;
|
||||
|
||||
logger.LogTrace("authenticationContext is for a disabled user!");
|
||||
context.Result = new ForbidResult();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TgsAuthorizeAttribute"/> class.
|
||||
/// </summary>
|
||||
@@ -122,23 +148,6 @@ namespace Tgstation.Server.Host.Security
|
||||
|
||||
/// <inheritdoc />
|
||||
public void OnAuthorization(AuthorizationFilterContext context)
|
||||
{
|
||||
var services = context.HttpContext.RequestServices;
|
||||
var authenticationContext = services.GetRequiredService<IAuthenticationContext>();
|
||||
var logger = services.GetRequiredService<ILogger<TgsAuthorizeAttribute>>();
|
||||
|
||||
if (!authenticationContext.Valid)
|
||||
{
|
||||
logger.LogTrace("authenticationContext is invalid!");
|
||||
context.Result = new UnauthorizedResult();
|
||||
return;
|
||||
}
|
||||
|
||||
if (authenticationContext.User.Require(x => x.Enabled))
|
||||
return;
|
||||
|
||||
logger.LogTrace("authenticationContext is for a disabled user!");
|
||||
context.Result = new ForbidResult();
|
||||
}
|
||||
=> OnAuthorizationHelper(context);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Reflection;
|
||||
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
|
||||
using Tgstation.Server.Host.Authority.Core;
|
||||
|
||||
@@ -12,7 +13,7 @@ namespace Tgstation.Server.Host.Security
|
||||
/// </summary>
|
||||
/// <typeparam name="TAuthority">The <see cref="IAuthority"/> being wrapped.</typeparam>
|
||||
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
|
||||
public sealed class TgsRestAuthorizeAttribute<TAuthority> : AuthorizeAttribute
|
||||
public sealed class TgsRestAuthorizeAttribute<TAuthority> : AuthorizeAttribute, IAuthorizationFilter
|
||||
where TAuthority : IAuthority
|
||||
{
|
||||
/// <summary>
|
||||
@@ -40,5 +41,9 @@ namespace Tgstation.Server.Host.Security
|
||||
MethodName = methodName;
|
||||
Roles = authorizeAttribute.Roles;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void OnAuthorization(AuthorizationFilterContext context)
|
||||
=> TgsAuthorizeAttribute.OnAuthorizationHelper(context);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1380,27 +1380,27 @@ namespace Tgstation.Server.Tests.Live
|
||||
|
||||
await multiClient.ExecuteReadOnlyConfirmEquivalence(
|
||||
restClient => restClient.ServerInformation(cancellationToken),
|
||||
async gqlClient => (await gqlClient.ServerInformationQuery.ExecuteAsync(cancellationToken)).Data,
|
||||
async gqlClient => (await gqlClient.ServerInformation.ExecuteAsync(cancellationToken)).Data,
|
||||
(restServerInfo, gqlServerInfo) => restServerInfo.UpdateInProgress == gqlServerInfo.Swarm.Metadata.UpdateInProgress
|
||||
&& restServerInfo.Version == gqlServerInfo.Swarm.Metadata.Version
|
||||
&& restServerInfo.DMApiVersion == gqlServerInfo.Swarm.Metadata.DmApiVersion
|
||||
&& restServerInfo.InstanceLimit == gqlServerInfo.Swarm.LocalServer.Information.InstanceLimit
|
||||
&& restServerInfo.UserGroupLimit == gqlServerInfo.Swarm.LocalServer.Information.UserGroupLimit
|
||||
&& restServerInfo.ValidInstancePaths.SequenceEqual(gqlServerInfo.Swarm.LocalServer.Information.ValidInstancePaths)
|
||||
&& restServerInfo.UserLimit == gqlServerInfo.Swarm.LocalServer.Information.UserLimit
|
||||
&& restServerInfo.MinimumPasswordLength == gqlServerInfo.Swarm.LocalServer.Information.MinimumPasswordLength
|
||||
&& (restServerInfo.SwarmServers == gqlServerInfo.Swarm.Servers
|
||||
|| restServerInfo.SwarmServers.SequenceEqual(gqlServerInfo.Swarm.Servers.Select(x => new SwarmServerResponse(new Api.Models.Internal.SwarmServerInformation
|
||||
&& restServerInfo.InstanceLimit == gqlServerInfo.Swarm.CurrentNode.Gateway.Information.InstanceLimit
|
||||
&& restServerInfo.UserGroupLimit == gqlServerInfo.Swarm.CurrentNode.Gateway.Information.UserGroupLimit
|
||||
&& restServerInfo.ValidInstancePaths.SequenceEqual(gqlServerInfo.Swarm.CurrentNode.Gateway.Information.ValidInstancePaths)
|
||||
&& restServerInfo.UserLimit == gqlServerInfo.Swarm.CurrentNode.Gateway.Information.UserLimit
|
||||
&& restServerInfo.MinimumPasswordLength == gqlServerInfo.Swarm.CurrentNode.Gateway.Information.MinimumPasswordLength
|
||||
&& ((object)restServerInfo.SwarmServers == gqlServerInfo.Swarm.Nodes
|
||||
|| restServerInfo.SwarmServers.SequenceEqual(gqlServerInfo.Swarm.Nodes.Select(x => new SwarmServerResponse(new Api.Models.Internal.SwarmServerInformation
|
||||
{
|
||||
Address = x.Address,
|
||||
PublicAddress = x.PublicAddress,
|
||||
Controller = x.Controller,
|
||||
Identifier = x.Identifier,
|
||||
Address = x.Info.Address,
|
||||
PublicAddress = x.Info.PublicAddress,
|
||||
Controller = x.Info.Controller,
|
||||
Identifier = x.Info.Identifier,
|
||||
}))))
|
||||
&& (restServerInfo.OAuthProviderInfos == gqlServerInfo.Swarm.LocalServer.Information.OAuthProviderInfos
|
||||
&& (restServerInfo.OAuthProviderInfos == gqlServerInfo.Swarm.CurrentNode.Gateway.Information.OAuthProviderInfos
|
||||
|| restServerInfo.OAuthProviderInfos.All(kvp =>
|
||||
{
|
||||
var info = gqlServerInfo.Swarm.LocalServer.Information.OAuthProviderInfos.FirstOrDefault(x => (int)x.Key == (int)kvp.Key);
|
||||
var info = gqlServerInfo.Swarm.CurrentNode.Gateway.Information.OAuthProviderInfos.FirstOrDefault(x => (int)x.Key == (int)kvp.Key);
|
||||
return info != null
|
||||
&& info.Value.ServerUrl == kvp.Value.ServerUrl
|
||||
&& info.Value.ClientId == kvp.Value.ClientId
|
||||
|
||||
Reference in New Issue
Block a user