Skip to content

Commit

Permalink
Patch v1.3.0
Browse files Browse the repository at this point in the history
  • Loading branch information
K4ryuu committed May 18, 2024
1 parent ee615a5 commit 5315bc1
Show file tree
Hide file tree
Showing 5 changed files with 201 additions and 23 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
-- 2024. 05. 18 - v1.3.0

- feat: Add configuration json file to allow players to bypass specific restrictions
- feat: Add database to store allowed players for a while and dont validate them all the time

-- 2024. 04. 26 - v1.2.1

- update: Updated from NET7 to NET8
Expand Down
110 changes: 87 additions & 23 deletions src/KitsuneSteamRestrict.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Core.Attributes;
using CounterStrikeSharp.API.Modules.Timers;
using CounterStrikeSharp.API.Modules.Admin;

using System.Text.Json.Serialization;
using Microsoft.Extensions.Logging;
using CounterStrikeSharp.API.Modules.Admin;

namespace KitsuneSteamRestrict;

Expand Down Expand Up @@ -49,13 +49,46 @@ public class PluginConfig : BasePluginConfig

[JsonPropertyName("BlockGameBanned")]
public bool BlockGameBanned { get; set; } = false;

[JsonPropertyName("DatabaseSettings")]
public DatabaseSettings DatabaseSettings = new DatabaseSettings();

[JsonPropertyName("ConfigVersion")]
public override int Version { get; set; } = 2;
}

public sealed class DatabaseSettings
{
[JsonPropertyName("host")]
public string Host { get; set; } = "localhost";

[JsonPropertyName("username")]
public string Username { get; set; } = "root";

[JsonPropertyName("database")]
public string Database { get; set; } = "database";

[JsonPropertyName("password")]
public string Password { get; set; } = "password";

[JsonPropertyName("port")]
public int Port { get; set; } = 3306;

[JsonPropertyName("sslmode")]
public string Sslmode { get; set; } = "none";

[JsonPropertyName("table-prefix")]
public string TablePrefix { get; set; } = "";

[JsonPropertyName("table-purge-days")]
public int TablePurgeDays { get; set; } = 30;
}

