Skip to main content

Ban System

The ACHCE Client ban system architecture provides a blueprint for real-time access control through Firebase Realtime Database integration. The design combines hardware-based identification with automatic session tracking to ensure banned players cannot access protected servers.
Implementation Status: The current version (1.0.0) implements basic session tracking in Firebase (adding/removing player IP on connect/disconnect). The ban checking logic, hardware ID integration, and administrative ban management features described in this document represent the planned architecture for future releases.
This document describes the complete ban system architecture, including both the currently implemented session tracking foundation and planned ban enforcement features.

Architecture Overview

The ban system consists of three key components:

Database Structure

Firebase Realtime Database organizes data in a JSON tree:
{
  "PlayerIpList": {
    "randomSessionName1": {
      "IP": "203.0.113.45",
      "HardwareID": "abc123...",
      "FirstSeen": "2024-03-15T14:30:00Z",
      "LastSeen": "2024-03-15T15:45:00Z"
    },
    "randomSessionName2": {
      "IP": "198.51.100.78",
      "HardwareID": "def456...",
      "FirstSeen": "2024-03-15T14:35:00Z",
      "LastSeen": "2024-03-15T15:50:00Z"
    }
  },
  "BannedPlayers": {
    "abc123...": {
      "HardwareID": "abc123...",
      "Reason": "Using injector tools",
      "BanDate": "2024-03-15T15:00:00Z",
      "IsPermanent": true,
      "BannedBy": "admin"
    }
  }
}
The PlayerIpList tracks active sessions, while BannedPlayers stores permanent ban records indexed by hardware ID.

Firebase Configuration

Connection Setup

The current implementation in Form1.cs demonstrates Firebase initialization:
using FireSharp.Config;
using FireSharp.Interfaces;

// Firebase configuration
IFirebaseConfig fcon = new FirebaseConfig()
{
    AuthSecret = "", // Firebase authentication token
    BasePath = ""    // Firebase database URL (e.g., https://your-app.firebaseio.com/)
};

IFirebaseClient client; // Firebase client instance

public void Form1_Load(object sender, EventArgs e)
{
    try
    {
        // Initialize Firebase client
        client = new FireSharp.FirebaseClient(fcon);
    }
    catch
    {
        MessageBox.Show("there was problem in the internet.");
    }
    
    // Continue with session registration...
}
Never hardcode Firebase credentials in production code. Use configuration files, environment variables, or secure key management systems.

Secure Configuration Example

using System.Configuration;

public class SecureFirebaseConfig
{
    public static IFirebaseConfig GetConfiguration()
    {
        return new FirebaseConfig()
        {
            AuthSecret = ConfigurationManager.AppSettings["FirebaseAuthSecret"],
            BasePath = ConfigurationManager.AppSettings["FirebaseBasePath"]
        };
    }
}

// In App.config:
// <appSettings>
//   <add key="FirebaseAuthSecret" value="your-secret-here"/>
//   <add key="FirebaseBasePath" value="https://your-app.firebaseio.com/"/>
// </appSettings>

Session Management

Session Registration

When a player launches ACHCE Client, their session is registered in the database:
// Form1.cs - Current implementation
private void PlayAcON()
{
    Player ply = new Player()
    {
        IP = IpPlayer,
    };
    
    // Register player session in Firebase
    var setter = client.Set("PlayerIpList/" + randomName, ply);
}

Enhanced Session Registration

With hardware identification and additional tracking:
private async Task<bool> RegisterPlayerSession()
{
    try
    {
        // Collect player information
        string ipAddress = GetPlayerIP();
        string hardwareId = GetHardwareFingerprint();
        
        // Check ban status first
        if (await IsPlayerBanned(hardwareId))
        {
            return false; // Player is banned, deny access
        }
        
        // Create player session object
        Player player = new Player()
        {
            IP = ipAddress,
            HardwareID = hardwareId,
            FirstSeen = DateTime.UtcNow,
            LastSeen = DateTime.UtcNow,
            IsBanned = false
        };
        
        // Register in Firebase
        var response = await client.SetAsync("PlayerIpList/" + randomName, player);
        
        if (response.StatusCode == System.Net.HttpStatusCode.OK)
        {
            return true; // Session registered successfully
        }
        
        return false;
    }
    catch (Exception ex)
    {
        LogError($"Session registration failed: {ex.Message}");
        return false;
    }
}
Always check ban status before registering the session to prevent banned players from consuming database resources.

