/* TShock, a server mod for Terraria Copyright (C) 2011 The TShock Team This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ using System; using System.Data; using System.IO; using MySql.Data.MySqlClient; namespace TShockAPI.DB { public class UserManager { private IDbConnection database; public UserManager(IDbConnection db) { database = db; var table = new SqlTable("Users", new SqlColumn("ID", MySqlDbType.Int32) { Primary = true, AutoIncrement = true }, new SqlColumn("Username", MySqlDbType.VarChar, 32) { Unique = true }, new SqlColumn("Password", MySqlDbType.VarChar, 64), new SqlColumn("Usergroup", MySqlDbType.Text), new SqlColumn("IP", MySqlDbType.VarChar, 32) ); var creator = new SqlTableCreator(db, db.GetSqlType() == SqlType.Sqlite ? (IQueryBuilder)new SqliteQueryCreator() : new MysqlQueryCreator()); creator.EnsureExists(table); String file = Path.Combine(TShock.SavePath, "users.txt"); if (File.Exists(file)) { using (StreamReader sr = new StreamReader(file)) { String line; while ((line = sr.ReadLine()) != null) { if (line.Equals("") || line.Substring(0, 1).Equals("#")) continue; String[] info = line.Split(' '); String username = ""; String sha = ""; String group = ""; String ip = ""; String[] nameSha = info[0].Split(':'); if (nameSha.Length < 2) { username = nameSha[0]; ip = nameSha[0]; group = info[1]; } else { username = nameSha[0]; sha = nameSha[1]; group = info[1]; } string query = (TShock.Config.StorageType.ToLower() == "sqlite") ? "INSERT OR IGNORE INTO Users (Username, Password, Usergroup, IP) VALUES (@0, @1, @2, @3)" : "INSERT IGNORE INTO Users SET Username=@0, Password=@1, Usergroup=@2, IP=@3"; database.Query(query, username.Trim(), sha.Trim(), group.Trim(), ip.Trim()); } } String path = Path.Combine(TShock.SavePath, "old_configs"); String file2 = Path.Combine(path, "users.txt"); if (!Directory.Exists(path)) Directory.CreateDirectory(path); if (File.Exists(file2)) File.Delete(file2); File.Move(file, file2); } } /// /// Adds a given username to the database /// /// User user public void AddUser(User user) { try { if (!TShock.Groups.GroupExists(user.Group)) throw new GroupNotExistsException(user.Group); if (database.Query("INSERT INTO Users (Username, Password, UserGroup, IP) VALUES (@0, @1, @2, @3);", user.Name, Tools.HashPassword(user.Password), user.Group, user.Address) < 1) throw new UserExistsException(user.Name); } catch (Exception ex) { throw new UserManagerException("AddUser SQL returned an error", ex); } } /// /// Removes a given username from the database /// /// User user public void RemoveUser(User user) { try { int affected = -1; if (!string.IsNullOrEmpty(user.Address)) { affected = database.Query("DELETE FROM Users WHERE IP=@0", user.Address); } else { affected = database.Query("DELETE FROM Users WHERE Username=@0", user.Name); } if (affected < 1) throw new UserNotExistException(string.IsNullOrEmpty(user.Address) ? user.Name : user.Address); } catch (Exception ex) { throw new UserManagerException("RemoveUser SQL returned an error", ex); } } /// /// Sets the Hashed Password for a given username /// /// User user /// string password public void SetUserPassword(User user, string password) { try { if (database.Query("UPDATE Users SET Password = @0 WHERE Username = @1;", Tools.HashPassword(password), user.Name) == 0) throw new UserNotExistException(user.Name); } catch (Exception ex) { throw new UserManagerException("SetUserPassword SQL returned an error", ex); } } /// /// Sets the group for a given username /// /// User user /// string group public void SetUserGroup(User user, string group) { try { if (!TShock.Groups.GroupExists(group)) throw new GroupNotExistsException(group); if (database.Query("UPDATE Users SET UserGroup = @0 WHERE Username = @1;", group, user.Name) == 0) throw new UserNotExistException(user.Name); } catch (Exception ex) { throw new UserManagerException("SetUserGroup SQL returned an error", ex); } } public int GetUserID(string username) { try { using (var reader = database.QueryReader("SELECT * FROM Users WHERE Username=@0", username)) { if (reader.Read()) { return reader.Get("ID"); } } } catch (Exception ex) { Log.ConsoleError("FetchHashedPasswordAndGroup SQL returned an error: " + ex); } return -1; } /// /// Returns a Group for a ip from the database /// /// string ip public Group GetGroupForIP(string ip) { try { using (var reader = database.QueryReader("SELECT * FROM Users WHERE IP=@0", ip)) { if (reader.Read()) { string group = reader.Get("UserGroup"); return Tools.GetGroup(group); } } } catch (Exception ex) { Log.ConsoleError("GetGroupForIP SQL returned an error: " + ex); } return Tools.GetGroup("default"); } public Group GetGroupForIPExpensive(string ip) { try { using (var reader = database.QueryReader("SELECT IP, UserGroup FROM Users")) { while (reader.Read()) { if (Tools.GetIPv4Address(reader.Get("IP")) == ip) { return Tools.GetGroup(reader.Get("UserGroup")); } } } } catch (Exception ex) { Log.ConsoleError("GetGroupForIP SQL returned an error: " + ex); } return Tools.GetGroup("default"); } public User GetUserByName(string name) { try { return GetUser(new User { Name = name }); } catch (UserManagerException) { return null; } } public User GetUserByIP(string ip) { try { return GetUser(new User { Address = ip }); } catch (UserManagerException) { return null; } } public User GetUser(User user) { try { QueryResult result; if (string.IsNullOrEmpty(user.Address)) { result = database.QueryReader("SELECT * FROM Users WHERE Username=@0", user.Name); } else { result = database.QueryReader("SELECT * FROM Users WHERE IP=@0", user.Address); } using (var reader = result) { if (reader.Read()) { user.ID = reader.Get("ID"); user.Group = reader.Get("Usergroup"); user.Password = reader.Get("Password"); user.Name = reader.Get("Username"); user.Address = reader.Get("IP"); return user; } } } catch (Exception ex) { throw new UserManagerException("GetUserID SQL returned an error", ex); } throw new UserNotExistException(string.IsNullOrEmpty(user.Address) ? user.Name : user.Address); } } public class User { public int ID { get; set; } public string Name { get; set; } public string Password { get; set; } public string Group { get; set; } public string Address { get; set; } public User(string ip, string name, string pass, string group) { Address = ip; Name = name; Password = pass; Group = group; } public User() { Address = ""; Name = ""; Password = ""; Group = ""; } } [Serializable] public class UserManagerException : Exception { public UserManagerException(string message) : base(message) { } public UserManagerException(string message, Exception inner) : base(message, inner) { } } [Serializable] public class UserExistsException : UserManagerException { public UserExistsException(string name) : base("User '" + name + "' already exists") { } } [Serializable] public class UserNotExistException : UserManagerException { public UserNotExistException(string name) : base("User '" + name + "' does not exist") { } } [Serializable] public class GroupNotExistsException : UserManagerException { public GroupNotExistsException(string group) : base("Group '" + group + "' does not exist") { } } }