[MinimumApiVersion(198)]
[MinimumApiVersion(227)]
public class SteamRestrictPlugin : BasePlugin, IPluginConfig<PluginConfig>
{
public override string ModuleName => "Steam Restrict";
public override string ModuleVersion => "1.2.1";
public override string ModuleVersion => "1.3.0";
public override string ModuleAuthor => "K4ryuu, Cruze @ KitsuneLab";
public override string ModuleDescription => "Restrict certain players from connecting to your server.";

Expand All @@ -64,20 +97,29 @@ public class SteamRestrictPlugin : BasePlugin, IPluginConfig<PluginConfig>

private CounterStrikeSharp.API.Modules.Timers.Timer?[] g_hAuthorize = new CounterStrikeSharp.API.Modules.Timers.Timer?[65];

private BypassConfig? _bypassConfig;
public PluginConfig Config { get; set; } = new();

public void OnConfigParsed(PluginConfig config)
{
Config = config;
if (config.Version < Config.Version)
base.Logger.LogWarning("Configuration version mismatch (Expected: {0} | Current: {1})", this.Config.Version, config.Version);

if (string.IsNullOrEmpty(config.SteamWebAPI))
{
Logger.LogError("This plugin won't work because Web API is empty.");
}
base.Logger.LogError("This plugin won't work because Web API is empty.");

Config = config;
}

public override void Load(bool hotReload)
{
string bypassConfigFilePath = "bypass_config.json";
var bypassConfigService = new BypassConfigService(bypassConfigFilePath);
_bypassConfig = bypassConfigService.LoadConfig();

var databaseService = new DatabaseService(Config.DatabaseSettings);
_ = databaseService.EnsureTablesExistAsync();

RegisterListener<Listeners.OnGameServerSteamAPIActivated>(() => { g_bSteamAPIActivated = true; });
RegisterListener<Listeners.OnClientConnect>((int slot, string name, string ipAddress) => { g_hAuthorize[slot]?.Kill(); });
RegisterListener<Listeners.OnClientDisconnect>((int slot) => { g_hAuthorize[slot]?.Kill(); });
Expand All @@ -96,8 +138,7 @@ public override void Load(bool hotReload)

public HookResult OnPlayerConnectFull(EventPlayerConnectFull @event, GameEventInfo info)
{
CCSPlayerController player = @event.Userid;

CCSPlayerController? player = @event.Userid;
if (player == null)
return HookResult.Continue;

Expand Down Expand Up @@ -131,10 +172,21 @@ private void OnPlayerConnectFull(CCSPlayerController player)
if (!g_bSteamAPIActivated)
return;

nint handle = player.Handle;
ulong authorizedSteamID = player.AuthorizedSteamID.SteamId64;
nint handle = player.Handle;

var databaseService = new DatabaseService(Config.DatabaseSettings);

_ = CheckUserViolations(handle, authorizedSteamID);
Task.Run(async () =>
{
if (await databaseService.IsSteamIdAllowedAsync(authorizedSteamID))
{
Server.NextWorldUpdate(() => Logger.LogInformation($"{player.PlayerName} ({authorizedSteamID}) was allowed to join without validations because they were found in the database."));
return;
}

await CheckUserViolations(handle, authorizedSteamID);
});
}

private async Task CheckUserViolations(nint handle, ulong authorizedSteamID)
Expand Down Expand Up @@ -168,6 +220,16 @@ private async Task CheckUserViolations(nint handle, ulong authorizedSteamID)
{
Server.ExecuteCommand($"kickid {player.UserId} \"You have been kicked for not meeting the minimum requirements.\"");
}
else
{
ulong steamID = player.AuthorizedSteamID?.SteamId64 ?? 0;

if (steamID != 0)
{
var databaseService = new DatabaseService(Config.DatabaseSettings);
Task.Run(async () => await databaseService.AddAllowedUserAsync(steamID, Config.DatabaseSettings.TablePurgeDays));
}
}
}
});
}
Expand All @@ -177,21 +239,23 @@ private bool IsRestrictionViolated(CCSPlayerController player, SteamUserInfo use
if (AdminManager.PlayerHasPermissions(player, "@css/bypasspremiumcheck"))
return false;

BypassConfig bypassConfig = _bypassConfig ?? new BypassConfig();

bool isPrime = userInfo.HasPrime;
var configChecks = new[]
{
(isPrime, Config.MinimumHourPrime, userInfo.CS2Playtime),
(isPrime, Config.MinimumLevelPrime, userInfo.SteamLevel),
(isPrime, Config.MinimumCS2LevelPrime, userInfo.CS2Level),
(!isPrime, Config.MinimumHourNonPrime, userInfo.CS2Playtime),
(!isPrime, Config.MinimumLevelNonPrime, userInfo.SteamLevel),
(!isPrime, Config.MinimumCS2LevelNonPrime, userInfo.CS2Level),
(true, Config.MinimumSteamAccountAgeInDays, (DateTime.Now - userInfo.SteamAccountAge).TotalDays),
(Config.BlockPrivateProfile, 1, userInfo.IsPrivate ? 0 : 1),
(Config.BlockTradeBanned, 1, userInfo.IsTradeBanned ? 0 : 1),
(Config.BlockGameBanned, 1, userInfo.IsGameBanned ? 0 : 1),
(!string.IsNullOrEmpty(Config.SteamGroupID), 1, userInfo.IsInSteamGroup ? 1 : 0),
(Config.BlockVACBanned, 1, userInfo.IsVACBanned ? 0 : 1),
(isPrime && !bypassConfig.BypassMinimumCS2Level, Config.MinimumCS2LevelPrime, userInfo.CS2Level),
(!isPrime && !bypassConfig.BypassMinimumCS2Level, Config.MinimumCS2LevelNonPrime, userInfo.CS2Level),
(isPrime && !bypassConfig.BypassMinimumHours, Config.MinimumHourPrime, userInfo.CS2Playtime),
(!isPrime && !bypassConfig.BypassMinimumHours, Config.MinimumHourNonPrime, userInfo.CS2Playtime),
(isPrime && !bypassConfig.BypassMinimumLevel, Config.MinimumLevelPrime, userInfo.SteamLevel),
(!isPrime && !bypassConfig.BypassMinimumLevel, Config.MinimumLevelNonPrime, userInfo.SteamLevel),
(!bypassConfig.BypassMinimumSteamAccountAge, Config.MinimumSteamAccountAgeInDays, (DateTime.Now - userInfo.SteamAccountAge).TotalDays),
(Config.BlockPrivateProfile && !bypassConfig.BypassPrivateProfile, 1, userInfo.IsPrivate ? 0 : 1),
(Config.BlockTradeBanned && !bypassConfig.BypassTradeBanned, 1, userInfo.IsTradeBanned ? 0 : 1),
(Config.BlockGameBanned && !bypassConfig.BypassGameBanned, 1, userInfo.IsGameBanned ? 0 : 1),
(!string.IsNullOrEmpty(Config.SteamGroupID) && !bypassConfig.BypassSteamGroupCheck, 1, userInfo.IsInSteamGroup ? 1 : 0),
(Config.BlockVACBanned && !bypassConfig.BypassVACBanned, 1, userInfo.IsVACBanned ? 0 : 1),
};

return configChecks.Any(check => check.Item1 && check.Item2 != -1 && check.Item3 < check.Item2);
Expand Down
2 changes: 2 additions & 0 deletions src/KitsuneSteamRestrict.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
<ExcludeAssets>runtime</ExcludeAssets>
<IncludeAssets>compile; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Dapper" Version="2.1.35" />
<PackageReference Include="MySqlConnector" Version="2.3.7" />
<PackageReference Include="Newtonsoft.Json" Version="*" />
<PackageReference Include="Steamworks.NET" Version="*" />
</ItemGroup>
Expand Down
58 changes: 58 additions & 0 deletions src/Models/BypassConfigService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
using System.Text.Json;

namespace KitsuneSteamRestrict
{
public class BypassConfig
{
public ulong SteamID { get; set; }
public bool BypassMinimumCS2Level { get; set; } = false;
public bool BypassMinimumHours { get; set; } = false;
public bool BypassMinimumLevel { get; set; } = false;
public bool BypassMinimumSteamAccountAge { get; set; } = false;
public bool BypassPrivateProfile { get; set; } = false;
public bool BypassTradeBanned { get; set; } = false;
public bool BypassVACBanned { get; set; } = false;
public bool BypassSteamGroupCheck { get; set; } = false;
public bool BypassGameBanned { get; set; } = false;
}

public class BypassConfigService
{
private readonly string _configFilePath;

public BypassConfigService(string configFilePath)
{
_configFilePath = configFilePath;
}

public BypassConfig LoadConfig()
{
if (File.Exists(_configFilePath))
{
string json = File.ReadAllText(_configFilePath);
return JsonSerializer.Deserialize<BypassConfig>(json)!;
}
else
{
BypassConfig defaultConfig = new BypassConfig
{
SteamID = 76561198345583467,
BypassMinimumCS2Level = true,
BypassMinimumHours = false,
BypassMinimumLevel = true,
BypassMinimumSteamAccountAge = false,
BypassPrivateProfile = true,
BypassTradeBanned = false,
BypassVACBanned = true,
BypassSteamGroupCheck = false,
BypassGameBanned = true
};

string json = JsonSerializer.Serialize(defaultConfig, new JsonSerializerOptions { WriteIndented = true });
File.WriteAllText(_configFilePath, json);

return defaultConfig;
}
}
}
}
49 changes: 49 additions & 0 deletions src/Models/DatabaseService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using Dapper;
using KitsuneSteamRestrict;
using MySqlConnector;

public class DatabaseService
{
private readonly string _tablePrefix;
private readonly string _connectionString;

public DatabaseService(DatabaseSettings settings)
{
_tablePrefix = settings.TablePrefix;
_connectionString = $"Server={settings.Host};Port={settings.Port};Database={settings.Database};Uid={settings.Username};Pwd={settings.Password};SslMode={Enum.Parse<MySqlSslMode>(settings.Sslmode, true)};";
}

public async Task<bool> IsSteamIdAllowedAsync(ulong steamId)
{
using var connection = new MySqlConnection(_connectionString);
var result = await connection.QueryFirstOrDefaultAsync<DateTime?>(
$"SELECT `expiration_date` FROM `{_tablePrefix}allowed_users` WHERE `steam_id` = @steamId AND `expiration_date` > NOW()",
new { steamId });

return result.HasValue;
}

public async Task AddAllowedUserAsync(ulong steamId, int daysValid)
{
using var connection = new MySqlConnection(_connectionString);
await connection.ExecuteAsync(
$"INSERT INTO `{_tablePrefix}allowed_users` (`steam_id`, `expiration_date`) VALUES (@steamId, DATE_ADD(NOW(), INTERVAL @daysValid DAY))",
new { steamId, daysValid });
}

public async Task EnsureTablesExistAsync()
{
using var connection = new MySqlConnection(_connectionString);
await connection.ExecuteAsync($@"
CREATE TABLE IF NOT EXISTS `{_tablePrefix}allowed_users` (
`steam_id` BIGINT UNSIGNED PRIMARY KEY,
`expiration_date` DATETIME
)");
}

public async Task PurgeExpiredSavesAsync()
{
using var connection = new MySqlConnection(_connectionString);
await connection.ExecuteAsync($"DELETE FROM `{_tablePrefix}allowed_users` WHERE `expiration_date` < NOW()");
}
}

0 comments on commit 5315bc1

Please sign in to comment.