Session Cleanup

The current implementation handles cleanup when the application closes:
// Form1.cs - Cleanup on form close
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
    // Remove player from active sessions
    var result = client.Delete("PlayerIpList/" + randomName);
    MessageBox.Show("data deleted successfully"); // Remove in production
}

Robust Cleanup Implementation

private async Task CleanupPlayerSession()
{
    try
    {
        if (!string.IsNullOrEmpty(randomName))
        {
            // Update last seen timestamp before removal
            await client.UpdateAsync("PlayerIpList/" + randomName, 
                new { LastSeen = DateTime.UtcNow });
            
            // Remove from active sessions
            var response = await client.DeleteAsync("PlayerIpList/" + randomName);
            
            if (response.StatusCode == System.Net.HttpStatusCode.OK)
            {
                LogInfo("Session cleaned up successfully");
            }
        }
    }
    catch (Exception ex)
    {
        LogError($"Session cleanup failed: {ex.Message}");
    }
}

// Ensure cleanup on all exit scenarios
protected override void OnFormClosing(FormClosingEventArgs e)
{
    base.OnFormClosing(e);
    CleanupPlayerSession().Wait();
}
The cleanup mechanism ensures that the active session list remains accurate, showing only currently connected players.

Random Session Names

ACHCE Client generates random session names to identify players without manual registration:
// GenerateRandomNames.cs - Current implementation
public class GenerateRandomNames
{
    public string GenerateRandomName(Random rand)
    {
        // Name length: 4-9 characters
        int nameLength = rand.Next(4, 10);

        // Allowed characters: lowercase letters
        char[] allowedChars = "abcdefghijklmnopqrstuvwxyz".ToCharArray();

        // Build random name
        char[] name = new char[nameLength];
        for (int i = 0; i < nameLength; i++)
        {
            name[i] = allowedChars[rand.Next(0, allowedChars.Length)];
        }

        return new string(name);
    }
}

Usage in Session Management

// Form1.cs - Generate session name
GenerateRandomNames names = new GenerateRandomNames();
Random rand = new Random();
randomName = names.GenerateRandomName(rand);
Random session names provide anonymous tracking without requiring user accounts. The hardware ID serves as the permanent identifier for ban enforcement.

Enhanced Session Name Generation

For better collision avoidance and debugging:
public class EnhancedSessionNames
{
    public string GenerateSessionName()
    {
        // Combine timestamp with random characters
        string timestamp = DateTime.UtcNow.ToString("yyyyMMddHHmmss");
        string randomPart = GenerateRandomString(6);
        
        return $"session_{timestamp}_{randomPart}";
    }
    
    private string GenerateRandomString(int length)
    {
        const string chars = "abcdefghijklmnopqrstuvwxyz0123456789";
        Random random = new Random();
        
        return new string(Enumerable.Repeat(chars, length)
            .Select(s => s[random.Next(s.Length)]).ToArray());
    }
}

Ban Enforcement

Checking Ban Status

Before allowing game access, verify the hardware ID against the ban database:
public class BanEnforcement
{
    private IFirebaseClient client;
    
    public BanEnforcement(IFirebaseClient firebaseClient)
    {
        client = firebaseClient;
    }
    
    /// <summary>
    /// Checks if a player is banned based on hardware ID
    /// </summary>
    public async Task<bool> IsPlayerBanned(string hardwareId)
    {
        try
        {
            var response = await client.GetAsync($"BannedPlayers/{hardwareId}");
            
            // If response is not null, player is banned
            if (response.Body != "null")
            {
                return true;
            }
            
            return false;
        }
        catch (Exception ex)
        {
            LogError($"Ban check failed: {ex.Message}");
            // Fail-safe: deny access if we can't verify ban status
            return true;
        }
    }
    
    /// <summary>
    /// Retrieves detailed ban information
    /// </summary>
    public async Task<BanRecord> GetBanDetails(string hardwareId)
    {
        try
        {
            var response = await client.GetAsync($"BannedPlayers/{hardwareId}");
            
            if (response.Body != "null")
            {
                return response.ResultAs<BanRecord>();
            }
            
            return null; // Not banned
        }
        catch (Exception ex)
        {
            LogError($"Failed to retrieve ban details: {ex.Message}");
            return null;
        }
    }
}

Ban Record Structure

