Promoveaza serverul
csb-steamid-validator / addons / amxmodx / scripting / csb_steamid_validator.sma
155 lines 3.8 KiB Pawn Raw Permalink History
/*
 * CSB SteamID Validator
 * Copyright (C) 2026 counter-strike-boost.com
 *
 * Validates authentication at client_authorized: rejects pending IDs past a
 * timeout, LAN/no-steam tokens, malformed STEAM_x:y:z strings and duplicate
 * SteamIDs, with a cvar to allow or kick no-steam clients.
 *
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version. It is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See <https://www.gnu.org/licenses/> for details.
 */

#include <amxmodx>

new const PLUGIN[] = "CSB SteamID Validator"
new const VERSION[] = "1.0.0"
new const AUTHOR[]  = "counter-strike-boost.com"

#define TASK_BASE 10000

new g_pEnabled, g_pAllowNoSteam, g_pPendingTimeout, g_pBlockDup

public plugin_init()
{
    register_plugin(PLUGIN, VERSION, AUTHOR)

    g_pEnabled        = register_cvar("csb_steamid_enabled", "1")
    g_pAllowNoSteam   = register_cvar("csb_steamid_allow_nosteam", "0")
    g_pPendingTimeout = register_cvar("csb_steamid_pending_timeout", "30")
    g_pBlockDup       = register_cvar("csb_steamid_block_dup", "1")
}

public client_authorized(id)
{
    if (!get_pcvar_num(g_pEnabled) || is_user_bot(id) || is_user_hltv(id))
        return

    new authid[40]
    get_user_authid(id, authid, charsmax(authid))

    // still resolving -> re-check after the timeout
    if (!authid[0] || equal(authid, "STEAM_ID_PENDING"))
    {
        set_task(float(get_pcvar_num(g_pPendingTimeout)), "taskPending", TASK_BASE + id)
        return
    }

    validate(id, authid)
}

public taskPending(taskid)
{
    new id = taskid - TASK_BASE

    if (id < 1 || id > 32 || !is_user_connected(id))
        return

    new authid[40]
    get_user_authid(id, authid, charsmax(authid))

    validate(id, authid)
}

validate(id, const authid[])
{
    // still pending or an obvious no-steam / LAN token
    if (!authid[0]
        || equal(authid, "STEAM_ID_PENDING")
        || equal(authid, "VALVE_ID_PENDING")
        || equal(authid, "STEAM_ID_LAN")
        || equal(authid, "VALVE_ID_LAN")
        || equal(authid, "HLTV"))
    {
        if (get_pcvar_num(g_pAllowNoSteam))
            return

        drop(id, authid, "no valid Steam ID")
        return
    }

    if (!isSteamFormat(authid))
    {
        if (get_pcvar_num(g_pAllowNoSteam))
            return

        drop(id, authid, "malformed Steam ID")
        return
    }

    if (get_pcvar_num(g_pBlockDup) && isDuplicate(id, authid))
    {
        drop(id, authid, "duplicate Steam ID")
        return
    }
}

bool:isSteamFormat(const s[])
{
    // expect STEAM_x:y:z
    if (strlen(s) < 11)
        return false

    if (!equal(s, "STEAM_", 6))
        return false

    new colons = 0

    for (new i = 6; s[i]; i++)
    {
        if (s[i] == ':')
            colons++
        else if (s[i] < '0' || s[i] > '9')
            return false
    }

    return colons == 2
}

bool:isDuplicate(id, const authid[])
{
    new players[32], num
    get_players(players, num)

    for (new i = 0; i < num; i++)
    {
        new pid = players[i]

        if (pid == id || is_user_bot(pid) || is_user_hltv(pid))
            continue

        new other[40]
        get_user_authid(pid, other, charsmax(other))

        if (equal(other, authid))
            return true
    }

    return false
}

drop(id, const authid[], const reason[])
{
    new name[32], ip[24]
    get_user_name(id, name, charsmax(name))
    get_user_ip(id, ip, charsmax(ip), 1)

    log_amx("[CSB SteamID] rejecting %s (%s) <%s>: %s", name, ip, authid, reason)

    server_cmd("kick #%d ^"CSB: %s^"", get_user_userid(id), reason)
    server_exec()
}