Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

THIS REPOSITORY IS A MIRROR AND WILL NOT ACCEPT PULL REQUESTS #1

Open
wants to merge 1 commit into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/Tgstation.Server.Host/Core/Application.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
using Tgstation.Server.Host.Components.Watchdog;
using Tgstation.Server.Host.Configuration;
using Tgstation.Server.Host.Controllers;
using Tgstation.Server.Host.Database;
using Tgstation.Server.Host.IO;
using Tgstation.Server.Host.Models;
using Tgstation.Server.Host.Security;
Expand Down Expand Up @@ -129,6 +130,7 @@ public void ConfigureServices(IServiceCollection services)
services.AddSingleton<ISetupWizard, SetupWizard>();
services.AddSingleton<IPlatformIdentifier, PlatformIdentifier>();
services.AddSingleton<IAsyncDelayer, AsyncDelayer>();
services.AddSingleton<IDefaultLogin, DefaultLogin>();

GeneralConfiguration generalConfiguration;
DatabaseConfiguration databaseConfiguration;
Expand Down
33 changes: 26 additions & 7 deletions src/Tgstation.Server.Host/Core/SetupWizard.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
using System.Threading;
using System.Threading.Tasks;
using Tgstation.Server.Host.Configuration;
using Tgstation.Server.Host.Database;
using Tgstation.Server.Host.IO;

namespace Tgstation.Server.Host.Core
Expand Down Expand Up @@ -62,7 +63,12 @@ sealed class SetupWizard : ISetupWizard
readonly ILogger<SetupWizard> logger;

/// <summary>
/// The <see cref="GeneralConfiguration"/> for the <see cref="SetupWizard"/>
/// The <see cref="IDefaultLogin"/> for the <see cref="SetupWizard"/>.
/// </summary>
readonly IDefaultLogin defaultLogin;

/// <summary>
/// The <see cref="GeneralConfiguration"/> for the <see cref="SetupWizard"/>.
/// </summary>
readonly GeneralConfiguration generalConfiguration;

Expand All @@ -76,9 +82,10 @@ sealed class SetupWizard : ISetupWizard
/// <param name="dbConnectionFactory">The value of <see cref="dbConnectionFactory"/></param>
/// <param name="platformIdentifier">The value of <see cref="platformIdentifier"/></param>
/// <param name="asyncDelayer">The value of <see cref="asyncDelayer"/></param>
/// <param name="defaultLogin">The value of <see cref="defaultLogin"/>.</param>
/// <param name="logger">The value of <see cref="logger"/></param>
/// <param name="generalConfigurationOptions">The <see cref="IOptions{TOptions}"/> containing the value of <see cref="generalConfiguration"/></param>
public SetupWizard(IIOManager ioManager, IConsole console, IHostingEnvironment hostingEnvironment, IApplication application, IDBConnectionFactory dbConnectionFactory, IPlatformIdentifier platformIdentifier, IAsyncDelayer asyncDelayer, ILogger<SetupWizard> logger, IOptions<GeneralConfiguration> generalConfigurationOptions)
public SetupWizard(IIOManager ioManager, IConsole console, IHostingEnvironment hostingEnvironment, IApplication application, IDBConnectionFactory dbConnectionFactory, IPlatformIdentifier platformIdentifier, IAsyncDelayer asyncDelayer, IDefaultLogin defaultLogin, ILogger<SetupWizard> logger, IOptions<GeneralConfiguration> generalConfigurationOptions)
{
this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager));
this.console = console ?? throw new ArgumentNullException(nameof(console));
Expand All @@ -87,6 +94,7 @@ public SetupWizard(IIOManager ioManager, IConsole console, IHostingEnvironment h
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.defaultLogin = defaultLogin ?? throw new ArgumentNullException(nameof(defaultLogin));
this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
generalConfiguration = generalConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(generalConfigurationOptions));
}
Expand Down Expand Up @@ -140,9 +148,10 @@ async Task<bool> PromptYesNo(string question, CancellationToken cancellationToke
/// <summary>
/// Prompts the user to create a <see cref="DatabaseConfiguration"/>
/// </summary>
/// <param name="noPromptDefaultUserPassword">Whether or not the default username and password should be prompted for.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation</param>
/// <returns>A <see cref="Task{TResult}"/> resulting in the new <see cref="DatabaseConfiguration"/></returns>
async Task<DatabaseConfiguration> ConfigureDatabase(CancellationToken cancellationToken)
async Task<DatabaseConfiguration> ConfigureDatabase(bool noPromptDefaultUserPassword, CancellationToken cancellationToken)
{
do
{
Expand Down Expand Up @@ -337,6 +346,14 @@ void CreateTestConnection(string connectionString)
await console.PressAnyKeyAsync(cancellationToken).ConfigureAwait(false);
}
}

if (!noPromptDefaultUserPassword)
{
await console.WriteAsync($"Enter initial admin password (optional, default \"{defaultLogin.Password}\"): ", false, cancellationToken).ConfigureAwait(false);
var defaultPassword = await console.ReadLineAsync(false, cancellationToken).ConfigureAwait(false);
if (!String.IsNullOrEmpty(defaultPassword))
defaultLogin.Password = defaultPassword;
}
}
}