public class BanRecord
{
    public string HardwareID { get; set; }
    public string IP { get; set; } // For reference only
    public string Reason { get; set; }
    public DateTime BanDate { get; set; }
    public bool IsPermanent { get; set; }
    public DateTime? ExpiryDate { get; set; }
    public string BannedBy { get; set; }
    public string Evidence { get; set; } // Screenshot URL, log file, etc.
}

Displaying Ban Information

private async Task HandleBannedPlayer(string hardwareId)
{
    BanEnforcement banEnforcement = new BanEnforcement(client);
    BanRecord ban = await banEnforcement.GetBanDetails(hardwareId);
    
    if (ban != null)
    {
        string message;
        
        if (ban.IsPermanent)
        {
            message = $"Your account has been permanently banned.\n\n" +
                     $"Reason: {ban.Reason}\n" +
                     $"Ban Date: {ban.BanDate:yyyy-MM-dd HH:mm}\n" +
                     $"Banned By: {ban.BannedBy}\n\n" +
                     $"This ban cannot be appealed.";
        }
        else
        {
            TimeSpan remaining = ban.ExpiryDate.Value - DateTime.UtcNow;
            
            message = $"Your account is temporarily banned.\n\n" +
                     $"Reason: {ban.Reason}\n" +
                     $"Ban Date: {ban.BanDate:yyyy-MM-dd HH:mm}\n" +
                     $"Expires: {ban.ExpiryDate:yyyy-MM-dd HH:mm}\n" +
                     $"Time Remaining: {remaining.Days} days, {remaining.Hours} hours\n" +
                     $"Banned By: {ban.BannedBy}";
        }
        
        MessageBox.Show(message, "Access Denied", 
            MessageBoxButtons.OK, MessageBoxIcon.Error);
        
        Application.Exit();
    }
}
Always terminate the application immediately after displaying a ban message to prevent any potential bypass attempts.

Administrative Functions

Banning a Player

Admin tools can add players to the ban database:
public class BanAdministration
{
    private IFirebaseClient client;
    
    public BanAdministration(IFirebaseClient firebaseClient)
    {
        client = firebaseClient;
    }
    
    /// <summary>
    /// Adds a player to the ban list
    /// </summary>
    public async Task<bool> BanPlayer(string hardwareId, string reason, 
        string bannedBy, bool isPermanent = true, DateTime? expiryDate = null)
    {
        try
        {
            BanRecord ban = new BanRecord()
            {
                HardwareID = hardwareId,
                Reason = reason,
                BanDate = DateTime.UtcNow,
                IsPermanent = isPermanent,
                ExpiryDate = expiryDate,
                BannedBy = bannedBy
            };
            
            // Add to ban database
            var response = await client.SetAsync($"BannedPlayers/{hardwareId}", ban);
            
            // Kick active session if player is currently connected
            await KickActiveSession(hardwareId);
            
            return response.StatusCode == System.Net.HttpStatusCode.OK;
        }
        catch (Exception ex)
        {
            LogError($"Failed to ban player: {ex.Message}");
            return false;
        }
    }
    
    /// <summary>
    /// Removes a player from the ban list
    /// </summary>
    public async Task<bool> UnbanPlayer(string hardwareId)
    {
        try
        {
            var response = await client.DeleteAsync($"BannedPlayers/{hardwareId}");
            return response.StatusCode == System.Net.HttpStatusCode.OK;
        }
        catch (Exception ex)
        {
            LogError($"Failed to unban player: {ex.Message}");
            return false;
        }
    }
    
    /// <summary>
    /// Finds and kicks active sessions for a hardware ID
    /// </summary>
    private async Task KickActiveSession(string hardwareId)
    {
        try
        {
            // Query all active sessions
            var response = await client.GetAsync("PlayerIpList");
            
            if (response.Body != "null")
            {
                var sessions = response.ResultAs<Dictionary<string, Player>>();
                
                // Find sessions matching hardware ID
                foreach (var session in sessions)
                {
                    if (session.Value.HardwareID == hardwareId)
                    {
                        // Remove session
                        await client.DeleteAsync($"PlayerIpList/{session.Key}");
                    }
                }
            }
        }
        catch (Exception ex)
        {
            LogError($"Failed to kick active session: {ex.Message}");
        }
    }
}
When banning a player, immediately kick their active session to prevent them from continuing to play until they restart the client.

Temporary Bans

