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
|
||||
{
|
||||
var user = new User();
|
||||
|
||||
string echoPassword = "";
|
||||
if (args.Parameters.Count == 1)
|
||||
{
|
||||
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)
|
||||
{
|
||||
user.Name = args.Parameters[0];
|
||||
user.Password = args.Parameters[1];
|
||||
echoPassword = args.Parameters[1];
|
||||
user.CreateBCryptHash(args.Parameters[1]);
|
||||
}
|
||||
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
|
||||
{
|
||||
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.Log.ConsoleInfo("{0} registered an account: \"{1}\".", args.Player.Name, user.Name);
|
||||
}
|
||||
|
|
@ -976,7 +978,7 @@ namespace TShockAPI
|
|||
var user = new User();
|
||||
|
||||
user.Name = args.Parameters[1];
|
||||
user.Password = args.Parameters[2];
|
||||
user.CreateBCryptHash(args.Parameters[2]);
|
||||
user.Group = args.Parameters[3];
|
||||
|
||||
try
|
||||
|
|
|
|||
|
|
@ -21,9 +21,11 @@ using System.CodeDom.Compiler;
|
|||
using System.Data;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using MySql.Data.MySqlClient;
|
||||
using System.Text.RegularExpressions;
|
||||
using BCrypt.Net;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace TShockAPI.DB
|
||||
{
|
||||
|
|
@ -309,7 +311,7 @@ namespace TShockAPI.DB
|
|||
{
|
||||
public int ID { 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 Group { get; set; }
|
||||
public string Registered { get; set; }
|
||||
|
|
@ -354,7 +356,7 @@ namespace TShockAPI.DB
|
|||
return true;
|
||||
}
|
||||
} 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
|
||||
upgradePasswordToBCrypt(password);
|
||||
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]
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ using System.Text;
|
|||
using System.Text.RegularExpressions;
|
||||
using Terraria;
|
||||
using TShockAPI.DB;
|
||||
using BCrypt.Net;
|
||||
|
||||
namespace TShockAPI
|
||||
{
|
||||
|
|
@ -719,14 +720,16 @@ namespace TShockAPI
|
|||
ply.SendErrorMessage("Use \"my query\" for items with spaces");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Default hashing algorithm.
|
||||
/// </summary>
|
||||
public string HashAlgo = "sha512";
|
||||
/// <summary>
|
||||
/// Default hashing algorithm.
|
||||
/// </summary>
|
||||
[Obsolete("This is no longer necessary, please use TShock.Config.HashAlgorithm instead.")]
|
||||
public string HashAlgo = "sha512";
|
||||
|
||||
/// <summary>
|
||||
/// A dictionary of hashing algortihms and an implementation object.
|
||||
/// </summary>
|
||||
/// <summary>
|
||||
/// A dictionary of hashing algortihms and an implementation object.
|
||||
/// </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>>
|
||||
{
|
||||
{"sha512", () => new SHA512Managed()},
|
||||
|
|
@ -742,6 +745,7 @@ namespace TShockAPI
|
|||
/// </summary>
|
||||
/// <param name="bytes">bytes to hash</param>
|
||||
/// <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)
|
||||
{
|
||||
if (bytes == null)
|
||||
|
|
@ -762,6 +766,7 @@ namespace TShockAPI
|
|||
/// </summary>
|
||||
/// <param name="password">string to hash</param>
|
||||
/// <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)
|
||||
{
|
||||
if (string.IsNullOrEmpty(password) || password == "non-existant password")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue