using System; using System.Collections.Generic; using System.Linq; using System.Data.SQLite; using System.Data; using System.IO; namespace SharedLibrary { public abstract class Database { private Interfaces.ILogger Logger; public Database(String FN, Interfaces.ILogger logger) { FileName = FN; Logger = logger; Init(); } protected SQLiteConnection GetNewConnection() { return new SQLiteConnection($"Data Source={FileName}"); } abstract public void Init(); protected bool Insert(String tableName, Dictionary data, bool ignore = false) { string names = ""; string parameters = ""; foreach (string key in data.Keys) { names += key + ','; parameters += '@' + key + ','; } names = names.Substring(0, names.Length - 1); parameters = parameters.Substring(0, parameters.Length - 1); var Con = GetNewConnection(); string ignoreCmd = ignore ? " OR IGNORE " : " "; SQLiteCommand insertcmd = new SQLiteCommand() { Connection = Con, CommandText = String.Format("INSERT{0}INTO `{1}` ({2}) VALUES ({3});", ignoreCmd, tableName, names, parameters) }; foreach (string key in data.Keys) { insertcmd.Parameters.AddWithValue('@' + key, data[key]); } try { Con.Open(); insertcmd.ExecuteNonQuery(); Con.Close(); return true; } catch (Exception E) { Logger.WriteWarning($"Database Insert failed"); Logger.WriteDebug($"Exception Message: {E.Message}"); Logger.WriteDebug($"SQL command: {insertcmd.CommandText}"); Logger.WriteDebug($"Database File: {FileName}"); return false; } } protected void UpdateIncrement(String tableName, string columnName, Dictionary data, KeyValuePair where) { string parameters = ""; foreach (string key in data.Keys) { parameters += $"{key}={key}+1,"; } parameters = parameters.Substring(0, parameters.Length - 1); var Con = GetNewConnection(); SQLiteCommand updatecmd = new SQLiteCommand() { Connection = Con, CommandText = String.Format("UPDATE `{0}` SET {1} WHERE {2}=@{2}", tableName, parameters, where.Key) }; foreach (string key in data.Keys) { updatecmd.Parameters.AddWithValue('@' + key, data[key]); } updatecmd.Parameters.AddWithValue('@' + where.Key, where.Value); try { Con.Open(); updatecmd.ExecuteNonQuery(); Con.Close(); } catch (Exception E) { Logger.WriteWarning($"Database UpdateIncrement failed"); Logger.WriteDebug($"Exception Message: {E.Message}"); Logger.WriteDebug($"SQL command: {updatecmd?.CommandText}"); Logger.WriteDebug($"Database File: {FileName}"); } } protected bool Update(String tableName, Dictionary data, KeyValuePair where) { string parameters = ""; foreach (string key in data.Keys) { parameters += key + '=' + '@' + key + ','; } parameters = parameters.Substring(0, parameters.Length - 1); var Con = GetNewConnection(); SQLiteCommand updatecmd = new SQLiteCommand() { Connection = Con, CommandText = String.Format("UPDATE `{0}` SET {1} WHERE {2}=@{2}", tableName, parameters, where.Key) }; foreach (string key in data.Keys) { updatecmd.Parameters.AddWithValue('@' + key, data[key]); } updatecmd.Parameters.AddWithValue('@' + where.Key, where.Value); try { Con.Open(); updatecmd.ExecuteNonQuery(); Con.Close(); return true; } catch (Exception E) { Logger.WriteWarning($"Database update failed"); Logger.WriteDebug($"Exception Message: {E.Message}"); Logger.WriteDebug($"SQL Query: {updatecmd.CommandText}"); Logger.WriteDebug($"Database File: {FileName}"); return false; } } protected DataRow GetDataRow(String Q) { DataRow Result = GetDataTable(Q).Rows[0]; return Result; } protected int ExecuteNonQuery(String Request) { int rowsUpdated = 0; Request = Request.Replace("!'", "").Replace("!", ""); var Con = GetNewConnection(); SQLiteCommand CMD = null; try { Con.Open(); CMD = new SQLiteCommand(Con) { CommandText = Request }; rowsUpdated = CMD.ExecuteNonQuery(); Con.Close(); return rowsUpdated; } catch (Exception E) { Logger.WriteWarning($"Database command failed"); Logger.WriteDebug($"Exception Message: {E.Message}"); Logger.WriteDebug($"SQL command: {CMD?.CommandText}"); Logger.WriteDebug($"Database File: {FileName}"); return 0; } } protected DataTable GetDataTable(string tableName, KeyValuePair where) { DataTable dt = new DataTable(); SQLiteCommand updatecmd = new SQLiteCommand() { CommandText = String.Format("SELECT * FROM {0} WHERE `{1}`=@{1};", tableName, where.Key) }; var Con = GetNewConnection(); updatecmd.Parameters.AddWithValue('@' + where.Key, where.Value); updatecmd.Connection = Con; try { Con.Open(); SQLiteDataReader reader = updatecmd.ExecuteReader(); dt.Load(reader); reader.Close(); Con.Close(); } catch (Exception E) { Logger.WriteWarning($"Database GetDataTable failed"); Logger.WriteDebug($"Exception Message: {E.Message}"); Logger.WriteDebug($"SQL command: {updatecmd.CommandText}"); Logger.WriteDebug($"Database File: {FileName}"); } return dt; } protected DataTable GetDataTable(SQLiteCommand cmd) { DataTable dt = new DataTable(); var Con = GetNewConnection(); cmd.Connection = Con; try { Con.Open(); SQLiteDataReader reader = cmd.ExecuteReader(); dt.Load(reader); reader.Close(); Con.Close(); } catch (Exception E) { Logger.WriteWarning($"Database GetDataTable failed"); Logger.WriteDebug($"Exception Message: {E.Message}"); Logger.WriteDebug($"SQL command: {cmd.CommandText}"); Logger.WriteDebug($"Database File: {FileName}"); } return dt; } protected DataTable GetDataTable(String sql) { DataTable dt = new DataTable(); var Con = GetNewConnection(); SQLiteCommand cmd = null; try { Con.Open(); cmd = new SQLiteCommand(Con) { CommandText = sql }; SQLiteDataReader reader = cmd.ExecuteReader(); dt.Load(reader); reader.Close(); Con.Close(); } catch (Exception E) { Logger.WriteWarning($"Database GetDataTable failed"); Logger.WriteDebug($"Exception Message: {E.Message}"); Logger.WriteDebug($"SQL command: {cmd?.CommandText}"); Logger.WriteDebug($"Database File: {FileName}"); return new DataTable(); } return dt; } protected String FileName; } public class ClientsDB : Database { public ClientsDB(String FN, Interfaces.ILogger logger) : base(FN, logger) { } public override void Init() { if (!File.Exists(FileName)) { String Create = "CREATE TABLE [CLIENTS] ( [Name] TEXT NULL, [npID] TEXT NULL, [Number] INTEGER PRIMARY KEY AUTOINCREMENT, [Level] INT DEFAULT 0 NULL, [LastOffense] TEXT NULL, [Connections] INT DEFAULT 1 NULL, [IP] TEXT NULL, [LastConnection] TEXT NULL, [UID] TEXT NULL, [Masked] INT DEFAULT 0, [Reserved] INT DEFAULT 0);"; ExecuteNonQuery(Create); Create = "CREATE TABLE [BANS] ( [TYPE] TEXT NULL, [Reason] TEXT NULL, [npID] TEXT NULL, [bannedByID] TEXT NULL, [IP] TEXT NULL, [TIME] TEXT NULL, [EXPIRES] TEXT);"; ExecuteNonQuery(Create); } } public List GetRecentPlayers() { List returnssss = new List(); //String Query = String.Format($"SELECT * FROM CLIENTS LIMIT 15 OFFSET (SELECT COUNT(*) FROM CLIENTS)-15"); String Query = "SELECT * FROM CLIENTS ORDER BY LastConnection DESC LIMIT 25"; DataTable Result = GetDataTable(Query); if (Result != null && Result.Rows.Count > 0) { foreach (DataRow ResponseRow in Result.Rows) { DateTime lastCon = DateTime.MinValue; DateTime.TryParse(ResponseRow["LastConnection"].ToString(), out lastCon); returnssss.Add(new Player(ResponseRow["Name"].ToString(), ResponseRow["npID"].ToString(), -1, (Player.Permission)(ResponseRow["Level"]), Convert.ToInt32(ResponseRow["Number"]), ResponseRow["LastOffense"].ToString(), (int)ResponseRow["Connections"], ResponseRow["IP"].ToString(), lastCon, ResponseRow["UID"].ToString(), ResponseRow["Masked"].ToString() == "1")); } } return returnssss.OrderByDescending(p => p.LastConnection).ToList(); ; } public List GetPlayers(List npIDs) { List returnssss = new List(); String test = String.Join("' OR npID = '", npIDs); String Query = String.Format("SELECT * FROM CLIENTS WHERE npID = '{0}'", test); DataTable Result = GetDataTable(Query); if (Result != null && Result.Rows.Count > 0) { foreach (DataRow ResponseRow in Result.Rows) { DateTime lastCon = DateTime.MinValue; DateTime.TryParse(ResponseRow["LastConnection"].ToString(), out lastCon); returnssss.Add(new Player(ResponseRow["Name"].ToString(), ResponseRow["npID"].ToString(), -1, (Player.Permission)(ResponseRow["Level"]), Convert.ToInt32(ResponseRow["Number"]), ResponseRow["LastOffense"].ToString(), (int)ResponseRow["Connections"], ResponseRow["IP"].ToString(), lastCon, ResponseRow["UID"].ToString(), ResponseRow["Masked"].ToString() == "1")); } } return returnssss; } public List GetPlayers(List databaseIDs) { List returnssss = new List(); String Condition = String.Join("' OR Number = '", databaseIDs); String Query = String.Format("SELECT * FROM CLIENTS WHERE Number = '{0}'", Condition); DataTable Result = GetDataTable(Query); if (Result != null && Result.Rows.Count > 0) { foreach (DataRow ResponseRow in Result.Rows) { DateTime lastCon = DateTime.MinValue; DateTime.TryParse(ResponseRow["LastConnection"].ToString(), out lastCon); returnssss.Add(new Player(ResponseRow["Name"].ToString(), ResponseRow["npID"].ToString(), -1, (Player.Permission)(ResponseRow["Level"]), Convert.ToInt32(ResponseRow["Number"]), ResponseRow["LastOffense"].ToString(), (int)ResponseRow["Connections"], ResponseRow["IP"].ToString(), lastCon, ResponseRow["UID"].ToString(), ResponseRow["Masked"].ToString() == "1")); } } return returnssss; } //Overloaded method for getPlayer, returns Client with matching DBIndex, null if none found public Player GetPlayer(int dbIndex) { DataTable Result = GetDataTable("CLIENTS", new KeyValuePair("Number", dbIndex)); if (Result != null && Result.Rows.Count > 0) { DataRow p = Result.Rows[0]; DateTime LC; try { LC = DateTime.Parse(p["LastConnection"].ToString()); } catch (Exception) { LC = DateTime.MinValue; } return new Player(p["Name"].ToString(), p["npID"].ToString(), -1, (Player.Permission)(p["Level"]), Convert.ToInt32(p["Number"]), p["LastOffense"].ToString(), Convert.ToInt32(p["Connections"]), p["IP"].ToString(), LC, p["UID"].ToString(), p["Masked"].ToString() == "1"); } else return null; } //get player by ip, (used for webfront) public Player GetPlayer(String IP) { DataTable Result = GetDataTable("CLIENTS", new KeyValuePair("IP", IP)); if (Result != null && Result.Rows.Count > 0) { List lastKnown = new List(); foreach (DataRow p in Result.Rows) { DateTime LC; try { LC = DateTime.Parse(p["LastConnection"].ToString()); lastKnown.Add(new Player(p["Name"].ToString(), p["npID"].ToString(), -1, (Player.Permission)(p["Level"]), Convert.ToInt32(p["Number"]), p["LastOffense"].ToString(), Convert.ToInt32((DateTime.Now - LC).TotalSeconds), p["IP"].ToString(), LC, p["UID"].ToString(), p["Masked"].ToString() == "1")); } catch (Exception) { continue; } } if (lastKnown.Count > 0) { List Returning = lastKnown.OrderBy(t => t.Connections).ToList(); return Returning[0]; } else return null; } else return null; } //Returns a single player object with matching GUID, false if no matches public Player GetPlayer(String ID, int cNum) { DataTable Result = GetDataTable("CLIENTS", new KeyValuePair("npID", ID)); if (Result != null && Result.Rows.Count > 0) { DataRow ResponseRow = Result.Rows[0]; DateTime lastCon = DateTime.MinValue; DateTime.TryParse(ResponseRow["LastConnection"].ToString(), out lastCon); return new Player(ResponseRow["Name"].ToString(), ResponseRow["npID"].ToString(), cNum, (Player.Permission)(ResponseRow["Level"]), Convert.ToInt32(ResponseRow["Number"]), ResponseRow["LastOffense"].ToString(), (int)ResponseRow["Connections"], ResponseRow["IP"].ToString(), lastCon, ResponseRow["UID"].ToString(), ResponseRow["Masked"].ToString() == "1"); } else return null; } //Returns a list of players matching name parameter, null if no players found matching public List FindPlayers(String name) { var Con = GetNewConnection(); SQLiteCommand cmd = new SQLiteCommand(Con) { CommandText = "SELECT * FROM CLIENTS WHERE Name LIKE @Name" }; cmd.Parameters.AddWithValue("@Name", '%' + name + '%'); var Result = GetDataTable(cmd); List Players = new List(); if (Result != null && Result.Rows.Count > 0) { foreach (DataRow p in Result.Rows) { DateTime LC; string Masked = null; try { LC = DateTime.Parse(p["LastConnection"].ToString()); Masked = p["Masked"].ToString(); } catch (Exception) { if (Masked == null) Masked = "0"; LC = DateTime.MinValue; } Players.Add(new Player(p["Name"].ToString(), p["npID"].ToString(), -1, (Player.Permission)(p["Level"]), Convert.ToInt32(p["Number"]), p["LastOffense"].ToString(), Convert.ToInt32(p["Connections"]), p["IP"].ToString(), LC, p["IP"].ToString(), Masked == "1")); } return Players; } else return null; } //Returns any player with level 4 permissions, null if no owner found public Player GetOwner() { String Query = String.Format("SELECT * FROM CLIENTS WHERE Level > '{0}'", 4); DataTable Result = GetDataTable(Query); if (Result != null && Result.Rows.Count > 0) { DataRow ResponseRow = Result.Rows[0]; if (ResponseRow["IP"].ToString().Length < 6) ResponseRow["IP"] = "0"; return new Player(ResponseRow["Name"].ToString(), ResponseRow["npID"].ToString(), -1, (Player.Permission)(ResponseRow["Level"]), Convert.ToInt32(ResponseRow["Number"]), null, 0, ResponseRow["IP"].ToString()); } else return null; } public List GetClientPenalties(Player P) { List ClientPenalties = new List(); String Query = $"SELECT * FROM `BANS` WHERE `npID` = '{P.NetworkID}' OR `IP` = '{P.IP}'"; DataTable Result = GetDataTable(Query); foreach (DataRow Row in Result.Rows) { if (Row["TIME"].ToString().Length < 2) //compatibility with my old database Row["TIME"] = DateTime.Now.ToString(); Penalty.Type BanType = Penalty.Type.Ban; if (Row["TYPE"].ToString().Length != 0) BanType = (Penalty.Type)Enum.Parse(typeof(Penalty.Type), Row["TYPE"].ToString()); ClientPenalties.Add(new Penalty(BanType, Row["Reason"].ToString().Trim(), Row["npID"].ToString(), Row["bannedByID"].ToString(), DateTime.Parse(Row["TIME"].ToString()), Row["IP"].ToString(), DateTime.Parse(Row["EXPIRES"].ToString()))); } return ClientPenalties; } public List GetPenaltiesChronologically(int offset, int count) { List ClientPenalties = new List(); DataTable Result = GetDataTable($"SELECT * FROM BANS LIMIT {count} OFFSET (SELECT COUNT(*) FROM BANS)-{offset + 10}"); foreach (DataRow Row in Result.Rows) { if (Row["TIME"].ToString().Length < 2) //compatibility with my old database Row["TIME"] = DateTime.Now.ToString(); var BanType = (Penalty.Type)Enum.Parse(typeof(Penalty.Type), Row["TYPE"].ToString()); ClientPenalties.Add(new Penalty(BanType, Row["Reason"].ToString().Trim(), Row["npID"].ToString(), Row["bannedByID"].ToString(), DateTime.Parse(Row["TIME"].ToString()), Row["IP"].ToString(), DateTime.Parse(Row["EXPIRES"].ToString()))); } return ClientPenalties; } //Returns all players with level > Flagged public List GetAdmins() { List Admins = new List(); String Query = String.Format("SELECT * FROM CLIENTS WHERE Level >= '{0}' ORDER BY Name", (int)Player.Permission.Trusted); DataTable Result = GetDataTable(Query); foreach (DataRow P in Result.Rows) Admins.Add(new Player(P["Name"].ToString(), P["npID"].ToString(), (Player.Permission)P["Level"], P["IP"].ToString(), P["UID"].ToString(), Convert.ToInt32(P["Number"].ToString()))); return Admins; } //Returns total number of player entries in database public int TotalPlayers() { DataTable Result = GetDataTable("SELECT * from CLIENTS ORDER BY Number DESC LIMIT 1"); if (Result.Rows.Count > 0) return Convert.ToInt32(Result.Rows[0]["Number"]); else return 0; } //Add specified player to database public void AddPlayer(Player P) { Dictionary newPlayer = new Dictionary { { "Name", Utilities.StripIllegalCharacters(P.Name) }, { "npID", P.NetworkID }, { "Level", (int)P.Level }, { "LastOffense", "" }, { "Connections", 1 }, { "IP", P.IP }, { "LastConnection", Utilities.DateTimeSQLite(DateTime.Now) }, { "UID", P.UID }, { "Masked", Convert.ToInt32(P.Masked) } }; Insert("CLIENTS", newPlayer); } ///Update information of specified player public void UpdatePlayer(Player P) { Dictionary updatedPlayer = new Dictionary { { "Name", P.Name }, { "npID", P.NetworkID }, { "Level", (int)P.Level }, { "LastOffense", P.lastOffense }, { "Connections", P.Connections }, { "IP", P.IP }, { "LastConnection", Utilities.DateTimeSQLite(DateTime.Now) }, { "UID", P.UID }, { "Masked", Convert.ToInt32(P.Masked) } }; Update("CLIENTS", updatedPlayer, new KeyValuePair("npID", P.NetworkID)); } //Add specified ban to database public void AddPenalty(Penalty B) { Dictionary newBan = new Dictionary { { "Reason", Utilities.StripIllegalCharacters(B.Reason) }, { "npID", B.OffenderID }, { "bannedByID", B.PenaltyOriginID }, { "IP", B.IP }, { "TIME", Utilities.DateTimeSQLite(DateTime.Now) }, { "TYPE", B.BType }, { "EXPIRES", B.Expires } }; Insert("BANS", newBan); } //Deletes ban with matching GUID public void RemoveBan(String GUID) { String Query = String.Format("DELETE FROM BANS WHERE npID = '{0}'", GUID); ExecuteNonQuery(Query); } public void RemoveBan(String GUID, String IP) { String Query = String.Format("DELETE FROM BANS WHERE npID = '{0}' or IP = '{1}'", GUID, IP); ExecuteNonQuery(Query); } } public class AliasesDB : Database { public AliasesDB(String FN, Interfaces.ILogger logger) : base(FN, logger) { } public override void Init() { if (!File.Exists(FileName)) { String Create = "CREATE TABLE [ALIASES] ( [Number] INTEGER, [NAMES] TEXT NULL, [IPS] TEXTNULL );"; ExecuteNonQuery(Create); } } public Aliases GetPlayerAliases(int dbIndex) { String Query = String.Format("SELECT * FROM ALIASES WHERE Number = '{0}' LIMIT 1", dbIndex); DataTable Result = GetDataTable(Query); if (Result != null && Result.Rows.Count > 0) { DataRow p = Result.Rows[0]; return new Aliases(Convert.ToInt32(p["Number"]), p["NAMES"].ToString(), p["IPS"].ToString()); } else return null; } public List GetPlayerAliases(String IP) { var Con = GetNewConnection(); SQLiteCommand cmd = new SQLiteCommand(Con) { CommandText = "SELECT * FROM ALIASES WHERE IPS LIKE @IP" }; cmd.Parameters.AddWithValue("@IP", IP); var Result = GetDataTable(cmd); List players = new List(); if (Result != null && Result.Rows.Count > 0) { foreach (DataRow p in Result.Rows) players.Add(new Aliases(Convert.ToInt32(p["Number"]), p["NAMES"].ToString(), p["IPS"].ToString())); } return players; } public List FindPlayerAliases(String name) { name = name.Replace("'", ""); String[] IP = name.Split('.'); String DefaultIP = "LEGACY_INVALID_IP"; if (IP.Length > 1) DefaultIP = (IP[0] + '.' + IP[1] + '.'); var Con = GetNewConnection(); SQLiteCommand cmd = new SQLiteCommand(Con) { CommandText = "SELECT * FROM ALIASES WHERE NAMES LIKE @name OR IPS LIKE @ip LIMIT 15" }; cmd.Parameters.AddWithValue("@name", '%' + name + '%'); cmd.Parameters.AddWithValue("@ip", '%' + DefaultIP + '%'); var Result = GetDataTable(cmd); List players = new List(); if (Result != null && Result.Rows.Count > 0) { foreach (DataRow p in Result.Rows) players.Add(new Aliases(Convert.ToInt32(p["Number"]), p["NAMES"].ToString(), p["IPS"].ToString())); } return players; } public void AddPlayerAliases(Aliases Alias) { Dictionary newPlayer = new Dictionary { { "Number", Alias.Number }, { "NAMES", Utilities.StripIllegalCharacters(String.Join(";", Alias.Names)) }, { "IPS", String.Join(";", Alias.IPS) } }; Insert("ALIASES", newPlayer); } public void UpdatePlayerAliases(Aliases Alias) { Dictionary updatedPlayer = new Dictionary { { "Number", Alias.Number }, { "NAMES", String.Join(";", Alias.Names) }, { "IPS", String.Join(";", Alias.IPS) } }; Update("ALIASES", updatedPlayer, new KeyValuePair("Number", Alias.Number)); } } }