From da055867c937101d01f558ccfbcfa9da544edf62 Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Thu, 30 Jun 2011 19:41:37 -0600 Subject: [PATCH] Added basic system for logging in and adding users ingame. --- TShockAPI/Commands.cs | 70 ++++++++++++++++++++++++++++++++++- TShockAPI/TSPlayer.cs | 1 + TShockAPI/Tools.cs | 75 ++++++++++++++++++++++++++++++++++++++ TShockAPI/UpdateManager.cs | 2 +- 4 files changed, 146 insertions(+), 2 deletions(-) diff --git a/TShockAPI/Commands.cs b/TShockAPI/Commands.cs index e53473d4..804c18f4 100755 --- a/TShockAPI/Commands.cs +++ b/TShockAPI/Commands.cs @@ -144,6 +144,8 @@ namespace TShockAPI ChatCommands.Add(new Command("p", "", PartyChat)); ChatCommands.Add(new Command("rules", "", Rules)); ChatCommands.Add(new Command("displaylogs", "logs", Rules)); + ChatCommands.Add(new Command("user", "manageusers", ManageUsers)); + ChatCommands.Add(new Command("login", "", AttemptLogin)); if (ConfigurationManager.DistributationAgent != "terraria-online") { ChatCommands.Add(new Command("kill", "kill", Kill)); @@ -157,7 +159,7 @@ namespace TShockAPI public static void AddUpdateCommand() { - Commands.ChatCommands.Add(new Command("updatenow", "maintenance", Commands.UpdateNow)); + //Commands.ChatCommands.Add(new Command("updatenow", "maintenance", Commands.UpdateNow)); } public static bool HandleCommand(TSPlayer player, string text) @@ -280,6 +282,72 @@ namespace TShockAPI return c == ' ' || c == '\t' || c == '\n'; } + #region Account commands + + public static void AttemptLogin(CommandArgs args) + { + if (args.Parameters.Count != 2) + { + args.Player.SendMessage("Syntax: /login [username] [password]"); + args.Player.SendMessage("If you forgot your password, there is no way to recover it."); + return; + } + + string encrPass = Tools.HashPassword(args.Parameters[1]); + string[] exr = Tools.FetchHashedPasswordAndGroup(args.Parameters[0]); + if (exr[0] == Tools.HashPassword(args.Parameters[1])) + { + args.Player.Group = Tools.GetGroup(exr[1]); + args.Player.SendMessage("Authenticated as " + args.Parameters[0] + "successfully.", Color.LimeGreen); + return; + } else + { + args.Player.SendMessage("Invalid login attempt. This incident has been reported.", Color.Red); + Log.Warn(args.Player.IP + " failed to authenticate as " + args.Parameters[0]); + args.Player.LoginAttempts++; + return; + } + } + + private static void ManageUsers(CommandArgs args) + { + if (args.Parameters.Count < 3) + { + args.Player.SendMessage("Syntax: /user add [group]"); + args.Player.SendMessage("Note: Passwords are stored with very basic Hashion. To reset a user's password, remove and re-add them."); + return; + } + + if (args.Parameters.Count > 2) + { + if (args.Parameters[0] == "add") + { + if (args.Parameters[1].Split(':').Length == 2) + { + TextWriter tw = new StreamWriter(FileTools.UsersPath, true); + tw.WriteLine("\n" + args.Parameters[1].Split(':')[0] + ":" + Tools.HashPassword(args.Parameters[1].Split(':')[0]) + " " + args.Parameters[2]); + tw.Close(); + //Notify the admin that they can now login + return; + } + else if (args.Parameters[1].Split(':').Length == 1) + { + TextWriter tw = new StreamWriter(FileTools.UsersPath, true); + tw.WriteLine("\n" + args.Parameters[1] + " " + args.Parameters[2]); + tw.Close(); + //Notify the admin that they can now login if they rejoin + //Notify admin that this is fucking insecure + return; + } + else + { + args.Player.SendMessage("Invalid syntax. Try /user help.", Color.Red); + } + } + } + } + #endregion + #region Player Management Commands private static void Kick(CommandArgs args) diff --git a/TShockAPI/TSPlayer.cs b/TShockAPI/TSPlayer.cs index c25eca69..da8e20ef 100644 --- a/TShockAPI/TSPlayer.cs +++ b/TShockAPI/TSPlayer.cs @@ -40,6 +40,7 @@ namespace TShockAPI public bool InitSpawn = false; public bool DisplayLogs = true; public Vector2 oldSpawn = Vector2.Zero; + public int LoginAttempts { get; set; } public bool RealPlayer { diff --git a/TShockAPI/Tools.cs b/TShockAPI/Tools.cs index f34094ab..0f815d70 100755 --- a/TShockAPI/Tools.cs +++ b/TShockAPI/Tools.cs @@ -18,6 +18,7 @@ along with this program. If not, see . using System; using System.Collections.Generic; using System.IO; +using System.Security.Cryptography; using System.Text; using System.Net; using Microsoft.Xna.Framework; @@ -552,6 +553,10 @@ namespace TShockAPI { continue; } + if (args[0].Contains(":")) + { + continue; + } if (lines[i].StartsWith("#")) { continue; @@ -568,6 +573,49 @@ namespace TShockAPI sr.Close(); return GetGroup("default"); } + /// + /// Fetches the hashed password and group for a given username + /// + /// string username + /// string[] {password, group} + public static string[] FetchHashedPasswordAndGroup(string username) + { + + StreamReader sr = new StreamReader(FileTools.UsersPath); + string data = sr.ReadToEnd(); + data = data.Replace("\r", ""); + string[] lines = data.Split('\n'); + string[] result = {"null", "null"}; + + for (int i = 0; i < lines.Length; i++) + { + string[] args = lines[i].Split(' '); + if (args.Length < 2) + { + continue; + } + if (lines[i].StartsWith("#")) + { + continue; + } + if (!lines[i].Contains(":")) + { + continue; + } + try + { + if (args[0].Split(':')[0].ToLower() == username.ToLower()) + { + result = new string[] {args[0].Split(':')[1], args[1]}; + return result; + } + } + catch (Exception ex) + { Log.Error(ex.ToString()); } + } + sr.Close(); + return result; + } /// /// Returns an IPv4 address from a DNS query @@ -586,5 +634,32 @@ namespace TShockAPI } return IP4Address; } + /// + /// Returns a byte array for a given string + /// + /// string str + /// byte[] string + public static byte[] StrToByteArray(string str) + { + System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding(); + return encoding.GetBytes(str); + } + /// + /// Returns a Sha256 string for a given string + /// + /// string password + /// string sha256 + public static string HashPassword(string password) + { + byte[] data = StrToByteArray(password); + byte[] result; + + using (SHA256 shaM = new SHA256Managed()) + { + result = shaM.ComputeHash(data); + } + System.Text.UTF8Encoding enc = new System.Text.UTF8Encoding(); + return enc.GetString(result); + } } } \ No newline at end of file diff --git a/TShockAPI/UpdateManager.cs b/TShockAPI/UpdateManager.cs index 4150f6d3..a53a122f 100644 --- a/TShockAPI/UpdateManager.cs +++ b/TShockAPI/UpdateManager.cs @@ -107,7 +107,7 @@ namespace TShockAPI private static void NotifyAdministrator(TSPlayer player, string[] changes) { - player.SendMessage("The server is out of date. To update, type /updatenow."); + player.SendMessage("The server is out of date.", Color.Red); for (int j = 4; j < changes.Length; j++) { player.SendMessage(changes[j], Color.Red);