Expand Down Expand Up @@ -592,9 +609,10 @@ async Task SaveConfiguration(string userConfigFileName, ushort? hostingPort, Dat
/// Runs the <see cref="SetupWizard"/>
/// </summary>
/// <param name="userConfigFileName">The path to the settings json to build</param>
/// <param name="noPromptDefaultUserPassword">Whether or not the default username and password should be prompted for.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation</param>
/// <returns>A <see cref="Task"/> representing the running operation</returns>
async Task RunWizard(string userConfigFileName, CancellationToken cancellationToken)
async Task RunWizard(string userConfigFileName, bool noPromptDefaultUserPassword, CancellationToken cancellationToken)
{
// welcome message
await console.WriteAsync(null, true, cancellationToken).ConfigureAwait(false);
Expand All @@ -603,7 +621,7 @@ async Task RunWizard(string userConfigFileName, CancellationToken cancellationTo

var hostingPort = await PromptForHostingPort(cancellationToken).ConfigureAwait(false);

var databaseConfiguration = await ConfigureDatabase(cancellationToken).ConfigureAwait(false);
var databaseConfiguration = await ConfigureDatabase(noPromptDefaultUserPassword, cancellationToken).ConfigureAwait(false);

var newGeneralConfiguration = await ConfigureGeneral(cancellationToken).ConfigureAwait(false);

Expand All @@ -628,7 +646,8 @@ public async Task<bool> CheckRunWizard(CancellationToken cancellationToken)
return false;
}

var forceRun = setupWizardMode == SetupWizardMode.Force || setupWizardMode == SetupWizardMode.Only;
var noPromptDefaultUserPassword = setupWizardMode == SetupWizardMode.Only;
var forceRun = setupWizardMode == SetupWizardMode.Force || noPromptDefaultUserPassword;
if (!console.Available)
{
if (forceRun)
Expand Down Expand Up @@ -685,7 +704,7 @@ async Task HandleSetupCancel()
// flush the logs to prevent console conflicts
await asyncDelayer.Delay(TimeSpan.FromSeconds(1), cancellationToken).ConfigureAwait(false);

await RunWizard(userConfigFileName, cancellationToken).ConfigureAwait(false);
await RunWizard(userConfigFileName, noPromptDefaultUserPassword, cancellationToken).ConfigureAwait(false);
}
finally
{
Expand Down
14 changes: 14 additions & 0 deletions src/Tgstation.Server.Host/Database/DefaultLogin.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using Tgstation.Server.Api.Models;

namespace Tgstation.Server.Host.Database
{
/// <inheritdoc />
sealed class DefaultLogin : IDefaultLogin
{
/// <inheritdoc />
public string UserName { get; } = User.AdminName;

/// <inheritdoc />
public string Password { get; set; } = User.DefaultAdminPassword;
}
}
18 changes: 18 additions & 0 deletions src/Tgstation.Server.Host/Database/IDefaultLogin.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
namespace Tgstation.Server.Host.Database
{
/// <summary>
/// For setting the default login credentials upon server setup.
/// </summary>
interface IDefaultLogin
{
/// <summary>
/// Gets the default username.
/// </summary>
string UserName { get; }

/// <summary>
/// Gets or sets the default password.
/// </summary>
string Password { get; set; }
}
}
22 changes: 16 additions & 6 deletions src/Tgstation.Server.Host/Models/DatabaseSeeder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,21 @@ sealed class DatabaseSeeder : IDatabaseSeeder
/// </summary>
readonly ICryptographySuite cryptographySuite;

/// <summary>
/// The <see cref="IDefaultLogin"/> for the <see cref="DatabaseSeeder"/>
/// </summary>
readonly IDefaultLogin defaultLogin;

/// <summary>
/// Construct a <see cref="DatabaseSeeder"/>
/// </summary>
/// <param name="cryptographySuite">The value of <see cref="cryptographySuite"/></param>
public DatabaseSeeder(ICryptographySuite cryptographySuite) => this.cryptographySuite = cryptographySuite ?? throw new ArgumentNullException(nameof(cryptographySuite));
/// <param name="defaultLogin">The value of <see cref="defaultLogin"/>.</param>
public DatabaseSeeder(ICryptographySuite cryptographySuite, IDefaultLogin defaultLogin)
{
this.cryptographySuite = cryptographySuite ?? throw new ArgumentNullException(nameof(cryptographySuite));
this.defaultLogin = defaultLogin ?? throw new ArgumentNullException(nameof(defaultLogin));
}

/// <summary>
/// Add a default admin <see cref="User"/> to a given <paramref name="databaseContext"/>
Expand All @@ -33,11 +43,11 @@ void SeedAdminUser(IDatabaseContext databaseContext)
AdministrationRights = (AdministrationRights)~0U,
CreatedAt = DateTimeOffset.Now,
InstanceManagerRights = (InstanceManagerRights)~0U,
Name = Api.Models.User.AdminName,
CanonicalName = Api.Models.User.AdminName.ToUpperInvariant(),
Name = defaultLogin.UserName,
CanonicalName = defaultLogin.UserName.ToUpperInvariant(),
Enabled = true,
};
cryptographySuite.SetUserPassword(admin, Api.Models.User.DefaultAdminPassword, true);
cryptographySuite.SetUserPassword(admin, defaultLogin.Password, true);
databaseContext.Users.Add(admin);
}

Expand All @@ -51,13 +61,13 @@ public async Task SeedDatabase(IDatabaseContext databaseContext, CancellationTok
/// <inheritdoc />
public async Task ResetAdminPassword(IDatabaseContext databaseContext, CancellationToken cancellationToken)
{
var admin = await databaseContext.Users.Where(x => x.CanonicalName == Api.Models.User.AdminName.ToUpperInvariant()).FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false);
var admin = await databaseContext.Users.Where(x => x.CanonicalName == defaultLogin.UserName.ToUpperInvariant()).FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false);
if (admin == default)
SeedAdminUser(databaseContext);
else
{
admin.Enabled = true;
cryptographySuite.SetUserPassword(admin, Api.Models.User.DefaultAdminPassword, false);
cryptographySuite.SetUserPassword(admin, defaultLogin.Password, false);
}

await databaseContext.Save(cancellationToken).ConfigureAwait(false);
Expand Down