Compare commits

...

5 Commits

Author SHA1 Message Date
530b0ddb75 fix issue with delay on map command 2020-10-17 10:47:56 -05:00
9f16d27630 add say all (broadcast) command 2020-10-07 08:48:12 -05:00
c636cc3e74 fix issue with button detection 2020-10-02 16:45:55 -05:00
4d9356982a hide flag status for non logged in users
remove erroneous anticheat detection reason on kick
2020-10-02 08:29:20 -05:00
fa75478998 fix anticheat detection type logic 2020-10-02 08:09:38 -05:00
11 changed files with 133 additions and 54 deletions

View File

@ -331,18 +331,18 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
if (!shouldIgnoreDetection)
{
validButtonHitCount++;
}
double lastDiff = hit.TimeOffset - hit.TimeSinceLastAttack;
if (validButtonHitCount > 0 && lastDiff <= 0)
{
results.Add(new DetectionPenaltyResult()
double lastDiff = hit.TimeOffset - hit.TimeSinceLastAttack;
if (validButtonHitCount > 0 && lastDiff <= 0)
{
ClientPenalty = EFPenalty.PenaltyType.Ban,
Value = lastDiff,
HitCount = HitCount,
Type = DetectionType.Button
});
results.Add(new DetectionPenaltyResult()
{
ClientPenalty = EFPenalty.PenaltyType.Ban,
Value = lastDiff,
HitCount = HitCount,
Type = DetectionType.Button
});
}
}
#endregion

View File

