diff --git a/src/Tgstation.Server.Api/Models/Administration.cs b/src/Tgstation.Server.Api/Models/Administration.cs
index 1aed2dad16..374d82a178 100644
--- a/src/Tgstation.Server.Api/Models/Administration.cs
+++ b/src/Tgstation.Server.Api/Models/Administration.cs
@@ -7,7 +7,6 @@ namespace Tgstation.Server.Api.Models
///
/// Metadata about an installation
///
- [Model(RightsType.Administration)]
public sealed class Administration : Internal.ServerSettings
{
///
diff --git a/src/Tgstation.Server.Api/Models/ChatChannel.cs b/src/Tgstation.Server.Api/Models/ChatChannel.cs
index 737b41203d..1ad3c74629 100644
--- a/src/Tgstation.Server.Api/Models/ChatChannel.cs
+++ b/src/Tgstation.Server.Api/Models/ChatChannel.cs
@@ -3,13 +3,8 @@
///
/// Indicates a chat channel
///
- public sealed class ChatChannel
+ public class ChatChannel
{
- ///
- /// The column ID
- ///
- public long Id { get; set; }
-
///
/// The IRC channel name
///
diff --git a/src/Tgstation.Server.Api/Models/ChatSettings.cs b/src/Tgstation.Server.Api/Models/ChatSettings.cs
index 593e6c4a8c..a6350f0aa3 100644
--- a/src/Tgstation.Server.Api/Models/ChatSettings.cs
+++ b/src/Tgstation.Server.Api/Models/ChatSettings.cs
@@ -1,63 +1,21 @@
using System.Collections.Generic;
-using System.ComponentModel.DataAnnotations;
-using System.ComponentModel.DataAnnotations.Schema;
using Tgstation.Server.Api.Rights;
namespace Tgstation.Server.Api.Models
{
- ///
- /// Manage the server chat bots
- ///
- [Model(RightsType.Chat, RequiresInstance = true)]
- public class ChatSettings
+ ///
+ public sealed class ChatSettings : Internal.ChatSettings
{
- ///
- /// If the IRC client is enabled
- ///
- [Permissions(WriteRight = ChatSettingsRights.SetIrcEnabled)]
- public bool IrcEnabled { get; set; }
-
- ///
- /// The IRC server name
- ///
- [Permissions(ReadRight = ChatSettingsRights.SetIrcSettings, WriteRight = ChatSettingsRights.SetIrcSettings)]
- [Required]
- public string IrcHost { get; set; }
-
- ///
- /// The IRC server port
- ///
- [Permissions(ReadRight = ChatSettingsRights.SetIrcSettings, WriteRight = ChatSettingsRights.SetIrcSettings)]
- public ushort IrcPort { get; set; }
-
- ///
- /// The IRC server NickServ password
- ///
- [Permissions(ReadRight = ChatSettingsRights.SetIrcSettings, WriteRight = ChatSettingsRights.SetIrcSettings)]
- public string IrcNickServPassword { get; set; }
-
- ///
- /// If the Discord bot is enabled
- ///
- [Permissions(WriteRight = ChatSettingsRights.SetDiscordEnabled)]
- public bool DiscordEnabled { get; set; }
-
- ///
- /// The Discord bot token
- ///
- [Permissions(ReadRight = ChatSettingsRights.SetDiscordSettings, WriteRight = ChatSettingsRights.SetDiscordSettings)]
- public string DiscordBotToken { get; set; }
-
///
/// Channels the bot should listen/announce in and allow admin commands
///
[Permissions(WriteRight = ChatSettingsRights.SetDiscordChannels)]
- public virtual List AdminChannels { get; set; }
+ public List AdminChannels { get; set; }
///
/// Channels the Discord bot should listen/announce in
///
[Permissions(WriteRight = ChatSettingsRights.SetDiscordChannels)]
- public virtual List GeneralChannels { get; set; }
+ public List GeneralChannels { get; set; }
}
}
diff --git a/src/Tgstation.Server.Api/Models/Internal/ChatSettings.cs b/src/Tgstation.Server.Api/Models/Internal/ChatSettings.cs
new file mode 100644
index 0000000000..b98d62b906
--- /dev/null
+++ b/src/Tgstation.Server.Api/Models/Internal/ChatSettings.cs
@@ -0,0 +1,51 @@
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations.Schema;
+using Tgstation.Server.Api.Rights;
+
+namespace Tgstation.Server.Api.Models.Internal
+{
+ ///
+ /// Manage the server chat bots
+ ///
+ [Model(RightsType.Chat, RequiresInstance = true)]
+ public class ChatSettings
+ {
+ ///
+ /// If the IRC client is enabled
+ ///
+ [Permissions(WriteRight = ChatSettingsRights.SetIrcEnabled)]
+ public bool IrcEnabled { get; set; }
+
+ ///
+ /// The IRC server name
+ ///
+ [Permissions(ReadRight = ChatSettingsRights.SetIrcSettings, WriteRight = ChatSettingsRights.SetIrcSettings)]
+ [Required]
+ public string IrcHost { get; set; }
+
+ ///
+ /// The IRC server port
+ ///
+ [Permissions(ReadRight = ChatSettingsRights.SetIrcSettings, WriteRight = ChatSettingsRights.SetIrcSettings)]
+ public ushort IrcPort { get; set; }
+
+ ///
+ /// The IRC server NickServ password
+ ///
+ [Permissions(ReadRight = ChatSettingsRights.SetIrcSettings, WriteRight = ChatSettingsRights.SetIrcSettings)]
+ public string IrcNickServPassword { get; set; }
+
+ ///
+ /// If the Discord bot is enabled
+ ///
+ [Permissions(WriteRight = ChatSettingsRights.SetDiscordEnabled)]
+ public bool DiscordEnabled { get; set; }
+
+ ///
+ /// The Discord bot token
+ ///
+ [Permissions(ReadRight = ChatSettingsRights.SetDiscordSettings, WriteRight = ChatSettingsRights.SetDiscordSettings)]
+ public string DiscordBotToken { get; set; }
+ }
+}
diff --git a/src/Tgstation.Server.Api/Models/Internal/ServerSettings.cs b/src/Tgstation.Server.Api/Models/Internal/ServerSettings.cs
index 7aa96da12b..9a46e42237 100644
--- a/src/Tgstation.Server.Api/Models/Internal/ServerSettings.cs
+++ b/src/Tgstation.Server.Api/Models/Internal/ServerSettings.cs
@@ -2,6 +2,7 @@
namespace Tgstation.Server.Api.Models.Internal
{
+ [Model(RightsType.Administration)]
public class ServerSettings
{
///
diff --git a/src/Tgstation.Server.Api/Models/Internal/User.cs b/src/Tgstation.Server.Api/Models/Internal/User.cs
new file mode 100644
index 0000000000..0368a0d1b9
--- /dev/null
+++ b/src/Tgstation.Server.Api/Models/Internal/User.cs
@@ -0,0 +1,48 @@
+using System;
+using System.ComponentModel.DataAnnotations;
+using Tgstation.Server.Api.Rights;
+
+namespace Tgstation.Server.Api.Models.Internal
+{
+ ///
+ /// Represents a server
+ ///
+ [Model(RightsType.Administration, WriteRight = AdministrationRights.EditUsers)]
+ public class User
+ {
+ ///
+ /// The ID of the
+ ///
+ [Permissions(DenyWrite = true)]
+ public long Id { get; set; }
+
+ [Permissions(DenyWrite = true)]
+ [Required]
+ public DateTimeOffset CreatedAt { get; set; }
+
+ ///
+ /// The SID/UID of the on Windows/POSIX respectively
+ ///
+ [Permissions(DenyWrite = true)]
+ public string SystemIdentifier { get; set; }
+
+ ///
+ /// The name of the
+ ///
+ [Permissions(WriteRight = AdministrationRights.EditUsers)]
+ [Required]
+ public string Name { get; set; }
+
+ ///
+ /// The for the
+ ///
+ [Permissions(WriteRight = AdministrationRights.EditUsers)]
+ public AdministrationRights AdministrationRights { get; set; }
+
+ ///
+ /// The for the
+ ///
+ [Permissions(WriteRight = AdministrationRights.EditUsers)]
+ public InstanceManagerRights InstanceManagerRights { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Tgstation.Server.Api/Models/User.cs b/src/Tgstation.Server.Api/Models/User.cs
index 70bd28bed1..bb8c604138 100644
--- a/src/Tgstation.Server.Api/Models/User.cs
+++ b/src/Tgstation.Server.Api/Models/User.cs
@@ -1,51 +1,11 @@
-using System;
-using System.ComponentModel.DataAnnotations;
-using Tgstation.Server.Api.Rights;
-
-namespace Tgstation.Server.Api.Models
+namespace Tgstation.Server.Api.Models
{
///
/// Represents a server
///
- [Model(RightsType.Administration, WriteRight = AdministrationRights.EditUsers)]
- public class User
+ public sealed class User : Internal.User
{
- ///
- /// The ID of the
- ///
- [Permissions(DenyWrite = true)]
- public long Id { get; set; }
-
- [Permissions(DenyWrite = true)]
- [Required]
- public DateTimeOffset CreatedAt { get; set; }
-
- ///
- /// The SID/UID of the on Windows/POSIX respectively
- ///
- [Permissions(DenyWrite = true)]
- public string SystemIdentifier { get; set; }
-
[Permissions(DenyWrite = true)]
public bool Enabled { get; set; }
-
- ///
- /// The name of the
- ///
- [Permissions(WriteRight = AdministrationRights.EditUsers)]
- [Required]
- public string Name { get; set; }
-
- ///
- /// The for the
- ///
- [Permissions(WriteRight = AdministrationRights.EditUsers)]
- public AdministrationRights AdministrationRights { get; set; }
-
- ///
- /// The for the
- ///
- [Permissions(WriteRight = AdministrationRights.EditUsers)]
- public InstanceManagerRights InstanceManagerRights { get; set; }
}
}
\ No newline at end of file
diff --git a/src/Tgstation.Server.Api/Rights/RightsHelper.cs b/src/Tgstation.Server.Api/Rights/RightsHelper.cs
index 0fc6e5efcc..0f754c4d13 100644
--- a/src/Tgstation.Server.Api/Rights/RightsHelper.cs
+++ b/src/Tgstation.Server.Api/Rights/RightsHelper.cs
@@ -15,7 +15,6 @@ namespace Tgstation.Server.Api.Rights
{
{ RightsType.Administration, typeof(AdministrationRights) },
{ RightsType.InstanceManager, typeof(InstanceManagerRights) },
- { RightsType.Token, typeof(TokenRights) },
{ RightsType.Repository, typeof(RepositoryRights) },
{ RightsType.Byond, typeof(ByondRights) },
diff --git a/src/Tgstation.Server.Api/Rights/RightsType.cs b/src/Tgstation.Server.Api/Rights/RightsType.cs
index a15d9d2d03..5b4ff0722c 100644
--- a/src/Tgstation.Server.Api/Rights/RightsType.cs
+++ b/src/Tgstation.Server.Api/Rights/RightsType.cs
@@ -13,11 +13,6 @@
///
///
InstanceManager,
- ///
- ///
- ///
- Token,
-
///
///
///
diff --git a/src/Tgstation.Server.Api/Rights/TokenRights.cs b/src/Tgstation.Server.Api/Rights/TokenRights.cs
deleted file mode 100644
index 98f5bf3f03..0000000000
--- a/src/Tgstation.Server.Api/Rights/TokenRights.cs
+++ /dev/null
@@ -1,32 +0,0 @@
-using System;
-
-namespace Tgstation.Server.Api.Rights
-{
- ///
- /// Rights for s
- ///
- [Flags]
- public enum TokenRights
- {
- ///
- /// User has no rights
- ///
- None = 0,
- ///
- /// User can create s
- ///
- Create = 1,
- ///
- /// User can delete s
- ///
- Delete = 2,
- ///
- /// User can list all their s
- ///
- List = 4,
- ///
- /// User can perform all the actions they can for themselves on behalf of other users except
- ///
- Admin = 8,
- }
-}
diff --git a/src/Tgstation.Server.Host/Core/Application.cs b/src/Tgstation.Server.Host/Core/Application.cs
index 2a8d4f6f78..3e392b41d2 100644
--- a/src/Tgstation.Server.Host/Core/Application.cs
+++ b/src/Tgstation.Server.Host/Core/Application.cs
@@ -1,6 +1,7 @@
using Cyberboss.AspNetCore.AsyncInitializer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System;
@@ -46,6 +47,10 @@ namespace Tgstation.Server.Host.Core
services.AddDbContext();
services.AddScoped(x => x.GetRequiredService());
+
+ services.AddSingleton();
+ services.AddSingleton();
+ services.AddSingleton, PasswordHasher>();
}
///
diff --git a/src/Tgstation.Server.Host/Core/CryptographySuite.cs b/src/Tgstation.Server.Host/Core/CryptographySuite.cs
new file mode 100644
index 0000000000..9cd7294780
--- /dev/null
+++ b/src/Tgstation.Server.Host/Core/CryptographySuite.cs
@@ -0,0 +1,70 @@
+using Microsoft.AspNetCore.Identity;
+using System;
+using System.Security.Cryptography;
+using System.Text;
+using Tgstation.Server.Host.Models;
+
+namespace Tgstation.Server.Host.Core
+{
+ ///
+ sealed class CryptographySuite : ICryptographySuite
+ {
+ ///
+ /// The length of secure strings used in the application
+ ///
+ public const int SecureStringLength = 40;
+
+ ///
+ /// Generates a secure ascii of length
+ ///
+ /// A secure ascii of length
+ static string GenerateSecureString()
+ {
+ using (var rng = new RNGCryptoServiceProvider())
+ {
+ var byt = new byte[1];
+ var result = new StringBuilder
+ {
+ Capacity = SecureStringLength
+ };
+ while (result.Length < SecureStringLength)
+ {
+ rng.GetBytes(byt);
+ var chr = (char)byt[0];
+ if (Char.IsLetterOrDigit(chr))
+ result.Append(chr);
+ }
+ return result.ToString();
+ }
+ }
+
+ ///
+ /// The for the
+ ///
+ readonly IPasswordHasher passwordHasher;
+
+ ///
+ /// Construct a
+ ///
+ /// The value of
+ public CryptographySuite(IPasswordHasher passwordHasher) => this.passwordHasher = passwordHasher ?? throw new ArgumentNullException(nameof(passwordHasher));
+
+ ///
+ public void RegenerateUserToken(User user)
+ {
+ if (user == null)
+ throw new ArgumentNullException(nameof(user));
+ user.TokenSecret = GenerateSecureString();
+ }
+
+ ///
+ public void SetUserPassword(User user, string newPassword)
+ {
+ if (user == null)
+ throw new ArgumentNullException(nameof(user));
+ if (String.IsNullOrEmpty(newPassword))
+ throw new ArgumentNullException(nameof(newPassword));
+ user.PasswordHash = passwordHasher.HashPassword(user, newPassword);
+ }
+ }
+}
diff --git a/src/Tgstation.Server.Host/Core/ICryptographySuite.cs b/src/Tgstation.Server.Host/Core/ICryptographySuite.cs
new file mode 100644
index 0000000000..f773c17301
--- /dev/null
+++ b/src/Tgstation.Server.Host/Core/ICryptographySuite.cs
@@ -0,0 +1,23 @@
+using Tgstation.Server.Host.Models;
+
+namespace Tgstation.Server.Host.Core
+{
+ ///
+ /// Contains various cryptographic functions
+ ///
+ interface ICryptographySuite
+ {
+ ///
+ /// Sets a for a given
+ ///
+ /// The whos is to be set
+ /// The new password for the
+ void SetUserPassword(User user, string newPassword);
+
+ ///
+ /// Sets a new for a givent
+ ///
+ /// The whos is to be set
+ void RegenerateUserToken(User user);
+ }
+}
diff --git a/src/Tgstation.Server.Host/Models/ChatChannel.cs b/src/Tgstation.Server.Host/Models/ChatChannel.cs
new file mode 100644
index 0000000000..8429585cdf
--- /dev/null
+++ b/src/Tgstation.Server.Host/Models/ChatChannel.cs
@@ -0,0 +1,10 @@
+namespace Tgstation.Server.Host.Models
+{
+ sealed class ChatChannel : Api.Models.ChatChannel
+ {
+ ///
+ /// The column ID
+ ///
+ public long Id { get; set; }
+ }
+}
diff --git a/src/Tgstation.Server.Host/Models/ChatSettings.cs b/src/Tgstation.Server.Host/Models/ChatSettings.cs
index 0b798988c0..c62d8e23dd 100644
--- a/src/Tgstation.Server.Host/Models/ChatSettings.cs
+++ b/src/Tgstation.Server.Host/Models/ChatSettings.cs
@@ -1,10 +1,9 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
-using Tgstation.Server.Api.Models;
namespace Tgstation.Server.Host.Models
{
- sealed class ChatSettings : Api.Models.ChatSettings
+ sealed class ChatSettings : Api.Models.Internal.ChatSettings
{
public long Id { get; set; }
@@ -12,5 +11,9 @@ namespace Tgstation.Server.Host.Models
[Required]
public Instance Instance { get; set; }
+
+ public List AdminChannels { get; set; }
+
+ public List GeneralChannels { get; set; }
}
}
diff --git a/src/Tgstation.Server.Host/Models/DatabaseContext.cs b/src/Tgstation.Server.Host/Models/DatabaseContext.cs
index 5880046f97..1a6cf81e00 100644
--- a/src/Tgstation.Server.Host/Models/DatabaseContext.cs
+++ b/src/Tgstation.Server.Host/Models/DatabaseContext.cs
@@ -3,10 +3,14 @@ using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System;
+using System.Linq;
+using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using Tgstation.Server.Api.Models;
+using Tgstation.Server.Api.Rights;
using Tgstation.Server.Host.Configuration;
+using Tgstation.Server.Host.Core;
using ZNetCS.AspNetCore.Logging.EntityFrameworkCore;
namespace Tgstation.Server.Host.Models
@@ -49,6 +53,10 @@ namespace Tgstation.Server.Host.Models
/// The for the
///
readonly IHostingEnvironment hostingEnvironment;
+ ///
+ /// The for the
+ ///
+ readonly IDatabaseSeeder databaseSeeder;
///
/// Construct a
@@ -57,11 +65,13 @@ namespace Tgstation.Server.Host.Models
/// The containing the value of
/// The value of
/// The value of
- public DatabaseContext(DbContextOptions dbContextOptions, IOptions databaseConfigurationOptions, ILoggerFactory loggerFactory, IHostingEnvironment hostingEnvironment) : base(dbContextOptions)
+ /// The value of
+ public DatabaseContext(DbContextOptions dbContextOptions, IOptions databaseConfigurationOptions, ILoggerFactory loggerFactory, IHostingEnvironment hostingEnvironment, IDatabaseSeeder databaseSeeder) : base(dbContextOptions)
{
databaseConfiguration = databaseConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(databaseConfigurationOptions));
this.loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory));
this.hostingEnvironment = hostingEnvironment ?? throw new ArgumentNullException(nameof(hostingEnvironment));
+ this.databaseSeeder = databaseSeeder ?? throw new ArgumentNullException(nameof(databaseSeeder));
}
///
@@ -98,13 +108,25 @@ namespace Tgstation.Server.Host.Models
}
///
- public Task GetServerSettings(CancellationToken cancellationToken) => ServerSettings.FirstOrDefaultAsync(cancellationToken);
+ public async Task GetServerSettings(CancellationToken cancellationToken)
+ {
+ var settings = await ServerSettings.FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false);
+ if (settings == default(ServerSettings))
+ {
+ settings = new ServerSettings();
+ ServerSettings.Add(settings);
+ }
+ return settings;
+ }
///
public async Task Initialize(CancellationToken cancellationToken)
{
- await Database.EnsureCreatedAsync(cancellationToken).ConfigureAwait(false);
+ var migrations = await Database.GetAppliedMigrationsAsync().ConfigureAwait(false);
+ var wasEmpty = !migrations.Any();
await Database.MigrateAsync(cancellationToken).ConfigureAwait(false);
+ if (wasEmpty)
+ await databaseSeeder.SeedDatabase(this, cancellationToken).ConfigureAwait(false);
}
///
diff --git a/src/Tgstation.Server.Host/Models/DatabaseSeeder.cs b/src/Tgstation.Server.Host/Models/DatabaseSeeder.cs
new file mode 100644
index 0000000000..278692554e
--- /dev/null
+++ b/src/Tgstation.Server.Host/Models/DatabaseSeeder.cs
@@ -0,0 +1,55 @@
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using Tgstation.Server.Api.Rights;
+using Tgstation.Server.Host.Core;
+
+namespace Tgstation.Server.Host.Models
+{
+ ///
+ sealed class DatabaseSeeder : IDatabaseSeeder
+ {
+ ///
+ /// The default password mode admin password
+ ///
+ const string DefaultAdminPassword = "ISolemlySwearToDeleteTheDataDirectory";
+
+ ///
+ /// The default git repository to pull server updates from
+ ///
+ const string DefaultUpstreamRepository = "https://github.com/tgstation/tgstation-server";
+
+ ///
+ /// The for the
+ ///
+ readonly ICryptographySuite cryptographySuite;
+
+ ///
+ /// Construct a
+ ///
+ /// The value of
+ public DatabaseSeeder(ICryptographySuite cryptographySuite) => this.cryptographySuite = cryptographySuite ?? throw new ArgumentNullException(nameof(cryptographySuite));
+
+ ///
+ public async Task SeedDatabase(IDatabaseContext databaseContext, CancellationToken cancellationToken)
+ {
+ var admin = new User
+ {
+ AdministrationRights = (AdministrationRights)~0,
+ CreatedAt = DateTimeOffset.Now,
+ InstanceManagerRights = (InstanceManagerRights)~0,
+ Name = "Admin"
+ };
+ cryptographySuite.RegenerateUserToken(admin);
+ cryptographySuite.SetUserPassword(admin, DefaultAdminPassword);
+ databaseContext.Users.Add(admin);
+
+ var serverSettings = await databaseContext.GetServerSettings(cancellationToken).ConfigureAwait(false);
+
+ serverSettings.EnableTelemetry = true;
+ serverSettings.UpstreamRepository = DefaultUpstreamRepository;
+
+ await databaseContext.Save(cancellationToken).ConfigureAwait(false);
+ }
+ }
+}
diff --git a/src/Tgstation.Server.Host/Models/IDatabaseSeeder.cs b/src/Tgstation.Server.Host/Models/IDatabaseSeeder.cs
new file mode 100644
index 0000000000..f57620fd0a
--- /dev/null
+++ b/src/Tgstation.Server.Host/Models/IDatabaseSeeder.cs
@@ -0,0 +1,19 @@
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Tgstation.Server.Host.Models
+{
+ ///
+ /// For initially seeding a database
+ ///
+ interface IDatabaseSeeder
+ {
+ ///
+ /// Initially seed a given
+ ///
+ /// The to seed
+ /// The for the operation
+ /// A representing the running operation
+ Task SeedDatabase(IDatabaseContext databaseContext, CancellationToken cancellationToken);
+ }
+}
diff --git a/src/Tgstation.Server.Host/Models/ServerSettings.cs b/src/Tgstation.Server.Host/Models/ServerSettings.cs
index 365d9b3aa2..8a84475dad 100644
--- a/src/Tgstation.Server.Host/Models/ServerSettings.cs
+++ b/src/Tgstation.Server.Host/Models/ServerSettings.cs
@@ -5,11 +5,5 @@ namespace Tgstation.Server.Host.Models
sealed class ServerSettings : Api.Models.Internal.ServerSettings
{
public long Id { get; set; }
-
- ///
- /// The value used for the to encrypt JWTs
- ///
- [Required]
- public byte[] TokenSecret { get; set; }
}
}
diff --git a/src/Tgstation.Server.Host/Models/User.cs b/src/Tgstation.Server.Host/Models/User.cs
index 149768c00d..be2d1ae09d 100644
--- a/src/Tgstation.Server.Host/Models/User.cs
+++ b/src/Tgstation.Server.Host/Models/User.cs
@@ -1,15 +1,21 @@
using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using Tgstation.Server.Host.Core;
namespace Tgstation.Server.Host.Models
{
///
/// Represents a in the database
///
- sealed class User : Api.Models.User
+ sealed class User : Api.Models.Internal.User
{
public string PasswordHash { get; set; }
- public string PasswordSalt { get; set; }
+ ///
+ /// The value used for the to encrypt JWTs
+ ///
+ [StringLength(CryptographySuite.SecureStringLength)]
+ public string TokenSecret { get; set; }
///
/// The s for the
diff --git a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj
index 3b031e0289..f97f3f42ea 100644
--- a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj
+++ b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj
@@ -38,6 +38,7 @@
+