mirror of
https://github.com/tgstation/tgstation-server.git
synced 2026-08-23 21:16:52 +01:00
API surface restructuring for GraphQL. Lockdown some API information that wasn't present previously. Validate nodes can be resolved
This commit is contained in:
@@ -461,7 +461,7 @@ namespace Tgstation.Server.Api.Models
|
||||
RepoTestMergeConflict,
|
||||
|
||||
/// <summary>
|
||||
/// Attempted to create an instance outside of the <see cref="Internal.GatewayInformationBase.ValidInstancePaths"/>.
|
||||
/// Attempted to create an instance outside of the <see cref="Internal.ServerInformationBase.ValidInstancePaths"/>.
|
||||
/// </summary>
|
||||
[Description("The new instance's path is not under a white-listed path.")]
|
||||
InstanceNotAtWhitelistedPath,
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Tgstation.Server.Api.Models.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// Information about the local tgstation-server.
|
||||
/// </summary>
|
||||
public class GatewayInformation : GatewayInformationBase
|
||||
{
|
||||
/// <summary>
|
||||
/// If the server is running on a windows operating system.
|
||||
/// </summary>
|
||||
public bool WindowsHost { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Map of <see cref="OAuthProvider"/> to the <see cref="OAuthProviderInfo"/> for them.
|
||||
/// </summary>
|
||||
public Dictionary<OAuthProvider, OAuthProviderInfo>? OAuthProviderInfos { get; set; }
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -5,7 +5,7 @@ namespace Tgstation.Server.Api.Models.Internal
|
||||
/// <summary>
|
||||
/// Base class for <see cref="Response.ServerInformationResponse"/>.
|
||||
/// </summary>
|
||||
public abstract class GatewayInformationBase
|
||||
public abstract class ServerInformationBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Minimum length of database user passwords.
|
||||
@@ -31,6 +31,6 @@ namespace Tgstation.Server.Api.Models.Internal
|
||||
/// Limits the locations instances may be created or attached from.
|
||||
/// </summary>
|
||||
[ResponseOptions]
|
||||
public ICollection<string>? ValidInstancePaths { get; set; }
|
||||
public List<string>? ValidInstancePaths { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ namespace Tgstation.Server.Api.Models.Response
|
||||
/// <summary>
|
||||
/// Represents basic server information.
|
||||
/// </summary>
|
||||
public sealed class ServerInformationResponse : Internal.GatewayInformation
|
||||
public sealed class ServerInformationResponse : Internal.ServerInformationBase
|
||||
{
|
||||
/// <summary>
|
||||
/// The version of the host.
|
||||
@@ -23,6 +23,16 @@ namespace Tgstation.Server.Api.Models.Response
|
||||
/// </summary>
|
||||
public Version? DMApiVersion { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If the server is running on a windows operating system.
|
||||
/// </summary>
|
||||
public bool WindowsHost { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Map of <see cref="OAuthProvider"/> to the <see cref="OAuthProviderInfo"/> for them.
|
||||
/// </summary>
|
||||
public Dictionary<OAuthProvider, OAuthProviderInfo>? OAuthProviderInfos { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If there is a server update in progress.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
query UnauthenticatedServerInformation {
|
||||
swarm {
|
||||
currentNode {
|
||||
gateway {
|
||||
information {
|
||||
majorApiVersion
|
||||
oAuthProviderInfos {
|
||||
key
|
||||
value {
|
||||
clientId
|
||||
redirectUri
|
||||
serverUrl
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@ namespace Tgstation.Server.Host.Configuration
|
||||
/// <summary>
|
||||
/// General configuration options.
|
||||
/// </summary>
|
||||
public sealed class GeneralConfiguration : GatewayInformationBase
|
||||
public sealed class GeneralConfiguration : ServerInformationBase
|
||||
{
|
||||
/// <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="GatewayInformationBase.MinimumPasswordLength"/>.
|
||||
/// The default value for <see cref="ServerInformationBase.MinimumPasswordLength"/>.
|
||||
/// </summary>
|
||||
const uint DefaultMinimumPasswordLength = 15;
|
||||
|
||||
/// <summary>
|
||||
/// The default value for <see cref="GatewayInformationBase.InstanceLimit"/>.
|
||||
/// The default value for <see cref="ServerInformationBase.InstanceLimit"/>.
|
||||
/// </summary>
|
||||
const uint DefaultInstanceLimit = 10;
|
||||
|
||||
/// <summary>
|
||||
/// The default value for <see cref="GatewayInformationBase.UserLimit"/>.
|
||||
/// The default value for <see cref="ServerInformationBase.UserLimit"/>.
|
||||
/// </summary>
|
||||
const uint DefaultUserLimit = 100;
|
||||
|
||||
/// <summary>
|
||||
/// The default value for <see cref="GatewayInformationBase.UserGroupLimit"/>.
|
||||
/// The default value for <see cref="ServerInformationBase.UserGroupLimit"/>.
|
||||
/// </summary>
|
||||
const uint DefaultUserGroupLimit = 25;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Frozen;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
@@ -57,7 +57,6 @@ 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.Interceptors;
|
||||
using Tgstation.Server.Host.GraphQL.Types.Scalars;
|
||||
using Tgstation.Server.Host.IO;
|
||||
using Tgstation.Server.Host.Jobs;
|
||||
@@ -297,7 +296,10 @@ namespace Tgstation.Server.Host.Core
|
||||
services
|
||||
.AddGraphQLServer(disableCostAnalyzer: true)
|
||||
.AddAuthorization()
|
||||
.TryAddTypeInterceptor<PublicAuthorizeDirectiveTypeInterceptor>()
|
||||
.ModifyOptions(options =>
|
||||
{
|
||||
options.EnsureAllNodesCanBeResolved = true;
|
||||
})
|
||||
.AddMutationConventions()
|
||||
.AddGlobalObjectIdentification()
|
||||
.AddQueryFieldToMutationPayloads()
|
||||
@@ -314,6 +316,7 @@ namespace Tgstation.Server.Host.Core
|
||||
.AddSorting()
|
||||
.AddHostTypes()
|
||||
.AddErrorFilter<ErrorMessageFilter>()
|
||||
.AddType<StandaloneNode>()
|
||||
.AddType<LocalGateway>()
|
||||
.AddType<RemoteGateway>()
|
||||
.AddType<GraphQL.Types.UserName>()
|
||||
|
||||
@@ -1,12 +1,4 @@
|
||||
using HotChocolate;
|
||||
using HotChocolate.Authorization;
|
||||
|
||||
using Microsoft.Extensions.Options;
|
||||
using Tgstation.Server.Api.Models.Internal;
|
||||
using Tgstation.Server.Host.Configuration;
|
||||
using Tgstation.Server.Host.GraphQL.Types;
|
||||
using Tgstation.Server.Host.Security.OAuth;
|
||||
using Tgstation.Server.Host.System;
|
||||
using Tgstation.Server.Host.GraphQL.Types;
|
||||
|
||||
namespace Tgstation.Server.Host.GraphQL.Interfaces
|
||||
{
|
||||
@@ -18,14 +10,7 @@ namespace Tgstation.Server.Host.GraphQL.Interfaces
|
||||
/// <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);
|
||||
/// <returns>The <see cref="GatewayInformation"/> for the <see cref="IGateway"/>.</returns>
|
||||
GatewayInformation Information();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
using HotChocolate;
|
||||
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
using Tgstation.Server.Host.Configuration;
|
||||
|
||||
namespace Tgstation.Server.Host.GraphQL.Interfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a tgstation-server installation.
|
||||
/// </summary>
|
||||
public interface IServerNode
|
||||
{
|
||||
/// <summary>
|
||||
/// Access the <see cref="IGateway"/> for the <see cref="IServerNode"/>.
|
||||
/// </summary>
|
||||
/// <param name="swarmConfigurationOptions">The <see cref="IOptionsSnapshot{TOptions}"/> of <see cref="SwarmConfiguration"/>.</param>
|
||||
/// <returns>The <see cref="IGateway"/> for the <see cref="IServerNode"/>.</returns>
|
||||
public IGateway Gateway([Service] IOptionsSnapshot<SwarmConfiguration> swarmConfigurationOptions);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using HotChocolate;
|
||||
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
using Tgstation.Server.Api;
|
||||
using Tgstation.Server.Api.Models;
|
||||
using Tgstation.Server.Api.Rights;
|
||||
using Tgstation.Server.Host.Components.Interop;
|
||||
using Tgstation.Server.Host.Configuration;
|
||||
using Tgstation.Server.Host.Properties;
|
||||
using Tgstation.Server.Host.Security;
|
||||
using Tgstation.Server.Host.Security.OAuth;
|
||||
using Tgstation.Server.Host.System;
|
||||
|
||||
namespace Tgstation.Server.Host.GraphQL.Types
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents information about a <see cref="SwarmNode"/> retrieved via a <see cref="Interfaces.IGateway"/>.
|
||||
/// </summary>
|
||||
public sealed class GatewayInformation
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the minimum valid password length for TGS users.
|
||||
/// </summary>
|
||||
/// <param name="generalConfigurationOptions">The <see cref="IOptionsSnapshot{TOptions}"/> containing the <see cref="GeneralConfiguration"/>.</param>
|
||||
/// <returns>A <see cref="uint"/> specifying the minimumn valid password length for TGS users.</returns>
|
||||
[TgsGraphQLAuthorize(AdministrationRights.WriteUsers | AdministrationRights.EditOwnPassword)]
|
||||
public uint? MinimumPasswordLength(
|
||||
[Service] IOptionsSnapshot<GeneralConfiguration> generalConfigurationOptions)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(generalConfigurationOptions);
|
||||
return generalConfigurationOptions.Value.MinimumPasswordLength;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the maximum allowed attached instances for the <see cref="SwarmNode"/>.
|
||||
/// </summary>
|
||||
/// <param name="generalConfigurationOptions">The <see cref="IOptionsSnapshot{TOptions}"/> containing the <see cref="GeneralConfiguration"/>.</param>
|
||||
/// <returns>A <see cref="uint"/> specifying the maximum allowed attached instances for the <see cref="SwarmNode"/>.</returns>
|
||||
[TgsGraphQLAuthorize(InstanceManagerRights.Create)]
|
||||
public uint? InstanceLimit(
|
||||
[Service] IOptionsSnapshot<GeneralConfiguration> generalConfigurationOptions)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(generalConfigurationOptions);
|
||||
return generalConfigurationOptions.Value.InstanceLimit;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the maximum allowed registered <see cref="User"/>s for the <see cref="ServerSwarm"/>.
|
||||
/// </summary>
|
||||
/// <param name="generalConfigurationOptions">The <see cref="IOptionsSnapshot{TOptions}"/> containing the <see cref="GeneralConfiguration"/>.</param>
|
||||
/// <returns>A <see cref="uint"/> specifying the maximum allowed registered users for the <see cref="ServerSwarm"/>.</returns>
|
||||
/// <remarks>This limit only applies to user creation attempts made via the current <see cref="SwarmNode"/>.</remarks>
|
||||
[TgsGraphQLAuthorize(AdministrationRights.WriteUsers)]
|
||||
public uint? UserLimit(
|
||||
[Service] IOptionsSnapshot<GeneralConfiguration> generalConfigurationOptions)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(generalConfigurationOptions);
|
||||
return generalConfigurationOptions.Value.UserLimit;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the maximum allowed registered <see cref="UserGroup"/>s for the <see cref="ServerSwarm"/>.
|
||||
/// </summary>
|
||||
/// <param name="generalConfigurationOptions">The <see cref="IOptionsSnapshot{TOptions}"/> containing the <see cref="GeneralConfiguration"/>.</param>
|
||||
/// <returns>A <see cref="uint"/> specifying the maximum allowed registered <see cref="UserGroup"/>s for the <see cref="ServerSwarm"/>.</returns>
|
||||
/// <remarks>This limit only applies to <see cref="UserGroup"/> creation attempts made via the current <see cref="SwarmNode"/>.</remarks>
|
||||
[TgsGraphQLAuthorize(AdministrationRights.WriteUsers)]
|
||||
public uint? UserGroupLimit(
|
||||
[Service] IOptionsSnapshot<GeneralConfiguration> generalConfigurationOptions)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(generalConfigurationOptions);
|
||||
return generalConfigurationOptions.Value.UserGroupLimit;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the locations <see cref="Instance"/>s may be created or attached from if there are restrictions.
|
||||
/// </summary>
|
||||
/// <param name="generalConfigurationOptions">The <see cref="IOptionsSnapshot{TOptions}"/> containing the <see cref="GeneralConfiguration"/>.</param>
|
||||
/// <returns>The locations <see cref="Instance"/>s may be created or attached from if there are restrictions, <see langword="null"/> otherwise.</returns>
|
||||
[TgsGraphQLAuthorize(InstanceManagerRights.Create | InstanceManagerRights.Relocate)]
|
||||
public IReadOnlyCollection<string>? ValidInstancePaths(
|
||||
[Service] IOptionsSnapshot<GeneralConfiguration> generalConfigurationOptions)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(generalConfigurationOptions);
|
||||
return generalConfigurationOptions.Value.ValidInstancePaths;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a flag indicating whether or not the current <see cref="SwarmNode"/> runs on a Windows operating system.
|
||||
/// </summary>
|
||||
/// <param name="platformIdentifier">The <see cref="IPlatformIdentifier"/> to use.</param>
|
||||
/// <returns><see langword="true"/> if the <see cref="SwarmNode"/> runs on a Windows operating system, <see langword="false"/> otherwise.</returns>
|
||||
[TgsGraphQLAuthorize]
|
||||
public bool? WindowsHost(
|
||||
[Service] IPlatformIdentifier platformIdentifier)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(platformIdentifier);
|
||||
return platformIdentifier.IsWindows;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the swarm protocol <see cref="Version"/>.
|
||||
/// </summary>
|
||||
[TgsGraphQLAuthorize]
|
||||
public Version? SwarmProtocolVersion => global::System.Version.Parse(MasterVersionsAttribute.Instance.RawSwarmProtocolVersion);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="global::System.Version"/> of tgstation-server the <see cref="SwarmNode"/> is running.
|
||||
/// </summary>
|
||||
/// <param name="assemblyInformationProvider">The <see cref="IAssemblyInformationProvider"/> to use.</param>
|
||||
/// <returns>The <see cref="global::System.Version"/> of tgstation-server the <see cref="SwarmNode"/> is running.</returns>
|
||||
[TgsGraphQLAuthorize]
|
||||
public Version? Version(
|
||||
[Service] IAssemblyInformationProvider assemblyInformationProvider)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(assemblyInformationProvider);
|
||||
return assemblyInformationProvider.Version;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the major HTTP API <see cref="global::System.Version"/> number of the <see cref="SwarmNode"/>.
|
||||
/// </summary>
|
||||
public int MajorApiVersion => ApiHeaders.Version.Major;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the HTTP API <see cref="global::System.Version"/> of the <see cref="SwarmNode"/>.
|
||||
/// </summary>
|
||||
[TgsGraphQLAuthorize]
|
||||
public Version? ApiVersion => ApiHeaders.Version;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the DMAPI interop <see cref="global::System.Version"/> the <see cref="SwarmNode"/> uses.
|
||||
/// </summary>
|
||||
[TgsGraphQLAuthorize]
|
||||
public Version? DMApiVersion => DMApiConstants.InteropVersion;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the information needed to perform open authentication with the <see cref="SwarmNode"/>.
|
||||
/// </summary>
|
||||
/// <param name="oAuthProviders">The <see cref="IOAuthProviders"/> to use.</param>
|
||||
/// <returns>A map of enabled <see cref="OAuthProvider"/>s to their <see cref="OAuthProviderInfo"/>.</returns>
|
||||
public IReadOnlyDictionary<OAuthProvider, OAuthProviderInfo> OAuthProviderInfos(
|
||||
[Service] IOAuthProviders oAuthProviders)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(oAuthProviders);
|
||||
return oAuthProviders.ProviderInfos();
|
||||
}
|
||||
}
|
||||
}
|
||||
-23
@@ -1,23 +0,0 @@
|
||||
using HotChocolate.Configuration;
|
||||
using HotChocolate.Types.Descriptors.Definitions;
|
||||
|
||||
namespace Tgstation.Server.Host.GraphQL.Types.Interceptors
|
||||
{
|
||||
/// <summary>
|
||||
/// Makes the @authorize directive public (It is internal by default).
|
||||
/// </summary>
|
||||
public sealed class PublicAuthorizeDirectiveTypeInterceptor : TypeInterceptor
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override void OnBeforeRegisterDependencies(ITypeDiscoveryContext discoveryContext, DefinitionBase definition)
|
||||
{
|
||||
if (definition is DirectiveTypeDefinition dtd
|
||||
&& dtd.Name == "authorize")
|
||||
{
|
||||
dtd.IsPublic = true;
|
||||
}
|
||||
|
||||
base.OnBeforeRegisterDependencies(discoveryContext, definition);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,4 @@
|
||||
using System;
|
||||
|
||||
using HotChocolate;
|
||||
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
using Tgstation.Server.Api.Models.Internal;
|
||||
using Tgstation.Server.Host.Configuration;
|
||||
using Tgstation.Server.Host.GraphQL.Interfaces;
|
||||
using Tgstation.Server.Host.Security.OAuth;
|
||||
using Tgstation.Server.Host.System;
|
||||
using Tgstation.Server.Host.GraphQL.Interfaces;
|
||||
|
||||
namespace Tgstation.Server.Host.GraphQL.Types
|
||||
{
|
||||
@@ -18,26 +8,6 @@ namespace Tgstation.Server.Host.GraphQL.Types
|
||||
public sealed class LocalGateway : IGateway
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public GatewayInformation Information(
|
||||
[Service] IOAuthProviders oAuthProviders,
|
||||
[Service] IPlatformIdentifier platformIdentifier,
|
||||
[Service] IOptionsSnapshot<GeneralConfiguration> generalConfigurationOptions)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(oAuthProviders);
|
||||
ArgumentNullException.ThrowIfNull(platformIdentifier);
|
||||
ArgumentNullException.ThrowIfNull(generalConfigurationOptions);
|
||||
|
||||
var generalConfiguration = generalConfigurationOptions.Value;
|
||||
return new GatewayInformation
|
||||
{
|
||||
MinimumPasswordLength = generalConfiguration.MinimumPasswordLength,
|
||||
InstanceLimit = generalConfiguration.InstanceLimit,
|
||||
UserLimit = generalConfiguration.UserLimit,
|
||||
UserGroupLimit = generalConfiguration.UserGroupLimit,
|
||||
ValidInstancePaths = generalConfiguration.ValidInstancePaths,
|
||||
WindowsHost = platformIdentifier.IsWindows,
|
||||
OAuthProviderInfos = oAuthProviders.ProviderInfos(),
|
||||
};
|
||||
}
|
||||
public GatewayInformation Information() => new();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
using HotChocolate;
|
||||
using HotChocolate.Types.Relay;
|
||||
|
||||
using Tgstation.Server.Host.Swarm;
|
||||
|
||||
namespace Tgstation.Server.Host.GraphQL.Types
|
||||
{
|
||||
/// <summary>
|
||||
/// Represent a server in the TGS server swarm.
|
||||
/// </summary>
|
||||
[Node]
|
||||
public sealed class NodeInformation
|
||||
{
|
||||
/// <summary>
|
||||
/// Node resolver for <see cref="NodeInformation"/>s.
|
||||
/// </summary>
|
||||
/// <param name="identifier">The <see cref="Identifier"/> to lookup.</param>
|
||||
/// <param name="swarmService">The <see cref="ISwarmService"/> to use.</param>
|
||||
/// <returns>The queried <see cref="NodeInformation"/>, if present.</returns>
|
||||
public NodeInformation? GetNodeInformation(
|
||||
string identifier,
|
||||
[Service] ISwarmService swarmService)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(identifier);
|
||||
ArgumentNullException.ThrowIfNull(swarmService);
|
||||
|
||||
var node = swarmService.GetSwarmServers()
|
||||
?.FirstOrDefault(node => node.Identifier == identifier);
|
||||
if (node == null)
|
||||
return null;
|
||||
|
||||
return new NodeInformation(node);
|
||||
}
|
||||
|
||||
/// <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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,5 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
using HotChocolate.Types.Relay;
|
||||
|
||||
using Tgstation.Server.Api.Rights;
|
||||
|
||||
namespace Tgstation.Server.Host.GraphQL.Types
|
||||
@@ -9,7 +7,6 @@ namespace Tgstation.Server.Host.GraphQL.Types
|
||||
/// <summary>
|
||||
/// Represents a set of permissions for the server.
|
||||
/// </summary>
|
||||
[Node]
|
||||
public sealed class PermissionSet : Entity
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -1,15 +1,6 @@
|
||||
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.GraphQL.Interfaces;
|
||||
using Tgstation.Server.Host.Security.OAuth;
|
||||
using Tgstation.Server.Host.System;
|
||||
|
||||
namespace Tgstation.Server.Host.GraphQL.Types
|
||||
{
|
||||
@@ -20,16 +11,6 @@ namespace Tgstation.Server.Host.GraphQL.Types
|
||||
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);
|
||||
}
|
||||
public GatewayInformation Information() => throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,8 +8,10 @@ using Microsoft.Extensions.Options;
|
||||
|
||||
using Tgstation.Server.Host.Configuration;
|
||||
using Tgstation.Server.Host.Core;
|
||||
using Tgstation.Server.Host.GraphQL.Interfaces;
|
||||
using Tgstation.Server.Host.Properties;
|
||||
using Tgstation.Server.Host.Security;
|
||||
using Tgstation.Server.Host.Swarm;
|
||||
using Tgstation.Server.Host.System;
|
||||
|
||||
namespace Tgstation.Server.Host.GraphQL.Types
|
||||
{
|
||||
@@ -19,56 +21,62 @@ namespace Tgstation.Server.Host.GraphQL.Types
|
||||
public sealed class ServerSwarm
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the <see cref="SwarmMetadata"/> for the swarm.
|
||||
/// If there is a swarm update in progress.
|
||||
/// </summary>
|
||||
/// <param name="assemblyInformationProvider">The <see cref="IAssemblyInformationProvider"/> to use.</param>
|
||||
/// <param name="serverControl">The <see cref="IServerControl"/> to use.</param>
|
||||
/// <returns>A new <see cref="SwarmMetadata"/>.</returns>
|
||||
public SwarmMetadata Metadata(
|
||||
[Service] IAssemblyInformationProvider assemblyInformationProvider,
|
||||
/// <returns><see langword="true"/> if there is an update in progress, <see langword="false"/> otherwise.</returns>
|
||||
[TgsGraphQLAuthorize]
|
||||
public bool UpdateInProgress(
|
||||
[Service] IServerControl serverControl)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(assemblyInformationProvider);
|
||||
ArgumentNullException.ThrowIfNull(serverControl);
|
||||
return new SwarmMetadata(assemblyInformationProvider, serverControl.UpdateInProgress);
|
||||
return serverControl.UpdateInProgress;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the swarm protocol major version in use.
|
||||
/// </summary>
|
||||
[TgsGraphQLAuthorize]
|
||||
public int ProtocolMajorVersion => Version.Parse(MasterVersionsAttribute.Instance.RawSwarmProtocolVersion).Major;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the swarm's <see cref="Types.Users"/>.
|
||||
/// </summary>
|
||||
/// <returns>A new <see cref="Types.Users"/>.</returns>
|
||||
[TgsGraphQLAuthorize]
|
||||
public Users Users() => new();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the connected <see cref="SwarmNode"/> server.
|
||||
/// </summary>
|
||||
/// <param name="swarmService">The <see cref="ISwarmService"/> to use.</param>
|
||||
/// <param name="swarmConfigurationOptions">The <see cref="IOptionsSnapshot{TOptions}"/> containing the current <see cref="SwarmConfiguration"/>.</param>
|
||||
/// <returns>A new <see cref="SwarmNode"/>.</returns>
|
||||
public SwarmNode CurrentNode(
|
||||
[Service] ISwarmService swarmService,
|
||||
[Service] IOptionsSnapshot<SwarmConfiguration> swarmConfigurationOptions)
|
||||
/// <param name="swarmService">The <see cref="ISwarmService"/> to use.</param>
|
||||
/// <returns>A new <see cref="SwarmNode"/> for the local node if it is part of a swarm, <see langword="null"/> otherwise.</returns>
|
||||
public IServerNode CurrentNode(
|
||||
[Service] IOptionsSnapshot<SwarmConfiguration> swarmConfigurationOptions,
|
||||
[Service] ISwarmService swarmService)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(swarmService);
|
||||
ArgumentNullException.ThrowIfNull(swarmConfigurationOptions);
|
||||
ArgumentNullException.ThrowIfNull(swarmService);
|
||||
|
||||
var nodeInfos = Nodes(swarmService);
|
||||
if (nodeInfos != null)
|
||||
return nodeInfos.First(x => x.Info!.Identifier == swarmConfigurationOptions.Value.Identifier);
|
||||
var ourIdentifier = swarmConfigurationOptions.Value.Identifier;
|
||||
if (ourIdentifier == null)
|
||||
return new StandaloneNode();
|
||||
|
||||
return new SwarmNode(null);
|
||||
return (IServerNode?)SwarmNode.GetSwarmNode(ourIdentifier, swarmService) ?? new StandaloneNode();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all <see cref="SwarmNode"/> servers in the swarm.
|
||||
/// </summary>
|
||||
/// <param name="swarmService">The <see cref="ISwarmService"/> to use.</param>
|
||||
/// <returns>A <see cref="List{T}"/> of <see cref="SwarmNode"/>s if the local server is part of a swarm, <see langword="null"/> otherwise.</returns>
|
||||
/// <returns>A <see cref="List{T}"/> of <see cref="SwarmNode"/>s if the local node is part of a swarm, <see langword="null"/> otherwise.</returns>
|
||||
[TgsGraphQLAuthorize]
|
||||
public List<SwarmNode>? Nodes(
|
||||
[Service] ISwarmService swarmService)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(swarmService);
|
||||
return swarmService.GetSwarmServers()?.Select(x => new SwarmNode(new NodeInformation(x))).ToList();
|
||||
return swarmService.GetSwarmServers()?.Select(x => new SwarmNode(x)).ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
using HotChocolate;
|
||||
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
using Tgstation.Server.Host.Configuration;
|
||||
using Tgstation.Server.Host.GraphQL.Interfaces;
|
||||
|
||||
namespace Tgstation.Server.Host.GraphQL.Types
|
||||
{
|
||||
/// <summary>
|
||||
/// A <see cref="IServerNode"/> not running as part of a larger <see cref="ServerSwarm"/>.
|
||||
/// </summary>
|
||||
public sealed class StandaloneNode : IServerNode
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public IGateway Gateway([Service] IOptionsSnapshot<SwarmConfiguration> swarmConfigurationOptions)
|
||||
=> new LocalGateway();
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
using System;
|
||||
|
||||
using Tgstation.Server.Api;
|
||||
using Tgstation.Server.Host.Components.Interop;
|
||||
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"/>.
|
||||
/// </summary>
|
||||
public sealed class SwarmMetadata
|
||||
{
|
||||
/// <summary>
|
||||
/// The version of the host.
|
||||
/// </summary>
|
||||
public Version Version { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="Api"/> version of the host.
|
||||
/// </summary>
|
||||
public Version ApiVersion => ApiHeaders.Version;
|
||||
|
||||
/// <summary>
|
||||
/// The DMAPI interop version the server uses.
|
||||
/// </summary>
|
||||
public Version DMApiVersion => DMApiConstants.InteropVersion;
|
||||
|
||||
/// <summary>
|
||||
/// If there is a server update in progress.
|
||||
/// </summary>
|
||||
public bool UpdateInProgress { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SwarmMetadata"/> class.
|
||||
/// </summary>
|
||||
/// <param name="assemblyInformationProvider">The <see cref="IAssemblyInformationProvider"/> used to derive the <see cref="Version"/>.</param>
|
||||
/// <param name="updateInProgress">The value of <see cref="UpdateInProgress"/>.</param>
|
||||
public SwarmMetadata(IAssemblyInformationProvider assemblyInformationProvider, bool updateInProgress)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(assemblyInformationProvider);
|
||||
Version = assemblyInformationProvider.Version;
|
||||
UpdateInProgress = updateInProgress;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,32 +1,80 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
using HotChocolate;
|
||||
using HotChocolate.Types.Relay;
|
||||
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
using Tgstation.Server.Api.Models;
|
||||
using Tgstation.Server.Api.Models.Internal;
|
||||
using Tgstation.Server.Host.Configuration;
|
||||
using Tgstation.Server.Host.GraphQL.Interfaces;
|
||||
using Tgstation.Server.Host.Swarm;
|
||||
|
||||
namespace Tgstation.Server.Host.GraphQL.Types
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a node server in a swarm.
|
||||
/// </summary>
|
||||
public sealed class SwarmNode
|
||||
[Node(IdField = nameof(Identifier))]
|
||||
public sealed class SwarmNode : IServerNode
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the <see cref="NodeInformation"/>.
|
||||
/// The swarm server ID.
|
||||
/// </summary>
|
||||
public NodeInformation? Info { get; }
|
||||
[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>
|
||||
/// Node resolver for <see cref="SwarmNode"/>s.
|
||||
/// </summary>
|
||||
/// <param name="identifier">The <see cref="Identifier"/>.</param>
|
||||
/// <param name="swarmService">The <see cref="ISwarmService"/> to load from.</param>
|
||||
/// <returns>A new <see cref="SwarmNode"/> with the matching <paramref name="identifier"/> if found, <see langword="null"/> otherwise.</returns>
|
||||
public static SwarmNode? GetSwarmNode(
|
||||
string identifier,
|
||||
[Service] ISwarmService swarmService)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(identifier);
|
||||
ArgumentNullException.ThrowIfNull(swarmService);
|
||||
var info = swarmService
|
||||
.GetSwarmServers()
|
||||
?.FirstOrDefault(x => x.Identifier == identifier);
|
||||
|
||||
if (info == null)
|
||||
return null;
|
||||
|
||||
return new SwarmNode(info);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SwarmNode"/> class.
|
||||
/// </summary>
|
||||
/// <param name="info">The value of <see cref="Info"/>.</param>
|
||||
public SwarmNode(NodeInformation? info)
|
||||
/// <param name="nodeInformation">The <see cref="SwarmServerInformation"/> to use for initialization.</param>
|
||||
public SwarmNode(SwarmServerInformation? nodeInformation)
|
||||
{
|
||||
Info = info;
|
||||
ArgumentNullException.ThrowIfNull(nodeInformation);
|
||||
|
||||
Identifier = nodeInformation.Identifier!;
|
||||
Address = nodeInformation.Address!;
|
||||
PublicAddress = nodeInformation.PublicAddress;
|
||||
Controller = nodeInformation.Controller;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -35,11 +83,11 @@ namespace Tgstation.Server.Host.GraphQL.Types
|
||||
/// <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="SwarmNode"/>'s <see cref="IGateway"/>.</remarks>
|
||||
public IGateway? Gateway([Service] IOptionsSnapshot<SwarmConfiguration> swarmConfigurationOptions)
|
||||
public IGateway Gateway([Service] IOptionsSnapshot<SwarmConfiguration> swarmConfigurationOptions)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(swarmConfigurationOptions);
|
||||
|
||||
bool local = Info == null || Info.Identifier == swarmConfigurationOptions.Value.Identifier;
|
||||
bool local = Identifier == swarmConfigurationOptions.Value.Identifier;
|
||||
if (local)
|
||||
return new LocalGateway();
|
||||
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
using System;
|
||||
|
||||
using HotChocolate.Authorization;
|
||||
|
||||
using Tgstation.Server.Api.Rights;
|
||||
|
||||
namespace Tgstation.Server.Host.Security
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper for using the <see cref="AuthorizeAttribute"/> with the <see cref="Api.Rights"/> system.
|
||||
/// </summary>
|
||||
#pragma warning disable CA1019
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = true, Inherited = true)]
|
||||
sealed class TgsGraphQLAuthorizeAttribute : AuthorizeAttribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the <see cref="Api.Rights.RightsType"/> associated with the <see cref="TgsAuthorizeAttribute"/> if any.
|
||||
/// </summary>
|
||||
public RightsType? RightsType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TgsGraphQLAuthorizeAttribute"/> class.
|
||||
/// </summary>
|
||||
public TgsGraphQLAuthorizeAttribute()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TgsGraphQLAuthorizeAttribute"/> class.
|
||||
/// </summary>
|
||||
/// <param name="requiredRights">The <see cref="AdministrationRights"/> required.</param>
|
||||
public TgsGraphQLAuthorizeAttribute(AdministrationRights requiredRights)
|
||||
{
|
||||
Roles = RightsHelper.RoleNames(requiredRights).Split(',');
|
||||
RightsType = Api.Rights.RightsType.Administration;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TgsGraphQLAuthorizeAttribute"/> class.
|
||||
/// </summary>
|
||||
/// <param name="requiredRights">The <see cref="InstanceManagerRights"/> required.</param>
|
||||
public TgsGraphQLAuthorizeAttribute(InstanceManagerRights requiredRights)
|
||||
{
|
||||
Roles = RightsHelper.RoleNames(requiredRights).Split(',');
|
||||
RightsType = Api.Rights.RightsType.InstanceManager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TgsGraphQLAuthorizeAttribute"/> class.
|
||||
/// </summary>
|
||||
/// <param name="requiredRights">The <see cref="RepositoryRights"/> required.</param>
|
||||
public TgsGraphQLAuthorizeAttribute(RepositoryRights requiredRights)
|
||||
{
|
||||
Roles = RightsHelper.RoleNames(requiredRights).Split(',');
|
||||
RightsType = Api.Rights.RightsType.Repository;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TgsGraphQLAuthorizeAttribute"/> class.
|
||||
/// </summary>
|
||||
/// <param name="requiredRights">The <see cref="EngineRights"/> required.</param>
|
||||
public TgsGraphQLAuthorizeAttribute(EngineRights requiredRights)
|
||||
{
|
||||
Roles = RightsHelper.RoleNames(requiredRights).Split(',');
|
||||
RightsType = Api.Rights.RightsType.Engine;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TgsGraphQLAuthorizeAttribute"/> class.
|
||||
/// </summary>
|
||||
/// <param name="requiredRights">The <see cref="DreamMakerRights"/> required.</param>
|
||||
public TgsGraphQLAuthorizeAttribute(DreamMakerRights requiredRights)
|
||||
{
|
||||
Roles = RightsHelper.RoleNames(requiredRights).Split(',');
|
||||
RightsType = Api.Rights.RightsType.DreamMaker;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TgsGraphQLAuthorizeAttribute"/> class.
|
||||
/// </summary>
|
||||
/// <param name="requiredRights">The <see cref="DreamDaemonRights"/> required.</param>
|
||||
public TgsGraphQLAuthorizeAttribute(DreamDaemonRights requiredRights)
|
||||
{
|
||||
Roles = RightsHelper.RoleNames(requiredRights).Split(',');
|
||||
RightsType = Api.Rights.RightsType.DreamDaemon;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TgsGraphQLAuthorizeAttribute"/> class.
|
||||
/// </summary>
|
||||
/// <param name="requiredRights">The <see cref="ChatBotRights"/> required.</param>
|
||||
public TgsGraphQLAuthorizeAttribute(ChatBotRights requiredRights)
|
||||
{
|
||||
Roles = RightsHelper.RoleNames(requiredRights).Split(',');
|
||||
RightsType = Api.Rights.RightsType.ChatBots;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TgsGraphQLAuthorizeAttribute"/> class.
|
||||
/// </summary>
|
||||
/// <param name="requiredRights">The <see cref="ConfigurationRights"/> required.</param>
|
||||
public TgsGraphQLAuthorizeAttribute(ConfigurationRights requiredRights)
|
||||
{
|
||||
Roles = RightsHelper.RoleNames(requiredRights).Split(',');
|
||||
RightsType = Api.Rights.RightsType.Configuration;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TgsGraphQLAuthorizeAttribute"/> class.
|
||||
/// </summary>
|
||||
/// <param name="requiredRights">The <see cref="InstancePermissionSetRights"/> required.</param>
|
||||
public TgsGraphQLAuthorizeAttribute(InstancePermissionSetRights requiredRights)
|
||||
{
|
||||
Roles = RightsHelper.RoleNames(requiredRights).Split(',');
|
||||
RightsType = Api.Rights.RightsType.InstancePermissionSet;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1380,23 +1380,8 @@ namespace Tgstation.Server.Tests.Live
|
||||
|
||||
await multiClient.ExecuteReadOnlyConfirmEquivalence(
|
||||
restClient => restClient.ServerInformation(cancellationToken),
|
||||
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.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.Info.Address,
|
||||
PublicAddress = x.Info.PublicAddress,
|
||||
Controller = x.Info.Controller,
|
||||
Identifier = x.Info.Identifier,
|
||||
}))))
|
||||
async gqlClient => (await gqlClient.UnauthenticatedServerInformation.ExecuteAsync(cancellationToken)).Data,
|
||||
(restServerInfo, gqlServerInfo) => restServerInfo.ApiVersion.Major == gqlServerInfo.Swarm.CurrentNode.Gateway.Information.MajorApiVersion
|
||||
&& (restServerInfo.OAuthProviderInfos == gqlServerInfo.Swarm.CurrentNode.Gateway.Information.OAuthProviderInfos
|
||||
|| restServerInfo.OAuthProviderInfos.All(kvp =>
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user