Migrate some manual password creation to BCrypt
Note that several times, user.Password was set to a plain text password, but then later changed to a hashed password, creating data inconsistency. This also changes User.Password to private set to prevent further accidents.
This commit is contained in:
parent
a5aa31376a
commit
ed34a87c3f
3 changed files with 78 additions and 14 deletions
|
|
@ -919,16 +919,18 @@ namespace TShockAPI
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var user = new User();
|
var user = new User();
|
||||||
|
string echoPassword = "";
|
||||||
if (args.Parameters.Count == 1)
|
if (args.Parameters.Count == 1)
|
||||||
{
|
{
|
||||||
user.Name = args.Player.Name;
|
user.Name = args.Player.Name;
|
||||||
user.Password = args.Parameters[0];
|
echoPassword = args.Parameters[0];
|
||||||
|
user.CreateBCryptHash(args.Parameters[0]);
|
||||||
}
|
}
|
||||||
else if (args.Parameters.Count == 2 && TShock.Config.AllowRegisterAnyUsername)
|
else if (args.Parameters.Count == 2 && TShock.Config.AllowRegisterAnyUsername)
|
||||||
{
|
{
|
||||||
user.Name = args.Parameters[0];
|
user.Name = args.Parameters[0];
|
||||||
user.Password = args.Parameters[1];
|
echoPassword = args.Parameters[1];
|
||||||
|
user.CreateBCryptHash(args.Parameters[1]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -942,7 +944,7 @@ namespace TShockAPI
|
||||||
if (TShock.Users.GetUserByName(user.Name) == null && user.Name != TSServerPlayer.AccountName) // Cheap way of checking for existance of a user
|
if (TShock.Users.GetUserByName(user.Name) == null && user.Name != TSServerPlayer.AccountName) // Cheap way of checking for existance of a user
|
||||||
{
|
{
|
||||||
args.Player.SendSuccessMessage("Account \"{0}\" has been registered.", user.Name);
|
args.Player.SendSuccessMessage("Account \"{0}\" has been registered.", user.Name);
|
||||||
args.Player.SendSuccessMessage("Your password is {0}.", user.Password);
|
args.Player.SendSuccessMessage("Your password is {0}.", echoPassword);
|
||||||
TShock.Users.AddUser(user);
|
TShock.Users.AddUser(user);
|
||||||
TShock.Log.ConsoleInfo("{0} registered an account: \"{1}\".", args.Player.Name, user.Name);
|
TShock.Log.ConsoleInfo("{0} registered an account: \"{1}\".", args.Player.Name, user.Name);
|
||||||
}
|
}
|
||||||
|
|
@ -976,7 +978,7 @@ namespace TShockAPI
|
||||||
var user = new User();
|
var user = new User();
|
||||||
|
|
||||||
user.Name = args.Parameters[1];
|
user.Name = args.Parameters[1];
|
||||||
user.Password = args.Parameters[2];
|
user.CreateBCryptHash(args.Parameters[2]);
|
||||||
user.Group = args.Parameters[3];
|
user.Group = args.Parameters[3];
|
||||||
|
|
||||||
try
|
try
|
||||||
|
|
|
||||||
|
|
@ -21,9 +21,11 @@ using System.CodeDom.Compiler;
|
||||||
using System.Data;
|
using System.Data;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
using MySql.Data.MySqlClient;
|
using MySql.Data.MySqlClient;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using BCrypt.Net;
|
using BCrypt.Net;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
|
||||||
namespace TShockAPI.DB
|
namespace TShockAPI.DB
|
||||||
{
|
{
|
||||||
|
|
@ -309,7 +311,7 @@ namespace TShockAPI.DB
|
||||||
{
|
{
|
||||||
public int ID { get; set; }
|
public int ID { get; set; }
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public string Password { get; set; }
|
public string Password { get; internal set; }
|
||||||
public string UUID { get; set; }
|
public string UUID { get; set; }
|
||||||
public string Group { get; set; }
|
public string Group { get; set; }
|
||||||
public string Registered { get; set; }
|
public string Registered { get; set; }
|
||||||
|
|
@ -354,7 +356,7 @@ namespace TShockAPI.DB
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} catch (SaltParseException) {
|
} catch (SaltParseException) {
|
||||||
if (TShock.Utils.HashPassword(password).ToUpper() == this.Password.ToUpper()) {
|
if (hashPassword(password).ToUpper() == this.Password.ToUpper()) {
|
||||||
// The password is not stored using BCrypt; upgrade it to BCrypt immediately
|
// The password is not stored using BCrypt; upgrade it to BCrypt immediately
|
||||||
upgradePasswordToBCrypt(password);
|
upgradePasswordToBCrypt(password);
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -406,6 +408,61 @@ namespace TShockAPI.DB
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void CreateBCryptHash(string password) {
|
||||||
|
try {
|
||||||
|
this.Password = BCrypt.Net.BCrypt.HashPassword(password, TShock.Config.WorkFactor);
|
||||||
|
} catch (ArgumentOutOfRangeException) {
|
||||||
|
TShock.Log.ConsoleError("Invalid BCrypt work factor! Creating new hash using default work factor.");
|
||||||
|
this.Password = BCrypt.Net.BCrypt.HashPassword(password);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A dictionary of hashing algortihms and an implementation object.
|
||||||
|
/// </summary>
|
||||||
|
internal readonly Dictionary<string, Func<HashAlgorithm>> HashTypes = new Dictionary<string, Func<HashAlgorithm>>
|
||||||
|
{
|
||||||
|
{"sha512", () => new SHA512Managed()},
|
||||||
|
{"sha256", () => new SHA256Managed()},
|
||||||
|
{"md5", () => new MD5Cng()},
|
||||||
|
{"sha512-xp", () => SHA512.Create()},
|
||||||
|
{"sha256-xp", () => SHA256.Create()},
|
||||||
|
{"md5-xp", () => MD5.Create()},
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a Sha256 string for a given string
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="bytes">bytes to hash</param>
|
||||||
|
/// <returns>string sha256</returns>
|
||||||
|
internal string hashPassword(byte[] bytes)
|
||||||
|
{
|
||||||
|
if (bytes == null)
|
||||||
|
throw new NullReferenceException("bytes");
|
||||||
|
Func<HashAlgorithm> func;
|
||||||
|
if (!HashTypes.TryGetValue(TShock.Config.HashAlgorithm.ToLower(), out func))
|
||||||
|
throw new NotSupportedException("Hashing algorithm {0} is not supported".SFormat(TShock.Config.HashAlgorithm.ToLower()));
|
||||||
|
|
||||||
|
using (var hash = func())
|
||||||
|
{
|
||||||
|
var ret = hash.ComputeHash(bytes);
|
||||||
|
return ret.Aggregate("", (s, b) => s + b.ToString("X2"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a hashed password string for a given string
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="password">string to hash</param>
|
||||||
|
/// <returns>string sha256</returns>
|
||||||
|
internal string hashPassword(string password)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(password) || password == "non-existant password")
|
||||||
|
return null;
|
||||||
|
return hashPassword(Encoding.UTF8.GetBytes(password));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using Terraria;
|
using Terraria;
|
||||||
using TShockAPI.DB;
|
using TShockAPI.DB;
|
||||||
|
using BCrypt.Net;
|
||||||
|
|
||||||
namespace TShockAPI
|
namespace TShockAPI
|
||||||
{
|
{
|
||||||
|
|
@ -722,11 +723,13 @@ namespace TShockAPI
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default hashing algorithm.
|
/// Default hashing algorithm.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[Obsolete("This is no longer necessary, please use TShock.Config.HashAlgorithm instead.")]
|
||||||
public string HashAlgo = "sha512";
|
public string HashAlgo = "sha512";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A dictionary of hashing algortihms and an implementation object.
|
/// A dictionary of hashing algortihms and an implementation object.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[Obsolete("This is no longer necessary, after switching to User.VerifyPassword(password) instead.")]
|
||||||
public readonly Dictionary<string, Func<HashAlgorithm>> HashTypes = new Dictionary<string, Func<HashAlgorithm>>
|
public readonly Dictionary<string, Func<HashAlgorithm>> HashTypes = new Dictionary<string, Func<HashAlgorithm>>
|
||||||
{
|
{
|
||||||
{"sha512", () => new SHA512Managed()},
|
{"sha512", () => new SHA512Managed()},
|
||||||
|
|
@ -742,6 +745,7 @@ namespace TShockAPI
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="bytes">bytes to hash</param>
|
/// <param name="bytes">bytes to hash</param>
|
||||||
/// <returns>string sha256</returns>
|
/// <returns>string sha256</returns>
|
||||||
|
[Obsolete("Please use User.VerifyPassword(password) instead. Warning: This will upgrade passwords to BCrypt. Already converted passwords will not hash correctly using this method.")]
|
||||||
public string HashPassword(byte[] bytes)
|
public string HashPassword(byte[] bytes)
|
||||||
{
|
{
|
||||||
if (bytes == null)
|
if (bytes == null)
|
||||||
|
|
@ -762,6 +766,7 @@ namespace TShockAPI
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="password">string to hash</param>
|
/// <param name="password">string to hash</param>
|
||||||
/// <returns>string sha256</returns>
|
/// <returns>string sha256</returns>
|
||||||
|
[Obsolete("Please use User.VerifyPassword(password) instead. Warning: This will upgrade passwords to BCrypt. Already converted passwords will not hash correctly using this method.")]
|
||||||
public string HashPassword(string password)
|
public string HashPassword(string password)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(password) || password == "non-existant password")
|
if (string.IsNullOrEmpty(password) || password == "non-existant password")
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue