C#:
//steam api C2AB21AD2A5F38CE7DC8B22D7F219259
//iphub api OTk5NDpUa3EzanBIbmhJRnIyTzkxd0RvYk9IYWFYTlM4YkF5Zg==
using Network;
using Oxide.Core.Plugins;
using Newtonsoft.Json.Linq;
using System.Text.RegularExpressions;
using Oxide.Core;
using System.Collections.Generic;
using Newtonsoft.Json;
using System;
using System.Runtime.CompilerServices;
namespace Oxide.Plugins
{
[Info("PlayerProtection", "TimMorse", "0.3.1")]
public class PlayerProtection : RustPlugin
{
[PluginReference] Plugin VKBot;
#region Permissions / Разрешения
const string AdminPermission = "playerprotection.flags";
#endregion
#region Classes / Классы
private class NickNameList
{
[JsonProperty("SteamID")]
public ulong SteamID;
[JsonProperty("DateTime")]
public string DateTime;
}
private class WhiteListIP
{
[JsonProperty("NickName")]
public string NickName;
[JsonProperty("SteamID")]
public ulong SteamID;
[JsonProperty("Country")]
public string Country;
[JsonProperty("DateTime")]
public string DateTime;
}
private class BlackListIP
{
[JsonProperty("NickName")]
public string NickName;
[JsonProperty("SteamID")]
public ulong SteamID;
[JsonProperty("Country")]
public string Country;
[JsonProperty("DateTime")]
public string DateTime;
}
private class SteamWhiteList
{
[JsonProperty("NickName")]
public string NickName;
[JsonProperty("IP")]
public List<string> IP;
[JsonProperty("LastNickNames")]
public List<string> LastNickNames;
[JsonProperty("URL")]
public string ProfileUrl;
[JsonProperty("ProfileCreated")]
public string ProfileCreated;
[JsonProperty("DateTime")]
public string DateTime;
}
private class SteamBlackList
{
[JsonProperty("NickName")]
public string NickName;
[JsonProperty("URL")]
public string ProfileUrl;
[JsonProperty("IP")]
public List<string> IP;
[JsonProperty("ProfileCreated")]
public string ProfileCreated;
[JsonProperty("DateTime")]
public string DateTime;
}
private class DisconnectReasonList
{
[JsonProperty("NickName")]
public string NickName;
[JsonProperty("IP")]
public List<string> IP;
[JsonProperty("Reasons")]
public List<string> Reasons;
[JsonProperty("DateTimes")]
public List<string> DateTimes;
}
#endregion
#region Variables / Переменные
Dictionary<string, NickNameList> nicknameList = new Dictionary<string, NickNameList>();
Dictionary<string, WhiteListIP> whiteListIP = new Dictionary<string, WhiteListIP>();
Dictionary<string, BlackListIP> blackListIP = new Dictionary<string, BlackListIP>();
Dictionary<ulong, SteamWhiteList> steamWhiteList = new Dictionary<ulong, SteamWhiteList>();
Dictionary<ulong, SteamBlackList> steamBlackList = new Dictionary<ulong, SteamBlackList>();
Dictionary<ulong, DisconnectReasonList> disconnectReasonList = new Dictionary<ulong, DisconnectReasonList>();
List<string> blacklistCMD = new List<string>()
{
"oxide.plugins",
"global.plugins",
"oxide.load",
"global.load",
"oxide.reload",
"global.reload",
"oxide.unload",
"global.unload",
"oxide.grant",
"global.grant",
"oxide.group",
"global.group",
"oxide.revoke",
"global.revoke",
"oxide.show",
"global.show",
"oxide.usergroup",
"global.usergroup",
"oxide.version",
"global.ownerid"
};
#endregion
#region Config / Конфигурация
private static ConfigData config;
private class ConfigData
{
public class NickName
{
[JsonProperty("Включить проверку ников")]
public bool Enabled;
[JsonProperty("Минимальная длина ника")]
public int MinLength;
[JsonProperty("Максимальная длина ника")]
public int MaxLength;
[JsonProperty("Проверять на запрещённые символы")]
public bool Validate;
[JsonProperty("Список запрещённых ников")]
public List<string> BlackList;
[JsonProperty("Привязка ника к игроку (защита от фейков)")]
public bool CheckUniqueName;
}
public class Steam
{
[JsonProperty("Включить проверку игрока в Steam")]
public bool Enabled;
[JsonProperty("API ключ Steam")]
public string Api;
[JsonProperty("Дополнительная проверка аккаунта по статусу и игре в Steam (Учитывайте, что аккаунт может быть приватным или находитс невидимки)")]
public bool CheckStatus;
}
public class IPHub
{
[JsonProperty("Включить проверку IP в сервисе IPHub")]
public bool Enabled;
[JsonProperty("API ключ")]
public string Api;
}
public class DisconnectReasonChecker
{
[JsonProperty("Включить чекер")]
public bool Enabled;
[JsonProperty("Список запрещённых слов")]
public List<string> BlackList;
}
public class VKBotLog
{
[JsonProperty("Включить логирование в беседу")]
public bool Enabled;
[JsonProperty("ID беседы")]
public string ChatID;
}
[JsonProperty("Настройка ника игрока")]
public NickName nickName;
[JsonProperty("Настройка Steam")]
public Steam steam;
[JsonProperty("Настройка IPHub")]
public IPHub iphub;
[JsonProperty("Настройка чекера Disconnect`ов")]
public DisconnectReasonChecker disconnectReasonChecker;
[JsonProperty("VKBot logger")]
public VKBotLog vKBotLog;
}
protected override void LoadConfig()
{
base.LoadConfig();
try
{
config = Config.ReadObject<ConfigData>();
if (config == null)
LoadDefaultConfig();
}
catch
{
LoadDefaultConfig();
}
SaveConfig();
}
private ConfigData GetDefaultConfig()
{
return new ConfigData
{
nickName = new ConfigData.NickName
{
Enabled = true,
MinLength = 2,
MaxLength = 18,
Validate = true,
BlackList = new List<string>
{
"ХУЙНЯ",
"XУЙНЯ"
},
CheckUniqueName = true
},
steam = new ConfigData.Steam
{
Enabled = false,
Api = "Ключ получаем здесь (https://steamcommunity.com/dev/apikey)",
CheckStatus = false
},
iphub = new ConfigData.IPHub
{
Enabled = false,
Api = "Ключ получаем в личном кабинете (https://iphub.info/)"
},
disconnectReasonChecker = new ConfigData.DisconnectReasonChecker
{
Enabled = true,
BlackList = new List<string>
{
"Cheat",
"Hack",
"ESP"
}
},
vKBotLog = new ConfigData.VKBotLog
{
Enabled = true,
ChatID = "2"
}
};
}
protected override void LoadDefaultConfig()
{
PrintWarning("Файл конфигурации поврежден (или не существует), создаем новый...");
config = GetDefaultConfig();
}
protected override void SaveConfig() => Config.WriteObject(config);
#endregion
#region Hooks / Обработчики
[HookMethod("CanUserLogin")]
private object CanUserLogin(string name, string steamid, string ip)
{
if (config.iphub.Enabled && blackListIP.ContainsKey(ip))
{
Log($"[BLACKLIST VPN] {name} ({steamid}) ({ip}) - Данный IP заблокирован на сервере.", 2);
return GetMessage("BLACKLIST_IP", steamid);
}
ulong PlayerID = Convert.ToUInt64(steamid);
if (config.steam.Enabled && steamBlackList.ContainsKey(PlayerID) && steamBlackList[PlayerID].IP.Contains(ip))
{
Log($"[BLACKLIST STEAM] {name} ({steamid}) ({ip}) - Данный STEAM профиль заблокирован на сервере.", 2);
return GetMessage("BLACKLIST_STEAM", steamid);
}
if (!config.nickName.Enabled) return null;
if (config.nickName.BlackList.Count > 0 && config.nickName.BlackList.Contains(name))
{
Log($"[BLACKLIST NICKNAME] {name} ({steamid}) ({ip}) - Данный ник запрещён для использования на сервере.", 2);
ConsoleSystem.Run.Server.Normal($"player.ban {ip} \"blacklist nickname\"");
return GetMessage("BLACKLIST_NICKNAME", steamid);
}
if (name.Length < config.nickName.MinLength || name.Length > config.nickName.MaxLength)
{
Log($"[NICKNAME] {name} ({steamid}) ({ip}) - Некорректная длина ника.", 1);
return GetMessage("LENGTH_NICKNAME", steamid, config.nickName.MinLength, config.nickName.MaxLength);
}
if (config.nickName.Validate && !Regex.Match(name, "^[А-Яа-яA-Za-z0-9\\s\\#]+$").Success)
{
Log($"[NICKNAME] {name} ({steamid}) ({ip}) - Запрещённые символы в нике.", 1);
return GetMessage("INVALID_NICKNAME", steamid);
}
if (config.nickName.CheckUniqueName && nicknameList.ContainsKey(name) && nicknameList[name].SteamID != PlayerID)
{
Log($"[NICKNAME] {name} ({steamid}) ({ip}) - Использует ник игрока {name} ({nicknameList[name].SteamID}).", 1);
return GetMessage("NOUNIQUE_NICKNAME", steamid);
}
return null;
}
private void RequestIPHub(Connection connection, string ip)
{
ulong userid = connection.userid;
string userid_string = connection.userid.ToString();
string username = connection.username;
if (whiteListIP.ContainsKey(ip))
{
Log($"[IP WHITELIST] {username} ({userid}) ({ip}) - Найден в белом списке.Проверка не требуется.");
if (config.steam.Enabled) RequestSteamProfile(connection, ip);
return;
}
webrequest.EnqueueGet($"http://v2.api.iphub.info/ip/{ip}", (code, response) =>
{
if(code != 200)
{
PrintError($"[IPHUB API] {code} {response}");
return;
}
JObject info = JObject.Parse(response);
string countryName = (string) info["countryName"];
string block = (string) info["block"];
if (block.Contains("1"))
{
ConnectionAuth.Reject(connection, GetMessage("INVALID_IP", userid_string));
connection.rejected = true;
blackListIP.Add(ip, new BlackListIP()
{
NickName = username,
SteamID = userid,
Country = countryName,
DateTime = GetCurrentDateTimeString()
});
Log($"[VPN] {username} ({userid}) ({ip}) ({countryName}) - Внесён в чёрный список.", 2);
ConsoleSystem.Run.Server.Normal($"player.ban {ip} \"vpn\"");
return;
}
whiteListIP.Add(ip, new WhiteListIP()
{
NickName = username,
SteamID = userid,
Country = countryName,
DateTime = GetCurrentDateTimeString()
});
if (config.steam.Enabled) RequestSteamProfile(connection, ip);
return;
}, this, new Dictionary<string, string>{{"X-Key", config.iphub.Api}});
}
private void RequestSteamProfile(Connection connection, string ip)
{
ulong userid = connection.userid;
string userid_string = connection.userid.ToString();
string username = connection.username;
if (config.steam.Enabled && steamWhiteList.ContainsKey(userid) && steamWhiteList[userid].IP.Contains(ip) && steamWhiteList[userid].NickName == username)
{
Log($"[STEAM WHITELIST] {username} ({userid}) ({ip}) - Найден в белом списке.Проверка не требуется.");
return;
}
webrequest.EnqueueGet($"https://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0002/?key={config.steam.Api}&steamids={connection.userid}&personalname&format=json", (code, response) =>
{
if (code != 200)
{
PrintError($"[STEAM API] {code} {response}");
return;
}
JObject info = JObject.Parse(response);
if (!info["response"]["players"].HasValues)
{
ConnectionAuth.Reject(connection, GetMessage("INVALID_STEAM", userid_string));
connection.rejected = true;
if (!steamBlackList.ContainsKey(userid))
{
steamBlackList.Add(userid, new SteamBlackList()
{
NickName = username,
IP = new List<string>() { ip },
ProfileUrl = "fake",
ProfileCreated = "fake",
DateTime = GetCurrentDateTimeString()
});
}
else steamBlackList[userid].IP.Add(ip);
Log($"[STEAM] {username} ({userid}) ({ip}) - Данный профиль не существует в Steam.", 2);
ConsoleSystem.Run.Server.Normal($"player.ban {ip} \"fake steam\"");
return;
}
foreach (var item in info["response"]["players"])
{
if (!item["personaname"].ToString().Contains(username))
{
ConnectionAuth.Reject(connection, GetMessage("INVALID_STEAM", userid_string));
connection.rejected = true;
if (!steamBlackList.ContainsKey(userid))
{
steamBlackList.Add(userid, new SteamBlackList()
{
NickName = username,
IP = new List<string>() { ip },
ProfileUrl = "fake",
ProfileCreated = "fake",
DateTime = GetCurrentDateTimeString()
});
}
else steamBlackList[userid].IP.Add(ip);
Log($"[STEAM] {username} ({userid}) ({ip}) - Не соответствие ника с профилем Steam.", 2);
//ConsoleSystem.Run.Server.Normal($"player.ban {ip} \"fake steam\"");
return;
}
if (config.steam.CheckStatus && (item["communityvisibilitystate"].ToString().Contains("1") || item["communityvisibilitystate"].ToString().Contains("2")))
{
ConnectionAuth.Reject(connection, GetMessage("PRIVATE_ACCOUNT", userid_string));
connection.rejected = true;
Log($"[STEAM] {username} ({userid}) ({ip}) - Профиль находится в привате.", 1);
return;
}
if (config.steam.CheckStatus && (item["personastate"].ToString().Contains("0") || item["personastate"].ToString().Contains("3")))
{
ConnectionAuth.Reject(connection, GetMessage("OFFLINE_STATUS", userid_string));
connection.rejected = true;
Log($"[STEAM] {username} ({userid}) ({ip}) - У профиля нет статуса `Онлайн`.", 1);
return;
}
if (!steamWhiteList.ContainsKey(userid))
{
steamWhiteList.Add(userid, new SteamWhiteList()
{
NickName = username,
IP = new List<string>() { ip },
ProfileUrl = item["profileurl"].ToString(),
ProfileCreated = GetDateTimeString((double) item["timecreated"]),
DateTime = GetCurrentDateTimeString()
});
nicknameList.Add(username, new NickNameList()
{
SteamID = userid,
DateTime = GetCurrentDateTimeString()
});
Log($"[STEAM WHITELIST] {username} ({userid}) ({ip}) - Steam профиль игрока внесён в белый список.");
}
else
{
Log($"[STEAM WHITELIST] {username} ({userid}) ({ip}) - Изменились данные.Обновляем список.", 1);
if(!steamWhiteList[userid].IP.Contains(ip)) steamWhiteList[userid].IP.Add(ip);
if(steamWhiteList[userid].LastNickNames == null)
steamWhiteList[userid].LastNickNames = new List<string>() { steamWhiteList[userid].NickName };
else if(!steamWhiteList[userid].LastNickNames.Contains(steamWhiteList[userid].NickName))
steamWhiteList[userid].LastNickNames.Add(steamWhiteList[userid].NickName);
if (steamWhiteList[userid].DateTime == null)
steamWhiteList[userid].DateTime = GetCurrentDateTimeString();
if (nicknameList.ContainsKey(steamWhiteList[userid].NickName)) nicknameList.Remove(steamWhiteList[userid].NickName);
steamWhiteList[userid].NickName = username;
nicknameList.Add(username, new NickNameList()
{
SteamID = userid,
DateTime = GetCurrentDateTimeString()
});
}
}
return;
}, this);
}
[HookMethod("OnUserApprove")]
private void OnUserApprove(Connection connection)
{
if (!config.steam.Enabled && !config.iphub.Enabled) return;
string ip = connection.ipaddress.Split(':')[0];
ulong userid = connection.userid;
string username = connection.username;
if (config.steam.Enabled &&
config.iphub.Enabled && whiteListIP.ContainsKey(ip) &&
steamWhiteList.ContainsKey(userid) &&
steamWhiteList[userid].IP.Contains(ip) &&
steamWhiteList[userid].NickName == username)
{
Log($"[WHITELIST] {username} ({userid}) ({ip}) - Игрок не нуждается в проверке, пропускаем.");
return;
}
else if (config.iphub.Enabled) RequestIPHub(connection, ip);
else if (config.steam.Enabled) RequestSteamProfile(connection, ip);
return;
}
[HookMethod("OnServerInitialized")]
void OnServerInitialized()
{
InitMessage();
if (!permission.PermissionExists(AdminPermission, this)) permission.RegisterPermission(AdminPermission, this);
if (Interface.Oxide.DataFileSystem.ExistsDatafile($"{Name}/NickNameList"))
nicknameList = Interface.Oxide.DataFileSystem.ReadObject<Dictionary<string, NickNameList>>($"{Name}/NickNameList");
if (nicknameList.Count > 0) PrintWarning($"[NICKNAME LIST] загружено {nicknameList.Count} никнеймов");
if (Interface.Oxide.DataFileSystem.ExistsDatafile($"{Name}/WhiteListIP"))
whiteListIP = Interface.Oxide.DataFileSystem.ReadObject<Dictionary<string, WhiteListIP>>($"{Name}/WhiteListIP");
if (whiteListIP.Count > 0) PrintWarning($"[IP WHITELIST] загружено {whiteListIP.Count} профилей");
if (Interface.Oxide.DataFileSystem.ExistsDatafile($"{Name}/BlackListIP"))
blackListIP = Interface.Oxide.DataFileSystem.ReadObject<Dictionary<string, BlackListIP>>($"{Name}/BlackListIP");
if (blackListIP.Count > 0) PrintWarning($"[IP BLACKLIST] загружено {blackListIP.Count} профилей");
if (Interface.Oxide.DataFileSystem.ExistsDatafile($"{Name}/SteamWhiteList"))
steamWhiteList = Interface.Oxide.DataFileSystem.ReadObject<Dictionary<ulong, SteamWhiteList>>($"{Name}/SteamWhiteList");
if (steamWhiteList.Count > 0) PrintWarning($"[STEAM WHITELIST] загружено {steamWhiteList.Count} профилей");
if (Interface.Oxide.DataFileSystem.ExistsDatafile($"{Name}/SteamBlackList"))
steamBlackList = Interface.Oxide.DataFileSystem.ReadObject<Dictionary<ulong, SteamBlackList>>($"{Name}/SteamBlackList");
if (steamBlackList.Count > 0) PrintWarning($"[STEAM BLACKLIST] загружено {steamBlackList.Count} профилей");
if (Interface.Oxide.DataFileSystem.ExistsDatafile($"{Name}/DisconnectReasonList"))
disconnectReasonList = Interface.Oxide.DataFileSystem.ReadObject<Dictionary<ulong, DisconnectReasonList>>($"{Name}/DisconnectReasonList");
if (disconnectReasonList.Count > 0) PrintWarning($"[DISCONNECT REASON LIST] загружено {disconnectReasonList.Count} профилей");
}
[HookMethod("Unload")]
private void Unload() => SaveData();
[HookMethod("OnServerSave")]
private void OnServerSave() => SaveData();
[HookMethod("CanBypassQueue")]
private object CanBypassQueue(Connection connection) { return true; }
[HookMethod("OnPlayerInit")]
private void OnPlayerInit(BasePlayer player)
{
string country = GetPlayerCountry(player) == null ? "" : (string) GetPlayerCountry(player);
Log($"[CONNECTED] {player.displayName} ({player.userID}) ({country}) - зашёл на сервер.");
if (permission.UserHasPermission(player.userID.ToString(), AdminPermission))
{
player.SendConsoleCommand("camlerp 1");
return;
}
player.SendConsoleCommand("camlerp 0");
player.SetPlayerFlag(BasePlayer.PlayerFlags.IsAdmin, false);
player.SetPlayerFlag(BasePlayer.PlayerFlags.IsDeveloper, false);
}
/*private void OnPlayerDisconnected(BasePlayer player, string reason)
{
Log($"[DISCONNECT] {player.displayName} ({player.userID}) - вышел с сервера.Причина ({reason})");
}*/
[HookMethod("OnPlayerDisconnectedEx")]
private void OnPlayerDisconnectedEx(BasePlayer player, string reason)
{
if (player == null || reason == null || reason.Length < 1) return;
foreach (var item in config.disconnectReasonChecker.BlackList)
{
if (!reason.Contains(item)) continue;
string ip = player.net.connection.ipaddress.Split(':')[0];
Log($"[REASON CHECKER] {player.displayName} ({player.userID}) - Использует читы, reason: {item}.", 2);
ConsoleSystem.Run.Server.Normal($"player.ban {ip} \"Use cheats\"");
if (disconnectReasonList.ContainsKey(player.userID))
{
if (!disconnectReasonList[player.userID].IP.Contains(ip)) disconnectReasonList[player.userID].IP.Add(ip);
disconnectReasonList[player.userID].Reasons.Add(reason);
disconnectReasonList[player.userID].DateTimes.Add(GetCurrentDateTimeString());
}
else
{
disconnectReasonList.Add(player.userID, new DisconnectReasonList()
{
NickName = player.displayName,
IP = new List<string>() { ip },
Reasons = new List<string>() { reason },
DateTimes = new List<string>() { GetCurrentDateTimeString() }
});
}
break;
}
Log($"[DISCONNECT] {player.displayName} ({player.userID}) - вышел с сервера.Причина: ({reason})");
}
[HookMethod("OnServerCommand")]
private object OnServerCommand(ConsoleSystem.Arg arg)
{
if (arg == null || arg.connection == null || arg.cmd == null) return null;
if (blacklistCMD.Contains(arg.cmd.namefull) && !permission.UserHasPermission(arg.connection.userid.ToString(), AdminPermission))
{
Log($"[BLACKLIST COMMANDS] {arg.connection.username} ({arg.connection.userid}) ({arg.connection.ipaddress.Split(':')[0]}) - ввёл консольную команду {arg.cmd.namefull}", 1);
return true;
}
return null;
}
#endregion
#region Localization
private string GetMessage(string messageKey, string playerID, params object[] args)
{
return string.Format(lang.GetMessage(messageKey, this, playerID), args);
}
private void InitMessage()
{
lang.RegisterMessages(new Dictionary<string, string>
{
{"LENGTH_NICKNAME", "Длина ника должна быть от ({0}) до ({1}) символов."},
{"BLACKLIST_NICKNAME", "Ник, который Вы используете находится в чёрном списке"},
{"INVALID_NICKNAME", "Смените ник в steam.Допускаемые символы: А-Я а-я A-Z a-z 0-9"},
{"INVALID_STEAM", "Fake Steam аккаунт"},
{"PRIVATE_ACCOUNT", "Установите Ваш steam профиль публичным в настройках аккаунта"},
{"OFFLINE_STATUS", "Установите статус \"В сети\" Своего steam профиля"},
{"INVALID_IP", "У Вас был обнаружен VPN" },
{"BLACKLIST_IP", "Ваш IP находится в чёрном списке"},
{"BLACKLIST_STEAM", "Ваш Steam профиль находится в чёрном списке"},
{"CHANGED_NICKNAME", "Ваш профиль привязан к нику ({0}).Пожалуйста смените ник в Steam"},
{"NOUNIQUE_NICKNAME", "Ваш ник уже занят другим игроком.Смените на другой"}
}, this);
PrintWarning("Языковой файл успешно загружен");
}
#endregion
#region Helper
void SaveData()
{
Interface.Oxide.DataFileSystem.WriteObject($"{Name}/NickNameList", nicknameList);
Interface.Oxide.DataFileSystem.WriteObject($"{Name}/SteamWhiteList", steamWhiteList);
Interface.Oxide.DataFileSystem.WriteObject($"{Name}/SteamBlackList", steamBlackList);
Interface.Oxide.DataFileSystem.WriteObject($"{Name}/WhiteListIP", whiteListIP);
Interface.Oxide.DataFileSystem.WriteObject($"{Name}/BlackListIP", blackListIP);
Interface.Oxide.DataFileSystem.WriteObject($"{Name}/DisconnectReasonList", disconnectReasonList);
}
private void Log(string message, int type = 0)
{
switch (type)
{
case 0:
Puts(message);
break;
case 1:
PrintWarning(message);
break;
case 2:
PrintError(message);
break;
}
if (config.vKBotLog.Enabled) SendChatMessage(config.vKBotLog.ChatID, URLEncode(message));
ConVar.Server.Log("player_protection_log.txt", message);
}
private object GetPlayerCountry(BasePlayer player)
{
if (player == null || player.net.connection.ipaddress == null) return null;
string ip = player.net.connection.ipaddress.Split(':')[0];
return whiteListIP[ip].Country;
}
private void SendChatMessage(string chatid, string msg) => VKBot.CallHook("SendChatMessage", chatid, msg);
private string URLEncode(string input)
{
if (input.Contains("#")) input = input.Replace("#", "%23");
if (input.Contains("$")) input = input.Replace("$", "%24");
if (input.Contains("+")) input = input.Replace("+", "%2B");
if (input.Contains("/")) input = input.Replace("/", "%2F");
if (input.Contains(":")) input = input.Replace(":", "%3A");
if (input.Contains(";")) input = input.Replace(";", "%3B");
if (input.Contains("?")) input = input.Replace("?", "%3F");
if (input.Contains("@")) input = input.Replace("@", "%40");
if (input.Contains("&")) input = input.Replace("&", "%26");
return input;
}
private string GetCurrentDateTimeString() => $"{DateTime.Now.ToShortDateString()} {DateTime.Now.ToShortTimeString()}";
private string GetDateTimeString(double unixtime) => new DateTime(1970, 1, 1, 0, 0, 0, 0).AddSeconds(unixtime).ToString();
#endregion
}
}