diff --git a/TShockAPI/Commands.cs b/TShockAPI/Commands.cs index a24b33dd..747bfa43 100755 --- a/TShockAPI/Commands.cs +++ b/TShockAPI/Commands.cs @@ -404,17 +404,23 @@ namespace TShockAPI User user = TShock.Users.GetUserByName(args.Player.Name); string encrPass = ""; - if (args.Parameters.Count == 1) + if (args.Parameters.Count == 0) { - if (Hooks.PlayerHooks.OnPlayerPreLogin(args.Player, args.Player.Name, args.Parameters[0])) - return; + if (Hooks.PlayerHooks.OnPlayerPreLogin(args.Player, args.Player.Name, "")) + return; + user = TShock.Users.GetUserByName(args.Player.Name); + } + else if (args.Parameters.Count == 1) + { + if (Hooks.PlayerHooks.OnPlayerPreLogin(args.Player, args.Player.Name, args.Parameters[0])) + return; user = TShock.Users.GetUserByName(args.Player.Name); encrPass = TShock.Utils.HashPassword(args.Parameters[0]); } else if (args.Parameters.Count == 2 && TShock.Config.AllowLoginAnyUsername) { - if (Hooks.PlayerHooks.OnPlayerPreLogin(args.Player, args.Parameters[0], args.Parameters[1])) - return; + if (Hooks.PlayerHooks.OnPlayerPreLogin(args.Player, args.Parameters[0], args.Parameters[1])) + return; user = TShock.Users.GetUserByName(args.Parameters[0]); encrPass = TShock.Utils.HashPassword(args.Parameters[1]); @@ -426,7 +432,7 @@ namespace TShockAPI } else { - args.Player.SendErrorMessage(String.Format("Syntax: /login{0} ", TShock.Config.AllowLoginAnyUsername ? " [username]" : " ")); + args.Player.SendErrorMessage(String.Format("Syntax: /login{0} [password]", TShock.Config.AllowLoginAnyUsername ? " [username]" : " ")); args.Player.SendErrorMessage("If you forgot your password, there is no way to recover it."); return; } @@ -436,7 +442,7 @@ namespace TShockAPI { args.Player.SendErrorMessage("A user by that name does not exist."); } - else if (user.Password.ToUpper() == encrPass.ToUpper()) + else if (user.Password.ToUpper() == encrPass.ToUpper() || (user.UUID == args.Player.UUID && !TShock.Config.DisableUUIDLogin)) { args.Player.PlayerData = TShock.InventoryDB.GetPlayerData(args.Player, TShock.Users.GetUserID(user.Name)); @@ -489,6 +495,7 @@ namespace TShockAPI args.Player.LoginHarassed = false; } + TShock.Users.SetUserUUID(user, args.Player.UUID); Hooks.PlayerHooks.OnPlayerPostLogin(args.Player); } @@ -562,6 +569,7 @@ namespace TShockAPI } user.Group = TShock.Config.DefaultRegistrationGroupName; // FIXME -- we should get this from the DB. --Why? + user.UUID = args.Player.UUID; if (TShock.Users.GetUserByName(user.Name) == null && user.Name != TSServerPlayer.AccountName) // Cheap way of checking for existance of a user { @@ -959,7 +967,7 @@ namespace TShockAPI string reason = args.Parameters.Count > 2 ? String.Join(" ", args.Parameters.GetRange(2, args.Parameters.Count - 2)) : "Manually added IP address ban."; - TShock.Bans.AddBan(ip, "", reason, false, args.Player.UserAccountName); + TShock.Bans.AddBan(ip, "", "", reason, false, args.Player.UserAccountName); args.Player.SendSuccessMessage(ip + " banned."); return; #endregion Add ip ban diff --git a/TShockAPI/ConfigFile.cs b/TShockAPI/ConfigFile.cs index c032da71..b890bf6b 100644 --- a/TShockAPI/ConfigFile.cs +++ b/TShockAPI/ConfigFile.cs @@ -105,6 +105,8 @@ namespace TShockAPI [Description("Enables kicking of banned users by matching their IP Address.")] public bool EnableIPBans = true; + [Description("Enables kicking of banned users by matching their client UUID.")] public bool EnableUUIDBans = true; + [Description("Enables kicking of banned users by matching their Character Name.")] public bool EnableBanOnUsernames; [Description("Selects the default group name to place new registrants under.")] public string @@ -206,6 +208,10 @@ namespace TShockAPI [Description("Disable users from being able to login with account password when joining.")] public bool DisableLoginBeforeJoin; + [Description("Disable users from being able to login with their client UUID.")] + public bool + DisableUUIDLogin; + [Description("Allows users to register any username with /register.")] public bool AllowRegisterAnyUsername; [Description("Allows users to login with any username with /login.")] public bool AllowLoginAnyUsername = true; diff --git a/TShockAPI/DB/BanManager.cs b/TShockAPI/DB/BanManager.cs index 4e7d1f92..1cece0df 100644 --- a/TShockAPI/DB/BanManager.cs +++ b/TShockAPI/DB/BanManager.cs @@ -34,6 +34,7 @@ namespace TShockAPI.DB var table = new SqlTable("Bans", new SqlColumn("IP", MySqlDbType.String, 16) {Primary = true}, new SqlColumn("Name", MySqlDbType.Text), + new SqlColumn("UUID", MySqlDbType.Text), new SqlColumn("Reason", MySqlDbType.Text), new SqlColumn("BanningUser", MySqlDbType.Text), new SqlColumn("Date", MySqlDbType.Text), @@ -61,7 +62,7 @@ namespace TShockAPI.DB using (var reader = database.QueryReader("SELECT * FROM Bans WHERE IP=@0", ip)) { if (reader.Read()) - return new Ban(reader.Get("IP"), reader.Get("Name"), reader.Get("Reason"), reader.Get("BanningUser"), reader.Get("Date"), reader.Get("Expiration")); + return new Ban(reader.Get("IP"), reader.Get("Name"), reader.Get("UUID"), reader.Get("Reason"), reader.Get("BanningUser"), reader.Get("Date"), reader.Get("Expiration")); } } catch (Exception ex) @@ -80,7 +81,7 @@ namespace TShockAPI.DB { while (reader.Read()) { - banlist.Add(new Ban(reader.Get("IP"), reader.Get("Name"), reader.Get("Reason"), reader.Get("BanningUser"), reader.Get("Date"), reader.Get("Expiration"))); + banlist.Add(new Ban(reader.Get("IP"), reader.Get("Name"), reader.Get("UUID"), reader.Get("Reason"), reader.Get("BanningUser"), reader.Get("Date"), reader.Get("Expiration"))); } return banlist; } @@ -103,7 +104,24 @@ namespace TShockAPI.DB using (var reader = database.QueryReader("SELECT * FROM Bans WHERE " + namecol + "=@0", name)) { if (reader.Read()) - return new Ban(reader.Get("IP"), reader.Get("Name"), reader.Get("Reason"), reader.Get("BanningUser"), reader.Get("Date"), reader.Get("Expiration")); + return new Ban(reader.Get("IP"), reader.Get("Name"), reader.Get("UUID"), reader.Get("Reason"), reader.Get("BanningUser"), reader.Get("Date"), reader.Get("Expiration")); + } + } + catch (Exception ex) + { + Log.Error(ex.ToString()); + } + return null; + } + + public Ban GetBanByUUID(string uuid) + { + try + { + using (var reader = database.QueryReader("SELECT * FROM Bans WHERE UUID=@0", uuid)) + { + if (reader.Read()) + return new Ban(reader.Get("IP"), reader.Get("Name"), reader.Get("UUID"), reader.Get("Reason"), reader.Get("BanningUser"), reader.Get("Date"), reader.Get("Expiration")); } } catch (Exception ex) @@ -120,11 +138,11 @@ namespace TShockAPI.DB return AddBan(ip, name, reason, false, "", ""); } #endif - public bool AddBan(string ip, string name = "", string reason = "", bool exceptions = false, string banner = "", string expiration = "") + public bool AddBan(string ip, string name = "", string uuid = "", string reason = "", bool exceptions = false, string banner = "", string expiration = "") { try { - return database.Query("INSERT INTO Bans (IP, Name, Reason, BanningUser, Date, Expiration) VALUES (@0, @1, @2, @3, @4, @5);", ip, name, reason, banner, DateTime.UtcNow.ToString("s"), expiration) != 0; + return database.Query("INSERT INTO Bans (IP, Name, UUID Reason, BanningUser, Date, Expiration) VALUES (@0, @1, @2, @3, @4, @5, @6);", ip, name, uuid, reason, banner, DateTime.UtcNow.ToString("s"), expiration) != 0; } catch (Exception ex) { @@ -181,6 +199,8 @@ namespace TShockAPI.DB public string Name { get; set; } + public string UUID { get; set; } + public string Reason { get; set; } public string BanningUser { get; set; } @@ -189,10 +209,11 @@ namespace TShockAPI.DB public string Expiration { get; set; } - public Ban(string ip, string name, string reason, string banner, string date, string exp) + public Ban(string ip, string name, string uuid, string reason, string banner, string date, string exp) { IP = ip; Name = name; + UUID = UUID; Reason = reason; BanningUser = banner; Date = date; @@ -203,6 +224,7 @@ namespace TShockAPI.DB { IP = string.Empty; Name = string.Empty; + UUID = string.Empty; Reason = string.Empty; BanningUser = ""; Date = ""; diff --git a/TShockAPI/DB/UserManager.cs b/TShockAPI/DB/UserManager.cs index 8585d907..37267b79 100644 --- a/TShockAPI/DB/UserManager.cs +++ b/TShockAPI/DB/UserManager.cs @@ -38,6 +38,7 @@ namespace TShockAPI.DB new SqlColumn("ID", MySqlDbType.Int32) {Primary = true, AutoIncrement = true}, new SqlColumn("Username", MySqlDbType.VarChar, 32) {Unique = true}, new SqlColumn("Password", MySqlDbType.VarChar, 128), + new SqlColumn("UUID", MySqlDbType.VarChar, 128), new SqlColumn("Usergroup", MySqlDbType.Text), new SqlColumn("Registered", MySqlDbType.Text), new SqlColumn("LastAccessed", MySqlDbType.Text), @@ -62,8 +63,8 @@ namespace TShockAPI.DB int ret; try { - ret = database.Query("INSERT INTO Users (Username, Password, UserGroup, Registered) VALUES (@0, @1, @2, @3);", user.Name, - TShock.Utils.HashPassword(user.Password), user.Group, DateTime.UtcNow.ToString("s")); + ret = database.Query("INSERT INTO Users (Username, Password, UUID, UserGroup, Registered) VALUES (@0, @1, @2, @3, @4);", user.Name, + TShock.Utils.HashPassword(user.Password), user.UUID, user.Group, DateTime.UtcNow.ToString("s")); } catch (Exception ex) { @@ -116,6 +117,26 @@ namespace TShockAPI.DB } } + /// + /// Sets the UUID for a given username + /// + /// User user + /// string uuid + public void SetUserUUID(User user, string uuid) + { + try + { + if ( + database.Query("UPDATE Users SET UUID = @0 WHERE Username = @1;", uuid, + user.Name) == 0) + throw new UserNotExistException(user.Name); + } + catch (Exception ex) + { + throw new UserManagerException("SetUserUUID SQL returned an error", ex); + } + } + /// /// Sets the group for a given username /// @@ -269,6 +290,7 @@ namespace TShockAPI.DB user.ID = result.Get("ID"); user.Group = result.Get("Usergroup"); user.Password = result.Get("Password"); + user.UUID = result.Get("UUID"); user.Name = result.Get("Username"); user.Registered = result.Get("Registered"); user.LastAccessed = result.Get("LastAccessed"); @@ -282,15 +304,17 @@ namespace TShockAPI.DB public int ID { get; set; } public string Name { get; set; } public string Password { get; set; } + public string UUID { get; set; } public string Group { get; set; } public string Registered { get; set; } public string LastAccessed { get; set; } public string KnownIps { get; set; } - public User(string name, string pass, string group, string registered, string last, string known) + public User(string name, string pass, string uuid, string group, string registered, string last, string known) { Name = name; Password = pass; + UUID = uuid; Group = group; Registered = registered; LastAccessed = last; @@ -301,6 +325,7 @@ namespace TShockAPI.DB { Name = ""; Password = ""; + UUID = ""; Group = ""; Registered = ""; LastAccessed = ""; diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs index e352e15f..d489bc1d 100755 --- a/TShockAPI/GetDataHandlers.cs +++ b/TShockAPI/GetDataHandlers.cs @@ -1396,7 +1396,59 @@ namespace TShockAPI { var user = TShock.Users.GetUserByName(args.Player.Name); - if (user != null && !TShock.Config.DisableLoginBeforeJoin) + if (user != null && !TShock.Config.DisableUUIDLogin) + { + if(user.UUID == args.Player.UUID) + { + args.Player.PlayerData = TShock.InventoryDB.GetPlayerData(args.Player, TShock.Users.GetUserID(args.Player.Name)); + + if (args.Player.State == 1) + args.Player.State = 2; + NetMessage.SendData((int)PacketTypes.WorldInfo, args.Player.Index); + + var group = TShock.Utils.GetGroup(user.Group); + + if (TShock.Config.ServerSideInventory) + { + if (group.HasPermission(Permissions.bypassinventorychecks)) + { + args.Player.IgnoreActionsForClearingTrashCan = false; + } + else if (!TShock.CheckInventory(args.Player)) + { + args.Player.LoginFailsBySsi = true; + args.Player.SendMessage("Login Failed, Please fix the above errors then /login again.", Color.Cyan); + args.Player.IgnoreActionsForClearingTrashCan = true; + return true; + } + } + args.Player.LoginFailsBySsi = false; + + if (group.HasPermission(Permissions.ignorestackhackdetection)) + args.Player.IgnoreActionsForCheating = "none"; + + if (group.HasPermission(Permissions.usebanneditem)) + args.Player.IgnoreActionsForDisabledArmor = "none"; + + args.Player.Group = group; + args.Player.tempGroup = null; + args.Player.UserAccountName = args.Player.Name; + args.Player.UserID = TShock.Users.GetUserID(args.Player.UserAccountName); + args.Player.IsLoggedIn = true; + args.Player.IgnoreActionsForInventory = "none"; + + if (!args.Player.IgnoreActionsForClearingTrashCan) + { + args.Player.PlayerData.CopyInventory(args.Player); + TShock.InventoryDB.InsertPlayerData(args.Player); + } + args.Player.SendMessage("Authenticated as " + args.Player.Name + " successfully.", Color.LimeGreen); + Log.ConsoleInfo(args.Player.Name + " authenticated successfully as user " + args.Player.Name + "."); + Hooks.PlayerHooks.OnPlayerPostLogin(args.Player); + return true; + } + } + else if (user != null && !TShock.Config.DisableLoginBeforeJoin) { args.Player.RequiresPassword = true; NetMessage.SendData((int) PacketTypes.PasswordRequired, args.Player.Index); @@ -1476,6 +1528,7 @@ namespace TShockAPI } args.Player.SendMessage("Authenticated as " + args.Player.Name + " successfully.", Color.LimeGreen); Log.ConsoleInfo(args.Player.Name + " authenticated successfully as user " + args.Player.Name + "."); + TShock.Users.SetUserUUID(user, args.Player.UUID); Hooks.PlayerHooks.OnPlayerPostLogin(args.Player); return true; } @@ -2163,6 +2216,11 @@ namespace TShockAPI return true; } + if (pulley > 2) + { + return true; + } + if (args.Player.LastNetPosition == Vector2.Zero) { return true; diff --git a/TShockAPI/Net/WorldInfoMsg.cs b/TShockAPI/Net/WorldInfoMsg.cs index 472fd861..9c94bbd5 100644 --- a/TShockAPI/Net/WorldInfoMsg.cs +++ b/TShockAPI/Net/WorldInfoMsg.cs @@ -32,7 +32,8 @@ namespace TShockAPI.Net DownedBoss2 = 4, DownedBoss3 = 8, HardMode = 16, - DownedClown = 32 + DownedClown = 32, + ServerSideCharacter = 64 } [Flags] @@ -141,7 +142,7 @@ namespace TShockAPI.Net stream.WriteByte(HellBackStyle); stream.WriteSingle(WindSpeed); stream.WriteByte(NumberOfClouds); - stream.WriteInt8((byte) BossFlags); + stream.WriteInt8((byte)BossFlags); stream.WriteInt8((byte)BossFlags2); stream.WriteSingle(Rain); stream.WriteBytes(Encoding.UTF8.GetBytes(WorldName)); diff --git a/TShockAPI/Rest/RestManager.cs b/TShockAPI/Rest/RestManager.cs index c14e38d8..63f48d62 100644 --- a/TShockAPI/Rest/RestManager.cs +++ b/TShockAPI/Rest/RestManager.cs @@ -307,7 +307,7 @@ namespace TShockAPI return RestMissingParam("password"); // NOTE: ip can be blank - User user = new User(username, password, group, "", "", ""); + User user = new User(username, password, "", group, "", "", ""); try { TShock.Users.AddUser(user); @@ -404,7 +404,7 @@ namespace TShockAPI try { - TShock.Bans.AddBan(ip, name, parameters["reason"], true, tokenData.Username); + TShock.Bans.AddBan(ip, name, "", parameters["reason"], true, tokenData.Username); } catch (Exception e) { @@ -622,7 +622,7 @@ namespace TShockAPI TSPlayer player = (TSPlayer)ret; var reason = null == parameters["reason"] ? "Banned via web" : parameters["reason"]; - TShock.Bans.AddBan(player.IP, player.Name, reason); + TShock.Bans.AddBan(player.IP, player.Name, "", reason); TShock.Utils.ForceKick(player, reason, false, true); return RestResponse("Player " + player.Name + " was banned"); } diff --git a/TShockAPI/TSPlayer.cs b/TShockAPI/TSPlayer.cs index 1f695a20..e49e76b1 100644 --- a/TShockAPI/TSPlayer.cs +++ b/TShockAPI/TSPlayer.cs @@ -305,6 +305,15 @@ namespace TShockAPI set { Netplay.serverSock[Index].state = value; } } + public string UUID + { + get { + return RealPlayer + ? Netplay.serverSock[Index].clientUUID + : ""; + } + } + public string IP { get @@ -495,7 +504,8 @@ namespace TShockAPI (NPC.downedBoss2 ? BossFlags.DownedBoss2 : BossFlags.None) | (NPC.downedBoss3 ? BossFlags.DownedBoss3 : BossFlags.None) | (Main.hardMode ? BossFlags.HardMode : BossFlags.None) | - (NPC.downedClown ? BossFlags.DownedClown : BossFlags.None), + (NPC.downedClown ? BossFlags.DownedClown : BossFlags.None) | + (Main.ServerSideCharacter ? BossFlags.ServerSideCharacter : BossFlags.None), BossFlags2 = (NPC.downedMechBoss1 ? BossFlags2.DownedMechBoss1 : BossFlags2.None) | (NPC.downedMechBoss2 ? BossFlags2.DownedMechBoss2 : BossFlags2.None) | (NPC.downedMechBoss3 ? BossFlags2.DownedMechBoss3 : BossFlags2.None) | diff --git a/TShockAPI/TShock.cs b/TShockAPI/TShock.cs index 290c1a27..5fdc1da8 100755 --- a/TShockAPI/TShock.cs +++ b/TShockAPI/TShock.cs @@ -845,6 +845,11 @@ namespace TShockAPI ban = Bans.GetBanByIp(player.IP); } + if (Config.EnableUUIDBans && null == ban) + { + ban = Bans.GetBanByUUID(player.UUID); + } + if (ban != null) { if (!Utils.HasBanExpired(ban)) diff --git a/TShockAPI/Utils.cs b/TShockAPI/Utils.cs index 351d5e77..ec0316a7 100644 --- a/TShockAPI/Utils.cs +++ b/TShockAPI/Utils.cs @@ -673,8 +673,9 @@ namespace TShockAPI if (force || !player.Group.HasPermission(Permissions.immunetoban)) { string ip = player.IP; + string uuid = player.UUID; string playerName = player.Name; - TShock.Bans.AddBan(ip, playerName, reason, false, adminUserName); + TShock.Bans.AddBan(ip, playerName, uuid, reason, false, adminUserName); player.Disconnect(string.Format("Banned: {0}", reason)); Log.ConsoleInfo(string.Format("Banned {0} for : {1}", playerName, reason)); string verb = force ? "force " : ""; diff --git a/UnitTests/BanManagerTest.cs b/UnitTests/BanManagerTest.cs index 730f11f0..b1eabc0c 100644 --- a/UnitTests/BanManagerTest.cs +++ b/UnitTests/BanManagerTest.cs @@ -54,7 +54,7 @@ namespace UnitTests [TestMethod] public void AddBanTest() { - Assert.IsTrue(Bans.AddBan("127.0.0.1", "BanTest", "Ban Testing")); + Assert.IsTrue(Bans.AddBan("127.0.0.1", "BanTest", "BanTest2", "Ban Testing")); } [TestMethod] @@ -62,6 +62,7 @@ namespace UnitTests { Assert.IsNotNull(Bans.GetBanByIp("127.0.0.1")); Assert.IsNotNull(Bans.GetBanByName("BanTest")); + Assert.IsNotNull(Bans.GetBanByUUID("BanTest2")); } } }