@@ -25,7 +25,8 @@ public sealed class NyaCheckClientSystem : EntitySystem
|
|||||||
"Content.Shared.Database",
|
"Content.Shared.Database",
|
||||||
"Robust.Client",
|
"Robust.Client",
|
||||||
"Robust.Shared",
|
"Robust.Shared",
|
||||||
"Robust.Server"
|
"Robust.Server",
|
||||||
|
"Content.Anticheat",
|
||||||
];
|
];
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
@@ -47,7 +48,6 @@ public sealed class NyaCheckClientSystem : EntitySystem
|
|||||||
HasPatchMetadata = FoundPatchMetadataTypes(),
|
HasPatchMetadata = FoundPatchMetadataTypes(),
|
||||||
ReflectionOffender = FoundExtraTypesIReflection(out var reflectionOffender) ? reflectionOffender : null,
|
ReflectionOffender = FoundExtraTypesIReflection(out var reflectionOffender) ? reflectionOffender : null,
|
||||||
HasMoonyware = FoundMoonywareModuleReflection(),
|
HasMoonyware = FoundMoonywareModuleReflection(),
|
||||||
HasHarmony = CheckForHarmony(),
|
|
||||||
IoCOffender = TypesNotFromContentIoC(out var iocOffender) ? iocOffender : null,
|
IoCOffender = TypesNotFromContentIoC(out var iocOffender) ? iocOffender : null,
|
||||||
ExtraModuleOffender = CheckExtraModule(out var moduleOffender) ? moduleOffender : null,
|
ExtraModuleOffender = CheckExtraModule(out var moduleOffender) ? moduleOffender : null,
|
||||||
CvarOffender = CheckCommonCheatCvars(out var cvarOffender) ? cvarOffender : null,
|
CvarOffender = CheckCommonCheatCvars(out var cvarOffender) ? cvarOffender : null,
|
||||||
@@ -63,16 +63,10 @@ public sealed class NyaCheckClientSystem : EntitySystem
|
|||||||
return found is not null;
|
return found is not null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool CheckForHarmony()
|
|
||||||
{
|
|
||||||
var harmonyType = Type.GetType("HarmonyLib.Harmony, 0Harmony");
|
|
||||||
return harmonyType != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool FoundExtraTypesIReflection([NotNullWhen(true)] out string? offender)
|
private bool FoundExtraTypesIReflection([NotNullWhen(true)] out string? offender)
|
||||||
{
|
{
|
||||||
offender = null;
|
offender = null;
|
||||||
string[] typenames = ["SubverterPatch", "MarseyPatch", "MarseyEntry", "Sedition", "Ware"];
|
string[] typenames = ["SubverterPatch", "MarseyPatch", "MarseyEntry", "Sedition"];
|
||||||
|
|
||||||
var types = _reflection.FindAllTypes();
|
var types = _reflection.FindAllTypes();
|
||||||
|
|
||||||
@@ -174,12 +168,9 @@ public sealed class NyaCheckClientSystem : EntitySystem
|
|||||||
string[] keywords =
|
string[] keywords =
|
||||||
[
|
[
|
||||||
"aimbot",
|
"aimbot",
|
||||||
"visuals",
|
|
||||||
"esp",
|
"esp",
|
||||||
"noslip",
|
"noslip",
|
||||||
"exploit",
|
"exploit",
|
||||||
"fun",
|
|
||||||
"scan",
|
|
||||||
];
|
];
|
||||||
|
|
||||||
offend = null;
|
offend = null;
|
||||||
|
|||||||
@@ -6,9 +6,6 @@ using Robust.Shared.Timing;
|
|||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using Content.Server.GameTicking;
|
|
||||||
using Content.Shared._White;
|
|
||||||
using Robust.Shared.Configuration;
|
|
||||||
|
|
||||||
namespace Content.Server._Miracle.Nya;
|
namespace Content.Server._Miracle.Nya;
|
||||||
|
|
||||||
@@ -17,30 +14,18 @@ public sealed class ExpectedReplySystem : EntitySystem
|
|||||||
[Dependency] private readonly ISharedPlayerManager _playMan = default!;
|
[Dependency] private readonly ISharedPlayerManager _playMan = default!;
|
||||||
[Dependency] private readonly IGameTiming _timing = default!;
|
[Dependency] private readonly IGameTiming _timing = default!;
|
||||||
[Dependency] private readonly IChatManager _chatManager = default!;
|
[Dependency] private readonly IChatManager _chatManager = default!;
|
||||||
[Dependency] private readonly IConfigurationManager _configuration = default!;
|
|
||||||
[Dependency] private readonly CheatCheckSystem _cheatCheckSystem = default!;
|
|
||||||
|
|
||||||
private readonly Dictionary<ICommonSession, PendingReply> _pendingReplies = new();
|
private readonly Dictionary<ICommonSession, PendingReply> _pendingReplies = new();
|
||||||
|
|
||||||
private const float ReplyTimeoutSeconds = 6.0f;
|
private const float ReplyTimeoutSeconds = 5.0f;
|
||||||
private readonly HttpClient _httpClient = new();
|
private readonly HttpClient _httpClient = new();
|
||||||
|
|
||||||
private string _webhookUrl = "";
|
private const string WebhookUrl = "https://discord.com/api/webhooks/1300204694395945021/jO_2nmXDXfMm2hKHH019gk1HqujhcHlW8yfmyMBeuScaOvCOiRJK9XurSJLf6AxpHmRv";
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
_playMan.PlayerStatusChanged += OnPlayerStatusChanged;
|
_playMan.PlayerStatusChanged += OnPlayerStatusChanged;
|
||||||
|
|
||||||
SubscribeLocalEvent<PlayerJoinedLobbyEvent>(OnPlayerJoinedLobby);
|
|
||||||
|
|
||||||
_configuration.OnValueChanged(WhiteCVars.ACWebhook, s => _webhookUrl = s, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnPlayerJoinedLobby(PlayerJoinedLobbyEvent ev)
|
|
||||||
{
|
|
||||||
_cheatCheckSystem.RequestCheck(ev.PlayerSession);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnPlayerStatusChanged(object? sender, SessionStatusEventArgs e)
|
private void OnPlayerStatusChanged(object? sender, SessionStatusEventArgs e)
|
||||||
@@ -49,7 +34,7 @@ public sealed class ExpectedReplySystem : EntitySystem
|
|||||||
{
|
{
|
||||||
if (_pendingReplies.ContainsKey(e.Session))
|
if (_pendingReplies.ContainsKey(e.Session))
|
||||||
{
|
{
|
||||||
var warningMsg = $"Игрок отключился во время ожидания ответа! Nya должен был получить: {_pendingReplies[e.Session].Request.ExpectedReplyType}.";
|
var warningMsg = $"Игрок отключился во время ожидания ответа!";
|
||||||
SendSuspiciousActivityAlert(e.Session, warningMsg, 80);
|
SendSuspiciousActivityAlert(e.Session, warningMsg, 80);
|
||||||
_pendingReplies.Remove(e.Session);
|
_pendingReplies.Remove(e.Session);
|
||||||
}
|
}
|
||||||
@@ -118,7 +103,7 @@ public sealed class ExpectedReplySystem : EntitySystem
|
|||||||
|
|
||||||
private void HandleTimeout(ICommonSession player)
|
private void HandleTimeout(ICommonSession player)
|
||||||
{
|
{
|
||||||
var warningMsg = $"Не получен ответ в течение {ReplyTimeoutSeconds} секунд. Будьте бдительны с этим игроком! Nya советует использовать nyagrab!";
|
var warningMsg = $"Не получен ответ в течение {ReplyTimeoutSeconds} секунд";
|
||||||
SendSuspiciousActivityAlert(player, warningMsg, 65);
|
SendSuspiciousActivityAlert(player, warningMsg, 65);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,14 +140,14 @@ public sealed class ExpectedReplySystem : EntitySystem
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await _httpClient.PostAsync(_webhookUrl, content);
|
await _httpClient.PostAsync(WebhookUrl, content);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Log.Error($"Failed to send Discord webhook: {e}");
|
Log.Error($"Failed to send Discord webhook: {e}");
|
||||||
}
|
}
|
||||||
|
|
||||||
var inGameMsg = $"[Anticheat] Внимание! Подозрительная активность:\n" +
|
var inGameMsg = $"[color=red][Anticheat][/color] Внимание! Подозрительная активность:\n" +
|
||||||
$"Игрок {player.Name} возможно читер!\n" +
|
$"Игрок {player.Name} возможно читер!\n" +
|
||||||
$"Причина обнаружения: {reason}";
|
$"Причина обнаружения: {reason}";
|
||||||
|
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ using System.Text;
|
|||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using Content.Server.Chat.Managers;
|
using Content.Server.Chat.Managers;
|
||||||
using Content.Shared._Miracle.Nya;
|
using Content.Shared._Miracle.Nya;
|
||||||
using Content.Shared._White;
|
|
||||||
using Robust.Shared.Configuration;
|
|
||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
|
|
||||||
namespace Content.Server._Miracle.Nya;
|
namespace Content.Server._Miracle.Nya;
|
||||||
@@ -14,18 +12,15 @@ public sealed class CheatCheckSystem : EntitySystem
|
|||||||
{
|
{
|
||||||
[Dependency] private readonly ExpectedReplySystem _expectedReply = default!;
|
[Dependency] private readonly ExpectedReplySystem _expectedReply = default!;
|
||||||
[Dependency] private readonly IChatManager _chatManager = default!;
|
[Dependency] private readonly IChatManager _chatManager = default!;
|
||||||
[Dependency] private readonly IConfigurationManager _configuration = default!;
|
|
||||||
|
|
||||||
private readonly HttpClient _httpClient = new();
|
private readonly HttpClient _httpClient = new();
|
||||||
|
|
||||||
private string _webhookUrl = "";
|
private const string WebhookUrl = "https://discord.com/api/webhooks/1300204694395945021/jO_2nmXDXfMm2hKHH019gk1HqujhcHlW8yfmyMBeuScaOvCOiRJK9XurSJLf6AxpHmRv";
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
SubscribeNetworkEvent<CheatCheckResponseEvent>(OnCheckResponse);
|
SubscribeNetworkEvent<CheatCheckResponseEvent>(OnCheckResponse);
|
||||||
|
|
||||||
_configuration.OnValueChanged(WhiteCVars.ACWebhook, s => _webhookUrl = s, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RequestCheck(ICommonSession player)
|
public void RequestCheck(ICommonSession player)
|
||||||
@@ -56,9 +51,6 @@ public sealed class CheatCheckSystem : EntitySystem
|
|||||||
if (ev.HasMoonyware)
|
if (ev.HasMoonyware)
|
||||||
detections.Add(("Чит-клиент", "Обнаружен Moonyware", 95));
|
detections.Add(("Чит-клиент", "Обнаружен Moonyware", 95));
|
||||||
|
|
||||||
if (ev.HasHarmony)
|
|
||||||
detections.Add(("Чит-клиент", "Имеется 0Harmony. Возможны читы/патчи. Будьте бдительны!", 70));
|
|
||||||
|
|
||||||
if (ev.IoCOffender != null)
|
if (ev.IoCOffender != null)
|
||||||
detections.Add(("IoC манипуляция", $"Неразрешенный тип: {ev.IoCOffender}", 70));
|
detections.Add(("IoC манипуляция", $"Неразрешенный тип: {ev.IoCOffender}", 70));
|
||||||
|
|
||||||
@@ -78,44 +70,7 @@ public sealed class CheatCheckSystem : EntitySystem
|
|||||||
detections.Add(("UI вмешательство", $"Неразрешенное окно: {ev.WindowOffender}", 65));
|
detections.Add(("UI вмешательство", $"Неразрешенное окно: {ev.WindowOffender}", 65));
|
||||||
|
|
||||||
if (detections.Count == 0)
|
if (detections.Count == 0)
|
||||||
{
|
|
||||||
var cleanMsg = $"✅ **Античит завершил проверку**\n\n" +
|
|
||||||
$"**Игрок:** {args.SenderSession.Name}\n" +
|
|
||||||
$"**IP:** {args.SenderSession.Channel.RemoteEndPoint}\n" +
|
|
||||||
$"**Результат:** Нарушений не выявлено";
|
|
||||||
|
|
||||||
var cleanEmbed = new
|
|
||||||
{
|
|
||||||
title = "✅ Проверка завершена",
|
|
||||||
description = cleanMsg,
|
|
||||||
color = 0x00FF00, // Зеленый
|
|
||||||
timestamp = DateTime.UtcNow.ToString("o")
|
|
||||||
};
|
|
||||||
|
|
||||||
var cleanPayload = new
|
|
||||||
{
|
|
||||||
embeds = new[] { cleanEmbed }
|
|
||||||
};
|
|
||||||
|
|
||||||
var json = JsonSerializer.Serialize(cleanPayload);
|
|
||||||
var content = new StringContent(json, Encoding.UTF8, "application/json");
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await _httpClient.PostAsync(_webhookUrl, content);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Log.Error($"Failed to send Discord webhook: {e}");
|
|
||||||
}
|
|
||||||
|
|
||||||
var cleanInGameMsg = $"[Anticheat] Проверка завершена\n" +
|
|
||||||
$"Игрок: {args.SenderSession.Name}\n" +
|
|
||||||
$"Результат: Нарушений не выявлено";
|
|
||||||
|
|
||||||
_chatManager.SendAdminAnnouncement(cleanInGameMsg);
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
var maxSeverity = detections.Max(d => d.Severity);
|
var maxSeverity = detections.Max(d => d.Severity);
|
||||||
var avgSeverity = detections.Average(d => d.Severity);
|
var avgSeverity = detections.Average(d => d.Severity);
|
||||||
@@ -152,26 +107,26 @@ public sealed class CheatCheckSystem : EntitySystem
|
|||||||
embeds = new[] { embed }
|
embeds = new[] { embed }
|
||||||
};
|
};
|
||||||
|
|
||||||
var jsonA = JsonSerializer.Serialize(payload);
|
var json = JsonSerializer.Serialize(payload);
|
||||||
var contentA = new StringContent(jsonA, Encoding.UTF8, "application/json");
|
var content = new StringContent(json, Encoding.UTF8, "application/json");
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await _httpClient.PostAsync(_webhookUrl, contentA);
|
await _httpClient.PostAsync(WebhookUrl, content);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Log.Error($"Failed to send Discord webhook: {e}");
|
Log.Error($"Failed to send Discord webhook: {e}");
|
||||||
}
|
}
|
||||||
|
|
||||||
var inGameMsg = $"[Anticheat] Обнаружена подозрительная активность!\n" +
|
var inGameMsg = $"[color=red][Anticheat][/color] Обнаружена подозрительная активность!\n" +
|
||||||
$"Игрок: {args.SenderSession.Name}\n" +
|
$"Игрок: {args.SenderSession.Name}\n" +
|
||||||
$"Вероятность использования читов: {totalSeverity}%\n" +
|
$"Вероятность использования читов: {totalSeverity}%\n" +
|
||||||
$"Обнаруженные нарушения:";
|
$"Обнаруженные нарушения:";
|
||||||
|
|
||||||
foreach (var (type, details, severity) in detections)
|
foreach (var (type, details, severity) in detections)
|
||||||
{
|
{
|
||||||
inGameMsg += $"\n•{type} ({severity}%): {details}";
|
inGameMsg += $"\n[color=yellow]• {type}[/color] ({severity}%): {details}";
|
||||||
}
|
}
|
||||||
|
|
||||||
_chatManager.SendAdminAnnouncement(inGameMsg);
|
_chatManager.SendAdminAnnouncement(inGameMsg);
|
||||||
|
|||||||
@@ -2,8 +2,6 @@
|
|||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using Content.Shared._Miracle.Nya;
|
using Content.Shared._Miracle.Nya;
|
||||||
using Content.Shared._White;
|
|
||||||
using Robust.Shared.Configuration;
|
|
||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
using SixLabors.ImageSharp;
|
using SixLabors.ImageSharp;
|
||||||
using SixLabors.ImageSharp.PixelFormats;
|
using SixLabors.ImageSharp.PixelFormats;
|
||||||
@@ -13,18 +11,15 @@ namespace Content.Server._Miracle.Nya;
|
|||||||
public sealed class NyaGrabSystem : EntitySystem
|
public sealed class NyaGrabSystem : EntitySystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly ExpectedReplySystem _expectedReply = default!;
|
[Dependency] private readonly ExpectedReplySystem _expectedReply = default!;
|
||||||
[Dependency] private readonly IConfigurationManager _configuration = default!;
|
|
||||||
|
|
||||||
private readonly HttpClient _httpClient = new();
|
private readonly HttpClient _httpClient = new();
|
||||||
|
|
||||||
private string _webhookUrl = "";
|
private const string WebhookUrl = "https://discord.com/api/webhooks/1300204694395945021/jO_2nmXDXfMm2hKHH019gk1HqujhcHlW8yfmyMBeuScaOvCOiRJK9XurSJLf6AxpHmRv";
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
SubscribeNetworkEvent<ScreengrabResponseEvent>(OnScreengrabResponse);
|
SubscribeNetworkEvent<ScreengrabResponseEvent>(OnScreengrabResponse);
|
||||||
|
|
||||||
_configuration.OnValueChanged(WhiteCVars.ACWebhook, s => _webhookUrl = s, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RequestScreengrab(ICommonSession player)
|
public void RequestScreengrab(ICommonSession player)
|
||||||
@@ -58,12 +53,15 @@ public sealed class NyaGrabSystem : EntitySystem
|
|||||||
fileContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("image/jpeg");
|
fileContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("image/jpeg");
|
||||||
content.Add(fileContent, "file", fileName);
|
content.Add(fileContent, "file", fileName);
|
||||||
|
|
||||||
|
var hwIdString = string.Join("", args.SenderSession.Channel.UserData.HWId.Select(b => b.ToString("X2")));
|
||||||
|
|
||||||
var embed = new
|
var embed = new
|
||||||
{
|
{
|
||||||
title = "📸 Скриншот игрока",
|
title = "📸 Скриншот игрока",
|
||||||
description = $"**Игрок**: {args.SenderSession.Name}\n" +
|
description = $"**Игрок**: {args.SenderSession.Name}\n" +
|
||||||
$"**UserId**: {args.SenderSession.UserId}\n" +
|
$"**UserId**: {args.SenderSession.UserId}\n" +
|
||||||
$"**IP**: {args.SenderSession.Channel.RemoteEndPoint}\n" +
|
$"**IP**: {args.SenderSession.Channel.RemoteEndPoint}\n" +
|
||||||
|
$"**HWId**: {hwIdString}\n" +
|
||||||
$"**Дата и время**: {timestamp:yyyy-MM-dd HH:mm:ss} UTC\n" +
|
$"**Дата и время**: {timestamp:yyyy-MM-dd HH:mm:ss} UTC\n" +
|
||||||
$"**Разрешение**: {image.Width}x{image.Height}\n" +
|
$"**Разрешение**: {image.Width}x{image.Height}\n" +
|
||||||
$"**Размер**: {(imagedata.Length / 1024.0):F2} KB",
|
$"**Размер**: {(imagedata.Length / 1024.0):F2} KB",
|
||||||
@@ -81,7 +79,7 @@ public sealed class NyaGrabSystem : EntitySystem
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await _httpClient.PostAsync(_webhookUrl, content);
|
await _httpClient.PostAsync(WebhookUrl, content);
|
||||||
Log.Info($"Screenshot sent to Discord for player {args.SenderSession.Name}");
|
Log.Info($"Screenshot sent to Discord for player {args.SenderSession.Name}");
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ public sealed class CheatCheckResponseEvent : EntityEventArgs
|
|||||||
public bool HasPatchMetadata;
|
public bool HasPatchMetadata;
|
||||||
public string? ReflectionOffender;
|
public string? ReflectionOffender;
|
||||||
public bool HasMoonyware;
|
public bool HasMoonyware;
|
||||||
public bool HasHarmony;
|
|
||||||
public string? IoCOffender;
|
public string? IoCOffender;
|
||||||
public string? ExtraModuleOffender;
|
public string? ExtraModuleOffender;
|
||||||
public string? CvarOffender;
|
public string? CvarOffender;
|
||||||
|
|||||||
Reference in New Issue
Block a user