Implement time-based ban expiration:
public class TemporaryBanManager
{
    /// <summary>
    /// Checks if a temporary ban has expired
    /// </summary>
    public bool IsBanExpired(BanRecord ban)
    {
        if (ban.IsPermanent)
        {
            return false; // Permanent bans never expire
        }
        
        if (ban.ExpiryDate.HasValue)
        {
            return DateTime.UtcNow >= ban.ExpiryDate.Value;
        }
        
        return true; // No expiry date set, consider expired
    }
    
    /// <summary>
    /// Cleans up expired bans from database
    /// </summary>
    public async Task CleanupExpiredBans(IFirebaseClient client)
    {
        try
        {
            var response = await client.GetAsync("BannedPlayers");
            
            if (response.Body != "null")
            {
                var bans = response.ResultAs<Dictionary<string, BanRecord>>();
                
                foreach (var kvp in bans)
                {
                    if (IsBanExpired(kvp.Value))
                    {
                        // Remove expired ban
                        await client.DeleteAsync($"BannedPlayers/{kvp.Key}");
                        LogInfo($"Removed expired ban for: {kvp.Key}");
                    }
                }
            }
        }
        catch (Exception ex)
        {
            LogError($"Failed to cleanup expired bans: {ex.Message}");
        }
    }
}

Ban History Tracking

Maintain a history of all bans for auditing:
public class BanHistory
{
    /// <summary>
    /// Records ban in history database
    /// </summary>
    public async Task RecordBanHistory(IFirebaseClient client, BanRecord ban)
    {
        try
        {
            string historyKey = $"{ban.HardwareID}_{DateTime.UtcNow.Ticks}";
            
            await client.SetAsync($"BanHistory/{historyKey}", ban);
        }
        catch (Exception ex)
        {
            LogError($"Failed to record ban history: {ex.Message}");
        }
    }
    
    /// <summary>
    /// Retrieves ban history for a hardware ID
    /// </summary>
    public async Task<List<BanRecord>> GetPlayerBanHistory(
        IFirebaseClient client, string hardwareId)
    {
        try
        {
            var response = await client.GetAsync("BanHistory");
            
            if (response.Body != "null")
            {
                var allHistory = response.ResultAs<Dictionary<string, BanRecord>>();
                
                return allHistory.Values
                    .Where(b => b.HardwareID == hardwareId)
                    .OrderByDescending(b => b.BanDate)
                    .ToList();
            }
            
            return new List<BanRecord>();
        }
        catch (Exception ex)
        {
            LogError($"Failed to retrieve ban history: {ex.Message}");
            return new List<BanRecord>();
        }
    }
}

Active Session Monitoring

Real-Time Session Tracking

Monitor active players in real-time:
public class SessionMonitor
{
    private IFirebaseClient client;
    
    public SessionMonitor(IFirebaseClient firebaseClient)
    {
        client = firebaseClient;
    }
    
    /// <summary>
    /// Gets list of currently active sessions
    /// </summary>
    public async Task<List<PlayerSession>> GetActiveSessions()
    {
        try
        {
            var response = await client.GetAsync("PlayerIpList");
            
            if (response.Body != "null")
            {
                var sessions = response.ResultAs<Dictionary<string, Player>>();
                
                return sessions.Select(kvp => new PlayerSession
                {
                    SessionName = kvp.Key,
                    Player = kvp.Value
                }).ToList();
            }
            
            return new List<PlayerSession>();
        }
        catch (Exception ex)
        {
            LogError($"Failed to retrieve active sessions: {ex.Message}");
            return new List<PlayerSession>();
        }
    }
    
    /// <summary>
    /// Gets count of active players
    /// </summary>
    public async Task<int> GetActivePlayerCount()
    {
        var sessions = await GetActiveSessions();
        return sessions.Count;
    }
}

public class PlayerSession
{
    public string SessionName { get; set; }
    public Player Player { get; set; }
}

Heartbeat System

Keep session data fresh with periodic updates:
public class SessionHeartbeat
{
    private Timer heartbeatTimer;
    private IFirebaseClient client;
    private string sessionName;
    
    public void StartHeartbeat(IFirebaseClient client, string sessionName)
    {
        this.client = client;
        this.sessionName = sessionName;
        
        // Update every 60 seconds
        heartbeatTimer = new Timer();
        heartbeatTimer.Interval = 60000;
        heartbeatTimer.Tick += UpdateHeartbeat;
        heartbeatTimer.Start();
    }
    
