C#:
using Newtonsoft.Json;
using Oxide.Core;
using Oxide.Core.Configuration;
using Oxide.Core.Database;
using Oxide.Core.Libraries.Covalence;
using Oxide.Core.Plugins;
using System;
using System.Collections.Generic;
using System.Linq;
using Oxide.Core.SQLite.Libraries;
using System.Text.RegularExpressions;
namespace Oxide.Plugins {
[Info("Enhanced Ban System", "Reneb/Slut", "5.2.5")]
class EnhancedBanSystem : CovalencePlugin {
[PluginReference]
private Plugin PlayerDatabase, DiscordMessages;
////////////////////////////////////////////////////////////
// Static fields
////////////////////////////////////////////////////////////
static DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0);
char[] ipChrArray = new char[] {
'.'
}
;
private static BanSystem banSystem;
static Hash<int, BanData> cachedBans = new Hash<int, BanData>();
static List<int> wasBanned = new List<int>();
////////////////////////////////////////////////////////////
// Config fields
////////////////////////////////////////////////////////////
private static string Platform = "Steam";
private static string Server = "1.1.1.1:28015";
private static string Game = "Rust";
string PermissionBan = "enhancedbansystem.ban";
string PermissionUnban = "enhancedbansystem.unban";
string PermissionBanlist = "enhancedbansystem.banlist";
string PermissionKick = "enhancedbansystem.kick";
private bool SQLite_use = false;
private string SQLite_DB = "banlist.db";
private bool MySQL_use = false;
private string MySQL_Host = "localhost";
private int MySQL_Port = 3306;
private string MySQL_DB = "banlist";
private string MySQL_User = "root";
private string MySQL_Pass = "toor";
private bool PlayerDatabase_use = false;
private string PlayerDatabase_IPFile = "EnhancedBanSystem_IPs.json";
private bool Files_use = false;
private bool WebAPI_use = false;
private string WebAPI_Ban_Request = "http://webpage.com/api.php?action=ban&pass=mypassword&id={id}&steamid={steamid}&name={name}&ip={ip}&reason={reason}&source={source}&game={game}&platform={platform}&server={server}&tempban={expiration}";
private string WebAPI_Unban_Request = "http://webpage.com/api.php?action=unban&pass=mypassword&steamid={steamid}&name={name}&ip={ip}&name={name}&source={source}";
private string WebAPI_IsBanned_Request = "http://webpage.com/api.php?action=isbanned&pass=mypassword&id={id}&update={update}&steamid={steamid}&ip={ip}&time={time}&name={name}&game=Rust&server=rust.kortal.org:28015";
private string WebAPI_Banlist_Request = "http://webpage.com/banlist.php?startid={startid}";
private bool Native_use = false;
private string BanDefaultReason = "Banned";
private string BanEvadeReason = "Ban Evade";
private bool Kick_Broadcast = true;
private bool Kick_Log = true;
private bool Kick_OnBan = true;
private bool Ban_Broadcast = true;
private bool Ban_Log = true;
private bool Discord_use = false;
private string Discord_Webhook = "https://support.discordapp.com/hc/en-us/articles/228383668-Intro-to-Webhooks";
private bool Ban_Escape = true;
private bool Log_Denied = true;
protected override void LoadDefaultConfig() {
}
private void CheckCfg<T>(string Key, ref T var) {
if (Config[Key] is T) var = (T)Config[Key];
else Config[Key] = var;
}
void Init() {
CheckCfg<string>("Server Info - Platform", ref Platform);
CheckCfg<string>("Server Info - Game", ref Game);
CheckCfg<string>("Server Info - IP:PORT", ref Server);
CheckCfg<string>("Permissions - Ban", ref PermissionBan);
CheckCfg<string>("Permissions - Unban", ref PermissionUnban);
CheckCfg<string>("Permissions - Banlist", ref PermissionBanlist);
CheckCfg<string>("Permissions - Kick", ref PermissionKick);
CheckCfg<bool>("DataType - SQLite - use", ref SQLite_use);
CheckCfg<string>("DataType - SQLite - Database Filename", ref SQLite_DB);
CheckCfg<bool>("DataType - MySQL - use", ref MySQL_use);
CheckCfg<string>("DataType - MySQL - Host", ref MySQL_Host);
CheckCfg<int>("DataType - MySQL - Port", ref MySQL_Port);
CheckCfg<string>("DataType - MySQL - Database", ref MySQL_DB);
CheckCfg<string>("DataType - MySQL - User", ref MySQL_User);
CheckCfg<string>("DataType - MySQL - Pass", ref MySQL_Pass);
CheckCfg<bool>("DataType - Files - use", ref Files_use);
CheckCfg<bool>("DataType - PlayerDatabase - use", ref PlayerDatabase_use);
CheckCfg<string>("DataType - PlayerDatabase - IP Filename", ref PlayerDatabase_IPFile);
CheckCfg<bool>("DataType - WebAPI - use", ref WebAPI_use);
CheckCfg<string>("DataType - WebAPI - Host", ref WebAPI_Ban_Request);
CheckCfg<string>("DataType - WebAPI - Unban", ref WebAPI_Unban_Request);
CheckCfg<string>("DataType - WebAPI - IsBanned", ref WebAPI_IsBanned_Request);
CheckCfg<string>("DataType - WebAPI - Banlist", ref WebAPI_Banlist_Request);
CheckCfg<bool>("DataType - Native - use", ref Native_use);
CheckCfg<bool>("Ban - Evade", ref Ban_Escape);
CheckCfg<string>("Ban - Default Reason", ref BanDefaultReason);
CheckCfg<string>("Ban - Evade Reason", ref BanEvadeReason);
CheckCfg<bool>("Ban - Broadcast", ref Ban_Broadcast);
CheckCfg<bool>("Ban - Log", ref Ban_Log);
CheckCfg<bool>("DiscordMessages - Use Discord", ref Discord_use);
CheckCfg<string>("DiscordMessages - Discord Webhook", ref Discord_Webhook);
CheckCfg<bool>("Kick - Broadcast", ref Kick_Broadcast);
CheckCfg<bool>("Kick - Log", ref Kick_Log);
CheckCfg<bool>("Kick - On Ban", ref Kick_OnBan);
CheckCfg<bool>("Denied Connection - Log", ref Log_Denied);
SaveConfig();
if (SQLite_use) banSystem |= BanSystem.SQLite;
if (MySQL_use) banSystem |= BanSystem.MySQL;
if (Native_use) banSystem |= BanSystem.Native;
if (PlayerDatabase_use) banSystem |= BanSystem.PlayerDatabase;
if (Files_use) banSystem |= BanSystem.Files;
if (WebAPI_use) banSystem |= BanSystem.WebAPI;
InitializeLang();
}
void InitializeLang() {
lang.RegisterMessages(new Dictionary<string, string> {
{
"PlayerNotFound", "No matching player was found.\n"
}
, {
"PlayerTempBanned", "You are temporarily banned from this server ({0}).{1} left"
}
, {
"PlayerPermBanned", "You are permanently banned from this server ({0})."
}
, {
"LoadedBans", "Loaded {0} bans"
}
, {
"BanExists", "This ban already exists ({0})."
}
, {
"BanAdded", "Successfully added {0} to the banlist."
}
, {
"MultipleBans", "Multiple Bans Found:\n\r"
}
, {
"BansRemoved", "{0} matching bans were removed"
}
, {
"PlayerNotBanned", "{0} - {1} isn't banned.\n"
}
, {
"Loaded", "Loaded"
}
, {
"NoPermission", "You don't have the permission to use this command."
}
, {
"KickSyntax", "Syntax: kick < Name | SteamID | IP | IP Range > < reason(optional) >"
}
, {
"UnbanSyntax", "Syntax: unban < Name | SteamID | IP | IP Range >"
}
, {
"BanSyntax", "Syntax: ban < Name | SteamID | IP | IP Range > < reason(optional) > < time in secondes(optional) > "
}
, {
"BanlistSyntax", "Syntax: banlist <BanSystem> <startid>"
}
, {
"BanSystems", "Avaible BanSystems:\n"
}
, {
"BanlistSyntax1", "Wrong usage of /banlist"
}
, {
"OutOfRange", "Index is out of range.Current bans recorded: {0}"
}
, {
"Banlist", "Banlist - {0}-{1}/{2}\n"
}
, {
"PlayerPermBan", "{0} was permanently banned from the server for {1}"
}
, {
"PlayerTempBan", "{0} was temporarily banned for {1} for {2}"
}
, {
"PlayerKick", "<color=red>{0}</color> <color=silver>was kicked from the server for</color> <color=red>{1}</color>"
}
, {
"IPPermBan", "An IP was banned from the server for {0}"
}
, {
"IPTempBan", "An IP was temporarily banned for {0} for {1}"
}
, {
"BanUpdated", "Succesfully updated {0} in the banlist."
}
}
, this);
}
////////////////////////////////////////////////////////////
// ID Save
////////////////////////////////////////////////////////////
private static DynamicConfigFile Ban_ID_File;
private static int Ban_ID = 0;
void Load_ID() {
try {
Ban_ID_File = Interface.Oxide.DataFileSystem.GetDatafile(Name + "_ID");
Ban_ID = (int)Ban_ID_File["id"];
}
catch {
Ban_ID = 0;
Ban_ID_File["id"] = Ban_ID;
Save_ID();
}
}
void Save_ID() {
Interface.Oxide.DataFileSystem.SaveDatafile(Name + "_ID");
}
static int GetNewID() {
Ban_ID++;
Ban_ID_File["id"] = Ban_ID;
return Ban_ID;
}
////////////////////////////////////////////////////////////
// Enum & Class
////////////////////////////////////////////////////////////
enum BanSystem {
Native = 1, MySQL = 2, SQLite = 4, WebAPI = 8, PlayerDatabase = 16, Files = 32,
}
class BanData {
public int id;
public string steamid;
public string ip;
public string name;
public string game;
public string server;
public string source;
public double date;
public double expire;
public string reason;
public string platform;
public BanData() {
}
public BanData(object source, string userID, string name, string ip, string reason, double duration) {
this.id = GetNewID();
this.source = source is IPlayer ? ((IPlayer)source).Name : source is string ? (string)source : "Console";
this.steamid = userID;
this.name = name;
this.ip = ip;
this.reason = reason;
this.expire = duration != 0.0 ? LogTime() + duration : 0.0;
this.date = LogTime();
this.platform = Platform;
this.game = Game;
this.server = Server;
}
public BanData(int id, string source, string userID, string name, string ip, string reason, string duration) {
this.id = id;
this.source = source;
this.steamid = userID;
this.name = name;
this.ip = ip;
this.reason = reason;
this.expire = double.Parse(duration);
this.date = LogTime();
this.platform = Platform;
this.game = Game;
this.server = Server;
}
public string ToJson() {
return JsonConvert.SerializeObject(this);
}
public override string ToString() {
return string.Format("{0} - {1} - {2} - {3} - {4}", steamid, name, ip, reason, expire == 0.0 ? "Permanent" : expire < LogTime() ? "Expired" : string.Format("Temporary: {0}s", (expire - LogTime()).ToString()));
}
}
////////////////////////////////////////////////////////////
// General Methods
////////////////////////////////////////////////////////////
private bool IsPluginLoaded(Plugin plugin) {
if (plugin != null) {
return plugins.GetAll().Where(x => x.Equals(plugin) && x.IsLoaded) != null;
}
else {
return false;
}
}
string FormatTime(TimeSpan time) => $"{(time.Days == 0 ? string.Empty : $" {
time.Days
}
day(s)")}{(time.Days != 0 && time.Hours != 0 ? $", " : string.Empty)}{(time.Hours == 0 ? string.Empty : $" {
time.Hours
}
hour(s)")}{(time.Hours != 0 && time.Minutes != 0 ? $", " : string.Empty)}{(time.Minutes == 0 ? string.Empty : $" {
time.Minutes
}
minute(s)")}{(time.Minutes != 0 && time.Seconds != 0 ? $", " : string.Empty)}{(time.Seconds == 0 ? string.Empty : $" {
time.Seconds
}
second(s)")}";
private bool TryParseTimeSpan(string source, out TimeSpan timeSpan) {
int seconds = 0, minutes = 0, hours = 0, days = 0;
Match s = new Regex(@"(\d+?)s", RegexOptions.IgnoreCase).Match(source);
Match m = new Regex(@"(\d+?)m", RegexOptions.IgnoreCase).Match(source);
Match h = new Regex(@"(\d+?)h", RegexOptions.IgnoreCase).Match(source);
Match d = new Regex(@"(\d+?)d", RegexOptions.IgnoreCase).Match(source);
if (s.Success) seconds = Convert.ToInt32(s.Groups[1].ToString());
if (m.Success) minutes = Convert.ToInt32(m.Groups[1].ToString());
if (h.Success) hours = Convert.ToInt32(h.Groups[1].ToString());
if (d.Success) days = Convert.ToInt32(d.Groups[1].ToString());
source = source.Replace(seconds + "s", string.Empty);
source = source.Replace(minutes + "m", string.Empty);
source = source.Replace(hours + "h", string.Empty);
source = source.Replace(days + "d", string.Empty);
if (!string.IsNullOrEmpty(source) || (!s.Success && !m.Success && !h.Success && !d.Success)) {
timeSpan = default(TimeSpan);
return false;
}
timeSpan = new TimeSpan(days, hours, minutes, seconds);
return true;
}
static double LogTime() => DateTime.UtcNow.Subtract(epoch).TotalSeconds;
string GetMsg(string key, object steamid = null, params object[] args) {
if (args.Length != 0) {
return string.Format(lang.GetMessage(key, this, steamid is IPlayer ? ((IPlayer)steamid).Id : steamid == null ? null : steamid.ToString()), args);
}
else {
return lang.GetMessage(key, this, steamid is IPlayer ? ((IPlayer)steamid).Id : steamid == null ? null : steamid.ToString());
}
}
bool hasPermission(IPlayer player, string permissionName) {
if (player.IsAdmin) return true;
return permission.UserHasPermission(player.Id.ToString(), permissionName);
}
bool isIPAddress(string arg) {
int subIP;
string[] strArray = arg.Split(ipChrArray);
if (strArray.Length != 4) {
return false;
}
foreach (string str in strArray) {
if (str.Length == 0) {
return false;
}
if (!int.TryParse(str, out subIP) && str != "*") {
return false;
}
if (!(str == "*" || (subIP >= 0 && subIP <= 255))) {
return false;
}
}
return true;
}
bool IPRange(string sourceIP, string targetIP) {
string[] srcArray = sourceIP.Split(ipChrArray);
string[] trgArray = targetIP.Split(ipChrArray);
for (int i = 0; i < 4; i++) {
if (srcArray[i] != trgArray[i] && srcArray[i] != "*") {
return false;
}
}
return true;
}
bool RangeFromIP(string sourceIP, out string range1, out string range2, out string range3) {
range1 = string.Empty;
range2 = string.Empty;
range3 = string.Empty;
if (sourceIP == string.Empty) return false;
string[] strArray = sourceIP.Split(ipChrArray);
if (strArray.Length != 4) {
return false;
}
range1 = string.Format("{0}.*.*.*", strArray[0]);
range2 = string.Format("{0}.{1}.*.*", strArray[0], strArray[1]);
range3 = string.Format("{0}.{1}.{2}.*", strArray[0], strArray[1], strArray[2]);
return true;
}
List<IPlayer> FindPlayers(string userIDorNameorIP, object source, out string reason) {
reason = string.Empty;
var FoundPlayers = players.FindPlayers(userIDorNameorIP).ToList();
if (FoundPlayers.Count == 0) {
reason = GetMsg("PlayerNotFound", source) + "xd ";
}
if (FoundPlayers.Count > 1) {
foreach (var iplayer in FoundPlayers) {
reason += string.Format("{0} {1}\r\n", iplayer.Id, iplayer.Name);
}
}
return FoundPlayers;
}
List<IPlayer> FindConnectedPlayers(string userIDorNameorIP, object source, out string reason) {
reason = string.Empty;
ulong steamid = 0L;
var FoundPlayers = new List<IPlayer>();
ulong.TryParse(userIDorNameorIP, out steamid);
if (isIPAddress(userIDorNameorIP)) {
FoundPlayers = players.All.Where(x => x.IsConnected).Where(w => IPRange(userIDorNameorIP, w.Address)).ToList();
}
else if (steamid != 0L) {
var p = players.FindPlayer(userIDorNameorIP);
if (p != null && p.IsConnected) {
FoundPlayers.Add(p);
}
}
else {
FoundPlayers = players.FindPlayers(userIDorNameorIP).Where(x => x.IsConnected).ToList();
if (FoundPlayers.Count > 1) {
foreach (var iplayer in FoundPlayers) {
reason += string.Format("{0} {1}\r\n", iplayer.Id, iplayer.Name);
}
}
}
if (FoundPlayers.Count == 0) {
reason = GetMsg("PlayerNotFound", source);
}
return FoundPlayers;
}
string GetPlayerIP(IPlayer iplayer) {
try {
if (iplayer.IsConnected) return iplayer.Address;
return GetPlayerIP(iplayer.Id);
}
catch {
return GetPlayerIP(iplayer.Id);
}
}
string GetPlayerIP(string userID) {
if (PlayerDatabase != null) {
return (string)PlayerDatabase.Call("GetPlayerData", userID, "ip") ?? string.Empty;
}
return string.Empty;
}
string GetPlayerName(string userID) {
if (PlayerDatabase != null) {
return (string)PlayerDatabase.Call("GetPlayerData", userID, "name") ?? string.Empty;
}
return string.Empty;
}
bool HasDelayedAnswer() => BanSystemHasFlag(banSystem, BanSystem.MySQL) || BanSystemHasFlag(banSystem, BanSystem.SQLite) || (BanSystemHasFlag(banSystem, BanSystem.WebAPI));
bool BanSystemHasFlag(BanSystem b, BanSystem t) => (b & t) == t;
string FormatReturn(BanSystem system, string msg, params object[] args) => string.Format("{0}: {1}", system.ToString(), string.Format(msg, args));
void SendReply(object source, string msg) {
if (source is IPlayer) ((IPlayer)source).Reply(msg);
else if (source is string) return;
else Interface.Oxide.LogInfo(msg);
}
public static string ToShortString(TimeSpan timeSpan) {
return string.Format("{0:00}:{1:00}:{2:00}", (int)timeSpan.TotalHours, timeSpan.Minutes, timeSpan.Seconds);
}
////////////////////////////////////////////////////////////
// Oxide Hooks
////////////////////////////////////////////////////////////
void OnServerInitialized() {
Load_ID();
List<string> returnString = new List<string>();
if (BanSystemHasFlag(banSystem, BanSystem.PlayerDatabase)) {
returnString.Add(PlayerDatabase_Load());
}
if (BanSystemHasFlag(banSystem, BanSystem.Files)) {
returnString.Add(Files_Load());
}
if (BanSystemHasFlag(banSystem, BanSystem.MySQL)) {
returnString.Add(MySQL_Load());
}
if (BanSystemHasFlag(banSystem, BanSystem.SQLite)) {
returnString.Add(SQLite_Load());
}
if (BanSystemHasFlag(banSystem, BanSystem.WebAPI)) {
returnString.Add(WebAPI_Load());
}
if (BanSystemHasFlag(banSystem, BanSystem.Native)) {
returnString.Add(Native_Load());
}
if (returnString.Count == 0) {
this.LogWarning("You must enable at least one Ban System to use this plugin!");
Interface.Oxide.UnloadPlugin(Name);
}
permission.RegisterPermission(PermissionBan, this);
permission.RegisterPermission(PermissionBanlist, this);
permission.RegisterPermission(PermissionKick, this);
permission.RegisterPermission(PermissionUnban, this);
Interface.Oxide.LogInfo(string.Join("\n", returnString.ToArray()));
if (Discord_use && (!IsPluginLoaded(DiscordMessages) || Discord_Webhook.Equals("https://support.discordapp.com/hc/en-us/articles/228383668-Intro-to-Webhooks"))) {
LogError("DiscordMessages enabled but it isn't setup correctly.");
Discord_use = false;
}
}
void Unload() => OnServerSave();
void OnServerSave() {
Save_ID();
if (BanSystemHasFlag(banSystem, BanSystem.PlayerDatabase)) {
Save_PlayerDatabaseIP();
}
if (BanSystemHasFlag(banSystem, BanSystem.Files)) {
Save_Files();
}
}
private void OnUserBanned(string name, string id, string address, string reason) {
timer.Once(5f, () => {
if (!isBanned_Check(name, id, address)) {
Puts("Adding banned player to EnhancedBanSystem");
BanData bd = new BanData("Auto Ban", id, name, address, reason, 0.0);
ExecuteBan("Auto Ban", bd, false);
}
}
);
}
object CanUserLogin(string name, string id, string ip) {
BanData bd = null;
if (isBanned_NonDelayed(name, id, ip, Ban_Escape, out bd)) {
if (bd != null && bd.expire != 0.0) {
return GetMsg("PlayerTempBanned", id, bd.reason, FormatTime(TimeSpan.FromSeconds(bd.expire - LogTime())));
}
return GetMsg("PlayerPermBanned", id, bd == null ? string.Empty : bd.reason);
}
return null;
}
void OnUserConnected(IPlayer player) {
if (player == null) return;
string ip = player.Address;
string name = player.Name;
string steamid = player.Id;
isBanned_Delayed(name, steamid, ip, Ban_Escape);
}
////////////////////////////////////////////////////////////
// Files
////////////////////////////////////////////////////////////
StoredData storedData;
class StoredData {
public HashSet<string> Banlist = new HashSet<string>();
}
string Files_Load() {
try {
storedData = Interface.Oxide.DataFileSystem.ReadObject<StoredData>(Name);
}
catch {
storedData = new StoredData();
}
foreach (var b in storedData.Banlist) {
var bd = JsonConvert.DeserializeObject<BanData>(b);
if (!cachedBans.ContainsKey(bd.id)) cachedBans.Add(bd.id, bd);
}
return FormatReturn(BanSystem.Files, GetMsg("LoadedBans", null), storedData.Banlist.Count.ToString());
}
void Save_Files() {
if (storedData.Banlist == null) {
return;
}
Interface.Oxide.DataFileSystem.WriteObject(Name, storedData);
}
string Files_UpdateBan(BanData bandata) {
if (!cachedBans.ContainsKey(bandata.id)) return FormatReturn(BanSystem.Files, "No such ban id {0}", bandata.id);
storedData.Banlist.Remove(cachedBans[bandata.id].ToJson());
cachedBans.Remove(bandata.id);
storedData.Banlist.Add(bandata.ToJson());
if (!cachedBans.ContainsKey(bandata.id)) cachedBans.Add(bandata.id, bandata);
return FormatReturn(BanSystem.Files, GetMsg("BanUpdated"), bandata.ToString());
}
string Files_ExecuteBan(BanData bandata) {
var f = cachedBans.Values.Where(x => x.ip == bandata.ip).Where(x => x.steamid == bandata.steamid).ToList();
if (f.Count > 0) {
var i = f.ToList();
foreach (var id in i) {
if (id.expire == 0.0 || id.expire < LogTime()) continue;
storedData.Banlist.Remove(id.ToJson());
f.Remove(id);
}
if (f.Count > 0) {
return FormatReturn(BanSystem.Files, GetMsg("BanExists"), f[0].ToString());
}
}
storedData.Banlist.Add(bandata.ToJson());
Save_Files();
if (!cachedBans.ContainsKey(bandata.id)) cachedBans.Add(bandata.id, bandata);
return FormatReturn(BanSystem.Files, GetMsg("BanAdded"), bandata.ToString());
}
string Files_RawUnban(List<BanData> unbanList) {
int i = 0;
foreach (var u in unbanList) {
var json = u.ToJson();
if (storedData.Banlist.Contains(json)) {
i++;
storedData.Banlist.Remove(json);
}
}
return FormatReturn(BanSystem.Files, GetMsg("BansRemoved"), i.ToString());
}
string Files_ExecuteUnban(string steamid, string name, string ip, out List<BanData> unbanList) {
unbanList = new List<BanData>();
if (ip != string.Empty) {
unbanList = cachedBans.Values.Where(x => x.ip == ip).ToList();
}
else if (steamid != string.Empty) {
unbanList = cachedBans.Values.Where(x => x.steamid == steamid).ToList();
}
else {
var list = cachedBans.Values.Where(x => x.name.ToLower().Equals(name.ToLower())).ToList();
if (list.Count > 1) {
var ret = FormatReturn(BanSystem.Files, GetMsg("MultipleBans"));
foreach (var b in list) {
ret += string.Format("{0} - {1} - {2}\n\r", b.steamid, b.name, b.reason);
}
return ret;
}
else {
unbanList = list;
}
}
return Files_RawUnban(unbanList);
}
bool Files_IsBanned(string steamid, string ip, out BanData bandata) {
bandata = null;
double cTime = LogTime();
bool permanent = false;
List<BanData> unbanList = new List<BanData>();
List<BanData> list = new List<BanData>();
// check by ID then IP
var b_steamid = cachedBans.Values.Where(x => x.steamid == steamid).ToList();
var b_steamid_ip = ip != null ? b_steamid.Where(w => w.ip == ip).ToList() : new List<BanData>();
foreach (var b in b_steamid_ip) {
if (b.expire != 0.0 && cTime >= b.expire) {
unbanList.Add(b);
}
else {
if (b.expire == 0.0) {
permanent = true;
}
if (b.ip == ip) {
bandata = b;
}
}
}
if (unbanList.Count > 0) {
Files_RawUnban(unbanList);
foreach (var u in unbanList) {
b_steamid_ip.Remove(u);
}
unbanList.Clear();
}
foreach (var b in b_steamid) {
if (b.expire != 0.0 && cTime >= b.expire) {
unbanList.Add(b);
}
else {
if (b.expire == 0.0) {
permanent = true;
}
if (b.ip == ip) {
bandata = b;
}
}
}
if (unbanList.Count > 0) {
Files_RawUnban(unbanList);
foreach (var u in unbanList) {
b_steamid.Remove(u);
}
unbanList.Clear();
}
if (bandata == null) {
if (b_steamid_ip.Count > 0) {
bandata = b_steamid_ip[0];
}
else if (b_steamid.Count > 0) {
bandata = b_steamid[0];
}
}
if (bandata == null && !permanent) {
// check by IP & IP Range
list = ip != null ? cachedBans.Values.Where(x => x.ip != null && IPRange(x.ip, ip)).ToList() : new List<BanData>();
foreach (var b in list) {
if (b.expire != 0.0 && cTime >= b.expire) {
unbanList.Add(b);
}
else {
if (b.expire == 0.0) {
permanent = true;
}
}
}
if (unbanList.Count > 0) {
Files_RawUnban(unbanList);
foreach (var u in unbanList) {
list.Remove(u);
}
unbanList.Clear();
}
if (list.Count > 0) {
bandata = list[0];
}
}
if (bandata != null && bandata.expire != 0.0 && permanent) {
bandata.expire = 0.0;
Files_UpdateBan(bandata);
}
return bandata != null;
}
string Files_Banlist(object source, int startid) {
if (startid > cachedBans.Count) {
return FormatReturn(BanSystem.Files, "Index is out of range.Current bans recorded: {0}", cachedBans.Count.ToString());
}
int i = -1;
int max = startid + 9;
string returnstring = FormatReturn(BanSystem.Files, GetMsg("Banlist"), startid.ToString(), max.ToString(), cachedBans.Count.ToString());
var bans = from pair in cachedBans orderby pair.Key descending select pair;
foreach (KeyValuePair<int, BanData> b in bans) {
i++;
if (i < startid) continue;
if (i > max) break;
returnstring += b.ToString() + "\n";
}
return returnstring;
}
////////////////////////////////////////////////////////////
// PlayerDatabase
////////////////////////////////////////////////////////////
static StoredIPData storedIPData;
class StoredIPData {
public HashSet<string> Banlist = new HashSet<string>();
}
string PlayerDatabase_Load() {
if (!IsPluginLoaded(PlayerDatabase)) return FormatReturn(BanSystem.PlayerDatabase, "Missing plugin: oxidemod.org/threads/playerdatabase.18409/");
try {
storedIPData = Interface.Oxide.DataFileSystem.ReadObject<StoredIPData>(PlayerDatabase_IPFile);
}
catch {
storedIPData = new StoredIPData();
}
if (storedIPData.Banlist.Count > 0) {
foreach (var b in storedIPData.Banlist) {
var bd = JsonConvert.DeserializeObject<BanData>(b);
if (!cachedBans.ContainsKey(bd.id)) cachedBans.Add(bd.id, bd);
}
}
var getKnownPlayers = (List<string>)PlayerDatabase.Call("GetAllKnownPlayers");
if (getKnownPlayers == null) return FormatReturn(BanSystem.PlayerDatabase, "Error P01");
int i = 0;
List<BanData> list = new List<BanData>();
foreach (var steamid in getKnownPlayers) {
var success = PlayerDatabase.Call("GetPlayerDataRaw", steamid, "Banned");
if (!(success is string)) continue;
list = JsonConvert.DeserializeObject<List<BanData>>((string)success);
foreach (var b in list) {
i++;
if (!cachedBans.ContainsKey(b.id)) cachedBans.Add(b.id, b);
}
}
return FormatReturn(BanSystem.PlayerDatabase, GetMsg("LoadedBans"), i.ToString());
}
void Save_PlayerDatabaseIP() {
Interface.Oxide.DataFileSystem.WriteObject(PlayerDatabase_IPFile, storedIPData);
}
string PlayerDatabase_ExecuteBan(BanData bandata) {
if (bandata.steamid != string.Empty) {
List<BanData> list = new List<BanData>();
var success = PlayerDatabase.Call("GetPlayerDataRaw", bandata.steamid, "Banned");
if (success is string) {
list = JsonConvert.DeserializeObject<List<BanData>>((string)success);
}
var f = list.Where(x => x.ip == bandata.ip).ToList();
if (f.Count > 0) {
return FormatReturn(BanSystem.PlayerDatabase, GetMsg("BanExists"), f[0].ToString());
}
f.Add(bandata);
PlayerDatabase.Call("SetPlayerData", bandata.steamid, "Banned", f);
}
else {
var f2 = cachedBans.Values.Where(x => x.ip == bandata.ip).Where(x => x.steamid == string.Empty).ToList();
if (f2.Count > 0) {
return FormatReturn(BanSystem.PlayerDatabase, GetMsg("BanExists"), f2[0].ToString());
}
storedIPData.Banlist.Add(bandata.ToJson());
}
if (!cachedBans.ContainsKey(bandata.id)) cachedBans.Add(bandata.id, bandata);
return FormatReturn(BanSystem.PlayerDatabase, GetMsg("BanAdded"), bandata.ToString());
}
string PlayerDatabase_UpdateBan(BanData bandata, double expire) {
if (bandata.steamid == string.Empty) {
if (cachedBans.ContainsKey(bandata.id)) {
var json = bandata.ToJson();
if (storedIPData.Banlist.Contains(json)) {
cachedBans.Remove(bandata.id);
storedIPData.Banlist.Remove(json);
bandata.expire = expire;
storedIPData.Banlist.Add(bandata.ToJson());
cachedBans.Add(bandata.id, bandata);
return FormatReturn(BanSystem.Files, GetMsg("BanUpdated"), bandata.ToString());
}
}
}
else {
List<BanData> list = new List<BanData>();
bandata.expire = expire;
var b_steamid = PlayerDatabase.Call("GetPlayerDataRaw", bandata.steamid, "Banned");
if (b_steamid is string) {
list = JsonConvert.DeserializeObject<List<BanData>>((string)b_steamid);
}
if (list.Count > 0) {
foreach (var b in list) {
b.expire = expire;
}
PlayerDatabase.Call("SetPlayerData", bandata.steamid, "Banned", list);
return FormatReturn(BanSystem.Files, GetMsg("BanUpdated"), bandata.ToString());
}
}
return string.Empty;
}
string PlayerDatabase_RawUnban(List<BanData> unbanList) {
int i = 0;
foreach (var u in unbanList) {
if (u.steamid == string.Empty) {
var json = u.ToJson();
if (storedIPData.Banlist.Contains(json)) {
i++;
storedIPData.Banlist.Remove(json);
}
}
else {
i++;
PlayerDatabase.Call("SetPlayerData", u.steamid, "Banned", new List<BanData>());
}
}
return FormatReturn(BanSystem.PlayerDatabase, GetMsg("BansRemoved"), i.ToString());
}
string PlayerDatabase_ExecuteUnban(string steamid, string name, string ip, out List<BanData> unbanList) {
unbanList = new List<BanData>();
if (ip != string.Empty) {
unbanList = cachedBans.Values.Where(x => x.ip == ip).ToList();
}
else if (steamid != string.Empty) {
unbanList = cachedBans.Values.Where(x => x.steamid == steamid).ToList();
}
else {
unbanList = cachedBans.Values.Where(x => x.name == name).ToList();
if (unbanList.Count == 0) {
var lname = name.ToLower();
unbanList = cachedBans.Values.Where(x => x.name.ToLower().Contains(lname)).ToList();
if (unbanList.Count > 1) {
var ret = FormatReturn(BanSystem.PlayerDatabase, GetMsg("MultipleBans"));
foreach (var b in unbanList) {
ret += string.Format("{0} - {1} - {2}\n\r", b.steamid, b.name, b.reason);
}
return ret;
}
}
}
return PlayerDatabase_RawUnban(unbanList);
}
bool PlayerDatabase_IsBanned(string steamid, string ip, out BanData bandata) {
bandata = null;
BanData possibleData = null;
double cTime = LogTime();
bool permanent = false;
List<BanData> unbanList = new List<BanData>();
List<BanData> list = new List<BanData>();
// check by ID then IP
var b_steamid = PlayerDatabase.Call("GetPlayerDataRaw", steamid, "Banned");
if (b_steamid is string) {
list = JsonConvert.DeserializeObject<List<BanData>>((string)b_steamid);
}
foreach (var b in list) {
if (b.expire != 0.0 && cTime >= b.expire) {
unbanList.Add(b);
}
else {
if (b.expire == 0.0) {
permanent = true;
}
if (b.ip == ip) {
bandata = b;
}
}
}
if (unbanList.Count > 0) {
PlayerDatabase_RawUnban(unbanList);
foreach (var b in unbanList) {
list.Remove(b);
}
unbanList.Clear();
}
if (list.Count > 0 && bandata == null) {
possibleData = list[0];
}
// check by IP & IP Range
list = ip != null ? cachedBans.Values.Where(x => x.ip != null && IPRange(x.ip, ip)).ToList() : new List<BanData>();
foreach (var b in list) {
if (b.expire != 0.0 && cTime >= b.expire) {
unbanList.Add(b);
}
else {
if (b.expire == 0.0) {
permanent = true;
}
}
}
if (unbanList.Count > 0) {
PlayerDatabase_RawUnban(unbanList);
foreach (var b in unbanList) {
list.Remove(b);
}
unbanList.Clear();
}
if (list.Count > 0 && bandata == null && possibleData == null) {
possibleData = list[0];
}
if (bandata == null && possibleData != null) {
bandata = possibleData;
}
if (bandata != null && bandata.expire != 0.0 && permanent) {
PlayerDatabase_UpdateBan(bandata, 0.0);
}
return bandata != null;
}
string PlayerDatabase_Banlist(object source, int startid) {
if (startid > cachedBans.Count) {
return FormatReturn(BanSystem.PlayerDatabase, GetMsg("OutOfRange"), cachedBans.Count.ToString());
}
int i = -1;
int max = startid + 9;
string returnstring = FormatReturn(BanSystem.PlayerDatabase, GetMsg("Banlist"), startid.ToString(), max.ToString(), cachedBans.Count.ToString());
var bans = from pair in cachedBans orderby pair.Key descending select pair;
foreach (KeyValuePair<int, BanData> b in bans) {
i++;
if (i < startid) continue;
if (i > max) break;
returnstring += b.ToString() + "\n";
}
return returnstring;
}
////////////////////////////////////////////////////////////
// WebAPI
////////////////////////////////////////////////////////////
string FormatOnlineBansystem(string line, Dictionary<string, string> args) {
foreach (KeyValuePair<string, string> pair in args) {
line = line.Replace(pair.Key, pair.Value);
}
return line;
}
string WebAPI_ExecuteBan(object source, BanData bandata) {
webrequest.Enqueue(FormatOnlineBansystem(WebAPI_Ban_Request, new Dictionary<string, string> {
{
"{id}", bandata.id.ToString()
}
, {
"{steamid}", bandata.steamid
}
, {
"{name}", bandata.name
}
, {
"{ip}", bandata.ip
}
, {
"{reason}", bandata.reason
}
, {
"{source}", bandata.source
}
, {
"{expiration}", bandata.expire.ToString()
}
, {
"{game}", bandata.game
}
, {
"{platform}", bandata.platform
}
, {
"{server}", bandata.server
}
}
), null, (code, response) => {
if (response == null && code == 200) {
response = FormatReturn(BanSystem.WebAPI, "Couldn't contact the WebAPI");
}
if (source is IPlayer) ((IPlayer)source).Reply(response);
else Interface.Oxide.LogInfo(response);
}
, this);
return string.Empty;
}
string WebAPI_ExecuteUnban(object source, string steamid, string name, string ip) {
webrequest.Enqueue(FormatOnlineBansystem(WebAPI_Unban_Request, new Dictionary<string, string> {
{
"{steamid}", steamid
}
, {
"{name}", name
}
, {
"{ip}", ip
}
}
), null, (code, response) => {
if (response == null && code == 200) {
response = FormatReturn(BanSystem.WebAPI, "Couldn't contact the WebAPI");
}
if (source is IPlayer) ((IPlayer)source).Reply(response);
else Interface.Oxide.LogInfo(response);
}
, this);
return string.Empty;
}
string WebAPI_IsBanned(BanData bandata, bool update) {
webrequest.Enqueue(FormatOnlineBansystem(WebAPI_IsBanned_Request, new Dictionary<string, string> {
{
"{id}", bandata.id.ToString()
}
, {
"{steamid}", bandata.steamid
}
, {
"{name}", bandata.name
}
, {
"{ip}", bandata.ip
}
, {
"{source}", "Auto Ban"
}
, {
"{update}", update.ToString()
}
, {
"{time}", LogTime().ToString()
}
}
), null, (code, response) => {
if (response != null || code != 200) {
if (response == "false" || response == "0") return;
timer.Once(0.01f, () => Kick(null, bandata.steamid, response == "true" || response == "1" ? "Banned" : response, false));
}
else {
Interface.Oxide.LogWarning("WebAPI couldn't be contacted or is not valid");
}
}
, this);
return string.Empty;
// ... [Code preview truncated due to length. Full source in attached file] ...