@ -633,7 +633,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
try
{
if (detectionTypes[server.EndPoint].Contains(detectionType))
if (!detectionTypes[server.EndPoint].Contains(detectionType))
{
return false;
}

View File

@ -239,6 +239,42 @@ namespace SharedLibraryCore.Commands
}
}
/// <summary>
/// Prints out a message to all clients on all servers
/// </summary>
public class SayAllCommand : Command
{
public SayAllCommand(CommandConfiguration config, ITranslationLookup translationLookup) : base(config, translationLookup)
{
Name = "sayall";
Description = _translationLookup["COMMANDS_SAY_ALL_DESC"];
Alias = "sa";
Permission = Permission.Moderator;
RequiresTarget = false;
Arguments = new[]
{
new CommandArgument()
{
Name = _translationLookup["COMMANDS_ARGS_MESSAGE"],
Required = true
}
};
}
public override Task ExecuteAsync(GameEvent E)
{
string message = _translationLookup["COMMANDS_SAY_ALL_MESSAGE_FORMAT"].FormatExt(E.Origin.Name, E.Data);
foreach (var server in E.Owner.Manager.GetServers())
{
server.Broadcast(message, E.Origin);
}
E.Origin.Tell(_translationLookup["COMMANDS_SAY_SUCCESS"]);
return Task.CompletedTask;
}
}
/// <summary>
/// Temporarily bans a client
/// </summary>
@ -596,11 +632,11 @@ namespace SharedLibraryCore.Commands
public override async Task ExecuteAsync(GameEvent E)
{
var _ = !E.Origin.Masked ?
_ = !E.Origin.Masked ?
E.Owner.Broadcast($"{_translationLookup["COMMANDS_MAPROTATE"]} [^5{E.Origin.Name}^7]", E.Origin) :
E.Owner.Broadcast(_translationLookup["COMMANDS_MAPROTATE"], E.Origin);
await Task.Delay(5000);
await Task.Delay(E.Owner.Manager.GetApplicationSettings().Configuration().MapChangeDelaySeconds * 1000);
await E.Owner.ExecuteCommandAsync("map_rotate");
}
}
@ -828,21 +864,17 @@ namespace SharedLibraryCore.Commands
public override async Task ExecuteAsync(GameEvent E)
{
string newMap = E.Data.Trim().ToLower();
foreach (Map m in E.Owner.Maps)
{
if (m.Name.ToLower() == newMap || m.Alias.ToLower() == newMap)
{
E.Owner.Broadcast(_translationLookup["COMMANDS_MAP_SUCCESS"].FormatExt(m.Alias));
await Task.Delay((int)(Utilities.DefaultCommandTimeout.TotalMilliseconds / 2.0));
await E.Owner.LoadMap(m.Name);
return;
}
}
string newMap = E.Data.Trim();
int delay = E.Owner.Manager.GetApplicationSettings().Configuration().MapChangeDelaySeconds * 1000;
// todo: this can be moved into a single statement
E.Owner.Broadcast(_translationLookup["COMMANDS_MAP_UKN"].FormatExt(newMap));
await Task.Delay(5000);
var foundMap = E.Owner.Maps.FirstOrDefault(_map => _map.Name.Equals(newMap, StringComparison.InvariantCultureIgnoreCase) ||
_map.Alias.Equals(newMap, StringComparison.InvariantCultureIgnoreCase));
_ = foundMap == null ?
E.Owner.Broadcast(_translationLookup["COMMANDS_MAP_UKN"].FormatExt(newMap)) :
E.Owner.Broadcast(_translationLookup["COMMANDS_MAP_SUCCESS"].FormatExt(foundMap.Alias));
await Task.Delay(delay);
await E.Owner.LoadMap(newMap);
}
}
@ -1529,7 +1561,7 @@ namespace SharedLibraryCore.Commands
/// </summary>
public class SetGravatarCommand : Command
{
private readonly IMetaService _metaService;
private readonly IMetaService _metaService;
public SetGravatarCommand(CommandConfiguration config, ITranslationLookup translationLookup, IMetaService metaService) : base(config, translationLookup)
{

View File

@ -91,6 +91,8 @@ namespace SharedLibraryCore.Configuration
public string[] GlobalRules { get; set; } = new string[0];
[LocalizedDisplayName("WEBFRONT_CONFIGURATION_DISALLOWED_NAMES")]
public string[] DisallowedClientNames { get; set; } = new string[0];
[LocalizedDisplayName("WEBFRONT_CONFIGURATION_MAP_CHANGE_DELAY")]
public int MapChangeDelaySeconds { get; set; } = 5;
[UIHint("ServerConfiguration")]
public ServerConfiguration[] Servers { get; set; }

View File

@ -205,7 +205,18 @@ namespace SharedLibraryCore.Database
pluginDir = Path.Join(Utilities.OperatingDirectory, "..", "..", "..", "..", "BUILD", "Plugins");
}
IEnumerable<string> directoryFiles = Directory.GetFiles(pluginDir).Where(f => f.EndsWith(".dll"));
IEnumerable<string> directoryFiles = Enumerable.Empty<string>();
try
{
directoryFiles = Directory.GetFiles(pluginDir).Where(f => f.EndsWith(".dll"));
}
catch (DirectoryNotFoundException)
{
// this is just an ugly thing for unit testing
directoryFiles = Directory.GetFiles(@"X:\IW4MAdmin\Tests\ApplicationTests\bin\Debug\netcoreapp3.1").Where(f => f.EndsWith("dll"));
}
foreach (string dllPath in directoryFiles)
{

View File

@ -122,7 +122,7 @@ namespace SharedLibraryCore
/// <param name="message">Message to be sent to all players</param>
public GameEvent Broadcast(string message, EFClient sender = null)
{
string formattedMessage = string.Format(RconParser.Configuration.CommandPrefixes.Say, $"{(CustomSayEnabled && GameName == Game.IW4 ? $"{CustomSayName}: " : "")}{message.FixIW4ForwardSlash()}");
string formattedMessage = string.Format(RconParser.Configuration.CommandPrefixes.Say ?? "", $"{(CustomSayEnabled && GameName == Game.IW4 ? $"{CustomSayName}: " : "")}{message.FixIW4ForwardSlash()}");
#if DEBUG == true
Logger.WriteVerbose(message.StripColors());
#endif

View File

@ -7,6 +7,7 @@
<ItemGroup>
<PackageReference Include="FakeItEasy" Version="6.2.0" />
<PackageReference Include="FluentAssertions" Version="5.10.3" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.0" />
<PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0">

View File

@ -14,6 +14,8 @@ using SharedLibraryCore;
using ApplicationTests.Mocks;
using SharedLibraryCore.Services;
using static SharedLibraryCore.Database.Models.EFClient;
using FluentAssertions;
using FluentAssertions.Extensions;
namespace ApplicationTests
{
@ -33,11 +35,14 @@ namespace ApplicationTests
public void Setup()
{
logger = A.Fake<ILogger>();
cmdConfig = new CommandConfiguration();
serviceProvider = new ServiceCollection()
.BuildBase(new EventHandlerMock(true))
.AddSingleton(A.Fake<ClientService>())
.AddSingleton<LoadMapCommand>()
.AddSingleton<SetLevelCommand>()
.AddSingleton<RunAsCommand>()
.AddSingleton<PrivateMessageAdminsCommand>()
.BuildServiceProvider()
.SetupTestHooks();
@ -46,6 +51,8 @@ namespace ApplicationTests
transLookup = serviceProvider.GetRequiredService<ITranslationLookup>();
clientService = serviceProvider.GetRequiredService<ClientService>();
appConfig = serviceProvider.GetRequiredService<ApplicationConfiguration>();
appConfig.MapChangeDelaySeconds = 1;
cmdConfig = serviceProvider.GetRequiredService<CommandConfiguration>();
A.CallTo(() => manager.GetClientService())
.Returns(clientService);
@ -69,7 +76,7 @@ namespace ApplicationTests
[Test]
public async Task Test_RunAsFailsOnSelf()
{
var cmd = new RunAsCommand(cmdConfig, transLookup);
var cmd = serviceProvider.GetRequiredService<RunAsCommand>();
var server = serviceProvider.GetRequiredService<IW4MServer>();
var target = ClientGenerators.CreateBasicClient(server);
@ -88,7 +95,7 @@ namespace ApplicationTests
[Test]
public async Task Test_RunAsFailsOnHigherPrivilege()
{
var cmd = new RunAsCommand(cmdConfig, transLookup);
var cmd = serviceProvider.GetRequiredService<RunAsCommand>();
var server = serviceProvider.GetRequiredService<IW4MServer>();
var target = ClientGenerators.CreateBasicClient(server);
target.Level = EFClient.Permission.Administrator;
@ -111,7 +118,7 @@ namespace ApplicationTests
[Test]
public async Task Test_RunAsFailsOnSamePrivilege()
{
var cmd = new RunAsCommand(cmdConfig, transLookup);
var cmd = serviceProvider.GetRequiredService<RunAsCommand>();
var server = serviceProvider.GetRequiredService<IW4MServer>();
var target = ClientGenerators.CreateBasicClient(server);
target.Level = EFClient.Permission.Administrator;
@ -134,7 +141,7 @@ namespace ApplicationTests
[Test]
public async Task Test_RunAsFailsOnDisallowedCommand()
{
var cmd = new RunAsCommand(cmdConfig, transLookup);
var cmd = serviceProvider.GetRequiredService<RunAsCommand>();
var server = serviceProvider.GetRequiredService<IW4MServer>();
var target = ClientGenerators.CreateBasicClient(server);
target.Level = EFClient.Permission.Moderator;
@ -160,7 +167,7 @@ namespace ApplicationTests
[Test]
public async Task Test_RunAsQueuesEventAndResponse()
{
var cmd = new RunAsCommand(cmdConfig, transLookup);
var cmd = serviceProvider.GetRequiredService<RunAsCommand>();
var server = serviceProvider.GetRequiredService<IW4MServer>();
var target = ClientGenerators.CreateBasicClient(server);
target.Level = EFClient.Permission.Moderator;
@ -187,7 +194,7 @@ namespace ApplicationTests
[Test]
public async Task Test_SetLevelFailOnSelf()
{
var cmd = new SetLevelCommand(cmdConfig, transLookup, logger);
var cmd = serviceProvider.GetRequiredService<SetLevelCommand>();
var server = serviceProvider.GetRequiredService<IW4MServer>();
var target = ClientGenerators.CreateBasicClient(server);
target.Level = Permission.Owner;
@ -211,7 +218,7 @@ namespace ApplicationTests
public async Task Test_SetLevelFailWithSourcePrivilegeTooLow()
{
var server = serviceProvider.GetRequiredService<IW4MServer>();
var cmd = new SetLevelCommand(cmdConfig, transLookup, logger);
var cmd = serviceProvider.GetRequiredService<SetLevelCommand>();
var origin = ClientGenerators.CreateBasicClient(server);
origin.Level = Permission.Moderator;
var target = ClientGenerators.CreateBasicClient(server);
@ -239,7 +246,7 @@ namespace ApplicationTests
public async Task Test_SetLevelFailWithExistingOwner_AndOnlyOneOwnerAllowed()
{
var server = serviceProvider.GetRequiredService<IW4MServer>();
var cmd = new SetLevelCommand(cmdConfig, transLookup, logger);
var cmd = serviceProvider.GetRequiredService<SetLevelCommand>();
var origin = ClientGenerators.CreateBasicClient(server);
var target = ClientGenerators.CreateBasicClient(server);
target.Level = Permission.User;
@ -266,7 +273,7 @@ namespace ApplicationTests
public async Task Test_SetLevelFailWithStepPrivilegesDisabled_AndNonOwner()
{
var server = serviceProvider.GetRequiredService<IW4MServer>();
var cmd = new SetLevelCommand(cmdConfig, transLookup, logger);
var cmd = serviceProvider.GetRequiredService<SetLevelCommand>();
var origin = ClientGenerators.CreateBasicClient(server);
origin.Level = Permission.SeniorAdmin;
var target = ClientGenerators.CreateBasicClient(server);
@ -294,7 +301,7 @@ namespace ApplicationTests
public async Task Test_SetLevelFailWithStepPrivilegesEnabled_ButNewPermissionTooHigh()
{
var server = serviceProvider.GetRequiredService<IW4MServer>();
var cmd = new SetLevelCommand(cmdConfig, transLookup, logger);
var cmd = serviceProvider.GetRequiredService<SetLevelCommand>();
var origin = ClientGenerators.CreateBasicClient(server);
origin.Level = Permission.Moderator;
var target = ClientGenerators.CreateBasicClient(server);
@ -320,7 +327,7 @@ namespace ApplicationTests
public async Task Test_SetLevelFailInvalidGroup()
{
var server = serviceProvider.GetRequiredService<IW4MServer>();
var cmd = new SetLevelCommand(cmdConfig, transLookup, logger);
var cmd = serviceProvider.GetRequiredService<SetLevelCommand>();
var origin = ClientGenerators.CreateBasicClient(server);
origin.Level = Permission.Owner;
var target = ClientGenerators.CreateBasicClient(server);
@ -345,7 +352,7 @@ namespace ApplicationTests
public async Task Test_SetLevelSucceedWithNoExistingOwner_AndOnlyOneOwnerAllowed()
{
var server = serviceProvider.GetRequiredService<IW4MServer>();
var cmd = new SetLevelCommand(cmdConfig, transLookup, logger);
var cmd = serviceProvider.GetRequiredService<SetLevelCommand>();
var origin = ClientGenerators.CreateBasicClient(server);
origin.Level = Permission.Owner;
var target = ClientGenerators.CreateBasicClient(server);
@ -373,7 +380,7 @@ namespace ApplicationTests
public async Task Test_SetLevelOwnerSucceedWithMultiOwnerAllowed()
{
var server = serviceProvider.GetRequiredService<IW4MServer>();
var cmd = new SetLevelCommand(cmdConfig, transLookup, logger);
var cmd = serviceProvider.GetRequiredService<SetLevelCommand>();
var origin = ClientGenerators.CreateBasicClient(server);
origin.Level = Permission.Owner;
var target = ClientGenerators.CreateBasicClient(server);
@ -402,7 +409,7 @@ namespace ApplicationTests
public async Task Test_SetLevelOwnerSucceedWithMultiOwnerAllowed_AndSteppedPrivileges()
{
var server = serviceProvider.GetRequiredService<IW4MServer>();
var cmd = new SetLevelCommand(cmdConfig, transLookup, logger);
var cmd = serviceProvider.GetRequiredService<SetLevelCommand>();
var origin = ClientGenerators.CreateBasicClient(server);
origin.Level = Permission.Owner;
var target = ClientGenerators.CreateBasicClient(server);
@ -432,7 +439,7 @@ namespace ApplicationTests
public async Task Test_SetLevelSucceedWithSteppedPrivileges()
{
var server = serviceProvider.GetRequiredService<IW4MServer>();
var cmd = new SetLevelCommand(cmdConfig, transLookup, logger);
var cmd = serviceProvider.GetRequiredService<SetLevelCommand>();
var origin = ClientGenerators.CreateBasicClient(server);
origin.Level = Permission.Moderator;
var target = ClientGenerators.CreateBasicClient(server);
@ -461,7 +468,7 @@ namespace ApplicationTests
public async Task Test_SetLevelSucceed()
{
var server = serviceProvider.GetRequiredService<IW4MServer>();
var cmd = new SetLevelCommand(cmdConfig, transLookup, logger);
var cmd = serviceProvider.GetRequiredService<SetLevelCommand>();
var origin = ClientGenerators.CreateBasicClient(server);
origin.Level = Permission.Owner;
var target = ClientGenerators.CreateBasicClient(server);
@ -490,7 +497,7 @@ namespace ApplicationTests
public async Task Test_SetLevelSucceed_AndFindsIngameClient()
{
var server = serviceProvider.GetRequiredService<IW4MServer>();
var cmd = new SetLevelCommand(cmdConfig, transLookup, logger);
var cmd = serviceProvider.GetRequiredService<SetLevelCommand>();
var origin = ClientGenerators.CreateBasicClient(server);
origin.Level = Permission.Owner;
var databaseTarget = ClientGenerators.CreateDatabaseClient();
@ -542,14 +549,14 @@ namespace ApplicationTests
[Test]
public async Task Test_PrivateMessageAdmins_HappyPath()
{
var cmd = new PrivateMessageAdminsCommand(cmdConfig, transLookup);
var cmd = serviceProvider.GetRequiredService<PrivateMessageAdminsCommand>();
var server = serviceProvider.GetRequiredService<IW4MServer>();
var origin = ClientGenerators.CreateDatabaseClient();
origin.Level = Permission.Administrator;
origin.CurrentServer = server;
var gameEvent = EventGenerators.GenerateEvent(GameEvent.EventType.Command, "", server);
cmdConfig.Commands.Add(nameof(PrivateMessageAdminsCommand), new CommandProperties { SupportedGames = new[] { server.GameName } });
server.Clients[0] = origin;
server.Clients[1] = origin;
await cmd.ExecuteAsync(gameEvent);
@ -561,7 +568,7 @@ namespace ApplicationTests
[Test]
public async Task Test_PrivateMessageAdmins_GameNotSupported()
{
var cmd = new PrivateMessageAdminsCommand(cmdConfig, transLookup);
var cmd = serviceProvider.GetRequiredService<PrivateMessageAdminsCommand>();
var server = serviceProvider.GetRequiredService<IW4MServer>();
var origin = ClientGenerators.CreateDatabaseClient();
origin.Level = Permission.Administrator;
@ -578,5 +585,27 @@ namespace ApplicationTests
Assert.AreEqual(expectedEvents, mockEventHandler.Events.Count(_event => _event.Type == GameEvent.EventType.Tell));
}
#endregion
#region LOADMAP
[Test]
public void Test_LoadMap_WaitsAppropriateTime_BeforeExecutingCommand()
{
var cmd = serviceProvider.GetRequiredService<LoadMapCommand>();
var server = serviceProvider.GetRequiredService<IW4MServer>();
var rconParser = serviceProvider.GetRequiredService<IRConParser>();
server.Maps.Add(new Map()
{
Name = "mp_test",
Alias = "test"
});
var gameEvent = EventGenerators.GenerateEvent(GameEvent.EventType.Command, server.Maps.First().Name, server);
Func<Task> act = () => cmd.ExecuteAsync(gameEvent);
act.ExecutionTime().Should().BeCloseTo(appConfig.MapChangeDelaySeconds.Seconds(), 500.Milliseconds());
A.CallTo(() => rconParser.ExecuteCommandAsync(A<IRConConnection>.Ignored, A<string>.Ignored))
.MustHaveHappened();
}
#endregion
}
}

View File

@ -30,6 +30,10 @@ namespace ApplicationTests
var manager = A.Fake<IManager>();
var logger = A.Fake<ILogger>();
var transLookup = A.Fake<ITranslationLookup>();
A.CallTo(() => transLookup[A<string>.Ignored])
.Returns("test");
A.CallTo(() => manager.GetLogger(A<long>.Ignored))
.Returns(logger);
@ -38,7 +42,7 @@ namespace ApplicationTests
.AddSingleton<IDatabaseContextFactory, DatabaseContextFactoryMock>()
.AddSingleton(A.Fake<IRConConnectionFactory>())
.AddSingleton(A.Fake<IRConConnection>())
.AddSingleton(A.Fake<ITranslationLookup>())
.AddSingleton(transLookup)
.AddSingleton(A.Fake<IRConParser>())
.AddSingleton(A.Fake<IParserRegexFactory>())
.AddSingleton<DataFileLoader>()

View File

@ -50,7 +50,7 @@
}
</div>
}
@if (Model.ActivePenalty != null)
@if (Model.ActivePenalty != null && (Model.ActivePenalty.Type != EFPenalty.PenaltyType.Flag || ViewBag.Authorized))
{
<div class="font-weight-bold h4 mb-0 penalties-color-@Model.ActivePenalty.Type.ToString().ToLower()">
@foreach (var result in Utilities.SplitTranslationTokens(translationKey))

View File

@ -28,7 +28,7 @@
else if (match.MatchValue == "reason")
{
<span class="text-white">
@if (ViewBag.Authorized && !string.IsNullOrEmpty(Model.AutomatedOffense) && Model.PenaltyType != SharedLibraryCore.Database.Models.EFPenalty.PenaltyType.Warning)
@if (ViewBag.Authorized && !string.IsNullOrEmpty(Model.AutomatedOffense) && Model.PenaltyType != SharedLibraryCore.Database.Models.EFPenalty.PenaltyType.Warning && Model.PenaltyType != SharedLibraryCore.Database.Models.EFPenalty.PenaltyType.Kick)
{
<span>@Utilities.FormatExt(ViewBag.Localization["WEBFRONT_PROFILE_ANTICHEAT_DETECTION"], Model.AutomatedOffense)</span>
<span class="oi oi-list-rich align-top text-primary automated-penalty-info-detailed" data-penalty-id="@Model.PenaltyId" style="margin-top: 0.125rem;" title="@ViewBag.Localization["WEBFRONT_CLIENT_META_AC_METRIC"]"></span>