Иконка ресурса

FREE TGPP : 1.3.6 1.3.6

Нет прав для скачивания
C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
 // -------------- PLUGIN CODE MACROSES --------------
// If you want to select and older version for the plugin, remove '//' near your version:
//#define RUST_DEVBLOG_198
//#define RUST_DEVBLOG_266
#if RUST_DEVBLOG_198
//#define USE_HARMONY
#define RUST_OLD_STEAM_AUTH
#define RUST_DISABLE_EASYANTICHEAT
#define OLD_NETWORKABLE
#define OLD_ITEMS
//#define RUST_OLD_HARMONY
//#define RUST_ORIGINAL_WIPE_ID
//#define RUST_TEAMS
//#define RUST_NPC
#define RUST_OLD_STEAMWORKS
#define RUST_NO_HELICOPTERS
#elif RUST_DEVBLOG_266
//#define USE_HARMONY
#define RUST_OLD_STEAM_AUTH
//#define RUST_DISABLE_EASYANTICHEAT
//#define RUST_OLD_HARMONY
//#define RUST_ORIGINAL_WIPE_ID
#define RUST_TEAMS
#define RUST_NPC
#define RUST_NO_HELICOPTERS
//#define RUST_OLD_STEAMWORKS
//#define OLD_ITEMS
#define OLD_NETWORKABLE
#else
#define RUST_LATEST
#define USE_HARMONY
//#define RUST_OLD_STEAM_AUTH
//#define RUST_DISABLE_EASYANTICHEAT
//#define RUST_OLD_HARMONY
#define RUST_ORIGINAL_WIPE_ID
#define RUST_TEAMS
#define RUST_NPC
//#define RUST_OLD_STEAMWORKS
#endif
//#define STAGE
#if USE_HARMONY
#if RUST_OLD_HARMONY
using Harmony;
#else
using HarmonyLib;
#endif
#endif
using Network;
using Newtonsoft.Json;
using Oxide.Core;
using Oxide.Core.Plugins;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using UnityEngine;
// Reference: 0Harmony
namespace Oxide.Plugins {
    [Info("TGPP", "", "1.3.6")]
    public class TGPP : RustPlugin {
        public const int PirateEncryptionLevel = 1;
        public const int MinTokenLength = 234;
        public const int AppIdOffset = 72;
        public const int CheatDetectIntervalSeconds = 300;
        public const int SessionsCheckIntervalSeconds = 60;
        internal readonly static Dictionary<string, PlayerHwid> _playerHwids = new Dictionary<string, PlayerHwid>();
        private static TGPP Singleton;
        [PluginReference]
        private Plugin MultiFighting;
        [PluginReference]
        private Plugin TirifyGamePluginRust;
#region [ Hooks ]
        private void Loaded() {
            Singleton = this;
            try {
                InitializeReflection();
                DetectOtherNS();
#if USE_HARMONY
                PatchManager.PatchAll();
#endif
                RegisterPirateController();
                RegisterCheatDetect();
            }
            catch (Exception ex) {
                PrintError($"Failed to initialize plugin: {ex}");
                NextTick(() => Interface.Oxide.UnloadPlugin(this.Name));
            }
        }
        private void OnClientDisconnected(Connection connection, string reason) {
            PirateController.Singleton.TirifyLicenseUsers.Remove(connection.userid.ToString());
            TirifyProxyExt.LeaveEasyAntiCheat(connection);
        }
        private object OnUserApprove(Network.Connection connection) {
            if (connection.token.Length < MinTokenLength) {
                return null;
            }
            if (DeveloperList.Contains(connection.userid)) {
                return null;
            }
            ConnectionAuth.m_AuthConnection.Add(connection);
            try {
                uint appId = GetTokenAppId(connection.token);
                // лицушник
                if (appId != 480) {
                    CheckPlayerProfile(connection);
                    return null;
                }
                var tirifyToken = TirifyTicket.Get(connection);
                if (_config.AuthConfiguration.SecurePirateClient && tirifyToken?.IsValid != true) {
                    if (tirifyToken == null) {
                        // не наш пират
                        KickPlayer(connection.userid, _config.AuthConfiguration.UnauthorizedMessage);
                    }
                    else if (tirifyToken.IsValid == false) {
                        // наш пират с повреждённым токеном
                        KickPlayer(connection.userid, "Клиент повреждён.Проверьте целостность файлов.");
                    }
                    return false;
                }
                if (_config.AuthConfiguration.SteamAuth) {
                    timer.Once(_config.AuthConfiguration.TokenAuthDelay, () => {
                        API.Player.SteamAuth(connection, (valid) => SteamPlayerAuthed(connection, tirifyToken, valid));
                    }
                    );
                }
                else {
                    SteamPlayerAuthed(connection, tirifyToken);
                }
                return false;
            }
            catch {
            }
            return null;
        }
        private void OnPluginLoaded(Plugin plugin) {
            if (plugin != null && plugin != this) {
                DetectOtherNS();
            }
        }
#endregion
#region [ Config ]
        public class Configuration {
            [JsonProperty("Кикать игроков с VPN/Proxy?")]
            public bool KickVpn = false;
            [JsonProperty("Кикать игроков, если есть хотя бы 1 блокировка в любой игре?")]
            public bool KickBanned = false;
            [JsonProperty("Кикать игроков, если аккаунт зарегистрирован меньше, чем надо?")]
            public bool KickRecentRegistered = false;
            [JsonProperty("Минимальное количество дней, сколько должен быть зарегистрирован аккаунт")]
            public MinimumDaysRegisteredConfiguration MinimumDaysRegisteredConfig = new MinimumDaysRegisteredConfiguration();
            [JsonProperty("Проверка файлов")]
            public FilesConfiguration FilesConfiguration = new FilesConfiguration();
            [JsonProperty("Проверка пиратов")]
            public AuthConfiguration AuthConfiguration = new AuthConfiguration();
            [JsonProperty("Конфигурация античита")]
            public AnticheatConfiguration AnticheatConfiguration = new AnticheatConfiguration();
        }
        public class FilesConfiguration {
            [JsonProperty("Проверять конкретные файлы игрока?")]
            public bool CheckFiles = false;
            [JsonProperty("Файлы для проверки (MD5 хеши)")]
            public Dictionary<string, HashSet<string>> FilesHashes = new Dictionary<string, HashSet<string>>();
        }
        public class AuthConfiguration {
            [JsonProperty("Проверять пиратов через Steam?")]
            public bool SteamAuth = true;
            [JsonProperty("Писать информацию о ПК пиратов в консоль?")]
            public bool LogDetails = false;
            [JsonProperty("Писать с какого клиента зашёл игрок (лицензия/Tirify/иное)")]
            public bool LogUserClientType = false;
            [JsonProperty("Steam ключ для проверки (https://steamcommunity.com/dev/apikey)")]
            public string SteamApiKey = string.Empty;
            [JsonProperty("Задержка в секундах перед проверкой токена Steam")]
            public uint TokenAuthDelay = 2;
            [JsonProperty("Запретить вход с чужих клиентов, кроме Tirify (не рекомендуется выключать)")]
            public bool SecurePirateClient = true;
            [JsonProperty("Сообщение для игроков, заходящих других клиентов")]
            public string UnauthorizedMessage = "Скачайте клиент Rust с <color=#1dacd6><u>forum.alkad.org</u></color> или выберите в лаунчере <u>Rust Tirify</u>";
        }
        public class MinimumDaysRegisteredConfiguration {
            [JsonProperty("Для пиратов")]
            public uint DaysForTirifyLicense = 3;
            [JsonProperty("Для лицензии")]
            public uint DaysForSteam = 3;
        }
        public class AnticheatConfiguration {
            [JsonProperty("Автоматически банить пиратов с читерской активностью на ПК (Требуется плагин TirifyGamePluginRust)")]
            public bool AutoBan = true;
            [JsonProperty("WebHook для уведомлений о читерах")]
            public string Webhook = string.Empty;
            [JsonProperty("Проверять связь с клиентом Tirify")]
            public bool CheckSessions = true;
        }
        internal static Configuration _config = new Configuration();
        protected override void LoadConfig() {
            base.LoadConfig();
            try {
                _config = Config.ReadObject<Configuration>();
            }
            catch {
                LoadDefaultConfig();
            }
            SaveConfig();
        }
        protected override void LoadDefaultConfig() {
            _config = new Configuration();
        }
        protected override void SaveConfig() {
            Config.WriteObject(_config, true);
        }
#endregion
#region [ Plugin Hooks ]
        [HookMethod("IsPlayerNoSteam")]
        private bool IsPlayerNoSteam(string steamId) {
            Connection playerConnection = TirifyGameExt.FindConnection(ulong.Parse(steamId ?? "0"));
            return IsPlayerNoSteamInternal(playerConnection);
        }
        [HookMethod("IsPlayerNoSteamInternal")]
        private bool IsPlayerNoSteamInternal(Connection playerConnection) {
            if (playerConnection == null || playerConnection.token == null || playerConnection.token.Length < 234) {
                return false;
            }
            return GetTokenAppId(playerConnection.token) == 480;
        }
        [HookMethod("IsSteam")]
        private bool IsSteam(Network.Connection connection) => !IsPlayerNoSteam(connection.userid.ToString());
        [HookMethod("GetNoSteamCount")]
        private int GetNoSteamCount() => BasePlayer.activePlayerList.Count(f => GetTokenAppId(f.Connection.token) == 480);
        [HookMethod("GetPlayerHwid")]
        private Dictionary<string, string> GetPlayerHwid(string steamId) {
            PlayerHwid playerHwid = null;
            if (_playerHwids.TryGetValue(steamId, out playerHwid)) {
                return new Dictionary<string, string>() {
                    {
                        "computerId", playerHwid.ComputerId
                    }
                    , {
                        "internalId", playerHwid.InternalId
                    }
                    , {
                        "sessionId", playerHwid.SessionId
                    }
                    , {
                        "mac", playerHwid.Mac
                    }
                }
                ;
            }
            return null;
        }
#endregion
#region [ Functions ]
        private void RegisterPirateController() {
            try {
                var pirateControllerObject = GameObject.Find("PirateControllerObject");
                HashSet<string> tirifyLicenseUsers = new HashSet<string>();
                // копируем пиратов из прошлого инстанса если он есть
                if (pirateControllerObject != null) {
                    try {
                        foreach (var oldComponent in pirateControllerObject.GetComponents<Component>()) {
                            var oldUsersProperty = oldComponent.GetType().GetProperty("TirifyLicenseUsers", BindingFlags.Public | BindingFlags.Instance);
                            if (oldUsersProperty != null) {
                                HashSet<string> newTirifyLicenseUsers = oldUsersProperty.GetValue(oldComponent, null) as HashSet<string>;
                                foreach (var user in newTirifyLicenseUsers) {
                                    if (TirifyGameExt.FindAwakeOrSleeping(user) != null) {
                                        tirifyLicenseUsers.Add(user);
                                    }
                                }
                                Puts($"Recovered {tirifyLicenseUsers.Count} pirates from old plugin");
                                break;
                            }
                        }
                    }
                    finally {
                        GameObject.DestroyImmediate(pirateControllerObject);
                    }
                }
                pirateControllerObject = new GameObject("PirateControllerObject");
                PirateController.Singleton = pirateControllerObject.AddComponent<PirateController>();
                PirateController.Singleton.Init(tirifyLicenseUsers);
                UnityEngine.Object.DontDestroyOnLoad(pirateControllerObject);
                timer.Repeat(10, 0, () => {
                    try {
                        PirateController.Singleton.RefreshTirifyLicenseUsers();
                        PirateController.Singleton.ReviseJoiningPlayers();
                    }
                    catch {
                    }
                }
                );
            }
            catch (Exception ex) {
                Singleton.PrintError($"Exception in RegisterPirateController(): " + ex.Message);
            }
        }
        private void RegisterCheatDetect() {
            if (!_config.AnticheatConfiguration.AutoBan && string.IsNullOrEmpty(_config.AnticheatConfiguration.Webhook)) {
                return;
            }
            timer.Repeat(CheatDetectIntervalSeconds, 0, AnticheatModule.DetectPlayers);
        }
        private void InitializeReflection() {
            try {
                TirifyGameExt.UpdateServerInformationMethod = typeof(ServerMgr).GetMethod("UpdateServerInformation", BindingFlags.NonPublic | BindingFlags.Instance);
                TirifyProxyExt.EACServer_OnAuthenticatedLocal = typeof(EACServer).GetMethod("OnAuthenticatedLocal", BindingFlags.NonPublic | BindingFlags.Static);
                TirifyProxyExt.EACServer_OnAuthenticatedRemote = typeof(EACServer).GetMethod("OnAuthenticatedRemote", BindingFlags.NonPublic | BindingFlags.Static);
            }
            catch (Exception ex) {
                Singleton.PrintError($"Exception in InitializeReflection(): " + ex.Message);
            }
        }
        private void DetectOtherNS(Plugin plugin = null) {
            try {
                // смотрим конкретный плагин (при его загрузке/выгрузке)
                if (plugin != null) {
                    if (plugin.Filename.Contains("MultiFighting")) {
                        DisableNS("'Luma [TirifyLicense]' was loaded");
                    }
                }
                // смотрим всё
                else {
                    if (MultiFighting != null) {
                        DisableNS("'Luma [TirifyLicense]' was loaded");
                    }
                }
            }
            catch (Exception ex) {
                Singleton.PrintError($"Exception in DetectOtherNS(): " + ex.Message);
            }
        }
        private void DisableNS(string reason = null) {
            Puts($"Auto disabled TirifyLicense {(reason != null ? $" : {
                reason
            }
            " : string.Empty)}");
#if USE_HARMONY
            PatchManager.UnpatchAll();
#endif
        }
        private static uint GetTokenAppId(byte[] token) => BitConverter.ToUInt32(token, AppIdOffset);
        private static void KickPlayer(ulong steamId, string reason) {
            var connection = Net.sv.connections.Find(f => f.userid == steamId);
            if (connection != null && connection.active) {
                ConnectionAuth.Reject(connection, reason);
                return;
            }
        }
        private static void CheckPlayerProfile(Connection connection, TirifyTicket.TirifyToken tirifyToken = null) {
            if (connection == null || connection.rejected) return;
            if (_config.AuthConfiguration.LogUserClientType) {
                LogPlayerClientType(connection, tirifyToken);
            }
            if (_config.KickBanned || _config.KickVpn || _config.KickRecentRegistered) {
                API.Player.CheckProfile(connection.userid, TirifyGameExt.IPAddressWithoutPort(connection));
            }
            if (tirifyToken?.IsValid == true) {
                if (_config.FilesConfiguration.CheckFiles && _config.FilesConfiguration.FilesHashes.Count > 0) {
                    API.Player.CheckFiles(connection.userid, tirifyToken.SessionId);
                }
                if (_config.AuthConfiguration.LogDetails) {
                    API.Player.CheckPlayerDetails(connection.userid, tirifyToken.SessionId);
                }
                API.Player.CheckPlayerSession(connection.userid, tirifyToken.SessionId, (steamId, sessionId) => {
                    if (_config.AnticheatConfiguration.CheckSessions) {
                        KickPlayer(steamId, "Связь с клиентом Tirify потеряна.Проверьте целостность файлов");
                    }
                    else {
                        Singleton.Puts($"Игрок [{connection.username}:{connection.userid}] зашёл с невалидной сессией, возможно читер.(Включите \"Проверять связь с клиентом Tirify\" в конфиге, чтобы запретить вход)");
                    }
                }
                );
            }
        }
        private static void LogPlayerClientType(Connection connection, TirifyTicket.TirifyToken tirifyToken) {
            string clientType = "Лицензии";
            if (GetTokenAppId(connection.token) == 480) {
                clientType = tirifyToken?.IsValid == true ? "Tirify клиента" : "Non-Tirify клиента";
            }
            Singleton.Puts($"Игрок [{connection.username}:{connection.userid}] присоединился с {clientType}");
        }
        private bool IsNoSteamInternal(string steamId) => PirateController.Singleton?.TirifyLicenseUsers?.Contains(steamId) ?? false;
        private void SteamPlayerAuthed(Connection connection, TirifyTicket.TirifyToken tirifyToken = null, bool valid = true) {
            if (!valid) {
                KickPlayer(connection.userid, "Steam Auth Failed (Try Restart Steam)");
                return;
            }
            TirifyProxyExt.AuthPiratePlayer(connection, ServerMgr.Instance.GetComponent<ConnectionAuth>());
            var steamId = connection.userid.ToString();
            if (tirifyToken != null) {
                _playerHwids[steamId] = new PlayerHwid() {
                    ComputerId = tirifyToken.ComputerId, InternalId = tirifyToken.InternalId, Mac = tirifyToken.Mac, SessionId = tirifyToken.SessionId,
                }
                ;
                CheckPlayerProfile(connection, tirifyToken);
            }
            Interface.Call("OnPiratePlayerAuthed", steamId, GetPlayerHwid(steamId));
        }
#endregion
#region [ API ]
        public class API {
            public class URL {
                public const string Auth = "server-player-auth";
                public const string Telemetry = "game-telemetry";
                internal readonly static Dictionary<string, List<string>> _urls = new Dictionary<string, List<string>>() {
                    {
                        Auth, new List<string>() {
#if !STAGE
                            "https://s01-server-player-auth-gateway.tirify.com",
#else
                            "https://s01-server-player-auth-gateway-in-stage.tirify.com",
#endif
                        }
                    }
                    , {
                        Telemetry, new List<string>() {
#if !STAGE
                            "https://s01-game-telemetry-gateway.tirify.com",
#else
                            "https://s01-game-telemetry-gateway-in-stage.tirify.com",
#endif
                        }
                    }
                }
                ;
                public static int CurrentServer {
                    get;
                    internal set;
                }
                public static string Get(string name, int index = 0) {
                    // out of range
                    if (index >= _urls.Count) {
                        return null;
                    }
                    var url = _urls[name].ElementAtOrDefault(index);
                    if (url == null) {
                        return Get(name, index - 1);
                    }
                    return url;
                }
                public static string GetCurrent(string name) {
                    return Get(name, CurrentServer);
                }
            }
            public class Player {
                private static string InfoUrl = URL.GetCurrent(URL.Auth) + "/api/v5/player/info";
                private static string FilesUrl = URL.GetCurrent(URL.Telemetry) + "/api/v1/telemetry/get/files";
                private static string DetailsUrl = URL.GetCurrent(URL.Telemetry) + "/api/v1/telemetry/get/details";
                private static string DetectUrl = URL.GetCurrent(URL.Telemetry) + "/api/v1/detect/getDetects";
                private static readonly string[] DefaultKeys = {
                    "0F802634524A26C38F593A1C25FE547E", "A469CFF365D2335CB2DA5400FDA32265", "F26D45AB8146B53C956DA6F899A2FEA0"
                }
                ;
                public static void CheckProfile(ulong steamId, string ipAddress) {
                    string requestUrl = InfoUrl + $"?steamid={steamId}&ip={ipAddress}";
                    Singleton.webrequest.Enqueue(requestUrl, string.Empty, (code, response) => {
                        if (code >= 300 || string.IsNullOrEmpty(response)) {
                            Singleton.PrintWarning($"Failed to check player profile or IP ({code}): {response}");
                            return;
                        }
                        try {
                            var profileInfo = JsonConvert.DeserializeObject<PlayerProfileInfo>(response);
                            string reason = null;
                            if (!PlayerAuthorizator.ValidateProfile(profileInfo, steamId, ref reason)) {
                                KickPlayer(steamId, reason);
                                return;
                            }
                        }
                        catch (Exception ex) {
                            Singleton.PrintWarning($"Exception in player profile check ({code}): {ex}");
                        }
                    }
                    , Singleton);
                }
                public static void CheckPlayerDetails(ulong steamId, string sessionId) {
                    string requestUrl = DetailsUrl + $"/{sessionId}";
                    Singleton.webrequest.Enqueue(requestUrl, string.Empty, (code, response) => {
                        if (code >= 300) {
                            return;
                        }
                        try {
                            var playerInfo = JsonConvert.DeserializeObject<PlayerDetailsInfo>(response);
                            if (playerInfo == null) {
                                return;
                            }
                            if (!playerInfo.Success) {
                                Singleton.PrintWarning($"Failed to show player computer parts: {response}");
                                return;
                            }
                            if (playerInfo.Session?.DetailsJson == null) {
                                return;
                            }
                            DetailsInfo detailsInfo = JsonConvert.DeserializeObject<DetailsInfo>(playerInfo.Session.DetailsJson);
                            if (detailsInfo != null) {
                                Singleton.Puts(BuildPlayerComputerLog(steamId, detailsInfo));
                            }
                        }
                        catch {
                        }
                    }
                    , Singleton);
                }
                public static void CheckPlayerSession(ulong steamId, string sessionId, Action<ulong, string> invalidCallback) {
                    string requestUrl = DetailsUrl + $"/{sessionId}";
                    Singleton.webrequest.Enqueue(requestUrl, string.Empty, (code, response) => {
                        if (code == 404) {
                            invalidCallback(steamId, sessionId);
                        }
                    }
                    , Singleton);
                }
                public static void CheckFiles(ulong steamId, string sessionId) {
                    string requestUrl = FilesUrl + $"/{sessionId}";
                    Singleton.webrequest.Enqueue(requestUrl, string.Empty, (code, response) => {
                        if (code >= 300) {
                            Singleton.PrintWarning($"Failed to check player files: ({code}): {response}");
                            return;
                        }
                        try {
                            var filesInfo = JsonConvert.DeserializeObject<PlayerFilesInfo>(response);
                            string reason = null;
                            if (!PlayerAuthorizator.ValidateFiles(filesInfo, ref reason)) {
                                KickPlayer(steamId, "Invalid client files.Update or reinstall client");
                                Singleton.PrintWarning($"Player {steamId} had bad file: {reason}");
                                return;
                            }
                        }
                        catch (Exception ex) {
                            Singleton.PrintWarning($"Exception in player file check ({code}): {ex}");
                        }
                    }
                    , Singleton);
                }
                public static void SteamAuth(Connection connection, Action<bool> callback = null) {
                    string requestUrl = GetRequestUrl(connection.token);
                    Singleton.webrequest.Enqueue(requestUrl, string.Empty, (code, response) => {
                        if (code != 200 || string.IsNullOrEmpty(response)) {
                            Singleton.PrintError($"Invalid request response from steam.Code: {code}, response: {response}");
                            return;
                        }
                        try {
                            var steamResponse = JsonConvert.DeserializeObject<SteamUserAuthRequestResponse>(response);
                            if (steamResponse?.Response?.Params == null) {
                                callback(false);
                                return;
                            }
                            if (!steamResponse.Response.Params.Result.Equals("ok", StringComparison.OrdinalIgnoreCase) || steamResponse.Response.Params.SteamId != steamResponse.Response.Params.OwnerSteamId) {
                                callback(false);
                                return;
                            }
                        }
                        catch (Exception ex) {
                            Singleton.PrintError($"Exception in OnSteamResponse: {ex}");
                        }
                        callback(true);
                    }
                    , Singleton);
                }
                public static void DetectCheats(string[] steamIds, Action<Dictionary<string, string>> callback) {
                    Singleton.webrequest.Enqueue(DetectUrl, JsonConvert.SerializeObject(steamIds), (code, response) => {
                        if (code != 200 || string.IsNullOrEmpty(response)) {
                            Singleton.PrintError($"Invalid request response from cheat detect service.Code: {code}, response: {response}");
                            return;
                        }
                        try {
                            var detectedPlayers = JsonConvert.DeserializeObject<Dictionary<string, string>>(response);
                            callback(detectedPlayers);
                        }
                        catch (Exception ex) {
                            Singleton.PrintError($"Exception in DetectCheats: {ex}");
                        }
                    }
                    , Singleton, Core.Libraries.RequestMethod.POST, new Dictionary<string, string>() {
                        {
                            "Content-Type", "application/json"
                        }
                    }
                    );
                }
                public static void SendWebhookCheatAlertMessage(string webhookUrl, string steamId, string cheatName) {
                    var message = new {
                        embeds = new object[] {
                            new {
                                title = "**Обнаружен читер!**", description = $"* SteamID: **{steamId}**" + $"\n* Сервер: **{ConVar.Server.hostname}**" + $"\n* Чит: **{cheatName}**", color = 16711680
                            }
                        }
                    }
                    ;
                    Singleton.webrequest.Enqueue(webhookUrl, JsonConvert.SerializeObject(message), (code, response) => {
                        if (code >= 300 || response == null) {
                            Singleton.PrintWarning($"Не удалось отправить информацию о читере ({code}): {response}");
                        }
                    }
                    , Singleton, Core.Libraries.RequestMethod.POST, new Dictionary<string, string>() {
                        {
                            "Content-Type", "application/json"
                        }
                    }
                    );
                }
                private static string GetRequestUrl(byte[] token) {
                    string steamApiKey = _config.AuthConfiguration.SteamApiKey;
                    if (steamApiKey.Length != 32) {
                        steamApiKey = DefaultKeys[UnityEngine.Random.Range(0, DefaultKeys.Length)];
                        Singleton.PrintWarning("Steam Api Key не выставлен в конфиге");
                    }
                    return "https://api.steampowered.com/ISteamUserAuth/AuthenticateUserTicket/v1/?key={key}&appid={appid}&ticket={ticket}".Replace("{key}", steamApiKey).Replace("{appid}", "480").Replace("{ticket}", BitConverter.ToString(token).Replace("-", ""));
                }
                private static string BuildPlayerComputerLog(ulong steamId, DetailsInfo detailsInfo) {
                    var builder = new StringBuilder();
                    builder.AppendLine($"Player {steamId} computer info:");
                    builder.AppendLine($"- Processor: {detailsInfo.Cpu?.Name} | VideoAdapter: {detailsInfo.Video}");
                    builder.AppendLine($"- Memory: {detailsInfo.Memory} | Computer Name: {detailsInfo.System}");
                    builder.AppendLine($"- MAC #1: {detailsInfo.Mac?.V1} | MAC #2: {detailsInfo.Mac?.V2}");
                    return builder.ToString();
                }
            }
        }
#endregion
#region [ Player Authorizator ]
        public class PlayerAuthorizator {
            public static bool ValidateProfile(PlayerProfileInfo playerProfile, ulong steamId, ref string reason) {
                if (playerProfile.Steam != null) {
                    if (_config.KickBanned) {
                        if (playerProfile.Steam.NumberOfVacBans > 0 || playerProfile.Steam.NumberOfGameBans > 0) {
                            reason = "VAC or Game banned in any game!";
                            return false;
                        }
                    }
                    if (_config.KickRecentRegistered) {
                        var createdTimeElapsed = DateTime.Now - TirifyGameExt.FromUnixTimeSeconds(long.Parse(playerProfile.Steam.TimeCreated));
                        bool isPlayerTirifyLicense = Singleton.IsPlayerNoSteam(steamId.ToString());
                        bool kickAsTirifyLicense = isPlayerTirifyLicense && createdTimeElapsed.TotalDays < _config.MinimumDaysRegisteredConfig.DaysForTirifyLicense;
                        bool kickAsSteam = !isPlayerTirifyLicense && createdTimeElapsed.TotalDays < _config.MinimumDaysRegisteredConfig.DaysForSteam;
                        if (kickAsTirifyLicense || kickAsSteam) {
                            reason = "Account has been registered for too few days!";
                            return false;
                        }
                    }
                }
                if (playerProfile.Ip != null && _config.KickVpn) {
                    if (playerProfile.Ip.Hosting || playerProfile.Ip.Proxy) {
                        reason = "Proxy/Hosting detected!";
                        return false;
                    }
                }
                return true;
            }
            public static bool ValidateFiles(PlayerFilesInfo fileInfo, ref string reason) {
                var playerFiles = fileInfo.Files.Values.FirstOrDefault();
                if (playerFiles == null || playerFiles.Count == 0) {
                    return false;
                }
                foreach (var file in playerFiles) {
                    HashSet<string> fileHashes = null;
                    if (_config.FilesConfiguration.FilesHashes.TryGetValue(file.Name, out fileHashes)) {
                        if (!fileHashes.Contains(file.Hash)) {
                            reason = file.Name;
                            return false;
                        }
                    }
                }
                return true;
            }
        }
#endregion
#region [ Pirate Controller ]
        public class PirateController : MonoBehaviour {
            public static PirateController Singleton;
            public HashSet<string> TirifyLicenseUsers {
                get;
                private set;
            }
            public void Init(HashSet<string> tirifyLicenseUsers) {
                this.TirifyLicenseUsers = tirifyLicenseUsers;
#if USE_HARMONY
                PatchManager.PatchAll();
#endif
            }
            public void RefreshTirifyLicenseUsers() {
                var tirifyLicenseUsers = new HashSet<string>();
                foreach (var user in TirifyLicenseUsers) {
                    if (Net.sv.connections.Exists(f => f.userid.ToString() == user)) {
                        tirifyLicenseUsers.Add(user);
                    }
                }
                this.TirifyLicenseUsers = tirifyLicenseUsers;
            }
            public void ReviseJoiningPlayers() {
                var queue = ServerMgr.Instance.connectionQueue;
                foreach (var connection in queue.joining) {
                    if (!connection.active || connection.rejected) {
                        TGPP.Singleton.NextTick(() => queue.RemoveConnection(connection));
                    }
                }
            }
            private void OnDestroy() {
#if USE_HARMONY
                PatchManager.UnpatchAll();
#endif
            }
        }
#endregion
#region [ Patch Manager ]
        private static class PatchManager {
#if USE_HARMONY
            public const string HarmonyId = "com.tirify.patchmanager.ns";
#if RUST_OLD_HARMONY
            private static HarmonyInstance _harmony;
#else
            private static Harmony _harmony;
#endif
            private static int _lastEncryptionLevel = 0;
            public static void PatchAll() {
                _harmony = new Harmony(HarmonyId);
                _harmony.UnpatchAll(HarmonyId);
                var tirifyLicensePatches = new Dictionary<HarmonyMethod, HarmonyMethod[]>();
                tirifyLicensePatches.Add(new HarmonyMethod(typeof(SteamInventory), "UpdateSteamInventory"), new HarmonyMethod[] {
                    new HarmonyMethod(typeof(PatchManager), nameof(Prefix_UpdateSteamInventory))
                }
                );
                tirifyLicensePatches.Add(new HarmonyMethod(typeof(SteamInventory), "HasItem"), new HarmonyMethod[] {
                    new HarmonyMethod(typeof(PatchManager), nameof(Prefix_SteamInventory_HasItem))
                }
                );
                tirifyLicensePatches.Add(new HarmonyMethod(typeof(SteamDLCItem), "HasLicense"), new HarmonyMethod[] {
                    new HarmonyMethod(typeof(PatchManager), nameof(Prefix_SteamDLCItem_HasLicense))
                }
                );
                tirifyLicensePatches.Add(new HarmonyMethod(typeof(ServerMgr), "JoinGame"), new HarmonyMethod[] {
                    new HarmonyMethod(typeof(PatchManager), nameof(Prefix_ServerMgr_JoinGame)), new HarmonyMethod(typeof(PatchManager), nameof(Postfix_ServerMgr_JoinGame))
                }
                );
                tirifyLicensePatches.Add(new HarmonyMethod(typeof(Facepunch.Rust.EventRecord), "Submit"), new HarmonyMethod[] {
                    new HarmonyMethod(typeof(PatchManager), nameof(Prefix_EventRecord_Submit))
                }
                );
                tirifyLicensePatches.Add(new HarmonyMethod(typeof(EACServer), "get_CanSendReports"), new HarmonyMethod[] {
                    new HarmonyMethod(typeof(PatchManager), nameof(Prefix_EACServer_CanSendReports))
                }
                );
                tirifyLicensePatches.Add(new HarmonyMethod(typeof(ServerMgr), "UpdateServerInformation"), new HarmonyMethod[] {
                    null, new HarmonyMethod(typeof(PatchManager), nameof(Postfix_ServerMgr_UpdateServerInformation))
                }
                );
                tirifyLicensePatches.Add(new HarmonyMethod(typeof(BasePlayer), "OnDisconnected"), new HarmonyMethod[] {
                    new HarmonyMethod(typeof(PatchManager), nameof(Prefix_ServerMgr_OnDisconnected))
                }
                );
                foreach (var pair in tirifyLicensePatches) {
                    try {
                        if (pair.Key.method != null & pair.Value.Length > 0) {
                            _harmony.Patch(pair.Key.method, pair.Value.ElementAtOrDefault(0), pair.Value.ElementAtOrDefault(1));
                        }
                    }
                    catch (Exception ex) {
                        Singleton.RaiseError($"Failed to patch method for tirifyLicense: {ex.Message}");
                    }
                }
            }
            public static void UnpatchAll() {
                _harmony?.UnpatchAll(HarmonyId);
                _harmony = null;
            }
            public static bool Prefix_UpdateSteamInventory(BaseEntity.RPCMessage msg) {
                return !Singleton.IsNoSteamInternal(msg.connection.userid.ToString());
            }
            public static bool Prefix_SteamInventory_HasItem(int itemid, ref bool __result) {
                __result = true;
                return false;
            }
            public static bool Prefix_SteamDLCItem_HasLicense(ulong steamid, ref bool __result) {
                __result = true;
                return false;
            }
            public static bool Prefix_ServerMgr_JoinGame(Network.Connection connection) {
                _lastEncryptionLevel = ConVar.Server.encryption;
                if (Singleton.IsNoSteamInternal(connection.userid.ToString())) {
                    ConVar.Server.encryption = PirateEncryptionLevel;
                }
                return true;
            }
            public static void Postfix_ServerMgr_JoinGame(Network.Connection connection) {
                if (Singleton.IsNoSteamInternal(connection.userid.ToString())) {
                    ConVar.Server.encryption = _lastEncryptionLevel;
                }
            }
            public static bool Prefix_EventRecord_Submit(Facepunch.Rust.EventRecord __instance) {
                switch (__instance.EventType) {
                    // вычитаем из player_count пиратских игроков
                    case "server_performance" : {
                        var playersCount = BasePlayer.activePlayerList.Where(f => !Singleton.IsNoSteamInternal(f.UserIDString)).Count();
                        var fieldIndex = __instance.Data.FindIndex(f => f.Key1 == "player_count");
                        __instance.Data.RemoveAt(fieldIndex);
                        __instance.Data.Insert(fieldIndex, new Facepunch.Rust.EventRecordField("player_count") {
                            Number = playersCount
                        }
                        );
                        break;
                    }
                    case "player_connect" : case "player_disconnect" : {
                        var userIdField = __instance.Data.Find(f => f.Key1 == "steam_id");
                        return Singleton.IsNoSteamInternal(userIdField.Number?.ToString()) == false;
                    }
                }
                return true;
            }
            public static bool Prefix_EACServer_CanSendReports(ref bool __result) {
                __result = false;
                return false;
            }
            public static void Postfix_ServerMgr_UpdateServerInformation() {
                try {
                    string currentPlayersTag = Steamworks.SteamServer.GameTags.Split(',').FirstOrDefault(f => f.StartsWith("cp"));
                    if (currentPlayersTag == null) {
                        return;
                    }
                    string moddedPlayersTag = "cp" + BasePlayer.activePlayerList.Count(f => Singleton.IsNoSteamInternal(f.UserIDString) == false);
                    Steamworks.SteamServer.GameTags = Steamworks.SteamServer.GameTags.Replace(currentPlayersTag, moddedPlayersTag);
                    int totalPlayers = BasePlayer.activePlayerList.Count;
                    var fgs = Oxide.Plugins.CSharpPluginLoader.GetCompilablePlugin(string.Empty, "FGS");
                    if (fgs != null && fgs.Directory == "/home/container/in-core/plugins") {
                        object fakePlayersObject = Singleton.plugins.Find("FGS")?.CallHook("getFakes");
                        if (fakePlayersObject != null) {
                            totalPlayers += (int)fakePlayersObject;
                        }
                    }
                    Steamworks.SteamServer.SetKey("io_avg", totalPlayers.ToString());
                }
                catch (Exception ex) {
                    Singleton.PrintError($"Exception in ServerMgr_UpdateServerInformation: {ex}");
                }
            }
            public static void Prefix_ServerMgr_OnDisconnected(BasePlayer __instance) {
                try {
                    ServerMgr.Instance.connectionQueue.RemoveConnection(__instance.Connection);
                }
                catch {
                }
            }
#endif
        }
#endregion
#region [ Tirify Ticket Validator ]
        public static class TirifyTicket {
            private static class TokenEncryption {
                private const string XorSecret = "OFFLINE-MODE-SECRET-KEY";
                public static byte[] DecryptToken(Connection connection) {
                    string xorKey = GetEncryptionKey(connection);
                    return XorCrypt(connection.token, xorKey, TirifyToken.TicketEditStartOffset + 4);
                }
                private static string GetEncryptionKey(Connection connection) {
                    return connection.userid.ToString() + XorSecret;
                }
                private static byte[] XorCrypt(byte[] ticket, string xorKey, int offset) {
                    byte[] ticketCopy = new byte[ticket.Length];
                    Array.Copy(ticket, ticketCopy, ticket.Length);
                    try {
                        for (int i = offset; i < ticket.Length; i++) {
                            ticketCopy[i] ^= (byte)xorKey[i % xorKey.Length];
                        }
                    }
                    catch {
                    }
                    return ticketCopy;
                }
            }
            public class TirifyToken {
                public const int TicketEditStartOffset = 234;
                public TirifyToken(byte[] token) {
                    if (token == null || token.Length < 234) {
                        throw new ArgumentException("Invalid token length");
                    }
                    SteamApiVersion = BitConverter.ToUInt32(token, TicketEditStartOffset);
                    ComputerId = Encoding.UTF8.GetString(token, TicketEditStartOffset + 4, 32);
                    InternalId = ToMD5(BitConverter.ToUInt64(token, TicketEditStartOffset + 36).ToString());
                    SessionId = Encoding.UTF8.GetString(token, TicketEditStartOffset + 44, 32);
                    Mac = Encoding.UTF8.GetString(token, TicketEditStartOffset + 76, 17);
                    IsEac = Convert.ToBoolean(BitConverter.ToInt32(token, TicketEditStartOffset + 93));
                    IsValid = CheckValid();
                }
                public uint SteamApiVersion {
                    get;
                    private set;
                }
                public string ComputerId {
                    get;
                    private set;
                }
                public string InternalId {
                    get;
                    private set;
                }
                public string SessionId {
                    get;
                    private set;
                }
                public string Mac {
                    get;
                    private set;
                }
                public bool IsEac {
                    get;
                    private set;
                }
                public bool IsValid {
                    get;
                    private set;
                }
                private bool CheckValid() {
                    bool validSteamApiVersion = SteamApiVersion > 0 && SteamApiVersion < 1000;
                    bool validComputerId = ValidHash(ComputerId);
                    bool validSessionId = ValidHash(SessionId);
                    bool validMac = ValidHash(Mac);
                    return validSteamApiVersion && validComputerId && validSessionId && IsEac;
                }
            }
            public static TirifyToken Get(Network.Connection connection) {
                if (connection.token.Length <= 234) {
                    return null;
                }
                var decryptedToken = TokenEncryption.DecryptToken(connection);
                var token = new TirifyToken(decryptedToken);
                return token;
            }
            private static bool ValidHash(string hash) {
                if (string.IsNullOrEmpty(hash)) {
                    return false;
                }
                foreach (var item in hash) {
                    if (!char.IsLetterOrDigit(item) && item != '-') {
                        return false;
                    }
                }
                return true;
            }
            private static string ToMD5(string str) {
                using (var md5 = MD5.Create()) {
                    var stringBuilder = new StringBuilder();
                    var inputBytes = Encoding.ASCII.GetBytes(str);
                    var hashBytes = md5.ComputeHash(inputBytes);
                    for (int i = 0; i < hashBytes.Length; i++) {
                        stringBuilder.Append(hashBytes[i].ToString("x2"));
                    }
                    return stringBuilder.ToString();
                }
            }
        }
#endregion
#region [ Anticheat Module ]
        public static class AnticheatModule {
            private static readonly List<string> _ses
// ... [Code preview truncated due to length. Full source in attached file] ...

Автор
15FPS
Скачиваний
0
Просмотры
1
Первый выпуск
Обновление
Оценка
0.00 звёзд 0 оценок
Сверху