From b51f147cd8f5153131a4efd7f989127be445632d Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Mon, 15 Oct 2018 10:38:42 -0400 Subject: [PATCH 01/27] Add IPlatformIdentifier --- .../Core/IPlatformIdentifier.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 src/Tgstation.Server.Host/Core/IPlatformIdentifier.cs diff --git a/src/Tgstation.Server.Host/Core/IPlatformIdentifier.cs b/src/Tgstation.Server.Host/Core/IPlatformIdentifier.cs new file mode 100644 index 0000000000..74e3484a79 --- /dev/null +++ b/src/Tgstation.Server.Host/Core/IPlatformIdentifier.cs @@ -0,0 +1,13 @@ +namespace Tgstation.Server.Host.Core +{ + /// + /// For identifying the current platform + /// + interface IPlatformIdentifier + { + /// + /// If the current platform is a Windows platform + /// + bool IsWindows { get; } + } +} From f9064cb2ccbc6be4e39a1ca4d3a4a9f24e9597d5 Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Mon, 15 Oct 2018 10:38:49 -0400 Subject: [PATCH 02/27] Add PlatformIdentifier --- .../Core/PlatformIdentifier.cs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 src/Tgstation.Server.Host/Core/PlatformIdentifier.cs diff --git a/src/Tgstation.Server.Host/Core/PlatformIdentifier.cs b/src/Tgstation.Server.Host/Core/PlatformIdentifier.cs new file mode 100644 index 0000000000..fbed84baf9 --- /dev/null +++ b/src/Tgstation.Server.Host/Core/PlatformIdentifier.cs @@ -0,0 +1,19 @@ +using System.Runtime.InteropServices; + +namespace Tgstation.Server.Host.Core +{ + /// + sealed class PlatformIdentifier : IPlatformIdentifier + { + /// + public bool IsWindows { get; } + + /// + /// Construct a + /// + public PlatformIdentifier() + { + IsWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); + } + } +} From 8b9496166e289a8ad051264817e69d32731bab7a Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Mon, 15 Oct 2018 10:40:28 -0400 Subject: [PATCH 03/27] Add TestPlatformIdentifier --- .../Core/TestPlatformIdentifier.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 tests/Tgstation.Server.Host.Tests/Core/TestPlatformIdentifier.cs diff --git a/tests/Tgstation.Server.Host.Tests/Core/TestPlatformIdentifier.cs b/tests/Tgstation.Server.Host.Tests/Core/TestPlatformIdentifier.cs new file mode 100644 index 0000000000..8e46e356c0 --- /dev/null +++ b/tests/Tgstation.Server.Host.Tests/Core/TestPlatformIdentifier.cs @@ -0,0 +1,16 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Runtime.InteropServices; + +namespace Tgstation.Server.Host.Core.Tests +{ + [TestClass] + public sealed class TestPlatformIdentifier + { + [TestMethod] + public void TestCorrectPlatform() + { + var identifier = new PlatformIdentifier(); + Assert.AreEqual(RuntimeInformation.IsOSPlatform(OSPlatform.Windows), identifier.IsWindows); + } + } +} From 0dc1a2f0f4f3cac2caaa2c024642dddbcd3ec505 Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Mon, 15 Oct 2018 10:41:36 -0400 Subject: [PATCH 04/27] Add IPlatformIdentifier to the composition root --- src/Tgstation.Server.Host/Core/Application.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Tgstation.Server.Host/Core/Application.cs b/src/Tgstation.Server.Host/Core/Application.cs index 1288324842..737e635a7c 100644 --- a/src/Tgstation.Server.Host/Core/Application.cs +++ b/src/Tgstation.Server.Host/Core/Application.cs @@ -97,11 +97,12 @@ namespace Tgstation.Server.Host.Core //enable options which give us config reloading services.AddOptions(); - //setup stuff for setup wizard + //other stuff needed for for setup wizard and configuration services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); //needed here for JWT configuration //we use a manually instatiated token factory to prevent it from regenerating the signing key after we configure it From 6003f57e06bf3e955cb91043949748edb67876e8 Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Mon, 15 Oct 2018 10:42:35 -0400 Subject: [PATCH 05/27] Makes Application use PlatformIdentifier --- src/Tgstation.Server.Host/Core/Application.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Tgstation.Server.Host/Core/Application.cs b/src/Tgstation.Server.Host/Core/Application.cs index 737e635a7c..b9c2e1bf33 100644 --- a/src/Tgstation.Server.Host/Core/Application.cs +++ b/src/Tgstation.Server.Host/Core/Application.cs @@ -113,6 +113,7 @@ namespace Tgstation.Server.Host.Core FileLoggingConfiguration fileLoggingConfiguration; ITokenFactory tokenFactory; IIOManager ioManager; + IPlatformIdentifier platformIdentifier; //temporarily build the service provider in it's current state //do it here so we can run the setup wizard if necessary @@ -141,6 +142,7 @@ namespace Tgstation.Server.Host.Core tokenFactory = provider.GetRequiredService(); ioManager = provider.GetRequiredService(); + platformIdentifier = provider.GetRequiredService(); } //setup file logging via serilog @@ -255,7 +257,7 @@ namespace Tgstation.Server.Host.Core services.AddSingleton, PasswordHasher>(); //configure platform specific services - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + if (platformIdentifier.IsWindows) { services.AddSingleton(); services.AddSingleton(); From e15ddd4d5a96a5fa58e687c668f60c8b637db776 Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Mon, 15 Oct 2018 10:43:45 -0400 Subject: [PATCH 06/27] Makes IPlatformIdentifier public --- src/Tgstation.Server.Host/Core/IPlatformIdentifier.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tgstation.Server.Host/Core/IPlatformIdentifier.cs b/src/Tgstation.Server.Host/Core/IPlatformIdentifier.cs index 74e3484a79..e893095bb1 100644 --- a/src/Tgstation.Server.Host/Core/IPlatformIdentifier.cs +++ b/src/Tgstation.Server.Host/Core/IPlatformIdentifier.cs @@ -3,7 +3,7 @@ /// /// For identifying the current platform /// - interface IPlatformIdentifier + public interface IPlatformIdentifier { /// /// If the current platform is a Windows platform From ee8ce6d69728eede384705b22a0615372cf035eb Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Mon, 15 Oct 2018 10:43:59 -0400 Subject: [PATCH 07/27] Add IPlatformIdentifier to the AdministrationController --- .../Controllers/AdministrationController.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Tgstation.Server.Host/Controllers/AdministrationController.cs b/src/Tgstation.Server.Host/Controllers/AdministrationController.cs index a7ed6593d4..6c9930ada0 100644 --- a/src/Tgstation.Server.Host/Controllers/AdministrationController.cs +++ b/src/Tgstation.Server.Host/Controllers/AdministrationController.cs @@ -52,6 +52,11 @@ namespace Tgstation.Server.Host.Controllers /// readonly IIOManager ioManager; + /// + /// The for the + /// + readonly IPlatformIdentifier platformIdentifier; + /// /// The for the /// @@ -71,15 +76,17 @@ namespace Tgstation.Server.Host.Controllers /// The value of /// The value of /// The value of + /// The value of /// The for the /// The containing value of /// The containing value of - public AdministrationController(IDatabaseContext databaseContext, IAuthenticationContextFactory authenticationContextFactory, IGitHubClientFactory gitHubClientFactory, IServerControl serverUpdater, IApplication application, IIOManager ioManager, ILogger logger, IOptions updatesConfigurationOptions, IOptions generalConfigurationOptions) : base(databaseContext, authenticationContextFactory, logger, false) + public AdministrationController(IDatabaseContext databaseContext, IAuthenticationContextFactory authenticationContextFactory, IGitHubClientFactory gitHubClientFactory, IServerControl serverUpdater, IApplication application, IIOManager ioManager, IPlatformIdentifier platformIdentifier, ILogger logger, IOptions updatesConfigurationOptions, IOptions generalConfigurationOptions) : base(databaseContext, authenticationContextFactory, logger, false) { this.gitHubClientFactory = gitHubClientFactory ?? throw new ArgumentNullException(nameof(gitHubClientFactory)); this.serverUpdater = serverUpdater ?? throw new ArgumentNullException(nameof(serverUpdater)); this.application = application ?? throw new ArgumentNullException(nameof(application)); this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager)); + this.platformIdentifier = platformIdentifier ?? throw new ArgumentNullException(nameof(platformIdentifier)); updatesConfiguration = updatesConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(updatesConfigurationOptions)); generalConfiguration = generalConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(generalConfigurationOptions)); } From ee7559a90c58d4411f63e81ca4d79978727c3421 Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Mon, 15 Oct 2018 10:46:53 -0400 Subject: [PATCH 08/27] Add IPlatformIdentifier.ScriptFileExtension --- src/Tgstation.Server.Host/Core/IPlatformIdentifier.cs | 5 +++++ src/Tgstation.Server.Host/Core/PlatformIdentifier.cs | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/src/Tgstation.Server.Host/Core/IPlatformIdentifier.cs b/src/Tgstation.Server.Host/Core/IPlatformIdentifier.cs index e893095bb1..300ca29866 100644 --- a/src/Tgstation.Server.Host/Core/IPlatformIdentifier.cs +++ b/src/Tgstation.Server.Host/Core/IPlatformIdentifier.cs @@ -9,5 +9,10 @@ /// If the current platform is a Windows platform /// bool IsWindows { get; } + + /// + /// The extension of executable script files for the system + /// + string ScriptFileExtension { get; } } } diff --git a/src/Tgstation.Server.Host/Core/PlatformIdentifier.cs b/src/Tgstation.Server.Host/Core/PlatformIdentifier.cs index fbed84baf9..df59c83356 100644 --- a/src/Tgstation.Server.Host/Core/PlatformIdentifier.cs +++ b/src/Tgstation.Server.Host/Core/PlatformIdentifier.cs @@ -8,12 +8,16 @@ namespace Tgstation.Server.Host.Core /// public bool IsWindows { get; } + /// + public string ScriptFileExtension { get; } + /// /// Construct a /// public PlatformIdentifier() { IsWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); + ScriptFileExtension = IsWindows ? "bat" : "sh"; } } } From e538ccca779e170f30c027b8d623a22bb4664bdd Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Mon, 15 Oct 2018 10:48:48 -0400 Subject: [PATCH 09/27] Update PlatformIdentifier unit test --- .../Core/TestPlatformIdentifier.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tests/Tgstation.Server.Host.Tests/Core/TestPlatformIdentifier.cs b/tests/Tgstation.Server.Host.Tests/Core/TestPlatformIdentifier.cs index 8e46e356c0..26d7459ed6 100644 --- a/tests/Tgstation.Server.Host.Tests/Core/TestPlatformIdentifier.cs +++ b/tests/Tgstation.Server.Host.Tests/Core/TestPlatformIdentifier.cs @@ -10,7 +10,15 @@ namespace Tgstation.Server.Host.Core.Tests public void TestCorrectPlatform() { var identifier = new PlatformIdentifier(); - Assert.AreEqual(RuntimeInformation.IsOSPlatform(OSPlatform.Windows), identifier.IsWindows); + + var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); + const string WindowsScriptExtension = "bat"; + const string PosixScriptExtension = "sh"; + + + Assert.AreEqual(isWindows, identifier.IsWindows); + + Assert.AreEqual(isWindows ? WindowsScriptExtension : PosixScriptExtension, identifier.ScriptFileExtension); } } } From 148ef744470f2fd156f613e8c6e7b9bdf92cf910 Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Mon, 15 Oct 2018 10:50:54 -0400 Subject: [PATCH 10/27] Adds IPlatformIdentifier to Configuration and InstanceFactory --- .../Components/InstanceFactory.cs | 11 +++++++++-- .../Components/StaticFiles/Configuration.cs | 15 ++++++++++----- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/InstanceFactory.cs b/src/Tgstation.Server.Host/Components/InstanceFactory.cs index 7d087d1c08..4dc72406b8 100644 --- a/src/Tgstation.Server.Host/Components/InstanceFactory.cs +++ b/src/Tgstation.Server.Host/Components/InstanceFactory.cs @@ -103,6 +103,11 @@ namespace Tgstation.Server.Host.Components /// readonly IGitHubClientFactory gitHubClientFactory; + /// + /// The for the + /// + readonly IPlatformIdentifier platformIdentifier; + /// /// Construct an /// @@ -123,7 +128,8 @@ namespace Tgstation.Server.Host.Components /// The value of /// The value of /// The value of - public InstanceFactory(IIOManager ioManager, IDatabaseContextFactory databaseContextFactory, IApplication application, ILoggerFactory loggerFactory, IByondTopicSender byondTopicSender, ICryptographySuite cryptographySuite, ISynchronousIOManager synchronousIOManager, ISymlinkFactory symlinkFactory, IByondInstaller byondInstaller, IChatFactory chatFactory, IProcessExecutor processExecutor, IPostWriteHandler postWriteHandler, IWatchdogFactory watchdogFactory, IJobManager jobManager, ICredentialsProvider credentialsProvider, INetworkPromptReaper networkPromptReaper, IGitHubClientFactory gitHubClientFactory) + /// The value of + public InstanceFactory(IIOManager ioManager, IDatabaseContextFactory databaseContextFactory, IApplication application, ILoggerFactory loggerFactory, IByondTopicSender byondTopicSender, ICryptographySuite cryptographySuite, ISynchronousIOManager synchronousIOManager, ISymlinkFactory symlinkFactory, IByondInstaller byondInstaller, IChatFactory chatFactory, IProcessExecutor processExecutor, IPostWriteHandler postWriteHandler, IWatchdogFactory watchdogFactory, IJobManager jobManager, ICredentialsProvider credentialsProvider, INetworkPromptReaper networkPromptReaper, IGitHubClientFactory gitHubClientFactory, IPlatformIdentifier platformIdentifier) { this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager)); this.databaseContextFactory = databaseContextFactory ?? throw new ArgumentNullException(nameof(databaseContextFactory)); @@ -142,6 +148,7 @@ namespace Tgstation.Server.Host.Components this.credentialsProvider = credentialsProvider ?? throw new ArgumentNullException(nameof(credentialsProvider)); this.networkPromptReaper = networkPromptReaper ?? throw new ArgumentNullException(nameof(networkPromptReaper)); this.gitHubClientFactory = gitHubClientFactory ?? throw new ArgumentNullException(nameof(gitHubClientFactory)); + this.platformIdentifier = platformIdentifier ?? throw new ArgumentNullException(nameof(platformIdentifier)); } /// @@ -156,7 +163,7 @@ namespace Tgstation.Server.Host.Components var gameIoManager = new ResolvingIOManager(instanceIoManager, "Game"); var configurationIoManager = new ResolvingIOManager(instanceIoManager, "Configuration"); - var configuration = new StaticFiles.Configuration(configurationIoManager, synchronousIOManager, symlinkFactory, processExecutor, postWriteHandler, loggerFactory.CreateLogger()); + var configuration = new StaticFiles.Configuration(configurationIoManager, synchronousIOManager, symlinkFactory, processExecutor, postWriteHandler, platformIdentifier, loggerFactory.CreateLogger()); var eventConsumer = new EventConsumer(configuration); var dmbFactory = new DmbFactory(databaseContextFactory, gameIoManager, loggerFactory.CreateLogger(), metadata.CloneMetadata()); diff --git a/src/Tgstation.Server.Host/Components/StaticFiles/Configuration.cs b/src/Tgstation.Server.Host/Components/StaticFiles/Configuration.cs index dcf009a8f6..bb19579a21 100644 --- a/src/Tgstation.Server.Host/Components/StaticFiles/Configuration.cs +++ b/src/Tgstation.Server.Host/Components/StaticFiles/Configuration.cs @@ -38,8 +38,6 @@ namespace Tgstation.Server.Host.Components.StaticFiles { EventType.RepoPreSynchronize, "PreSynchronize" } }; - static readonly string SystemScriptFileExtension = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "bat" : "sh"; - /// /// The for /// @@ -65,6 +63,11 @@ namespace Tgstation.Server.Host.Components.StaticFiles /// readonly IPostWriteHandler postWriteHandler; + /// + /// The for + /// + readonly IPlatformIdentifier platformIdentifier; + /// /// The for /// @@ -83,14 +86,16 @@ namespace Tgstation.Server.Host.Components.StaticFiles /// The value of /// The value of /// The value of + /// The value of /// The value of - public Configuration(IIOManager ioManager, ISynchronousIOManager synchronousIOManager, ISymlinkFactory symlinkFactory, IProcessExecutor processExecutor, IPostWriteHandler postWriteHandler, ILogger logger) + public Configuration(IIOManager ioManager, ISynchronousIOManager synchronousIOManager, ISymlinkFactory symlinkFactory, IProcessExecutor processExecutor, IPostWriteHandler postWriteHandler, IPlatformIdentifier platformIdentifier, ILogger logger) { this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager)); this.synchronousIOManager = synchronousIOManager ?? throw new ArgumentNullException(nameof(synchronousIOManager)); this.symlinkFactory = symlinkFactory ?? throw new ArgumentNullException(nameof(symlinkFactory)); this.processExecutor = processExecutor ?? throw new ArgumentNullException(nameof(processExecutor)); this.postWriteHandler = postWriteHandler ?? throw new ArgumentNullException(nameof(postWriteHandler)); + this.platformIdentifier = platformIdentifier ?? throw new ArgumentNullException(nameof(platformIdentifier)); this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); semaphore = new SemaphoreSlim(1); @@ -312,7 +317,7 @@ namespace Tgstation.Server.Host.Components.StaticFiles var fileName = ioManager.GetFileName(x); bool ignored; - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + if (platformIdentifier.IsWindows) //need to normalize ignored = ignoreFiles.Any(y => fileName.ToUpperInvariant() == y.ToUpperInvariant()); else @@ -438,7 +443,7 @@ namespace Tgstation.Server.Host.Components.StaticFiles //always execute in serial using (await SemaphoreSlimContext.Lock(semaphore, cancellationToken).ConfigureAwait(false)) { - var files = await ioManager.GetFilesWithExtension(EventScriptsSubdirectory, SystemScriptFileExtension, cancellationToken).ConfigureAwait(false); + var files = await ioManager.GetFilesWithExtension(EventScriptsSubdirectory, platformIdentifier.ScriptFileExtension, cancellationToken).ConfigureAwait(false); var resolvedScriptsDir = ioManager.ResolvePath(EventScriptsSubdirectory); foreach (var I in files.Select(x => ioManager.GetFileName(x)).Where(x => x.StartsWith(scriptName, StringComparison.Ordinal))) From df32217ddc5be969d5f34d98fa75e77a6a2950c4 Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Mon, 15 Oct 2018 10:56:24 -0400 Subject: [PATCH 11/27] Add IPlatformIdentifier to SetupWizard --- src/Tgstation.Server.Host/Core/SetupWizard.cs | 11 ++++-- .../Core/TestSetupWizard.cs | 36 +++++++++---------- 2 files changed, 25 insertions(+), 22 deletions(-) diff --git a/src/Tgstation.Server.Host/Core/SetupWizard.cs b/src/Tgstation.Server.Host/Core/SetupWizard.cs index 1d3cb0bd65..040bee0bc8 100644 --- a/src/Tgstation.Server.Host/Core/SetupWizard.cs +++ b/src/Tgstation.Server.Host/Core/SetupWizard.cs @@ -45,6 +45,11 @@ namespace Tgstation.Server.Host.Core /// readonly IDBConnectionFactory dbConnectionFactory; + /// + /// The for the + /// + readonly IPlatformIdentifier platformIdentifier; + /// /// The for the /// @@ -63,15 +68,17 @@ namespace Tgstation.Server.Host.Core /// The value of /// The value of /// The value of + /// The value of /// The value of /// The containing the value of - public SetupWizard(IIOManager ioManager, IConsole console, IHostingEnvironment hostingEnvironment, IApplication application, IDBConnectionFactory dbConnectionFactory, ILogger logger, IOptions generalConfigurationOptions) + public SetupWizard(IIOManager ioManager, IConsole console, IHostingEnvironment hostingEnvironment, IApplication application, IDBConnectionFactory dbConnectionFactory, IPlatformIdentifier platformIdentifier, ILogger logger, IOptions generalConfigurationOptions) { this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager)); this.console = console ?? throw new ArgumentNullException(nameof(console)); this.hostingEnvironment = hostingEnvironment ?? throw new ArgumentNullException(nameof(hostingEnvironment)); this.application = application ?? throw new ArgumentNullException(nameof(application)); this.dbConnectionFactory = dbConnectionFactory ?? throw new ArgumentNullException(nameof(dbConnectionFactory)); + this.platformIdentifier = platformIdentifier ?? throw new ArgumentNullException(nameof(platformIdentifier)); this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); generalConfiguration = generalConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(generalConfigurationOptions)); } @@ -170,7 +177,7 @@ namespace Tgstation.Server.Host.Core var dbExists = await PromptYesNo("Does this database already exist? (y/n): ", cancellationToken).ConfigureAwait(false); bool useWinAuth; - if (databaseConfiguration.DatabaseType == DatabaseType.SqlServer && RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + if (databaseConfiguration.DatabaseType == DatabaseType.SqlServer && platformIdentifier.IsWindows) useWinAuth = await PromptYesNo("Use Windows Authentication? (y/n): ", cancellationToken).ConfigureAwait(false); else useWinAuth = false; diff --git a/tests/Tgstation.Server.Host.Tests/Core/TestSetupWizard.cs b/tests/Tgstation.Server.Host.Tests/Core/TestSetupWizard.cs index 2aaed750da..2ef2576d7b 100644 --- a/tests/Tgstation.Server.Host.Tests/Core/TestSetupWizard.cs +++ b/tests/Tgstation.Server.Host.Tests/Core/TestSetupWizard.cs @@ -22,19 +22,21 @@ namespace Tgstation.Server.Host.Core.Tests [TestMethod] public void TestConstructionThrows() { - Assert.ThrowsException(() => new SetupWizard(null, null, null, null, null, null, null)); + Assert.ThrowsException(() => new SetupWizard(null, null, null, null, null, null, null, null)); var mockIOManager = new Mock(); - Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, null, null, null, null, null, null)); + Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, null, null, null, null, null, null, null)); var mockConsole = new Mock(); - Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, null, null, null, null, null)); + Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, null, null, null, null, null, null)); var mockHostingEnvironment = new Mock(); - Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, null, null, null, null)); + Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, null, null, null, null, null)); var mockApplication = new Mock(); - Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockApplication.Object, null, null, null)); + Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockApplication.Object, null, null, null, null)); var mockDBConnectionFactory = new Mock(); - Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockApplication.Object, mockDBConnectionFactory.Object, null, null)); + Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockApplication.Object, mockDBConnectionFactory.Object, null, null, null)); + var mockPlatformIdentifier = new Mock(); + Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockApplication.Object, mockDBConnectionFactory.Object, mockPlatformIdentifier.Object, null, null)); var mockLogger = new Mock>(); - Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockApplication.Object, mockDBConnectionFactory.Object, mockLogger.Object, null)); + Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockApplication.Object, mockDBConnectionFactory.Object, mockPlatformIdentifier.Object, mockLogger.Object, null)); } [TestMethod] @@ -47,6 +49,7 @@ namespace Tgstation.Server.Host.Core.Tests var mockDBConnectionFactory = new Mock(); var mockLogger = new Mock>(); var mockGeneralConfigurationOptions = new Mock>(); + var mockPlatformIdentifier = new Mock(); var testGeneralConfig = new GeneralConfiguration { @@ -54,7 +57,9 @@ namespace Tgstation.Server.Host.Core.Tests }; mockGeneralConfigurationOptions.SetupGet(x => x.Value).Returns(testGeneralConfig).Verifiable(); - var wizard = new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockApplication.Object, mockDBConnectionFactory.Object, mockLogger.Object, mockGeneralConfigurationOptions.Object); + var wizard = new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockApplication.Object, mockDBConnectionFactory.Object, mockPlatformIdentifier.Object, mockLogger.Object, mockGeneralConfigurationOptions.Object); + + mockPlatformIdentifier.SetupGet(x => x.IsWindows).Returns(true).Verifiable(); Assert.IsFalse(await wizard.CheckRunWizard(default).ConfigureAwait(false)); @@ -116,18 +121,8 @@ namespace Tgstation.Server.Host.Core.Tests "this isn't validated", "nor is this", "no", - }; - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) //test winauth - finalInputSequence.Add("yes"); - else - finalInputSequence.AddRange(new List - { - "username", - "password" - }); - finalInputSequence.AddRange(new List - { + "yes", //sql server will always fail so reconfigure with maria nameof(DatabaseType.MariaDB), "bleh", @@ -183,7 +178,7 @@ namespace Tgstation.Server.Host.Core.Tests "fake", "None", "Critical" - }); + }; var inputPos = 0; @@ -234,6 +229,7 @@ namespace Tgstation.Server.Host.Core.Tests mockUglyDbConnection.VerifyAll(); mockDBConnectionFactory.VerifyAll(); mockApplication.VerifyAll(); + mockPlatformIdentifier.VerifyAll(); } } } From d9b2115f3a45524d32caee6b26a0006efafc58c9 Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Mon, 15 Oct 2018 10:58:23 -0400 Subject: [PATCH 12/27] Add IPlatformIdentifier to SessionControllerFactory --- .../Components/InstanceFactory.cs | 2 +- .../Components/Watchdog/SessionControllerFactory.cs | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/InstanceFactory.cs b/src/Tgstation.Server.Host/Components/InstanceFactory.cs index 4dc72406b8..b54cbc4d68 100644 --- a/src/Tgstation.Server.Host/Components/InstanceFactory.cs +++ b/src/Tgstation.Server.Host/Components/InstanceFactory.cs @@ -179,7 +179,7 @@ namespace Tgstation.Server.Host.Components var chat = chatFactory.CreateChat(instanceIoManager, commandFactory, metadata.ChatSettings); try { - var sessionControllerFactory = new SessionControllerFactory(processExecutor, byond, byondTopicSender, cryptographySuite, application, gameIoManager, chat, networkPromptReaper, loggerFactory, metadata.CloneMetadata()); + var sessionControllerFactory = new SessionControllerFactory(processExecutor, byond, byondTopicSender, cryptographySuite, application, gameIoManager, chat, networkPromptReaper, platformIdentifier, loggerFactory, metadata.CloneMetadata()); var reattachInfoHandler = new ReattachInfoHandler(databaseContextFactory, dmbFactory, loggerFactory.CreateLogger(), metadata.CloneMetadata()); var watchdog = watchdogFactory.CreateWatchdog(chat, dmbFactory, reattachInfoHandler, configuration, sessionControllerFactory, metadata.CloneMetadata(), metadata.DreamDaemonSettings); eventConsumer.SetWatchdog(watchdog); diff --git a/src/Tgstation.Server.Host/Components/Watchdog/SessionControllerFactory.cs b/src/Tgstation.Server.Host/Components/Watchdog/SessionControllerFactory.cs index 63ee94c543..4715f6443e 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/SessionControllerFactory.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/SessionControllerFactory.cs @@ -63,6 +63,11 @@ namespace Tgstation.Server.Host.Components.Watchdog /// readonly INetworkPromptReaper networkPromptReaper; + /// + /// The for the + /// + readonly IPlatformIdentifier platformIdentifier; + /// /// The for the /// @@ -105,8 +110,9 @@ namespace Tgstation.Server.Host.Components.Watchdog /// The value of /// The value of /// The value of + /// The value of /// The value of - public SessionControllerFactory(IProcessExecutor processExecutor, IByondManager byond, IByondTopicSender byondTopicSender, ICryptographySuite cryptographySuite, IApplication application, IIOManager ioManager, IChat chat, INetworkPromptReaper networkPromptReaper, ILoggerFactory loggerFactory, Api.Models.Instance instance) + public SessionControllerFactory(IProcessExecutor processExecutor, IByondManager byond, IByondTopicSender byondTopicSender, ICryptographySuite cryptographySuite, IApplication application, IIOManager ioManager, IChat chat, INetworkPromptReaper networkPromptReaper, IPlatformIdentifier platformIdentifier, ILoggerFactory loggerFactory, Api.Models.Instance instance) { this.processExecutor = processExecutor ?? throw new ArgumentNullException(nameof(processExecutor)); this.byond = byond ?? throw new ArgumentNullException(nameof(byond)); @@ -117,6 +123,7 @@ namespace Tgstation.Server.Host.Components.Watchdog this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager)); this.chat = chat ?? throw new ArgumentNullException(nameof(chat)); this.networkPromptReaper = networkPromptReaper ?? throw new ArgumentNullException(nameof(networkPromptReaper)); + this.platformIdentifier = platformIdentifier ?? throw new ArgumentNullException(nameof(platformIdentifier)); this.loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory)); } @@ -211,7 +218,7 @@ namespace Tgstation.Server.Host.Components.Watchdog parameters); //See #719 - var noShellExecute = !RuntimeInformation.IsOSPlatform(OSPlatform.Windows); + var noShellExecute = !platformIdentifier.IsWindows; //launch dd var process = processExecutor.LaunchProcess(byondLock.DreamDaemonPath, basePath, arguments, noShellExecute: noShellExecute); try From ef6a03a22430737434359441636cfa89fcb3e6e6 Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Mon, 15 Oct 2018 10:59:42 -0400 Subject: [PATCH 13/27] Add IPlatformIdentifier to InstanceController --- .../Controllers/InstanceController.cs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Controllers/InstanceController.cs b/src/Tgstation.Server.Host/Controllers/InstanceController.cs index 5d6515dc7b..ddb7ae12d8 100644 --- a/src/Tgstation.Server.Host/Controllers/InstanceController.cs +++ b/src/Tgstation.Server.Host/Controllers/InstanceController.cs @@ -40,10 +40,12 @@ namespace Tgstation.Server.Host.Controllers /// The for the /// readonly IJobManager jobManager; + /// /// The for the /// readonly IInstanceManager instanceManager; + /// /// The for the /// @@ -54,6 +56,11 @@ namespace Tgstation.Server.Host.Controllers /// readonly IApplication application; + /// + /// The for the + /// + readonly IPlatformIdentifier platformIdentifier; + /// /// Construct a /// @@ -64,12 +71,13 @@ namespace Tgstation.Server.Host.Controllers /// The value of /// The value of /// The for the - public InstanceController(IDatabaseContext databaseContext, IAuthenticationContextFactory authenticationContextFactory, IJobManager jobManager, IInstanceManager instanceManager, IIOManager ioManager, IApplication application, ILogger logger) : base(databaseContext, authenticationContextFactory, logger, false) + public InstanceController(IDatabaseContext databaseContext, IAuthenticationContextFactory authenticationContextFactory, IJobManager jobManager, IInstanceManager instanceManager, IIOManager ioManager, IApplication application, IPlatformIdentifier platformIdentifier, ILogger logger) : base(databaseContext, authenticationContextFactory, logger, false) { this.jobManager = jobManager ?? throw new ArgumentNullException(nameof(jobManager)); this.instanceManager = instanceManager ?? throw new ArgumentNullException(nameof(instanceManager)); this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager)); this.application = application ?? throw new ArgumentNullException(nameof(application)); + this.platformIdentifier = platformIdentifier ?? throw new ArgumentNullException(nameof(platformIdentifier)); } void NormalizeModelPath(Api.Models.Instance model, out string absolutePath) @@ -80,7 +88,7 @@ namespace Tgstation.Server.Host.Controllers return; } absolutePath = ioManager.ResolvePath(model.Path); - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + if (platformIdentifier.IsWindows) model.Path = absolutePath.ToUpperInvariant(); else model.Path = absolutePath; From b426b7f5e822216224149d4cc5f7626bc3ac4822 Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Mon, 15 Oct 2018 11:00:36 -0400 Subject: [PATCH 14/27] Actually use platformIdentifier in AdministrationController --- .../Controllers/AdministrationController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tgstation.Server.Host/Controllers/AdministrationController.cs b/src/Tgstation.Server.Host/Controllers/AdministrationController.cs index 6c9930ada0..0899ab7db5 100644 --- a/src/Tgstation.Server.Host/Controllers/AdministrationController.cs +++ b/src/Tgstation.Server.Host/Controllers/AdministrationController.cs @@ -130,7 +130,7 @@ namespace Tgstation.Server.Host.Controllers { LatestVersion = greatestVersion, TrackedRepositoryUrl = repoUrl, - WindowsHost = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) + WindowsHost = platformIdentifier.IsWindows }); } catch (RateLimitExceededException e) From 501343299ddb20755a6659faac540947a2626ea2 Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Mon, 15 Oct 2018 11:01:59 -0400 Subject: [PATCH 15/27] Add missing doc comment --- src/Tgstation.Server.Host/Controllers/InstanceController.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Tgstation.Server.Host/Controllers/InstanceController.cs b/src/Tgstation.Server.Host/Controllers/InstanceController.cs index ddb7ae12d8..5db9cd5897 100644 --- a/src/Tgstation.Server.Host/Controllers/InstanceController.cs +++ b/src/Tgstation.Server.Host/Controllers/InstanceController.cs @@ -70,6 +70,7 @@ namespace Tgstation.Server.Host.Controllers /// The value of /// The value of /// The value of + /// The value of /// The for the public InstanceController(IDatabaseContext databaseContext, IAuthenticationContextFactory authenticationContextFactory, IJobManager jobManager, IInstanceManager instanceManager, IIOManager ioManager, IApplication application, IPlatformIdentifier platformIdentifier, ILogger logger) : base(databaseContext, authenticationContextFactory, logger, false) { From b8b88c78cead1ab39d3ce0dcfccfa0c1bcff3e68 Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Mon, 15 Oct 2018 11:06:48 -0400 Subject: [PATCH 16/27] Add IAsyncDelayer --- .../Core/IAsyncDelayer.cs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/Tgstation.Server.Host/Core/IAsyncDelayer.cs diff --git a/src/Tgstation.Server.Host/Core/IAsyncDelayer.cs b/src/Tgstation.Server.Host/Core/IAsyncDelayer.cs new file mode 100644 index 0000000000..ae0da1284d --- /dev/null +++ b/src/Tgstation.Server.Host/Core/IAsyncDelayer.cs @@ -0,0 +1,20 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace Tgstation.Server.Host.Core +{ + /// + /// For waiting asynchronously + /// + interface IAsyncDelayer + { + /// + /// Create a that completes after a given + /// + /// The that must elapse + /// The for the operation + /// A representing the running operation + Task Delay(TimeSpan timeSpan, CancellationToken cancellationToken); + } +} From a58fa143b189061997f87c77dd5f44bdc1f9d655 Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Mon, 15 Oct 2018 11:08:08 -0400 Subject: [PATCH 17/27] Add AsyncDelayer --- src/Tgstation.Server.Host/Core/AsyncDelayer.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 src/Tgstation.Server.Host/Core/AsyncDelayer.cs diff --git a/src/Tgstation.Server.Host/Core/AsyncDelayer.cs b/src/Tgstation.Server.Host/Core/AsyncDelayer.cs new file mode 100644 index 0000000000..1e874366d3 --- /dev/null +++ b/src/Tgstation.Server.Host/Core/AsyncDelayer.cs @@ -0,0 +1,13 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace Tgstation.Server.Host.Core +{ + /// + sealed class AsyncDelayer : IAsyncDelayer + { + /// + public Task Delay(TimeSpan timeSpan, CancellationToken cancellationToken) => Task.Delay(timeSpan, cancellationToken); + } +} From a06a6a0dff154b1a3e90f52da890db96c528e497 Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Mon, 15 Oct 2018 11:13:12 -0400 Subject: [PATCH 18/27] Add TestAsyncDelayer --- .../Core/TestAsyncDelayer.cs | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 tests/Tgstation.Server.Host.Tests/Core/TestAsyncDelayer.cs diff --git a/tests/Tgstation.Server.Host.Tests/Core/TestAsyncDelayer.cs b/tests/Tgstation.Server.Host.Tests/Core/TestAsyncDelayer.cs new file mode 100644 index 0000000000..c4927e3dee --- /dev/null +++ b/tests/Tgstation.Server.Host.Tests/Core/TestAsyncDelayer.cs @@ -0,0 +1,32 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace Tgstation.Server.Host.Core.Tests +{ + [TestClass] + public sealed class TestAsyncDelayer + { + [TestMethod] + public async Task TestDelay() + { + var delayer = new AsyncDelayer(); + var startDelay = delayer.Delay(TimeSpan.FromSeconds(1), default); + var checkDelay = Task.Delay(TimeSpan.FromSeconds(1) - TimeSpan.FromMilliseconds(10), default); + await startDelay.ConfigureAwait(false); + Assert.IsTrue(checkDelay.IsCompleted); + } + + [TestMethod] + public async Task TestCancel() + { + var delayer = new AsyncDelayer(); + using (var cts = new CancellationTokenSource()) + { + cts.Cancel(); + await Assert.ThrowsExceptionAsync(() => delayer.Delay(TimeSpan.FromSeconds(1), cts.Token)).ConfigureAwait(false); + } + } + } +} From 920ade7b6d267c544b365b4785edd5ab8b02255c Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Mon, 15 Oct 2018 11:13:45 -0400 Subject: [PATCH 19/27] Add IAsyncDelayer to composition root --- src/Tgstation.Server.Host/Core/Application.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Tgstation.Server.Host/Core/Application.cs b/src/Tgstation.Server.Host/Core/Application.cs index b9c2e1bf33..be0478420f 100644 --- a/src/Tgstation.Server.Host/Core/Application.cs +++ b/src/Tgstation.Server.Host/Core/Application.cs @@ -103,6 +103,7 @@ namespace Tgstation.Server.Host.Core services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); //needed here for JWT configuration //we use a manually instatiated token factory to prevent it from regenerating the signing key after we configure it From 973c0796ab36ab91cd5eccc30d1dbb9c7be6030e Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Mon, 15 Oct 2018 11:20:04 -0400 Subject: [PATCH 20/27] Add IAsyncDelayer to SetupWizard --- src/Tgstation.Server.Host/Core/SetupWizard.cs | 13 ++++++++--- .../Core/TestSetupWizard.cs | 23 +++++++++++-------- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/Tgstation.Server.Host/Core/SetupWizard.cs b/src/Tgstation.Server.Host/Core/SetupWizard.cs index 040bee0bc8..83b6456fe3 100644 --- a/src/Tgstation.Server.Host/Core/SetupWizard.cs +++ b/src/Tgstation.Server.Host/Core/SetupWizard.cs @@ -50,6 +50,11 @@ namespace Tgstation.Server.Host.Core /// readonly IPlatformIdentifier platformIdentifier; + /// + /// The for the + /// + readonly IAsyncDelayer asyncDelayer; + /// /// The for the /// @@ -69,9 +74,10 @@ namespace Tgstation.Server.Host.Core /// The value of /// The value of /// The value of + /// The value of /// The value of /// The containing the value of - public SetupWizard(IIOManager ioManager, IConsole console, IHostingEnvironment hostingEnvironment, IApplication application, IDBConnectionFactory dbConnectionFactory, IPlatformIdentifier platformIdentifier, ILogger logger, IOptions generalConfigurationOptions) + public SetupWizard(IIOManager ioManager, IConsole console, IHostingEnvironment hostingEnvironment, IApplication application, IDBConnectionFactory dbConnectionFactory, IPlatformIdentifier platformIdentifier, IAsyncDelayer asyncDelayer, ILogger logger, IOptions generalConfigurationOptions) { this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager)); this.console = console ?? throw new ArgumentNullException(nameof(console)); @@ -79,6 +85,7 @@ namespace Tgstation.Server.Host.Core this.application = application ?? throw new ArgumentNullException(nameof(application)); this.dbConnectionFactory = dbConnectionFactory ?? throw new ArgumentNullException(nameof(dbConnectionFactory)); this.platformIdentifier = platformIdentifier ?? throw new ArgumentNullException(nameof(platformIdentifier)); + this.asyncDelayer = asyncDelayer ?? throw new ArgumentNullException(nameof(asyncDelayer)); this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); generalConfiguration = generalConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(generalConfigurationOptions)); } @@ -501,7 +508,7 @@ namespace Tgstation.Server.Host.Core await console.WriteAsync("Waiting for configuration changes to reload...", true, cancellationToken).ConfigureAwait(false); //we need to wait for the configuration's file system watcher to read and reload the changes - await Task.Delay(TimeSpan.FromSeconds(5), cancellationToken).ConfigureAwait(false); + await asyncDelayer.Delay(TimeSpan.FromSeconds(5), cancellationToken).ConfigureAwait(false); } /// @@ -584,7 +591,7 @@ namespace Tgstation.Server.Host.Core } //flush the logs to prevent console conflicts - await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken).ConfigureAwait(false); + await asyncDelayer.Delay(TimeSpan.FromSeconds(1), cancellationToken).ConfigureAwait(false); await RunWizard(userConfigFileName, cancellationToken).ConfigureAwait(false); return true; diff --git a/tests/Tgstation.Server.Host.Tests/Core/TestSetupWizard.cs b/tests/Tgstation.Server.Host.Tests/Core/TestSetupWizard.cs index 2ef2576d7b..7824a93c27 100644 --- a/tests/Tgstation.Server.Host.Tests/Core/TestSetupWizard.cs +++ b/tests/Tgstation.Server.Host.Tests/Core/TestSetupWizard.cs @@ -22,21 +22,23 @@ namespace Tgstation.Server.Host.Core.Tests [TestMethod] public void TestConstructionThrows() { - Assert.ThrowsException(() => new SetupWizard(null, null, null, null, null, null, null, null)); + Assert.ThrowsException(() => new SetupWizard(null, null, null, null, null, null, null, null, null)); var mockIOManager = new Mock(); - Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, null, null, null, null, null, null, null)); + Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, null, null, null, null, null, null, null, null)); var mockConsole = new Mock(); - Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, null, null, null, null, null, null)); + Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, null, null, null, null, null, null, null)); var mockHostingEnvironment = new Mock(); - Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, null, null, null, null, null)); + Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, null, null, null, null, null, null)); var mockApplication = new Mock(); - Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockApplication.Object, null, null, null, null)); + Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockApplication.Object, null, null, null, null, null)); var mockDBConnectionFactory = new Mock(); - Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockApplication.Object, mockDBConnectionFactory.Object, null, null, null)); + Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockApplication.Object, mockDBConnectionFactory.Object, null, null, null, null)); var mockPlatformIdentifier = new Mock(); - Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockApplication.Object, mockDBConnectionFactory.Object, mockPlatformIdentifier.Object, null, null)); + Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockApplication.Object, mockDBConnectionFactory.Object, mockPlatformIdentifier.Object, null, null, null)); + var mockAsyncDelayer = new Mock(); + Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockApplication.Object, mockDBConnectionFactory.Object, mockPlatformIdentifier.Object, mockAsyncDelayer.Object, null, null)); var mockLogger = new Mock>(); - Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockApplication.Object, mockDBConnectionFactory.Object, mockPlatformIdentifier.Object, mockLogger.Object, null)); + Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockApplication.Object, mockDBConnectionFactory.Object, mockPlatformIdentifier.Object, mockAsyncDelayer.Object, mockLogger.Object, null)); } [TestMethod] @@ -50,6 +52,7 @@ namespace Tgstation.Server.Host.Core.Tests var mockLogger = new Mock>(); var mockGeneralConfigurationOptions = new Mock>(); var mockPlatformIdentifier = new Mock(); + var mockAsyncDelayer = new Mock(); var testGeneralConfig = new GeneralConfiguration { @@ -57,9 +60,10 @@ namespace Tgstation.Server.Host.Core.Tests }; mockGeneralConfigurationOptions.SetupGet(x => x.Value).Returns(testGeneralConfig).Verifiable(); - var wizard = new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockApplication.Object, mockDBConnectionFactory.Object, mockPlatformIdentifier.Object, mockLogger.Object, mockGeneralConfigurationOptions.Object); + var wizard = new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockApplication.Object, mockDBConnectionFactory.Object, mockPlatformIdentifier.Object, mockAsyncDelayer.Object, mockLogger.Object, mockGeneralConfigurationOptions.Object); mockPlatformIdentifier.SetupGet(x => x.IsWindows).Returns(true).Verifiable(); + mockAsyncDelayer.Setup(x => x.Delay(It.IsAny(), It.IsAny())).Returns(Task.CompletedTask).Verifiable(); Assert.IsFalse(await wizard.CheckRunWizard(default).ConfigureAwait(false)); @@ -230,6 +234,7 @@ namespace Tgstation.Server.Host.Core.Tests mockDBConnectionFactory.VerifyAll(); mockApplication.VerifyAll(); mockPlatformIdentifier.VerifyAll(); + mockAsyncDelayer.VerifyAll(); } } } From 695e44e54a8016e951cf20020eba1d25de174611 Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Mon, 15 Oct 2018 11:22:44 -0400 Subject: [PATCH 21/27] Add IAsyncDelayer to IdentityCache and IdentityCacheObject --- src/Tgstation.Server.Host/Security/IdentityCache.cs | 13 +++++++++++-- .../Security/IdentityCacheObject.cs | 6 ++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/Tgstation.Server.Host/Security/IdentityCache.cs b/src/Tgstation.Server.Host/Security/IdentityCache.cs index cb50e7ccb5..43a2b84302 100644 --- a/src/Tgstation.Server.Host/Security/IdentityCache.cs +++ b/src/Tgstation.Server.Host/Security/IdentityCache.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Tgstation.Server.Host.Core; using Tgstation.Server.Host.Models; namespace Tgstation.Server.Host.Security @@ -9,6 +10,11 @@ namespace Tgstation.Server.Host.Security /// sealed class IdentityCache : IIdentityCache, IDisposable { + /// + /// The for the + /// + readonly IAsyncDelayer asyncDelayer; + /// /// The for the /// @@ -22,8 +28,11 @@ namespace Tgstation.Server.Host.Security /// /// Construct an /// - public IdentityCache(ILogger logger) + /// The value of + /// The value of + public IdentityCache(IAsyncDelayer asyncDelayer, ILogger logger) { + this.asyncDelayer = asyncDelayer ?? throw new ArgumentNullException(nameof(asyncDelayer)); this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); cachedIdentities = new Dictionary(); @@ -54,7 +63,7 @@ namespace Tgstation.Server.Host.Security logger.LogTrace("Expiring previously cached identity..."); identCache.Dispose(); //also clears it out } - identCache = new IdentityCacheObject(systemIdentity.Clone(), () => + identCache = new IdentityCacheObject(systemIdentity.Clone(), asyncDelayer, () => { logger.LogDebug("Expiring system identity cache for user {1}", uid, user.Id); lock (cachedIdentities) diff --git a/src/Tgstation.Server.Host/Security/IdentityCacheObject.cs b/src/Tgstation.Server.Host/Security/IdentityCacheObject.cs index 02ea54ed04..33c48c38fd 100644 --- a/src/Tgstation.Server.Host/Security/IdentityCacheObject.cs +++ b/src/Tgstation.Server.Host/Security/IdentityCacheObject.cs @@ -1,6 +1,7 @@ using System; using System.Threading; using System.Threading.Tasks; +using Tgstation.Server.Host.Core; namespace Tgstation.Server.Host.Security { @@ -28,9 +29,10 @@ namespace Tgstation.Server.Host.Security /// Construct an /// /// The value of + /// The used to delay the expiry /// The to take on expiry /// The - public IdentityCacheObject(ISystemIdentity systemIdentity, Action onExpiry, DateTimeOffset expiry) + public IdentityCacheObject(ISystemIdentity systemIdentity, IAsyncDelayer asyncDelayer, Action onExpiry, DateTimeOffset expiry) { SystemIdentity = systemIdentity ?? throw new ArgumentNullException(nameof(systemIdentity)); if (onExpiry == null) @@ -46,7 +48,7 @@ namespace Tgstation.Server.Host.Security using (SystemIdentity) try { - await Task.Delay(expiry - now, cancellationToken).ConfigureAwait(false); + await asyncDelayer.Delay(expiry - now, cancellationToken).ConfigureAwait(false); } finally { From aff1fa354955452d4bf582eacc3e6a8da3552522 Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Mon, 15 Oct 2018 12:19:55 -0400 Subject: [PATCH 22/27] Add IAsyncDelayer to WindowsNetworkPromptReaper --- .../Components/Watchdog/WindowsNetworkPromptReaper.cs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Watchdog/WindowsNetworkPromptReaper.cs b/src/Tgstation.Server.Host/Components/Watchdog/WindowsNetworkPromptReaper.cs index ef11168489..719eb9f4f8 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/WindowsNetworkPromptReaper.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/WindowsNetworkPromptReaper.cs @@ -25,6 +25,11 @@ namespace Tgstation.Server.Host.Components.Watchdog /// const int RecheckDelayMs = 250; + /// + /// The for the + /// + readonly IAsyncDelayer asyncDelayer; + /// /// The for the /// @@ -78,9 +83,11 @@ namespace Tgstation.Server.Host.Components.Watchdog /// /// Construct a /// + /// The value of /// The value of - public WindowsNetworkPromptReaper(ILogger logger) + public WindowsNetworkPromptReaper(IAsyncDelayer asyncDelayer, ILogger logger) { + this.asyncDelayer = asyncDelayer ?? throw new ArgumentNullException(nameof(asyncDelayer)); this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); registeredProcesses = new List(); @@ -97,7 +104,7 @@ namespace Tgstation.Server.Host.Components.Watchdog { while (!cancellationToken.IsCancellationRequested) { - await Task.Delay(TimeSpan.FromMilliseconds(RecheckDelayMs), cancellationToken).ConfigureAwait(false); + await asyncDelayer.Delay(TimeSpan.FromMilliseconds(RecheckDelayMs), cancellationToken).ConfigureAwait(false); IntPtr window; int processId; From 13daef9a5413cb21fc3e186ada9f597313f6f51d Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Mon, 15 Oct 2018 12:41:10 -0400 Subject: [PATCH 23/27] Add IAsyncDelayer to Watchdog --- .../Components/Watchdog/Watchdog.cs | 27 ++++++++----- .../Components/Watchdog/WatchdogFactory.cs | 11 +++++- .../Components/Watchdog/TestWatchdog.cs | 38 +++++++++++-------- 3 files changed, 48 insertions(+), 28 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Watchdog/Watchdog.cs b/src/Tgstation.Server.Host/Components/Watchdog/Watchdog.cs index b79b9f5363..0302b24fce 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/Watchdog.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/Watchdog.cs @@ -60,11 +60,6 @@ namespace Tgstation.Server.Host.Components.Watchdog /// readonly IDmbFactory dmbFactory; - /// - /// The for the - /// - readonly ILogger logger; - /// /// The for the /// @@ -95,6 +90,16 @@ namespace Tgstation.Server.Host.Components.Watchdog /// readonly IRestartRegistration restartRegistration; + /// + /// The for the + /// + readonly IAsyncDelayer asyncDelayer; + + /// + /// The for the + /// + readonly ILogger logger; + /// /// The for the /// @@ -145,27 +150,29 @@ namespace Tgstation.Server.Host.Components.Watchdog /// The value of /// The value of /// The value of - /// The value of /// The value of /// The value of /// The value of /// The value of /// The value of /// The to populate with + /// The value of + /// The value of /// The initial value of . May be modified /// The value of /// The value of - public Watchdog(IChat chat, ISessionControllerFactory sessionControllerFactory, IDmbFactory dmbFactory, ILogger logger, IReattachInfoHandler reattachInfoHandler, IDatabaseContextFactory databaseContextFactory, IByondTopicSender byondTopicSender, IEventConsumer eventConsumer, IJobManager jobManager, IServerControl serverControl, DreamDaemonLaunchParameters initialLaunchParameters, Api.Models.Instance instance, bool autoStart) + public Watchdog(IChat chat, ISessionControllerFactory sessionControllerFactory, IDmbFactory dmbFactory, IReattachInfoHandler reattachInfoHandler, IDatabaseContextFactory databaseContextFactory, IByondTopicSender byondTopicSender, IEventConsumer eventConsumer, IJobManager jobManager, IServerControl serverControl, IAsyncDelayer asyncDelayer, ILogger logger, DreamDaemonLaunchParameters initialLaunchParameters, Api.Models.Instance instance, bool autoStart) { this.chat = chat ?? throw new ArgumentNullException(nameof(chat)); this.sessionControllerFactory = sessionControllerFactory ?? throw new ArgumentNullException(nameof(sessionControllerFactory)); this.dmbFactory = dmbFactory ?? throw new ArgumentNullException(nameof(dmbFactory)); - this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); this.reattachInfoHandler = reattachInfoHandler ?? throw new ArgumentNullException(nameof(reattachInfoHandler)); this.databaseContextFactory = databaseContextFactory ?? throw new ArgumentNullException(nameof(databaseContextFactory)); this.byondTopicSender = byondTopicSender ?? throw new ArgumentNullException(nameof(byondTopicSender)); this.eventConsumer = eventConsumer ?? throw new ArgumentNullException(nameof(eventConsumer)); this.jobManager = jobManager ?? throw new ArgumentNullException(nameof(jobManager)); + this.asyncDelayer = asyncDelayer ?? throw new ArgumentNullException(nameof(asyncDelayer)); + this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); ActiveLaunchParameters = initialLaunchParameters ?? throw new ArgumentNullException(nameof(initialLaunchParameters)); this.instance = instance ?? throw new ArgumentNullException(nameof(instance)); this.autoStart = autoStart; @@ -635,7 +642,7 @@ namespace Tgstation.Server.Host.Components.Watchdog logger.LogWarning("Failed to automatically restart the watchdog! Attempt: {0}, Exception: {1}", retryAttempts, launchException); var retryDelay = Math.Min(Math.Pow(2, retryAttempts), 3600); //max of one hour, increasing by a power of 2 each time chatTask = chat.SendWatchdogMessage(String.Format(CultureInfo.InvariantCulture, "Failed to restart watchdog (Attempt: {0}), retrying in {1} seconds...", retryAttempts, retryDelay), cancellationToken); - await Task.WhenAll(Task.Delay((int)retryDelay, cancellationToken), chatTask).ConfigureAwait(false); + await Task.WhenAll(asyncDelayer.Delay(TimeSpan.FromSeconds(retryDelay), cancellationToken), chatTask).ConfigureAwait(false); } } } @@ -751,7 +758,7 @@ namespace Tgstation.Server.Host.Components.Watchdog //definitely not if reattaching though if (reattachInfo == null && delay.TotalSeconds < AlphaBravoStartupSeperationInterval) - await Task.Delay(startTime.AddSeconds(AlphaBravoStartupSeperationInterval) - now, cancellationToken).ConfigureAwait(false); + await asyncDelayer.Delay(startTime.AddSeconds(AlphaBravoStartupSeperationInterval) - now, cancellationToken).ConfigureAwait(false); //now bring bravo up if (!doesntNeedNewDmb) diff --git a/src/Tgstation.Server.Host/Components/Watchdog/WatchdogFactory.cs b/src/Tgstation.Server.Host/Components/Watchdog/WatchdogFactory.cs index b2d33d838d..1c03523ee7 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/WatchdogFactory.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/WatchdogFactory.cs @@ -36,6 +36,11 @@ namespace Tgstation.Server.Host.Components.Watchdog /// readonly IJobManager jobManager; + /// + /// The for the + /// + readonly IAsyncDelayer asyncDelayer; + /// /// Construct a /// @@ -44,16 +49,18 @@ namespace Tgstation.Server.Host.Components.Watchdog /// The value of /// The value of /// The value of - public WatchdogFactory(IServerControl serverControl, ILoggerFactory loggerFactory, IDatabaseContextFactory databaseContextFactory, IByondTopicSender byondTopicSender, IJobManager jobManager) + /// The value of + public WatchdogFactory(IServerControl serverControl, ILoggerFactory loggerFactory, IDatabaseContextFactory databaseContextFactory, IByondTopicSender byondTopicSender, IJobManager jobManager, IAsyncDelayer asyncDelayer) { this.serverControl = serverControl ?? throw new ArgumentNullException(nameof(serverControl)); this.loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory)); this.databaseContextFactory = databaseContextFactory ?? throw new ArgumentNullException(nameof(databaseContextFactory)); this.byondTopicSender = byondTopicSender ?? throw new ArgumentNullException(nameof(byondTopicSender)); this.jobManager = jobManager ?? throw new ArgumentNullException(nameof(jobManager)); + this.asyncDelayer = asyncDelayer ?? throw new ArgumentNullException(nameof(asyncDelayer)); } /// - public IWatchdog CreateWatchdog(IChat chat, IDmbFactory dmbFactory, IReattachInfoHandler reattachInfoHandler, IEventConsumer eventConsumer, ISessionControllerFactory sessionControllerFactory, Api.Models.Instance instance, DreamDaemonSettings settings) => new Watchdog(chat, sessionControllerFactory, dmbFactory, loggerFactory.CreateLogger(), reattachInfoHandler, databaseContextFactory, byondTopicSender, eventConsumer, jobManager, serverControl, settings, instance, settings.AutoStart.Value); + public IWatchdog CreateWatchdog(IChat chat, IDmbFactory dmbFactory, IReattachInfoHandler reattachInfoHandler, IEventConsumer eventConsumer, ISessionControllerFactory sessionControllerFactory, Api.Models.Instance instance, DreamDaemonSettings settings) => new Watchdog(chat, sessionControllerFactory, dmbFactory, reattachInfoHandler, databaseContextFactory, byondTopicSender, eventConsumer, jobManager, serverControl, asyncDelayer, loggerFactory.CreateLogger(), settings, instance, settings.AutoStart.Value); } } diff --git a/tests/Tgstation.Server.Host.Tests/Components/Watchdog/TestWatchdog.cs b/tests/Tgstation.Server.Host.Tests/Components/Watchdog/TestWatchdog.cs index 3326386343..ff95faf9f4 100644 --- a/tests/Tgstation.Server.Host.Tests/Components/Watchdog/TestWatchdog.cs +++ b/tests/Tgstation.Server.Host.Tests/Components/Watchdog/TestWatchdog.cs @@ -19,47 +19,50 @@ namespace Tgstation.Server.Host.Components.Watchdog.Tests [TestMethod] public void TestConstruction() { - Assert.ThrowsException(() => new Watchdog(null, null, null, null, null, null, null, null, null, null, null, null, default)); + Assert.ThrowsException(() => new Watchdog(null, null, null, null, null, null, null, null, null, null, null, null, null, default)); var mockChat = new Mock(); mockChat.Setup(x => x.RegisterCommandHandler(It.IsNotNull())).Verifiable(); - Assert.ThrowsException(() => new Watchdog(mockChat.Object, null, null, null, null, null, null, null, null, null, null, null, default)); + Assert.ThrowsException(() => new Watchdog(mockChat.Object, null, null, null, null, null, null, null, null, null, null, null, null, default)); var mockSessionControllerFactory = new Mock(); - Assert.ThrowsException(() => new Watchdog(mockChat.Object, mockSessionControllerFactory.Object, null, null, null, null, null, null, null, null, null, null, default)); + Assert.ThrowsException(() => new Watchdog(mockChat.Object, mockSessionControllerFactory.Object, null, null, null, null, null, null, null, null, null, null, null, default)); var mockDmbFactory = new Mock(); - Assert.ThrowsException(() => new Watchdog(mockChat.Object, mockSessionControllerFactory.Object, null, null, null, null, null, null, null, null, null, null, default)); - - var mockLogger = new Mock>(); - Assert.ThrowsException(() => new Watchdog(mockChat.Object, mockSessionControllerFactory.Object, mockDmbFactory.Object, mockLogger.Object, null, null, null, null, null, null, null, null, default)); + Assert.ThrowsException(() => new Watchdog(mockChat.Object, mockSessionControllerFactory.Object, mockDmbFactory.Object, null, null, null, null, null, null, null, null, null, null, default)); var mockReattachInfoHandler = new Mock(); - Assert.ThrowsException(() => new Watchdog(mockChat.Object, mockSessionControllerFactory.Object, mockDmbFactory.Object, mockLogger.Object, mockReattachInfoHandler.Object, null, null, null, null, null, null, null, default)); + Assert.ThrowsException(() => new Watchdog(mockChat.Object, mockSessionControllerFactory.Object, mockDmbFactory.Object, mockReattachInfoHandler.Object, null, null, null, null, null, null, null, null, null, default)); var mockDatabaseContextFactory = new Mock(); - Assert.ThrowsException(() => new Watchdog(mockChat.Object, mockSessionControllerFactory.Object, mockDmbFactory.Object, mockLogger.Object, mockReattachInfoHandler.Object, mockDatabaseContextFactory.Object, null, null, null, null, null, null, default)); + Assert.ThrowsException(() => new Watchdog(mockChat.Object, mockSessionControllerFactory.Object, mockDmbFactory.Object, mockReattachInfoHandler.Object, mockDatabaseContextFactory.Object, null, null, null, null, null, null, null, null, default)); var mockByondTopicSender = new Mock(); - Assert.ThrowsException(() => new Watchdog(mockChat.Object, mockSessionControllerFactory.Object, mockDmbFactory.Object, mockLogger.Object, mockReattachInfoHandler.Object, mockDatabaseContextFactory.Object, mockByondTopicSender.Object, null, null, null, null, null, default)); + Assert.ThrowsException(() => new Watchdog(mockChat.Object, mockSessionControllerFactory.Object, mockDmbFactory.Object, mockReattachInfoHandler.Object, mockDatabaseContextFactory.Object, mockByondTopicSender.Object, null, null, null, null, null, null, null, default)); var mockEventConsumer = new Mock(); - Assert.ThrowsException(() => new Watchdog(mockChat.Object, mockSessionControllerFactory.Object, mockDmbFactory.Object, mockLogger.Object, mockReattachInfoHandler.Object, mockDatabaseContextFactory.Object, mockByondTopicSender.Object, mockEventConsumer.Object, null, null, null, null, default)); + Assert.ThrowsException(() => new Watchdog(mockChat.Object, mockSessionControllerFactory.Object, mockDmbFactory.Object, mockReattachInfoHandler.Object, mockDatabaseContextFactory.Object, mockByondTopicSender.Object, mockEventConsumer.Object, null, null, null, null, null, null, default)); var mockJobManager = new Mock(); - Assert.ThrowsException(() => new Watchdog(mockChat.Object, mockSessionControllerFactory.Object, mockDmbFactory.Object, mockLogger.Object, mockReattachInfoHandler.Object, mockDatabaseContextFactory.Object, mockByondTopicSender.Object, mockEventConsumer.Object, mockJobManager.Object, null, null, null, default)); + Assert.ThrowsException(() => new Watchdog(mockChat.Object, mockSessionControllerFactory.Object, mockDmbFactory.Object, mockReattachInfoHandler.Object, mockDatabaseContextFactory.Object, mockByondTopicSender.Object, mockEventConsumer.Object, mockJobManager.Object, null, null, null, null, null, default)); var mockRestartRegistration = new Mock(); mockRestartRegistration.Setup(x => x.Dispose()).Verifiable(); var mockServerControl = new Mock(); mockServerControl.Setup(x => x.RegisterForRestart(It.IsNotNull())).Returns(mockRestartRegistration.Object).Verifiable(); - Assert.ThrowsException(() => new Watchdog(mockChat.Object, mockSessionControllerFactory.Object, mockDmbFactory.Object, mockLogger.Object, mockReattachInfoHandler.Object, mockDatabaseContextFactory.Object, mockByondTopicSender.Object, mockEventConsumer.Object, mockJobManager.Object, mockServerControl.Object, null, null, default)); + Assert.ThrowsException(() => new Watchdog(mockChat.Object, mockSessionControllerFactory.Object, mockDmbFactory.Object, mockReattachInfoHandler.Object, mockDatabaseContextFactory.Object, mockByondTopicSender.Object, mockEventConsumer.Object, mockJobManager.Object, mockServerControl.Object, null, null, null, null, default)); + + var mockAsyncDelayer = new Mock(); + Assert.ThrowsException(() => new Watchdog(mockChat.Object, mockSessionControllerFactory.Object, mockDmbFactory.Object, mockReattachInfoHandler.Object, mockDatabaseContextFactory.Object, mockByondTopicSender.Object, mockEventConsumer.Object, mockJobManager.Object, mockServerControl.Object, mockAsyncDelayer.Object, null, null, null, default)); + + var mockLogger = new Mock>(); + Assert.ThrowsException(() => new Watchdog(mockChat.Object, mockSessionControllerFactory.Object, mockDmbFactory.Object, mockReattachInfoHandler.Object, mockDatabaseContextFactory.Object, mockByondTopicSender.Object, mockEventConsumer.Object, mockJobManager.Object, mockServerControl.Object, mockAsyncDelayer.Object, mockLogger.Object, null, null, default)); var mockLaunchParameters = new DreamDaemonLaunchParameters(); - Assert.ThrowsException(() => new Watchdog(mockChat.Object, mockSessionControllerFactory.Object, mockDmbFactory.Object, mockLogger.Object, mockReattachInfoHandler.Object, mockDatabaseContextFactory.Object, mockByondTopicSender.Object, mockEventConsumer.Object, mockJobManager.Object, mockServerControl.Object, mockLaunchParameters, null, default)); + Assert.ThrowsException(() => new Watchdog(mockChat.Object, mockSessionControllerFactory.Object, mockDmbFactory.Object, mockReattachInfoHandler.Object, mockDatabaseContextFactory.Object, mockByondTopicSender.Object, mockEventConsumer.Object, mockJobManager.Object, mockServerControl.Object, mockAsyncDelayer.Object, mockLogger.Object, mockLaunchParameters, null, default)); var mockInstance = new Models.Instance(); - new Watchdog(mockChat.Object, mockSessionControllerFactory.Object, mockDmbFactory.Object, mockLogger.Object, mockReattachInfoHandler.Object, mockDatabaseContextFactory.Object, mockByondTopicSender.Object, mockEventConsumer.Object, mockJobManager.Object, mockServerControl.Object, mockLaunchParameters, mockInstance, default).Dispose(); + new Watchdog(mockChat.Object, mockSessionControllerFactory.Object, mockDmbFactory.Object, mockReattachInfoHandler.Object, mockDatabaseContextFactory.Object, mockByondTopicSender.Object, mockEventConsumer.Object, mockJobManager.Object, mockServerControl.Object, mockAsyncDelayer.Object, mockLogger.Object, mockLaunchParameters, mockInstance, default).Dispose(); mockRestartRegistration.VerifyAll(); mockServerControl.VerifyAll(); @@ -85,8 +88,9 @@ namespace Tgstation.Server.Host.Components.Watchdog.Tests mockServerControl.Setup(x => x.RegisterForRestart(It.IsNotNull())).Returns(mockRestartRegistration.Object).Verifiable(); var mockLaunchParameters = new DreamDaemonLaunchParameters(); var mockInstance = new Models.Instance(); + var mockAsyncDelayer = new Mock(); - using (var wd = new Watchdog(mockChat.Object, mockSessionControllerFactory.Object, mockDmbFactory.Object, mockLogger.Object, mockReattachInfoHandler.Object, mockDatabaseContextFactory.Object, mockByondTopicSender.Object, mockEventConsumer.Object, mockJobManager.Object, mockServerControl.Object, mockLaunchParameters, mockInstance, default)) + using (var wd = new Watchdog(mockChat.Object, mockSessionControllerFactory.Object, mockDmbFactory.Object, mockReattachInfoHandler.Object, mockDatabaseContextFactory.Object, mockByondTopicSender.Object, mockEventConsumer.Object, mockJobManager.Object, mockServerControl.Object, mockAsyncDelayer.Object, mockLogger.Object, mockLaunchParameters, mockInstance, default)) using (var cts = new CancellationTokenSource()) { var mockCompileJob = new Models.CompileJob(); @@ -115,6 +119,7 @@ namespace Tgstation.Server.Host.Components.Watchdog.Tests sessionsToVerify.Add(mockSession); return Task.FromResult(mockSession.Object); }).Verifiable(); + mockAsyncDelayer.Setup(x => x.Delay(It.IsAny(), cancellationToken)).Returns(Task.CompletedTask).Verifiable(); cts.CancelAfter(TimeSpan.FromSeconds(15)); @@ -138,6 +143,7 @@ namespace Tgstation.Server.Host.Components.Watchdog.Tests mockRestartRegistration.VerifyAll(); mockServerControl.VerifyAll(); mockChat.VerifyAll(); + mockAsyncDelayer.VerifyAll(); } } } From 0c9a434140440c932f0785c06de219ed20b2b502 Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Mon, 15 Oct 2018 12:47:29 -0400 Subject: [PATCH 24/27] Cleans up a lot of nonsense regarding the snowflakeyness of TokenFactory and CryptographySuite Add IAsyncDelayer to TokenFactory --- src/Tgstation.Server.Host/Core/Application.cs | 26 ++++++++------ .../Security/CryptographySuite.cs | 36 ++++++++++--------- .../Security/ICryptographySuite.cs | 7 ++++ .../Security/TokenFactory.cs | 34 +++++++++++++++--- .../Core/TestApplication.cs | 13 ++++--- 5 files changed, 80 insertions(+), 36 deletions(-) diff --git a/src/Tgstation.Server.Host/Core/Application.cs b/src/Tgstation.Server.Host/Core/Application.cs index be0478420f..05b5234e0c 100644 --- a/src/Tgstation.Server.Host/Core/Application.cs +++ b/src/Tgstation.Server.Host/Core/Application.cs @@ -60,6 +60,11 @@ namespace Tgstation.Server.Host.Core /// readonly TaskCompletionSource startupTcs; + /// + /// The for the + /// + ITokenFactory tokenFactory; + /// /// Construct an /// @@ -105,14 +110,9 @@ namespace Tgstation.Server.Host.Core services.AddSingleton(); services.AddSingleton(); - //needed here for JWT configuration - //we use a manually instatiated token factory to prevent it from regenerating the signing key after we configure it - services.AddSingleton(new TokenFactory()); - GeneralConfiguration generalConfiguration; DatabaseConfiguration databaseConfiguration; FileLoggingConfiguration fileLoggingConfiguration; - ITokenFactory tokenFactory; IIOManager ioManager; IPlatformIdentifier platformIdentifier; @@ -141,7 +141,6 @@ namespace Tgstation.Server.Host.Core var loggingOptions = provider.GetRequiredService>(); fileLoggingConfiguration = loggingOptions.Value; - tokenFactory = provider.GetRequiredService(); ioManager = provider.GetRequiredService(); platformIdentifier = provider.GetRequiredService(); } @@ -199,6 +198,8 @@ namespace Tgstation.Server.Host.Core //configure bearer token validation services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(jwtBearerOptions => { + //this line isn't actually run until the first request is made + //at that point tokenFactory will be populated jwtBearerOptions.TokenValidationParameters = tokenFactory.ValidationParameters; jwtBearerOptions.Events = new JwtBearerEvents { @@ -255,6 +256,7 @@ namespace Tgstation.Server.Host.Core services.AddScoped(); services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); services.AddSingleton, PasswordHasher>(); //configure platform specific services @@ -307,17 +309,21 @@ namespace Tgstation.Server.Host.Core /// Configure the /// /// The to configure + /// The for the + /// The value of /// The for the - /// The for the application - public void Configure(IApplicationBuilder applicationBuilder, ILogger logger, IServerControl serverControl) + public void Configure(IApplicationBuilder applicationBuilder, IServerControl serverControl, ITokenFactory tokenFactory, ILogger logger) { if (applicationBuilder == null) throw new ArgumentNullException(nameof(applicationBuilder)); - if (logger == null) - throw new ArgumentNullException(nameof(logger)); if (serverControl == null) throw new ArgumentNullException(nameof(serverControl)); + this.tokenFactory = tokenFactory ?? throw new ArgumentNullException(nameof(tokenFactory)); + + if (logger == null) + throw new ArgumentNullException(nameof(logger)); + logger.LogInformation(VersionString); //attempt to restart the server if the configuration changes diff --git a/src/Tgstation.Server.Host/Security/CryptographySuite.cs b/src/Tgstation.Server.Host/Security/CryptographySuite.cs index b702fc0475..4cdd6be43a 100644 --- a/src/Tgstation.Server.Host/Security/CryptographySuite.cs +++ b/src/Tgstation.Server.Host/Security/CryptographySuite.cs @@ -9,18 +9,9 @@ namespace Tgstation.Server.Host.Security sealed class CryptographySuite : ICryptographySuite { /// - /// Generates a secure set of s + /// Length in s of generated base64 secure string /// - /// A secure set of s - public static byte[] GetSecureBytes(int amount) - { - using (var rng = new RNGCryptoServiceProvider()) - { - var byt = new byte[amount]; - rng.GetBytes(byt); - return byt; - } - } + const uint SecureStringLength = 30; /// /// The for the @@ -31,14 +22,28 @@ namespace Tgstation.Server.Host.Security /// Construct a /// /// The value of - public CryptographySuite(IPasswordHasher passwordHasher) => this.passwordHasher = passwordHasher ?? throw new ArgumentNullException(nameof(passwordHasher)); + public CryptographySuite(IPasswordHasher passwordHasher) + { + this.passwordHasher = passwordHasher ?? throw new ArgumentNullException(nameof(passwordHasher)); + } + + /// + public byte[] GetSecureBytes(uint amount) + { + using (var rng = new RNGCryptoServiceProvider()) + { + var byt = new byte[amount]; + rng.GetBytes(byt); + return byt; + } + } /// public void SetUserPassword(User user, string newPassword, bool newUser) { if (user == null) throw new ArgumentNullException(nameof(user)); - if (String.IsNullOrEmpty(newPassword)) + if (newPassword == null) throw new ArgumentNullException(nameof(newPassword)); user.PasswordHash = passwordHasher.HashPassword(user, newPassword); if (!newUser) @@ -53,14 +58,13 @@ namespace Tgstation.Server.Host.Security case PasswordVerificationResult.Failed: return false; case PasswordVerificationResult.SuccessRehashNeeded: - user.PasswordHash = passwordHasher.HashPassword(user, password); - //don't update LastPasswordUpdate since it hasn't actually changed + SetUserPassword(user, password, false); break; } return true; } /// - public string GetSecureString() => Convert.ToBase64String(GetSecureBytes(30)); + public string GetSecureString() => Convert.ToBase64String(GetSecureBytes(SecureStringLength)); } } diff --git a/src/Tgstation.Server.Host/Security/ICryptographySuite.cs b/src/Tgstation.Server.Host/Security/ICryptographySuite.cs index 87e64f7978..540fb60e9f 100644 --- a/src/Tgstation.Server.Host/Security/ICryptographySuite.cs +++ b/src/Tgstation.Server.Host/Security/ICryptographySuite.cs @@ -7,6 +7,13 @@ namespace Tgstation.Server.Host.Security /// public interface ICryptographySuite { + /// + /// Generates a secure set of s + /// + /// The amount of s to generate + /// A secure set of s + byte[] GetSecureBytes(uint amount); + /// /// Sets a for a given /// diff --git a/src/Tgstation.Server.Host/Security/TokenFactory.cs b/src/Tgstation.Server.Host/Security/TokenFactory.cs index 8fa34381ff..661f52f91a 100644 --- a/src/Tgstation.Server.Host/Security/TokenFactory.cs +++ b/src/Tgstation.Server.Host/Security/TokenFactory.cs @@ -7,6 +7,7 @@ using System.Security.Claims; using System.Threading; using System.Threading.Tasks; using Tgstation.Server.Api.Models; +using Tgstation.Server.Host.Core; namespace Tgstation.Server.Host.Security { @@ -16,20 +17,37 @@ namespace Tgstation.Server.Host.Security /// /// Amount of minutes until generated s expire /// - const int TokenExpiryMinutes = 15; + const uint TokenExpiryMinutes = 15; + + /// + /// Amount of minutes to skew the clock for validation + /// + const uint TokenClockSkewMinutes = 1; + + /// + /// Amount of bytes to use in the + /// + const uint TokenSigningKeyByteAmount = 256; /// public TokenValidationParameters ValidationParameters { get; } + /// + /// The for the + /// + readonly IAsyncDelayer asyncDelayer; + /// /// Construct a /// - public TokenFactory() + /// The value of + /// The used for generating the + public TokenFactory(IAsyncDelayer asyncDelayer, ICryptographySuite cryptographySuite) { ValidationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true, - IssuerSigningKey = new SymmetricSecurityKey(CryptographySuite.GetSecureBytes(256)), + IssuerSigningKey = new SymmetricSecurityKey(cryptographySuite.GetSecureBytes(TokenSigningKeyByteAmount)), ValidateIssuer = true, ValidIssuer = Assembly.GetExecutingAssembly().GetName().Name, @@ -38,12 +56,14 @@ namespace Tgstation.Server.Host.Security ValidateAudience = true, ValidAudience = typeof(Token).Assembly.GetName().Name, - ClockSkew = TimeSpan.FromMinutes(1), + ClockSkew = TimeSpan.FromMinutes(TokenClockSkewMinutes), RequireSignedTokens = true, RequireExpirationTime = true }; + + this.asyncDelayer = asyncDelayer ?? throw new ArgumentNullException(nameof(asyncDelayer)); } /// @@ -56,9 +76,13 @@ namespace Tgstation.Server.Host.Security var nowUnix = now.ToUnixTimeSeconds(); //this prevents validation conflicts down the line + //tldr we can (theoretically) send a token the same second we receive it + //since unix time rounds down, it looks like it came from before the user changed their password + //this happens occasionally in unit tests + //just delay a second so we can force a round up var lpuUnix = user.LastPasswordUpdate?.ToUnixTimeSeconds(); if (nowUnix == lpuUnix) - await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken).ConfigureAwait(false); + await asyncDelayer.Delay(TimeSpan.FromSeconds(1), cancellationToken).ConfigureAwait(false); var expiry = now.AddMinutes(TokenExpiryMinutes); var claims = new Claim[] diff --git a/tests/Tgstation.Server.Host.Tests/Core/TestApplication.cs b/tests/Tgstation.Server.Host.Tests/Core/TestApplication.cs index f3747f0fe7..191b5d05b4 100644 --- a/tests/Tgstation.Server.Host.Tests/Core/TestApplication.cs +++ b/tests/Tgstation.Server.Host.Tests/Core/TestApplication.cs @@ -2,7 +2,6 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; @@ -11,6 +10,7 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using Tgstation.Server.Host.Configuration; +using Tgstation.Server.Host.Security; namespace Tgstation.Server.Host.Core.Tests { @@ -32,13 +32,16 @@ namespace Tgstation.Server.Host.Core.Tests var app = new Application(mockConfiguration.Object, mockHostingEnvironment.Object); Assert.ThrowsException(() => app.ConfigureServices(null)); - Assert.ThrowsException(() => app.Configure(null, null, null)); + Assert.ThrowsException(() => app.Configure(null, null, null, null)); var mockAppBuilder = new Mock(); - Assert.ThrowsException(() => app.Configure(mockAppBuilder.Object, null, null)); + Assert.ThrowsException(() => app.Configure(mockAppBuilder.Object, null, null, null)); - var mockLogger = new Mock>(); - Assert.ThrowsException(() => app.Configure(mockAppBuilder.Object, mockLogger.Object, null)); + var mockServerControl = new Mock(); + Assert.ThrowsException(() => app.Configure(mockAppBuilder.Object, mockServerControl.Object, null, null)); + + var mockTokenFactory = new Mock(); + Assert.ThrowsException(() => app.Configure(mockAppBuilder.Object, mockServerControl.Object, mockTokenFactory.Object, null)); } class MockSetupWizard : ISetupWizard From 89a4ce2679edb12d793c215b55372300d7e75fd9 Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Mon, 15 Oct 2018 12:47:37 -0400 Subject: [PATCH 25/27] Add IAsyncDelayer to Chat --- src/Tgstation.Server.Host/Components/Chat/Chat.cs | 15 +++++++++++---- .../Components/Chat/ChatFactory.cs | 15 +++++++++++---- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Chat/Chat.cs b/src/Tgstation.Server.Host/Components/Chat/Chat.cs index de28124c76..b4d68b1139 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Chat.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Chat.cs @@ -39,6 +39,11 @@ namespace Tgstation.Server.Host.Components.Chat /// readonly IRestartRegistration restartRegistration; + /// + /// The for the + /// + readonly IAsyncDelayer asyncDelayer; + /// /// The for the /// @@ -109,18 +114,20 @@ namespace Tgstation.Server.Host.Components.Chat /// /// The value of /// The value of - /// The value of - /// The value of /// The value of /// The to populate with + /// The value of + /// The value of + /// The value of /// The used to populate - public Chat(IProviderFactory providerFactory, IIOManager ioManager, ICommandFactory commandFactory, IServerControl serverControl, ILoggerFactory loggerFactory, ILogger logger, IEnumerable initialChatBots) + public Chat(IProviderFactory providerFactory, IIOManager ioManager, ICommandFactory commandFactory, IServerControl serverControl, IAsyncDelayer asyncDelayer, ILoggerFactory loggerFactory, ILogger logger, IEnumerable initialChatBots) { this.providerFactory = providerFactory ?? throw new ArgumentNullException(nameof(providerFactory)); this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager)); this.commandFactory = commandFactory ?? throw new ArgumentNullException(nameof(commandFactory)); if (serverControl == null) throw new ArgumentNullException(nameof(serverControl)); + this.asyncDelayer = asyncDelayer ?? throw new ArgumentNullException(nameof(asyncDelayer)); this.loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory)); this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); this.initialChatBots = initialChatBots?.ToList() ?? throw new ArgumentNullException(nameof(initialChatBots)); @@ -344,7 +351,7 @@ namespace Tgstation.Server.Host.Components.Chat if (messageTasks.Count == 0) { - await Task.Delay(1000, cancellationToken).ConfigureAwait(false); + await asyncDelayer.Delay(TimeSpan.FromSeconds(1), cancellationToken).ConfigureAwait(false); continue; } diff --git a/src/Tgstation.Server.Host/Components/Chat/ChatFactory.cs b/src/Tgstation.Server.Host/Components/Chat/ChatFactory.cs index 28e1323dde..15d353e644 100644 --- a/src/Tgstation.Server.Host/Components/Chat/ChatFactory.cs +++ b/src/Tgstation.Server.Host/Components/Chat/ChatFactory.cs @@ -25,20 +25,27 @@ namespace Tgstation.Server.Host.Components.Chat /// readonly IServerControl serverControl; + /// + /// The for the + /// + readonly IAsyncDelayer asyncDelayer; + /// /// Construct a /// - /// The value of /// The value of /// The value of - public ChatFactory(ILoggerFactory loggerFactory, IProviderFactory providerFactory, IServerControl serverControl) + /// The value of + /// The value of + public ChatFactory(IProviderFactory providerFactory, IServerControl serverControl, IAsyncDelayer asyncDelayer, ILoggerFactory loggerFactory) { - this.loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory)); this.providerFactory = providerFactory ?? throw new ArgumentNullException(nameof(providerFactory)); this.serverControl = serverControl ?? throw new ArgumentNullException(nameof(serverControl)); + this.asyncDelayer = asyncDelayer ?? throw new ArgumentNullException(nameof(asyncDelayer)); + this.loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory)); } /// - public IChat CreateChat(IIOManager ioManager, ICommandFactory commandFactory, IEnumerable initialChatBots) => new Chat(providerFactory, ioManager, commandFactory, serverControl, loggerFactory, loggerFactory.CreateLogger(), initialChatBots); + public IChat CreateChat(IIOManager ioManager, ICommandFactory commandFactory, IEnumerable initialChatBots) => new Chat(providerFactory, ioManager, commandFactory, serverControl, asyncDelayer, loggerFactory, loggerFactory.CreateLogger(), initialChatBots); } } From f6c4c5361d7ae6964737a54c9e0e3632cfc578aa Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Mon, 15 Oct 2018 12:55:03 -0400 Subject: [PATCH 26/27] Adds IAsyncDelayer to IrcProvider --- .../Components/Chat/ProviderFactory.cs | 23 ++++++++++++------- .../Components/Chat/Providers/IrcProvider.cs | 19 +++++++++++---- 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Chat/ProviderFactory.cs b/src/Tgstation.Server.Host/Components/Chat/ProviderFactory.cs index aee9d43965..14df6b306c 100644 --- a/src/Tgstation.Server.Host/Components/Chat/ProviderFactory.cs +++ b/src/Tgstation.Server.Host/Components/Chat/ProviderFactory.cs @@ -11,24 +11,31 @@ namespace Tgstation.Server.Host.Components.Chat /// sealed class ProviderFactory : IProviderFactory { - /// - /// The for the - /// - readonly ILoggerFactory loggerFactory; - /// /// The for the /// readonly IApplication application; + /// + /// The for the + /// + readonly IAsyncDelayer asyncDelayer; + + /// + /// The for the + /// + readonly ILoggerFactory loggerFactory; + /// /// Construct a /// - /// The value of /// The value of - public ProviderFactory(ILoggerFactory loggerFactory, IApplication application) + /// The value of + /// The value of + public ProviderFactory(IApplication application, IAsyncDelayer asyncDelayer, ILoggerFactory loggerFactory) { this.loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory)); + this.asyncDelayer = asyncDelayer ?? throw new ArgumentNullException(nameof(asyncDelayer)); this.application = application ?? throw new ArgumentNullException(nameof(application)); } @@ -44,7 +51,7 @@ namespace Tgstation.Server.Host.Components.Chat { case ChatProvider.Irc: var ircBuilder = (IrcConnectionStringBuilder)builder; - return new IrcProvider(loggerFactory.CreateLogger(), application, ircBuilder.Address, ircBuilder.Port.Value, ircBuilder.Nickname, ircBuilder.Password, ircBuilder.PasswordType, ircBuilder.UseSsl.Value); + return new IrcProvider(application, asyncDelayer, loggerFactory.CreateLogger(), ircBuilder.Address, ircBuilder.Port.Value, ircBuilder.Nickname, ircBuilder.Password, ircBuilder.PasswordType, ircBuilder.UseSsl.Value); case ChatProvider.Discord: var discordBuilder = (DiscordConnectionStringBuilder)builder; return new DiscordProvider(loggerFactory.CreateLogger(), discordBuilder.BotToken); diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs index ea2ff03a1c..cd08c1760e 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs @@ -25,6 +25,11 @@ namespace Tgstation.Server.Host.Components.Chat.Providers /// public override string BotMention => client.Nickname; + /// + /// The for the + /// + readonly IAsyncDelayer asyncDelayer; + /// /// The for the /// @@ -84,19 +89,21 @@ namespace Tgstation.Server.Host.Components.Chat.Providers /// /// Construct an /// - /// The value of logger /// The to get the from + /// The value of + /// The value of logger /// The value of /// The value of /// The value of /// The value of /// The value of /// If should be used - public IrcProvider(ILogger logger, IApplication application, string address, ushort port, string nickname, string password, IrcPasswordType? passwordType, bool useSsl) + public IrcProvider(IApplication application, IAsyncDelayer asyncDelayer, ILogger logger, string address, ushort port, string nickname, string password, IrcPasswordType? passwordType, bool useSsl) { - this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); if (application == null) throw new ArgumentNullException(nameof(application)); + this.asyncDelayer = asyncDelayer ?? throw new ArgumentNullException(nameof(asyncDelayer)); + this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); this.address = address ?? throw new ArgumentNullException(nameof(address)); this.port = port; @@ -267,13 +274,15 @@ namespace Tgstation.Server.Host.Components.Chat.Providers var startTime = DateTimeOffset.Now; var endTime = DateTimeOffset.Now.AddSeconds(TimeoutSeconds); cancellationToken.ThrowIfCancellationRequested(); - for (; !recievedAck && DateTimeOffset.Now <= endTime; Task.Delay(10, cancellationToken).GetAwaiter().GetResult()) + + var listenTimeSpan = TimeSpan.FromMilliseconds(10); + for (; !recievedAck && DateTimeOffset.Now <= endTime; asyncDelayer.Delay(listenTimeSpan, cancellationToken).GetAwaiter().GetResult()) client.Listen(false); client.WriteLine("AUTHENTICATE PLAIN", Priority.Critical); cancellationToken.ThrowIfCancellationRequested(); - for (; !recievedPlus && DateTimeOffset.Now <= endTime; Task.Delay(10, cancellationToken).GetAwaiter().GetResult()) + for (; !recievedPlus && DateTimeOffset.Now <= endTime; asyncDelayer.Delay(listenTimeSpan, cancellationToken).GetAwaiter().GetResult()) client.Listen(false); //Stolen! https://github.com/znc/znc/blob/1e697580155d5a38f8b5a377f3b1d94aaa979539/modules/sasl.cpp#L196 From 6d0e80254ea157732e40d66ed41d7f204c4cd26e Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Mon, 15 Oct 2018 13:46:32 -0400 Subject: [PATCH 27/27] Add missing ArgumentNullException --- src/Tgstation.Server.Host/Security/IdentityCacheObject.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Tgstation.Server.Host/Security/IdentityCacheObject.cs b/src/Tgstation.Server.Host/Security/IdentityCacheObject.cs index 33c48c38fd..9b54996f93 100644 --- a/src/Tgstation.Server.Host/Security/IdentityCacheObject.cs +++ b/src/Tgstation.Server.Host/Security/IdentityCacheObject.cs @@ -35,6 +35,10 @@ namespace Tgstation.Server.Host.Security public IdentityCacheObject(ISystemIdentity systemIdentity, IAsyncDelayer asyncDelayer, Action onExpiry, DateTimeOffset expiry) { SystemIdentity = systemIdentity ?? throw new ArgumentNullException(nameof(systemIdentity)); + + if (asyncDelayer == null) + throw new ArgumentNullException(nameof(asyncDelayer)); + if (onExpiry == null) throw new ArgumentNullException(nameof(onExpiry)); var now = DateTimeOffset.Now;