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

FREE ServerArmour : 2.87.1 2.87.1

Нет прав для скачивания
C#:
using ConVar;
using Facepunch;
using Facepunch.Extend;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Oxide.Core;
using Oxide.Core.Libraries;
using Oxide.Core.Libraries.Covalence;
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Libraries;
using Rust;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using UnityEngine;
using UnityEngine.Networking;
using WebSocketSharp;
using Application = UnityEngine.Application;
using Time = Oxide.Core.Libraries.Time;
#pragma warning disable 8600
#pragma warning disable 8601
namespace Oxide.Plugins {
    [Info("Server Armour", "Pho3niX90", "2.87.1")]
    [Description("Protect your server! Auto ban known hackers, scripters and griefer accounts, and notify server owners of threats.")]
    class ServerArmour : CovalencePlugin {
#if CARBON
        bool isCarbon = true;
#else
        bool isCarbon = false;
#endif
#region Variables
        string api_hostname = "https://serverarmour.com";
        //
        Dictionary<string, ISAPlayer> _playerData = new Dictionary<string, ISAPlayer>();
        private Time _time = GetLibrary<Time>();
        private double cacheLifetime = 1;
        // minutes
        private SAConfig config;
        string specifier = "G";
        CultureInfo culture = CultureInfo.CreateSpecificCulture("en-US");
        //StringComparison defaultCompare = StringComparison.InvariantCultureIgnoreCase;
        const string DATE_FORMAT = "yyyy/MM/dd HH:mm";
        const string DATE_FORMAT2 = "yyyy-MM-dd HH:mm:ss";
        const string DATE_FORMAT_BAN = "yyyy-MM-ddTHH:mm:ss.fffZ";
        Regex logRegex = new Regex(@"(^assets.*prefab).*?position (.*) on");
        Regex logRegexNull = new Regex(@"(.*) changed its network group to null");
        bool debug = false;
        Timer debugDisableTimer;
        const int DefaultTempDebugMinutes = 15;
        const int MaxTempDebugMinutes = 120;
        bool apiConnected = false;
        bool serverStarted = false;
        int serverId;
        string orgUuid;
        private Dictionary<string, string> headers;
        string adminIds = "";
        Timer updateTimer;
        Timer mapUploadTimer;
        Timer nativeBanSyncTimer;
        readonly Queue<string> combatUploadQueue = new Queue<string>();
        Timer combatUploadFlushTimer;
        bool combatUploadInFlight;
        int combatDroppedEntries = 0;
        int combatUploadRequests = 0;
        int combatUploadFailures = 0;
        readonly System.Random retryRandom = new System.Random();
        private const int ApiMaxRetries = 8;
        private const float ApiWatchdogSeconds = 35f;
        private const int SteamVisibilityPrivate = 1;
        private const int SteamVisibilityFriendsOnly = 2;
        private const int SteamVisibilityPublic = 3;
        private readonly Dictionary<string, Timer> playerCheckDebounceTimers = new Dictionary<string, Timer>();
        private readonly Dictionary<string, Timer> playerPeriodicCheckTimers = new Dictionary<string, Timer>();
        private readonly Dictionary<string, Timer> playerRecheckTimers = new Dictionary<string, Timer>();
        private readonly Dictionary<string, bool> apiInFlight = new Dictionary<string, bool>();
        private readonly Dictionary<string, int> playerRecheckAttempts = new Dictionary<string, int>();
        private readonly HashSet<string> addBanInFlight = new HashSet<string>();
        private readonly List<ISABan> pendingBans = new List<ISABan>();
        private bool mapUploadInProgress = false;
        private string lastUploadedMapFingerprint = string.Empty;
        // related to auto updating
        Dictionary<string, byte[]> fileBackups = new Dictionary<string, byte[]>();
        List<string> ignoredPlugins = new List<string>();
#endregion
#region Libraries
        private readonly Game.Rust.Libraries.Player Player = Interface.Oxide.GetLibrary<Game.Rust.Libraries.Player>();
#endregion
#region Permissions
        const string PermissionToBan = "serverarmour.ban";
        const string PermissionToUnBan = "serverarmour.unban";
        const string PermissionAdminWebsite = "serverarmour.website.admin";
        const string PermissionWhitelistRecentVacKick = "serverarmour.whitelist.recentvac";
        const string PermissionWhitelistBadIPKick = "serverarmour.whitelist.badip";
        const string PermissionWhitelistVacCeilingKick = "serverarmour.whitelist.vacceiling";
        const string PermissionWhitelistServerCeilingKick = "serverarmour.whitelist.banceiling";
        const string PermissionWhitelistGameBanCeilingKick = "serverarmour.whitelist.gamebanceiling";
        const string PermissionWhitelistTotalBanCeiling = "serverarmour.whitelist.totalbanceiling";
        const string PermissionWhitelistSteamProfile = "serverarmour.whitelist.steamprofile";
        const string PermissionWhitelistFamilyShare = "serverarmour.whitelist.familyshare";
        const string PermissionWhitelistTwitterBan = "serverarmour.whitelist.twitterban";
        const string PermissionWhitelistAllowCountry = "serverarmour.whitelist.allowcountry";
        const string PermissionWhitelistAllowHighPing = "serverarmour.whitelist.allowhighping";
        const string PermissionWhitelistCombatGuidance = "serverarmour.whitelist.combatguidance";
        const string PermissionWhitelistAccountTrust = "serverarmour.whitelist.accounttrust";
        const string PermissionRadar = "serverarmour.radar";
        const string DISCORD_INTRO_URL = "https://support.discordapp.com/hc/en-us/articles/228383668-Intro-to-Webhooks";
        /**
         * Plugin Name, Download Url
         */
        Dictionary<string, string> requiredPlugins = new Dictionary<string, string> {
            {
                "DiscordApi", "https://serverarmour.com/api/v1/shop/product/379a27d9-d245-43c9-ad8f-332efa8a25e6/download"
            }
            , {
                "CombatLogInfo", "https://serverarmour.com/api/v1/shop/product/4195c37c-8eb5-47f6-8908-45aaa06df59c/download"
            }
        }
        ;
        // int serverId = 0;
#endregion
#region Plugins
#pragma warning disable 0649
        [PluginReference]
        Plugin DiscordApi, DiscordMessages, BetterChat, Ember, Clans, AdminToggle, CombatLogInfo, ServerArmourUpdater;
#pragma warning restore 0649
        void DiscordSend(string steamId, string name, EmbedFieldList report, int color = 39423, bool isBan = false) {
            string webHook;
            if (isBan) {
                if (config.DiscordBanWebhookURL.IsNullOrEmpty() || config.DiscordBanWebhookURL.Equals(DISCORD_INTRO_URL)) {
                    Puts("Discord webhook not setup.");
                    return;
                }
                webHook = config.DiscordBanWebhookURL;
            }
            else {
                if (config.DiscordWebhookURL.IsNullOrEmpty() || config.DiscordWebhookURL.Equals(DISCORD_INTRO_URL)) {
                    Puts("Discord webhook not setup.");
                    return;
                }
                webHook = config.DiscordWebhookURL;
            }
            List<EmbedFieldList> fields = new List<EmbedFieldList>();
            if (config.DiscordQuickConnect) {
                fields.Add(new EmbedFieldList() {
                    name = server.Name, value = $"[steam://connect/{config.ServerIp}:{server.Port}](steam://connect/{config.ServerIp}:{server.Port})", inline = true
                }
                );
            }
            fields.Add(new EmbedFieldList() {
                name = "Steam Profile", value = $"[{name}\n{steamId}](https://steamcommunity.com/profiles/{steamId})", inline = !config.DiscordQuickConnect
            }
            );
            fields.Add(new EmbedFieldList() {
                name = "Server Armour Profile ", value = $"[{name}\n{steamId}](https://serverarmour.com/profile/{steamId})", inline = !config.DiscordQuickConnect
            }
            );
            fields.Add(report);
            var fieldsObject = fields.Cast<object>().ToArray();
            string json = JsonConvert.SerializeObject(fieldsObject);
            if (DiscordApi != null && DiscordApi.IsLoaded) {
                DiscordApi?.Call("API_SendEmbeddedMessage", webHook, "Server Armour Report: ", color, json);
            }
            else if (DiscordMessages != null && DiscordMessages.IsLoaded) {
                DiscordMessages?.Call("API_SendFancyMessage", webHook, "Server Armour Report: ", color, json);
            }
            else {
                LogWarning("No discord API plugin loaded, will not publish to hook!");
            }
        }
        void CheckPing(IPlayer player) {
            // fix: https://discord.com/channels/751155344532570223/751155561776808158/1160293816104914974
            if (player == null || !player.IsConnected) return;
            try {
                if (!HasPerm(player.Id, PermissionWhitelistAllowHighPing) && (config.AutoKickMaxPing > 0 && config.AutoKickMaxPing < player.Ping)) {
                    KickPlayer(player.Id, GetMsg("Your Ping is too High", new Dictionary<string, string> {
                        ["ping"]
                        = player.Ping.ToString(), ["maxPing"] = config.AutoKickMaxPing.ToString()
                    }
                    ), "C", true);
                }
            }
            catch (Exception) {
            }
        }
#endregion
#region Hooks
        void OnServerSave() {
            if (config.AutoKickMaxPing > 0) foreach (var player in players.Connected) timer.Once(5f, () => CheckPing(player));
        }
        void OnServerInitialized(bool first) {
            LoadData();
            if (first) {
                //quick fix to ignore bans on server restart. (rust rebanning.)
                Unsubscribe(nameof(OnUserBanned));
                timer.Once(60, () => {
                    Subscribe(nameof(OnUserBanned));
                    serverStarted = true;
                    FlushPendingBans();
                    CheckLocalBans();
                }
                );
            }
            else {
                serverStarted = true;
                FlushPendingBans();
                CheckLocalBans();
            }
            // CheckOnlineUsers();
            string ServerGPort = ConVar.Server.port.ToString();
            string ServerQPort = ConVar.Server.queryport > 0 ? ConVar.Server.queryport.ToString() : ServerGPort;
            string ServerRPort = RCon.Port.ToString();
            Puts($"Server Ports are, Game Port: {ServerGPort} | Query Port:{ServerQPort} | RCON Port: {ServerRPort}");
            RegPerm(PermissionToBan);
            RegPerm(PermissionToUnBan);
            RegPerm(PermissionAdminWebsite);
            RegPerm(PermissionWhitelistBadIPKick);
            RegPerm(PermissionWhitelistRecentVacKick);
            RegPerm(PermissionWhitelistServerCeilingKick);
            RegPerm(PermissionWhitelistVacCeilingKick);
            RegPerm(PermissionWhitelistGameBanCeilingKick);
            RegPerm(PermissionWhitelistTotalBanCeiling);
            RegPerm(PermissionWhitelistSteamProfile);
            RegPerm(PermissionWhitelistFamilyShare);
            RegPerm(PermissionWhitelistTwitterBan);
            RegPerm(PermissionWhitelistAllowCountry);
            RegPerm(PermissionWhitelistAllowHighPing);
            RegPerm(PermissionWhitelistCombatGuidance);
            RegPerm(PermissionWhitelistAccountTrust);
            RegPerm(PermissionRadar);
            RegisterTag();
            string framework = this.isCarbon ? "Carbon" : "Oxide";
            headers = new Dictionary<string, string> {
                {
                    "server-key", config.ServerApiKey
                }
                , {
                    "Accept", "application/json"
                }
                , {
                    "Content-Type", "application/x-www-form-urlencoded; charset=UTF-8"
                }
                , {
                    "User-Agent", $"Server Armour/{this.Version} <{framework}>"
                }
            }
            ;
            config.CombatLogBatchSize = Math.Max(1, config.CombatLogBatchSize);
            config.CombatLogQueueMaxEntries = Math.Max(config.CombatLogBatchSize, config.CombatLogQueueMaxEntries);
            config.CombatLogPayloadTargetKb = Math.Max(64, config.CombatLogPayloadTargetKb);
            config.CombatLogRetryBaseSeconds = Math.Max(1, config.CombatLogRetryBaseSeconds);
            config.CombatLogFlushSeconds = Math.Max(0.1f, config.CombatLogFlushSeconds);
            InitChatModeration();
            InitTeamingSignals();
            string[] _admins = permission.GetUsersInGroup("admin");
            if (config.OwnerSteamId != null && config.OwnerSteamId.Length > 0 && !_admins.Contains(config.OwnerSteamId)) {
                var adminsList = new List<string>();
                adminsList.AddRange(_admins);
                adminsList.AddRange(config.OwnerSteamId.Split(','));
                var extraAdmins = permission.GetPermissionUsers(PermissionAdminWebsite);
                if (extraAdmins != null && extraAdmins.Length > 0) {
                    adminsList.AddRange(extraAdmins);
                }
                int e = 0;
                foreach (string extraAdminsGroups in permission.GetPermissionGroups(PermissionAdminWebsite)) {
                    foreach (string extraAdmin in permission.GetUsersInGroup(extraAdminsGroups)) {
                        if (!adminsList.Contains(extraAdmin)) {
                            adminsList.Add(extraAdmin);
                            e++;
                        }
                    }
                }
                _admins = adminsList.Distinct().ToArray();
            }
            for (int i = 0, n = _admins.Length; i < n; i++) {
                adminIds += $"{_admins[i].Substring(0, 17)}" + (i < _admins.Length - 1 ? "," : string.Empty);
            }
            CheckServerConnection();
            Application.logMessageReceived += HandleLog;
            if (ServerArmourUpdater != null && ServerArmourUpdater.IsLoaded) {
                foreach (var item in plugins.GetAll()) {
                    if (item.Filename == null || item.Filename.Length == 0) continue;
                    if (requiredPlugins.ContainsKey(item.Name)) requiredPlugins.Remove(item.Name);
                }
                Puts($"Needed plugins = {requiredPlugins.Count}");
                foreach (var plugin in requiredPlugins) {
                    ServerArmourUpdater?.Call("QueueDownload", plugin.Key, plugin.Value, "Server Armour");
                }
            }
        }
        void CheckServerConnection() {
            string body = ServerGetString();
            DoRequest("check_server", body, (code, response) => {
                JObject obj = null;
                try {
                    obj = JObject.Parse(response);
                }
                catch (Exception) {
                    timer.Once(15, CheckServerConnection);
                    return;
                }
                if (obj != null) {
                    var msg = obj["message"].ToString();
                    try {
                        this.serverId = int.Parse(obj["serverId"].ToString());
                        this.orgUuid = obj["orgUuid"].ToString();
                    }
                    catch (Exception) {
                    }
                    Puts(msg);
                    if (msg.Equals("connected")) {
                        apiConnected = true;
                        Puts($"Connected to SA API | Server ID = {this.serverId}" + (!this.orgUuid.IsNullOrEmpty() ? $" | orgUuid = ${this.orgUuid}" : ""));
                        ServerStatusUpdate();
                        updateTimer = timer.Every(60, ServerStatusUpdate);
                        nativeBanSyncTimer = timer.Every(180f, SyncPardonedNativeBans);
                        timer.Once(30f, SyncPardonedNativeBans);
                        QueueAutomaticMapUpload("api_connected", config.AutoUploadRconMapInitialDelaySeconds);
                    }
                    else {
                        Puts($"ServerApiKey = {config.ServerApiKey}");
                        var errMsg = "Server Armour has not initialized. Is your apikey correct? Get it from https://serverarmour.com/my-servers or join discord for support https://discord.gg/jxvRaPR";
                        LogError(errMsg);
                        timer.Once(500, () => LogError(errMsg));
                        return;
                    }
                    Puts("Server Armour has initialized.");
                }
                else {
                    timer.Once(5, CheckServerConnection);
                    return;
                }
            }
            );
        }
        void Unload() {
            _playerData?.Clear();
            _playerData = null;
            apiInFlight.Clear();
            foreach (var debounceTimer in playerCheckDebounceTimers.Values) {
                if (debounceTimer != null && !debounceTimer.Destroyed) debounceTimer.Destroy();
            }
            playerCheckDebounceTimers.Clear();
            foreach (var periodicTimer in playerPeriodicCheckTimers.Values) {
                if (periodicTimer != null && !periodicTimer.Destroyed) periodicTimer.Destroy();
            }
            playerPeriodicCheckTimers.Clear();
            foreach (var recheckTimer in playerRecheckTimers.Values) {
                if (recheckTimer != null && !recheckTimer.Destroyed) recheckTimer.Destroy();
            }
            playerRecheckTimers.Clear();
            playerRecheckAttempts.Clear();
            Application.logMessageReceived -= HandleLog;
            if (updateTimer != null && !updateTimer.Destroyed) updateTimer.Destroy();
            if (mapUploadTimer != null && !mapUploadTimer.Destroyed) mapUploadTimer.Destroy();
            if (nativeBanSyncTimer != null && !nativeBanSyncTimer.Destroyed) nativeBanSyncTimer.Destroy();
            if (debugDisableTimer != null && !debugDisableTimer.Destroyed) debugDisableTimer.Destroy();
            UnloadChatModeration();
            DestroyAllPlayerRadars();
        }
        void OnUserConnected(IPlayer iPlayer) {
            this.DoConnectionChecks(iPlayer);
        }
        object CanUserLogin(string name, string id, string ipAddress) {
            if (string.IsNullOrEmpty(id)) return null;
            if (TryGetNativeBanReason(id, out string nativeReason)) return nativeReason;
            ISABan cacheBan = IsBanned(id);
            if (cacheBan != null) return cacheBan.reason;
            return null;
        }
        void DoConnectionChecks(IPlayer player, string type = "C") {
            if (config.AutoKick_KickWeirdSteam64 && !player.Id.IsSteamId()) {
                KickPlayer(player.Id, GetMsg("Strange Steam64ID"), type);
                return;
            }
            if (EnforceNativeAndCacheBans(player, type)) return;
            if (!apiConnected && !config.ServerApiKey.IsNullOrEmpty()) {
                LogError("User not checked. Server armour is not loaded.");
            }
            else if (apiConnected) {
                CheckActiveBanFromApi(player.Id, player.Address, player.IsConnected);
                WebCheckPlayer(player.Id, player.Address, player.IsConnected);
                timer.Once(10f, () => CheckPing(player));
            }
            try {
                var connectedSeconds = GetConnectedSeconds(player);
                if (connectedSeconds < 600) SchedulePeriodicConnectionCheck(player);
                if (config.ShowProtectedMsg && connectedSeconds < 60) SendReplyWithIcon(player, GetMsg("Protected MSG"));
            }
            catch (Exception) {
            }
        }
        bool EnforceNativeAndCacheBans(IPlayer player, string type = "U") {
            if (player == null || string.IsNullOrEmpty(player.Id)) return false;
            if (TryKickIfNativelyBanned(player.Id, type)) return true;
            KickIfBanned(GetPlayerCache(player.Id));
            return false;
        }
        int GetConnectedSeconds(IPlayer player) {
            return BasePlayer.FindByID(ulong.Parse(player.Id))?.secondsConnected ?? int.MaxValue;
        }
        int GetConnectedSeconds(ISAPlayer player) {
            return BasePlayer.FindByID(ulong.Parse(player.steamid))?.secondsConnected ?? int.MaxValue;
        }
        void OnUserDisconnected(IPlayer player) {
            if (apiConnected) {
                try {
                    _playerData = _playerData?.Where(pair => MinutesAgo((uint)pair.Value.cacheTimestamp) < cacheLifetime) ?.ToDictionary(pair => pair.Key, pair => pair.Value);
                }
                catch (Exception) {
                }
            }
            if (player == null || string.IsNullOrEmpty(player.Id)) return;
            if (playerCheckDebounceTimers.TryGetValue(player.Id, out Timer debounceTimer) && debounceTimer != null && !debounceTimer.Destroyed) debounceTimer.Destroy();
            playerCheckDebounceTimers.Remove(player.Id);
            ClearPlayerRecheck(player.Id);
            ClearPeriodicConnectionCheck(player.Id);
            DestroyPlayerRadar(player.Object as BasePlayer);
        }
        void OnPluginLoaded(Plugin plugin) {
            if (plugin.Title == "BetterChat") RegisterTag();
        }
        void OnNewSave(string filename) {
            QueueAutomaticMapUpload("new_save", Mathf.Max(config.AutoUploadRconMapInitialDelaySeconds, 30f));
        }
        /**
         * To detect publisher bans
         */
        void OnPlayerKicked(BasePlayer player, string reason) {
            if (reason.Contains("PublisherBanned")) {
                DoRequest($"player/eacban", $"reason={FormEncode(reason)}&steamId={player.UserIDString}&username={FormEncode(player.displayName)}&serverId={this.serverId}", (code, response) => {
                }
                , RequestMethod.POST);
            }
        }
        void OnUserUnbanned(string name, string id, string ipAddress) {
            DoPardon(id);
        }
        void OnUserBanned(string name, string id, string ipAddress, string reason) {
            //this is to make sure that if an app like battlemetrics for example, bans a player, we catch it.
            if (config.IgnoreCheatDetected && reason.StartsWith("Cheat Detected")) {
                return;
            }
            try {
                if (AdminToggle != null && AdminToggle.Call<bool>("IsAdmin", id)) {
                    return;
                }
            }
            catch (Exception) {
            }
            timer.Once(10f, () => {
                //lets make sure first it wasn't us.
                if (!IsPlayerCached(id) || !ContainsMyBan(id)) {
                    IPlayer bPlayer = players.FindPlayerById(id);
                    if (bPlayer != null) {
                        if ((bPlayer.IsAdmin && config.IgnoreAdmins)) return;
                        DateTime nowUtc = DateTime.UtcNow;
                        long expiry = 0;
                        if (ulong.TryParse(bPlayer.Id, out ulong banSteamId)) expiry = ServerUsers.Get(banSteamId)?.expiry ?? 0;
                        AddBan(new ISABan {
                            steamid = ulong.Parse(bPlayer.Id), serverName = server.Name, serverIp = config.ServerIp, reason = reason, created = nowUtc.ToString(DATE_FORMAT), banUntil = ResolveBanUntil(expiry)
                        }
                        , false);
                    }
                }
            }
            );
        }
        void OnPlayerReported(BasePlayer reporter, string targetName, string targetId, string subject, string message, string type) {
            if (!serverStarted) return;
            string messageClean = FormEncode(message);
            string subjectClean = FormEncode(subject);
            DoRequest($"player/{reporter.UserIDString}/addf7", $"target={targetId}&subject={subjectClean}&message={messageClean}", (c, s) => {
            }
            );
        }
#endregion
#region Checks
        void GetPlayerRiskScore(ulong steamId) {
            GetJson($"player/{steamId}/risk", (c, s) => {
                if (c < 300) {
                    double riskscore = 0;
                    double.TryParse(s.GetValue("score").ToString(), out riskscore);
                    // TODO check the risk
                }
            }
            );
        }
#endregion
#region API_Hooks
#endregion
#region WebRequests
        void GetPlayerBans(IPlayer player) {
            if (player == null || player.Id == null) return;
            if (EnforceNativeAndCacheBans(player)) return;
            if (apiConnected) {
                WebCheckPlayer(player.Id, player.Address, player.IsConnected);
                timer.Once(10f, () => CheckPing(player));
            }
        }
        void GetPlayerBans(string playerId, string playerName) {
            if (TryKickIfNativelyBanned(playerId)) return;
            KickIfBanned(GetPlayerCache(playerId));
            if (apiConnected) WebCheckPlayer(playerId, "0.0.0.0", true);
        }
        void WebCheckPlayer(string id, string address, bool connected) {
            if (!apiConnected || string.IsNullOrEmpty(id)) return;
            string debounceKey = id;
            if (playerCheckDebounceTimers.TryGetValue(debounceKey, out Timer existing) && existing != null && !existing.Destroyed) existing.Destroy();
            playerCheckDebounceTimers[debounceKey] = timer.Once(0.35f, () => {
                playerCheckDebounceTimers.Remove(debounceKey);
                WebCheckPlayerNow(id, address, connected);
            }
            );
        }
        void WebCheckPlayerNow(string id, string address, bool connected) {
            if (!apiConnected) return;
            DoRequest($"player/{id}?bans=true&linked={config.AutoKick_ActiveBans.ToString().ToLowerInvariant()}", $"ipAddress={address}", (code, response) => {
                // LogDebug("Getting player from API");
                ISAPlayer isaPlayer = null;
                try {
                    isaPlayer = JsonConvert.DeserializeObject<ISAPlayer>(response);
                }
                catch (Exception) {
                    SchedulePlayerRecheck(id, address, connected);
                    return;
                }
                if (isaPlayer == null || string.IsNullOrEmpty(isaPlayer.steamid)) {
                    SchedulePlayerRecheck(id, address, connected);
                    return;
                }
                ClearPlayerRecheck(id);
                if (isaPlayer.bans == null) isaPlayer.bans = new List<ISABan>();
                if (isaPlayer.eacBans == null) isaPlayer.eacBans = new List<EacBan>();
                isaPlayer.cacheTimestamp = _time.GetUnixTimestamp();
                isaPlayer.lastConnected = _time.GetUnixTimestamp();
                // add cache for player
                // LogDebug("Checking cache");
                if (!IsPlayerCached(isaPlayer.steamid)) {
                    AddPlayerCached(isaPlayer);
                }
                else {
                    UpdatePlayerData(isaPlayer);
                }
                // lets check bans first
                try {
                    EnsureNativeBanMatchesApi(isaPlayer);
                    KickIfBanned(isaPlayer);
                }
                catch (Exception ane) {
                    LogDebug($"KickIfBanned error for {id}: {ane.Message}");
                }
                try {
                    SyncNativeBanIfPardoned(id);
                }
                catch (Exception ane) {
                    LogDebug($"SyncNativeBanIfPardoned error for {id}: {ane.Message}");
                }
                //script vars
                string pSteamId = isaPlayer.steamid ?? id;
                //string lSteamId = GetFamilyShare(isaPlayer.steamid);
                //
                LogDebug("Check for a twitter/eac game ban");
                if (config.AutoKick_KickTwitterGameBanned && !HasPerm(pSteamId, PermissionWhitelistTwitterBan) && isaPlayer.eacBans != null && isaPlayer.eacBans.Count > 0) {
                    KickPlayer(isaPlayer?.steamid, $"https://twitter.com/rusthackreport/status/{isaPlayer.eacBans[isaPlayer.eacBans.Count - 1].id}", "C");
                }
                LogDebug($"Check for a recent vac: DissallowVacBanDays = {config?.DissallowVacBanDays}, steamDaysSinceLastBan = {isaPlayer?.steamDaysSinceLastBan}, steamNumberOfVACBans = {isaPlayer?.steamNumberOfVACBans}, steamDaysSinceLastBan = {isaPlayer?.steamDaysSinceLastBan}, whitelisted = {HasPerm(pSteamId, PermissionWhitelistRecentVacKick)}");
                bool pRecentVac = (isaPlayer.steamNumberOfVACBans > 0 || isaPlayer.steamDaysSinceLastBan > 0) && isaPlayer.steamDaysSinceLastBan < config.DissallowVacBanDays;
                //check main player
                //bool lRecentVac = (isaPlayer.lender?.steamNumberOfVACBans > 0 || isaPlayer.lender?.steamDaysSinceLastBan > 0)
                //&& isaPlayer.lender?.steamDaysSinceLastBan < config.DissallowVacBanDays; //check the lender player
                if (config.AutoKickOn && !HasPerm(pSteamId, PermissionWhitelistRecentVacKick) && pRecentVac) {
                    int vacLast = isaPlayer.steamDaysSinceLastBan;
                    int until = config.DissallowVacBanDays - vacLast;
                    Interface.CallHook("OnSARecentVacKick", vacLast, until);
                    string msg = GetMsg(pRecentVac ? "Reason: VAC Ban Too Fresh" : "Reason: VAC Ban Too Fresh - Lender", new Dictionary<string, string> {
                        ["daysago"]
                        = vacLast.ToString(), ["daysto"] = until.ToString()
                    }
                    );
                    KickPlayer(isaPlayer?.steamid, msg, "C");
                }
                LogDebug("Check for too many vac bans");
                if (!HasPerm(pSteamId, PermissionWhitelistVacCeilingKick) && HasReachedVacCeiling(isaPlayer)) {
                    Interface.CallHook("OnSATooManyVacKick", pSteamId, isaPlayer?.steamNumberOfVACBans);
                    KickPlayer(isaPlayer?.steamid, GetMsg("VAC Ceiling Kick"), "C");
                }
                LogDebug("Check for too many game bans");
                if (!HasPerm(pSteamId, PermissionWhitelistGameBanCeilingKick) && HasReachedGameBanCeiling(isaPlayer)) {
                    Interface.CallHook("OnSATooManyGameBansKick", pSteamId, isaPlayer.steamNumberOfGameBans);
                    KickPlayer(isaPlayer?.steamid, GetMsg("Too Many Previous Game Bans"), "C");
                }
                // LogDebug("Check for players with too many server bans");
                //if (!HasPerm(pSteamId, PermissionWhitelistServerCeilingKick) && HasReachedServerCeiling(isaPlayer))
                //{
                //    Interface.CallHook("OnSATooManyServerBans", pSteamId, config.AutoKickCeiling, ServerBanCount(isaPlayer) + ServerBanCount(isaPlayer.lender));
                //    KickPlayer(isaPlayer?.steamid, GetMsg("Too Many Previous Bans"), "C");
                //}
                //if (!HasPerm(PermissionWhitelistTotalBanCeiling, pSteamId) && HasReachedTotalBanCeiling(isaPlayer))
                //{
                //    Interface.CallHook("OnSATooManyBans", pSteamId, config.AutoKickCeiling, TotalBans(isaPlayer.lender));
                //    KickPlayer(isaPlayer?.steamid, GetMsg("Too Many Previous Bans"), "C");
                //}
                LogDebug("Check for players with a private profile");
                int visibilityState = GetCommunityVisibilityState(isaPlayer);
                if (!HasPerm(pSteamId, PermissionWhitelistSteamProfile) && config.AutoKick_KickPrivateProfile) {
                    if (ShouldKickForPrivateProfile(visibilityState)) {
                        Interface.CallHook("OnSAProfilePrivate", pSteamId, visibilityState);
                        KickPlayer(isaPlayer?.steamid, GetMsg("Profile Private"), "C");
                    }
                    else if (!IsKnownCommunityVisibility(visibilityState)) {
                        SchedulePlayerRecheck(id, address, connected);
                    }
                }
                LogDebug("Check for a hidden steam level");
                if (!HasPerm(pSteamId, PermissionWhitelistSteamProfile) && isaPlayer.steamlevel == -1 && config.AutoKick_KickHiddenLevel) {
                    Interface.CallHook("OnSASteamLevelHidden", pSteamId);
                    KickPlayer(isaPlayer?.steamid, GetMsg("Steam Level Hidden"), "C");
                }
                LogDebug($"Player {isaPlayer.steamid} is at steam level {isaPlayer.steamlevel}");
                if (!HasPerm(pSteamId, PermissionWhitelistSteamProfile) && isaPlayer.steamlevel < config.AutoKick_MinSteamProfileLevel && isaPlayer.steamlevel >= 0) {
                    Interface.CallHook("OnSAProfileLevelLow", pSteamId, config.AutoKick_MinSteamProfileLevel, isaPlayer.steamlevel);
                    KickPlayer(isaPlayer?.steamid, GetMsg("Profile Low Level", new Dictionary<string, string> {
                        ["level"]
                        = config.AutoKick_MinSteamProfileLevel.ToString()
                    }
                    ), "C");
                }
                LogDebug($"IP/CACHE| ID:{id} ADD:{address} COUNTRY: {isaPlayer.ipInfo.isocode} RATING:{isaPlayer?.ipInfo?.rating} AGE: {isaPlayer.ipInfo?.lastcheck}");
                if (config.AutoKickOn && config.AutoKick_BadIp && !HasPerm(id, PermissionWhitelistBadIPKick) && config.AutoKick_BadIp) {
                    if (IsBadIp(isaPlayer)) {
                        if (isaPlayer.ipInfo?.proxy == "yes") KickPlayer(id, GetMsg("Reason: Proxy IP"), "C");
                        else KickPlayer(id, GetMsg("Reason: Bad IP"), "C");
                        Interface.CallHook("OnSAVPNKick", id, isaPlayer?.ipInfo?.rating);
                    }
                }
                if (!HasPerm(id, PermissionWhitelistAllowCountry) && !config.AutoKickLimitCountry.IsNullOrEmpty()) {
                    var playerIso = isaPlayer.ipInfo?.isocode?.Trim();
                    var countriesAllowed = config.AutoKickLimitCountry.Split(',');
                    if (playerIso != null && playerIso != "" && !countriesAllowed.Contains(playerIso)) KickPlayer(id, GetMsg("Country Not Allowed", new Dictionary<string, string> {
                        ["country"]
                        = playerIso, ["country2"] = config.AutoKickLimitCountry.ToString()
                    }
                    ), "C");
                }
                if (ShouldKickForCombatGuidance(isaPlayer) && !HasPerm(pSteamId, PermissionWhitelistCombatGuidance)) {
                    Interface.CallHook("OnSACombatAnomalyGuidanceKick", pSteamId, isaPlayer.combatAnomalyGuidanceAction, isaPlayer.combatAnomalyGuidanceRank);
                    KickPlayer(isaPlayer?.steamid, GetMsg("Combat Anomaly Guidance Kick", new Dictionary<string, string> {
                        ["action"]
                        = isaPlayer.combatAnomalyGuidanceAction ?? "review"
                    }
                    ), "C");
                }
                if (ShouldKickForAccountTrust(isaPlayer) && !HasPerm(pSteamId, PermissionWhitelistAccountTrust)) {
                    Interface.CallHook("OnSAAccountTrustKick", pSteamId, isaPlayer.accountTrustTier ?? "critical", isaPlayer.accountTrustTierRank);
                    KickPlayer(isaPlayer?.steamid, GetMsg("Account Trust Kick", new Dictionary<string, string> {
                        ["tier"]
                        = isaPlayer.accountTrustTier ?? "critical", ["eas"] = isaPlayer.accountTrustEas.ToString("0.##"), ["scs"] = isaPlayer.accountTrustScs.ToString("0.##")
                    }
                    ), "C");
                }
                GetPlayerReport(isaPlayer, connected);
            }
            , RequestMethod.POST, 5);
        }
        void KickIfBanned(ISAPlayer isaPlayer) {
            if (isaPlayer == null) return;
            IPlayer iPlayer = covalence.Players.FindPlayer(isaPlayer.steamid);
            if (iPlayer != null && iPlayer.IsAdmin && config.IgnoreAdmins) return;
            try {
                if (AdminToggle != null && AdminToggle.Call<bool>("IsAdmin", iPlayer.Id) && config.IgnoreAdmins) return;
            }
            catch (Exception) {
            }
            ISABan ban = IsBanned(isaPlayer?.steamid);
            if (ban != null) {
                if (!ban.steamid.ToString().Equals(isaPlayer.steamid)) {
                    KickPlayer(isaPlayer?.steamid, $"Linked: {ban.steamid}, {ban.reason}", "U");
                }
                else {
                    KickPlayer(isaPlayer?.steamid, ban.reason, "U");
                }
            }
        }
        void AddBan(ISABan thisBan, bool doNative = true) {
            if (thisBan == null) return;
            if (!serverStarted) {
                pendingBans.Add(thisBan);
                return;
            }
            string steamIdKey = thisBan.steamid.ToString();
            if (addBanInFlight.Contains(steamIdKey)) return;
            addBanInFlight.Add(steamIdKey);
            string reason = FormEncode(thisBan.reason);
            try {
                DoRequest($"player/{thisBan.steamid}/addban", $"reason={reason}&dateTime={FormEncode(thisBan.created)}&banUntil={FormEncode(thisBan.banUntil)}&createdBySteamId={thisBan.bannedBy}", (code, response) => {
                    addBanInFlight.Remove(steamIdKey);
                    if (IsPlayerCached(steamIdKey)) AddPlayerData(steamIdKey, thisBan);
                    else {
                        ISAPlayer newPlayer = new ISAPlayer((ulong)thisBan.steamid);
                        newPlayer.bans.Add(thisBan);
                        AddPlayerCached(newPlayer);
                    }
                }
                , RequestMethod.POST, 0);
            }
            catch (Exception) {
                addBanInFlight.Remove(steamIdKey);
            }
        }
        void FlushPendingBans() {
            if (pendingBans.Count == 0) return;
            foreach (ISABan pendingBan in pendingBans.ToList()) AddBan(pendingBan);
            pendingBans.Clear();
        }
#endregion
#region Commands
        [Command("sa.apply_key")]
        void ApplyKey(IPlayer player, string command, string[] args) {
            var key = args[0].ToString();
            if (!player.IsServer) {
                return;
            }
            this.config.ServerApiKey = key;
            Puts($"Applying key = {key}");
            config.SetConfig(ref config.ServerApiKey, "io.serverarmour.com", "Server Key");
            SaveConfig();
            if (headers != null) headers["server-key"] = key;
            InitChatModeration();
        }
        [Command("sa.clb", "getreport")]
        void SCmdCheckLocalBans(IPlayer player, string command, string[] args) {
            CheckLocalBans();
            SyncPardonedNativeBans();
        }
        [Command("unban", "playerunban", "sa.unban"), Permission(PermissionToUnBan)]
        void SCmdUnban(IPlayer player, string command, string[] args) {
            if (args == null || (args.Length > 2 || args.Length < 1)) {
                SendReplyWithIcon(player, GetMsg("UnBan Syntax"));
                return;
            }
            var reason = args.Length > 1 ? args[1] : "";
            SaUnban(args[0], player, reason);
        }
        void SilentBan(ulong steamId, TimeSpan timeSpan, string reason, IPlayer enforcer = null) {
            Unsubscribe(nameof(OnUserBanned));
            var username = covalence.Players.FindPlayerById(steamId.ToString())?.Name ?? "";
            NativeBan(steamId, reason, Convert.ToInt64(timeSpan.TotalSeconds), username, enforcer);
            Subscribe(nameof(OnUserBanned));
        }
        void SilentBan(ulong steamId, int timeSpan, string reason, IPlayer enforcer = null) {
            Unsubscribe(nameof(OnUserBanned));
            var username = covalence.Players.FindPlayerById(steamId.ToString())?.Name ?? "";
            NativeBan(steamId, reason, -1, username, enforcer);
            Subscribe(nameof(OnUserBanned));
        }
        bool SilentUnban(string playerId, IPlayer admin) {
            Unsubscribe(nameof(OnUserUnbanned));
            bool removed = NativeUnban(playerId, admin);
            Subscribe(nameof(OnUserUnbanned));
            return removed;
        }
        void NativeBan(ulong playerId, string reason, long duration = -1, string playerUsername = "unnamed", IPlayer player = null) {
            if (!playerId.IsSteamId()) {
                if (serverStarted) player?.Reply(string.Concat("This doesn't appear to be a 64bit steamid: ", playerId));
                return;
            }
            ServerUsers.User user = ServerUsers.Get(playerId);
            if (user != null && user.@group == ServerUsers.UserGroup.Banned && !user.IsExpired) {
                long epochDuration = duration == -1 ? -1 : (long)(DateTime.UtcNow.AddSeconds(duration) - Epoch).TotalSeconds;
                ServerUsers.Set(playerId, ServerUsers.UserGroup.Banned, playerUsername, reason, epochDuration);
                if (serverStarted) player?.Reply(string.Concat("User ", playerId, " is already banned"));
                return;
            }
            string str3 = "";
            BasePlayer basePlayer = BasePlayer.FindByID(playerId);
            string durationSuffix = (duration > (long)0 ? string.Concat(" for ", duration.FormatSecondsLong()) : "");
            if (basePlayer != null && basePlayer.IsConnected) {
                playerUsername = basePlayer.displayName;
                if (basePlayer.IsConnected && basePlayer.net.connection.ownerid != 0 && basePlayer.net.connection.ownerid != basePlayer.net.connection.userid) {
                    str3 = string.Concat(str3, string.Format(" and also banned ownerid {0}", basePlayer.net.connection.ownerid));
                    ServerUsers.Set(basePlayer.net.connection.ownerid, ServerUsers.UserGroup.Banned, basePlayer.displayName, reason, duration);
                }
                Chat.Broadcast(string.Concat(new string[] {
                    "Kickbanning ", basePlayer.displayName, durationSuffix, " (", reason, ")"
                }
                ), "SERVER", "#eee", (ulong)0);
                //Net.sv.Kick(basePlayer.net.connection, string.Concat("Banned", str, ": ", str2), false);
            }
            ServerUsers.Set(playerId, ServerUsers.UserGroup.Banned, playerUsername, reason, duration == -1 ? -1 : (long)(DateTime.UtcNow.AddSeconds(duration) - Epoch).TotalSeconds);
            if (serverStarted) player?.Reply(string.Format("Banned User{0}: {1} - \"{2}\" for \"{3}\"{4}", new object[] {
                durationSuffix, playerId, playerUsername, reason, str3
            }
            ));
        }
        bool NativeUnban(string playerId, IPlayer admin = null) {
            ulong playerIdLong = 0;
            if (!ulong.TryParse(playerId, out playerIdLong)) {
                var msg = string.Format("This doesn't appear to be a 64bit steamid: {0}", playerId);
                if (admin == null) {
                    Puts(msg);
                }
                else {
                    admin.Reply(msg);
                }
                return false;
            }
            ServerUsers.User user = ServerUsers.Get(playerIdLong);
            if (user == null || user.@group != ServerUsers.UserGroup.Banned) {
                admin?.Reply(string.Format("User {0} isn't banned", playerId));
                return false;
            }
            ServerUsers.Remove(playerIdLong);
            admin?.Reply($"Unbanned User: {playerId}");
            return true;
        }
        void SaUnban(string playerId, IPlayer admin = null, string reason = "") {
            try {
                SaUnbanInternal(playerId, admin, reason);
            }
            catch (Exception ex) {
                LogDebug($"SaUnban failed for {playerId}: {ex.Message}");
            }
        }
        void SaUnbanInternal(string playerId, IPlayer admin = null, string reason = "") {
            IPlayer iPlayer = players.FindPlayer(playerId);
            SilentUnban(playerId, admin);
            ulong playerIdLong = 0;
            ulong.TryParse(playerId, out playerIdLong);
            if (playerIdLong == 0 && iPlayer == null) {
                admin?.Reply(GetMsg("Player Not Found", new Dictionary<string, string> {
                    ["player"]
                    = playerId
                }
                ));
                return;
            }
            Puts($"Player {iPlayer?.Name ?? playerId} ({playerId}) was unbanned by {admin?.Name ?? "console"} ({admin?.Id ?? "console"})");
            // Add ember support.
            if (Ember != null) {
                Ember?.Call("Unban", playerId, Player.FindById(admin?.Id));
            }
            //
            if (serverStarted) {
                DoPardon(playerId, iPlayer, admin);
            }
            string msgClean;
            if (reason.IsNullOrEmpty()) {
                msgClean = GetMsg("Player Now Unbanned Clean - NoReason", new Dictionary<string, string> {
                    ["player"]
                    = iPlayer?.Name ?? playerId
                }
                );
            }
            else {
                msgClean = GetMsg("Player Now Unbanned Clean - Reason", new Dictionary<string, string> {
                    ["player"]
                    = iPlayer?.Name ?? playerId, ["reason"] = reason
                }
                );
            }
            if (config.DiscordBanReport) {
                DiscordSend(playerId, iPlayer?.Name ?? playerId, new EmbedFieldList() {
                    name = "Player Unbanned", value = msgClean, inline = true
                }
                , 3066993, true);
            }
        }
        void DoPardon(string playerId, IPlayer iPlayer = null, IPlayer admin = null) {
            try {
                RemoveBans(playerId);
            }
            catch (Exception ex) {
                LogDebug($"RemoveBans failed for {playerId}: {ex.Message}");
            }
            string pardonedBy = admin?.Id ?? admin?.Name ?? "console";
            DoRequest($"player/ban/pardon/{playerId}", $"pardonedBy={pardonedBy}", (code, response) => {
                if (config.RconBroadcast) RCon.Broadcast(RCon.LogType.Chat, new Chat.ChatEntry {
                    Message = $"Player was unbanned by {admin?.Name ?? "console"} ({admin?.Id ?? "console"})", UserId = playerId, Username = iPlayer?.Name ?? "", Time = Facepunch.Math.Epoch.Current
                }
                );
                if (admin != null && config.RconBroadcast) {
                    RCon.Broadcast(RCon.LogType.Chat, new Chat.ChatEntry {
                        Message = $"Player {iPlayer?.Name} ({playerId}) was unbanned", UserId = admin?.Id, Username = admin?.Name ?? "", Time = Facepunch.Math.Epoch.Current
                    }
                
// ... [Code preview truncated due to length. Full source in attached file] ...

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