mirror of
https://github.com/tgstation/tgstation-server.git
synced 2026-08-29 16:11:05 +01:00
Merge branch 'dev' of https://github.com/tgstation/tgstation-server into INTEGRATE
This commit is contained in:
@@ -69,4 +69,6 @@ COPY --from=build /repo/build/tgs.docker.sh tgs.sh
|
||||
|
||||
VOLUME ["/config_data", "/tgs_logs", "/app/lib"]
|
||||
|
||||
ENV General__ValidInstancePaths__0 /tgs4_instances
|
||||
|
||||
ENTRYPOINT ["./tgs.sh"]
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace Tgstation.Server.Api.Models
|
||||
/// <summary>
|
||||
/// Channels the Discord bot should listen/announce in
|
||||
/// </summary>
|
||||
public List<ChatChannel> Channels { get; set; }
|
||||
public ICollection<ChatChannel> Channels { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Validates <see cref="Channels"/> are correct for the <see cref="Internal.ChatBot.Provider"/>
|
||||
|
||||
@@ -459,5 +459,11 @@ namespace Tgstation.Server.Api.Models
|
||||
/// </summary>
|
||||
[Description("Encountered merge conflicts while test merging one or more pull requests!")]
|
||||
RepoTestMergeConflict,
|
||||
|
||||
/// <summary>
|
||||
/// Attempted to create an instance outside of the <see cref="Internal.ServerInformation.ValidInstancePaths"/>.
|
||||
/// </summary>
|
||||
[Description("The new instance's path is not under a white-listed path.")]
|
||||
InstanceNotAtWhitelistedPath,
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
namespace Tgstation.Server.Api.Models.Internal
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Tgstation.Server.Api.Models.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for <see cref="Models.ServerInformation"/>.
|
||||
@@ -19,5 +21,10 @@
|
||||
/// The maximum number of <see cref="Models.User"/>s allowed.
|
||||
/// </summary>
|
||||
public uint UserLimit { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Limits the locations instances may be created or attached from.
|
||||
/// </summary>
|
||||
public ICollection<string> ValidInstancePaths { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,11 +13,11 @@ namespace Tgstation.Server.Api.Models
|
||||
/// <summary>
|
||||
/// The <see cref="TestMerge"/>s active in the <see cref="RevisionInformation"/>
|
||||
/// </summary>
|
||||
public List<TestMerge> ActiveTestMerges { get; set; }
|
||||
public ICollection<TestMerge> ActiveTestMerges { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="CompileJob"/>s made from the <see cref="RevisionInformation"/>
|
||||
/// </summary>
|
||||
public List<CompileJob> CompileJobs { get; set; }
|
||||
public ICollection<CompileJob> CompileJobs { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,7 +126,8 @@ namespace Tgstation.Server.Host.Controllers
|
||||
ApiVersion = ApiHeaders.Version,
|
||||
MinimumPasswordLength = generalConfiguration.MinimumPasswordLength,
|
||||
InstanceLimit = generalConfiguration.InstanceLimit,
|
||||
UserLimit = generalConfiguration.UserLimit
|
||||
UserLimit = generalConfiguration.UserLimit,
|
||||
ValidInstancePaths = generalConfiguration.ValidInstancePaths
|
||||
});
|
||||
|
||||
// if we are using a browser and the control panel, soft redirect to the app page
|
||||
|
||||
@@ -151,28 +151,24 @@ namespace Tgstation.Server.Host.Controllers
|
||||
|
||||
var installationDirectoryPath = NormalizePath(DefaultIOManager.CurrentDirectory);
|
||||
|
||||
IActionResult CheckInstanceNotChildOf(string conflictingPath)
|
||||
bool InstanceIsChildOf(string otherPath)
|
||||
{
|
||||
if (targetInstancePath.StartsWith(conflictingPath, StringComparison.Ordinal))
|
||||
{
|
||||
bool sameLength = targetInstancePath.Length == conflictingPath.Length;
|
||||
char dirSeparatorChar = targetInstancePath.ToCharArray()[Math.Min(conflictingPath.Length, targetInstancePath.Length - 1)];
|
||||
if (sameLength
|
||||
|| dirSeparatorChar == Path.DirectorySeparatorChar
|
||||
|| dirSeparatorChar == Path.AltDirectorySeparatorChar)
|
||||
return Conflict(new ErrorMessage(ErrorCode.InstanceAtConflictingPath));
|
||||
}
|
||||
if (!targetInstancePath.StartsWith(otherPath, StringComparison.Ordinal))
|
||||
return false;
|
||||
|
||||
return null;
|
||||
bool sameLength = targetInstancePath.Length == otherPath.Length;
|
||||
char dirSeparatorChar = targetInstancePath.ToCharArray()[Math.Min(otherPath.Length, targetInstancePath.Length - 1)];
|
||||
return sameLength
|
||||
|| dirSeparatorChar == Path.DirectorySeparatorChar
|
||||
|| dirSeparatorChar == Path.AltDirectorySeparatorChar;
|
||||
}
|
||||
|
||||
var earlyOut = CheckInstanceNotChildOf(installationDirectoryPath);
|
||||
if (earlyOut != null)
|
||||
return earlyOut;
|
||||
|
||||
ulong countOfOtherInstances = 0;
|
||||
if (InstanceIsChildOf(installationDirectoryPath))
|
||||
return Conflict(new ErrorMessage(ErrorCode.InstanceAtConflictingPath));
|
||||
|
||||
// Validate it's not a child of any other instance
|
||||
IActionResult earlyOut = null;
|
||||
ulong countOfOtherInstances = 0;
|
||||
using (var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken))
|
||||
{
|
||||
var newCancellationToken = cts.Token;
|
||||
@@ -182,9 +178,9 @@ namespace Tgstation.Server.Host.Controllers
|
||||
otherInstance =>
|
||||
{
|
||||
if (++countOfOtherInstances >= generalConfiguration.InstanceLimit)
|
||||
earlyOut = Conflict(new ErrorMessage(ErrorCode.InstanceLimitReached));
|
||||
else
|
||||
earlyOut = earlyOut ?? CheckInstanceNotChildOf(otherInstance.Path);
|
||||
earlyOut ??= Conflict(new ErrorMessage(ErrorCode.InstanceLimitReached));
|
||||
else if (InstanceIsChildOf(otherInstance.Path))
|
||||
earlyOut ??= Conflict(new ErrorMessage(ErrorCode.InstanceAtConflictingPath));
|
||||
|
||||
if (earlyOut != null && !newCancellationToken.IsCancellationRequested)
|
||||
cts.Cancel();
|
||||
@@ -201,6 +197,12 @@ namespace Tgstation.Server.Host.Controllers
|
||||
if (earlyOut != null)
|
||||
return earlyOut;
|
||||
|
||||
// Last test, ensure it's in the list of valid paths
|
||||
if (!(generalConfiguration.ValidInstancePaths?
|
||||
.Select(path => NormalizePath(path))
|
||||
.Any(path => InstanceIsChildOf(path)) ?? true))
|
||||
return BadRequest(new ErrorMessage(ErrorCode.InstanceNotAtWhitelistedPath));
|
||||
|
||||
async Task<bool> DirExistsAndIsNotEmpty()
|
||||
{
|
||||
if (!await ioManager.DirectoryExists(model.Path, cancellationToken).ConfigureAwait(false))
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
"UseExperimentalWatchdog": false,
|
||||
"UseBasicWatchdogOnWindows": true,
|
||||
"UserLimit": 100,
|
||||
"InstanceLimit": 10
|
||||
"InstanceLimit": 10,
|
||||
"ValidInstancePaths": null
|
||||
},
|
||||
"FileLogging": {
|
||||
"Directory": null,
|
||||
|
||||
@@ -84,6 +84,15 @@ namespace Tgstation.Server.Tests
|
||||
Path = testNonEmpty
|
||||
}, cancellationToken), ErrorCode.InstanceAtExistingPath).ConfigureAwait(false);
|
||||
|
||||
// test can't create instance outside of whitelist
|
||||
await ApiAssert.ThrowsException<ApiConflictException>(() => instanceManagerClient.CreateOrAttach(new Api.Models.Instance
|
||||
{
|
||||
Name = "TestInstanceOutsideOfWhitelist",
|
||||
Path = Path.Combine(testRootPath, "..", Guid.NewGuid().ToString()),
|
||||
Online = true,
|
||||
ChatBotLimit = 1
|
||||
}, cancellationToken), ErrorCode.InstanceNotAtWhitelistedPath);
|
||||
|
||||
//test basic move
|
||||
Directory.Delete(testNonEmpty);
|
||||
var initialPath = firstTest.Path;
|
||||
|
||||
@@ -58,7 +58,7 @@ namespace Tgstation.Server.Tests
|
||||
Console.WriteLine("WARNING: No GitHub access token configured, test may fail due to rate limits!");
|
||||
|
||||
dumpOpenAPISpecpath = !String.IsNullOrEmpty(dumpOpenAPISpecPathEnvVar);
|
||||
|
||||
|
||||
var args = new List<string>()
|
||||
{
|
||||
String.Format(CultureInfo.InvariantCulture, "Kestrel:EndPoints:Http:Url={0}", UrlString),
|
||||
@@ -67,7 +67,8 @@ namespace Tgstation.Server.Tests
|
||||
String.Format(CultureInfo.InvariantCulture, "Database:DropDatabase={0}", true),
|
||||
String.Format(CultureInfo.InvariantCulture, "General:SetupWizardMode={0}", SetupWizardMode.Never),
|
||||
String.Format(CultureInfo.InvariantCulture, "General:InstanceLimit={0}", 10),
|
||||
String.Format(CultureInfo.InvariantCulture, "General:UserLimit={0}", 150)
|
||||
String.Format(CultureInfo.InvariantCulture, "General:UserLimit={0}", 150),
|
||||
String.Format(CultureInfo.InvariantCulture, "General:ValidInstancePaths:0={0}", Directory)
|
||||
};
|
||||
|
||||
if (!String.IsNullOrEmpty(gitHubAccessToken))
|
||||
|
||||
Reference in New Issue
Block a user