    private async void UpdateHeartbeat(object sender, EventArgs e)
    {
        try
        {
            // Update LastSeen timestamp
            await client.UpdateAsync($"PlayerIpList/{sessionName}", 
                new { LastSeen = DateTime.UtcNow });
        }
        catch (Exception ex)
        {
            LogError($"Heartbeat update failed: {ex.Message}");
        }
    }
    
    public void StopHeartbeat()
    {
        heartbeatTimer?.Stop();
        heartbeatTimer?.Dispose();
    }
}
Regular heartbeat updates help identify stale sessions that weren’t properly cleaned up due to crashes or network issues.

Database Security Rules

Firebase security rules control access to data:
{
  "rules": {
    "PlayerIpList": {
      ".read": "auth != null",
      ".write": "auth != null",
      "$sessionId": {
        ".validate": "newData.hasChildren(['IP', 'HardwareID'])"
      }
    },
    "BannedPlayers": {
      ".read": "auth != null",
      ".write": "auth.uid === 'admin-uid'",
      "$hardwareId": {
        ".validate": "newData.hasChildren(['HardwareID', 'Reason', 'BanDate'])"
      }
    },
    "BanHistory": {
      ".read": "auth.uid === 'admin-uid'",
      ".write": "auth.uid === 'admin-uid'"
    }
  }
}
Always implement proper security rules in production. The default rules allow anyone with the database URL to read/write data.

Error Handling

Robust error handling for database operations:
public class DatabaseErrorHandler
{
    public async Task<T> ExecuteWithRetry<T>(
        Func<Task<T>> operation, 
        int maxRetries = 3)
    {
        int attempts = 0;
        
        while (attempts < maxRetries)
        {
            try
            {
                return await operation();
            }
            catch (Exception ex)
            {
                attempts++;
                
                if (attempts >= maxRetries)
                {
                    LogError($"Operation failed after {maxRetries} attempts: {ex.Message}");
                    throw;
                }
                
                // Wait before retrying (exponential backoff)
                await Task.Delay(1000 * attempts);
            }
        }
        
        throw new Exception("Operation failed");
    }
}

// Usage example:
var errorHandler = new DatabaseErrorHandler();
var result = await errorHandler.ExecuteWithRetry(async () =>
{
    return await client.GetAsync("BannedPlayers/hardwareId");
});

Performance Considerations

Batch Operations

Process multiple bans efficiently:
public async Task BanMultiplePlayers(List<BanRequest> banRequests)
{
    var tasks = banRequests.Select(request => 
        BanPlayer(request.HardwareId, request.Reason, request.BannedBy));
    
    await Task.WhenAll(tasks);
}

Caching

Cache ban status locally to reduce database queries:
public class BanCache
{
    private Dictionary<string, CachedBanStatus> cache = 
        new Dictionary<string, CachedBanStatus>();
    private TimeSpan cacheExpiry = TimeSpan.FromMinutes(5);
    
    public bool? GetCachedBanStatus(string hardwareId)
    {
        if (cache.TryGetValue(hardwareId, out var cached))
        {
            if (DateTime.UtcNow - cached.Timestamp < cacheExpiry)
            {
                return cached.IsBanned;
            }
        }
        
        return null; // Not in cache or expired
    }
    
    public void UpdateCache(string hardwareId, bool isBanned)
    {
        cache[hardwareId] = new CachedBanStatus
        {
            IsBanned = isBanned,
            Timestamp = DateTime.UtcNow
        };
    }
}

private class CachedBanStatus
{
    public bool IsBanned { get; set; }
    public DateTime Timestamp { get; set; }
}

Summary

The ACHCE Client ban system provides:
  • Real-Time Enforcement: Immediate ban checking via Firebase
  • Hardware-Based Tracking: Bans persist across IP changes
  • Automatic Session Management: Players registered and cleaned up automatically
  • Administrative Control: Tools for banning, unbanning, and monitoring
  • Temporary Ban Support: Time-based ban expiration
  • Session Monitoring: Real-time visibility into active players
The implementation ensures that:
  1. Banned players cannot access protected servers
  2. Session data remains accurate and current
  3. Administrators have full control over ban management
  4. All operations are logged for auditing
Combine the ban system with behavior analysis and cheat detection to automatically flag suspicious activity for admin review before issuing bans.

Build docs developers (and LLMs) love