372 lines
11 KiB
SourcePawn
372 lines
11 KiB
SourcePawn
//----------------------------------------------------------------------------------------------------
|
|
// Leader3 whitelist: players allowed to self-assign leader without a vote or admin flags.
|
|
// Stored in the SourceMod database ("sourcemod" config when defined, else storage-local).
|
|
//----------------------------------------------------------------------------------------------------
|
|
|
|
void Whitelist_OnPluginStart()
|
|
{
|
|
char conf[64];
|
|
strcopy(conf, sizeof(conf), SQL_CheckConfig("sourcemod") ? "sourcemod" : "storage-local");
|
|
Database.Connect(Whitelist_OnDBConnected, conf);
|
|
}
|
|
|
|
public void Whitelist_OnDBConnected(Database db, const char[] error, any data)
|
|
{
|
|
if (db == null)
|
|
{
|
|
LogError("[Leader3] Whitelist database connection failed: %s", error);
|
|
return;
|
|
}
|
|
|
|
g_hWhitelistDB = db;
|
|
g_hWhitelistDB.SetCharset("utf8");
|
|
|
|
g_hWhitelistDB.Query(Whitelist_OnTableCreated,
|
|
"CREATE TABLE IF NOT EXISTS leader_whitelist ("
|
|
... "steam_id VARCHAR(32) NOT NULL PRIMARY KEY, "
|
|
... "name VARCHAR(64) NOT NULL DEFAULT '', "
|
|
... "added_by VARCHAR(96) NOT NULL DEFAULT '', "
|
|
... "added_at INTEGER NOT NULL DEFAULT 0)");
|
|
}
|
|
|
|
public void Whitelist_OnTableCreated(Database db, DBResultSet results, const char[] error, any data)
|
|
{
|
|
if (results == null)
|
|
{
|
|
LogError("[Leader3] Failed to create leader_whitelist table: %s", error);
|
|
delete g_hWhitelistDB;
|
|
return;
|
|
}
|
|
|
|
// Late load / slow connect: check everyone already on.
|
|
for (int i = 1; i <= MaxClients; i++)
|
|
{
|
|
if (IsClientInGame(i) && IsClientAuthorized(i))
|
|
Whitelist_CheckClient(i);
|
|
}
|
|
}
|
|
|
|
void Whitelist_CheckClient(int client)
|
|
{
|
|
g_bLeaderWhitelisted[client] = false;
|
|
|
|
char auth[32];
|
|
if (g_hWhitelistDB == null || IsFakeClient(client) || !GetClientAuthId(client, AuthId_Steam2, auth, sizeof(auth)))
|
|
return;
|
|
|
|
char query[128];
|
|
g_hWhitelistDB.Format(query, sizeof(query), "SELECT 1 FROM leader_whitelist WHERE steam_id = '%s'", auth);
|
|
g_hWhitelistDB.Query(Whitelist_OnCheckDone, query, GetClientUserId(client));
|
|
}
|
|
|
|
public void Whitelist_OnCheckDone(Database db, DBResultSet results, const char[] error, any userid)
|
|
{
|
|
if (results == null)
|
|
{
|
|
LogError("[Leader3] Whitelist lookup failed: %s", error);
|
|
return;
|
|
}
|
|
|
|
int client = GetClientOfUserId(userid);
|
|
if (client > 0)
|
|
g_bLeaderWhitelisted[client] = results.FetchRow();
|
|
}
|
|
|
|
bool Whitelist_IsWhitelisted(int client)
|
|
{
|
|
return client >= 1 && client <= MaxClients && g_bLeaderWhitelisted[client];
|
|
}
|
|
|
|
void Whitelist_Add(int admin, int target)
|
|
{
|
|
if (g_hWhitelistDB == null)
|
|
{
|
|
ReplyToCommand(admin, "%s The whitelist database is not available.", PREFIX_PLAIN);
|
|
return;
|
|
}
|
|
|
|
char auth[32];
|
|
if (!GetClientAuthId(target, AuthId_Steam2, auth, sizeof(auth)))
|
|
{
|
|
ReplyToCommand(admin, "%s %N is not authorized with Steam yet, try again shortly.", PREFIX_PLAIN, target);
|
|
return;
|
|
}
|
|
|
|
if (g_bLeaderWhitelisted[target])
|
|
{
|
|
ReplyToCommand(admin, "%s %N is already on the leader whitelist.", PREFIX_PLAIN, target);
|
|
return;
|
|
}
|
|
|
|
char name[MAX_NAME_LENGTH], adminAuth[96];
|
|
GetClientName(target, name, sizeof(name));
|
|
if (admin > 0)
|
|
GetClientAuthId(admin, AuthId_Steam2, adminAuth, sizeof(adminAuth));
|
|
else
|
|
strcopy(adminAuth, sizeof(adminAuth), "CONSOLE");
|
|
|
|
char query[512];
|
|
g_hWhitelistDB.Format(query, sizeof(query),
|
|
"REPLACE INTO leader_whitelist (steam_id, name, added_by, added_at) VALUES ('%s', '%s', '%s', %d)",
|
|
auth, name, adminAuth, GetTime());
|
|
g_hWhitelistDB.Query(Whitelist_OnWriteDone, query);
|
|
|
|
g_bLeaderWhitelisted[target] = true;
|
|
|
|
ReplyToCommand(admin, "%s Added %N (%s) to the leader whitelist.", PREFIX_PLAIN, target, auth);
|
|
PrintToChat(target, "%sYou are now on the \x04leader whitelist\x01! Type \x04!leader\x01 to lead at any time.", PREFIX);
|
|
LogAction(admin, target, "\"%L\" added \"%L\" to the leader whitelist", admin, target);
|
|
}
|
|
|
|
// Normalize a typed SteamID to canonical upper-case Steam2 form (STEAM_X:Y:Z).
|
|
// The steam_id column comparison is case-sensitive, so lower-case input must not reach the DB.
|
|
static bool Whitelist_NormalizeSteam2(const char[] input, char[] auth, int maxlen)
|
|
{
|
|
strcopy(auth, maxlen, input);
|
|
for (int i = 0; auth[i] != '\0'; i++)
|
|
auth[i] = CharToUpper(auth[i]);
|
|
|
|
if (StrContains(auth, "STEAM_", true) != 0)
|
|
return false;
|
|
if (!IsCharNumeric(auth[6]) || auth[7] != ':' || (auth[8] != '0' && auth[8] != '1') || auth[9] != ':' || !IsCharNumeric(auth[10]))
|
|
return false;
|
|
|
|
for (int i = 11; auth[i] != '\0'; i++)
|
|
{
|
|
if (!IsCharNumeric(auth[i]))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// Add a possibly offline player by SteamID (sm_addleaderwhitelist STEAM_0:X:XXXX [name]).
|
|
void Whitelist_AddAuth(int admin, const char[] authArg, const char[] name)
|
|
{
|
|
if (g_hWhitelistDB == null)
|
|
{
|
|
ReplyToCommand(admin, "%s The whitelist database is not available.", PREFIX_PLAIN);
|
|
return;
|
|
}
|
|
|
|
char auth[32];
|
|
if (!Whitelist_NormalizeSteam2(authArg, auth, sizeof(auth)))
|
|
{
|
|
ReplyToCommand(admin, "%s '%s' is not a valid SteamID (expected STEAM_0:X:XXXX).", PREFIX_PLAIN, authArg);
|
|
return;
|
|
}
|
|
|
|
char adminAuth[96];
|
|
if (admin > 0)
|
|
GetClientAuthId(admin, AuthId_Steam2, adminAuth, sizeof(adminAuth));
|
|
else
|
|
strcopy(adminAuth, sizeof(adminAuth), "CONSOLE");
|
|
|
|
char query[512];
|
|
g_hWhitelistDB.Format(query, sizeof(query),
|
|
"REPLACE INTO leader_whitelist (steam_id, name, added_by, added_at) VALUES ('%s', '%s', '%s', %d)",
|
|
auth, name, adminAuth, GetTime());
|
|
g_hWhitelistDB.Query(Whitelist_OnWriteDone, query);
|
|
|
|
// Update the cache should that player be connected under this ID.
|
|
char clientAuth[32];
|
|
for (int i = 1; i <= MaxClients; i++)
|
|
{
|
|
if (!g_bLeaderWhitelisted[i] && IsClientInGame(i) && !IsFakeClient(i)
|
|
&& GetClientAuthId(i, AuthId_Steam2, clientAuth, sizeof(clientAuth))
|
|
&& StrEqual(auth, clientAuth))
|
|
{
|
|
g_bLeaderWhitelisted[i] = true;
|
|
PrintToChat(i, "%sYou are now on the \x04leader whitelist\x01! Type \x04!leader\x01 to lead at any time.", PREFIX);
|
|
}
|
|
}
|
|
|
|
ReplyToCommand(admin, "%s Added %s to the leader whitelist.", PREFIX_PLAIN, auth);
|
|
LogAction(admin, -1, "\"%L\" added \"%s\" to the leader whitelist", admin, auth);
|
|
}
|
|
|
|
// Remove a connected client from the whitelist. Returns true if they were on it.
|
|
bool Whitelist_Remove(int admin, int target)
|
|
{
|
|
if (!g_bLeaderWhitelisted[target])
|
|
return false;
|
|
|
|
g_bLeaderWhitelisted[target] = false;
|
|
|
|
char auth[32];
|
|
if (GetClientAuthId(target, AuthId_Steam2, auth, sizeof(auth)))
|
|
Whitelist_DeleteAuth(auth);
|
|
|
|
ReplyToCommand(admin, "%s Removed %N from the leader whitelist.", PREFIX_PLAIN, target);
|
|
LogAction(admin, target, "\"%L\" removed \"%L\" from the leader whitelist", admin, target);
|
|
return true;
|
|
}
|
|
|
|
// Remove an offline player by SteamID (sm_removeleaderwhitelist STEAM_0:X:XXXX).
|
|
void Whitelist_RemoveAuth(int admin, const char[] authArg)
|
|
{
|
|
if (g_hWhitelistDB == null)
|
|
{
|
|
ReplyToCommand(admin, "%s The whitelist database is not available.", PREFIX_PLAIN);
|
|
return;
|
|
}
|
|
|
|
char auth[32];
|
|
if (!Whitelist_NormalizeSteam2(authArg, auth, sizeof(auth)))
|
|
{
|
|
ReplyToCommand(admin, "%s '%s' is not a valid SteamID (expected STEAM_0:X:XXXX).", PREFIX_PLAIN, authArg);
|
|
return;
|
|
}
|
|
|
|
Whitelist_DeleteAuth(auth);
|
|
|
|
// Clear the cache should that player be connected under this ID.
|
|
char clientAuth[32];
|
|
for (int i = 1; i <= MaxClients; i++)
|
|
{
|
|
if (g_bLeaderWhitelisted[i] && IsClientInGame(i)
|
|
&& GetClientAuthId(i, AuthId_Steam2, clientAuth, sizeof(clientAuth))
|
|
&& StrEqual(auth, clientAuth))
|
|
{
|
|
g_bLeaderWhitelisted[i] = false;
|
|
}
|
|
}
|
|
|
|
ReplyToCommand(admin, "%s Removed %s from the leader whitelist (if present).", PREFIX_PLAIN, auth);
|
|
LogAction(admin, -1, "\"%L\" removed \"%s\" from the leader whitelist", admin, auth);
|
|
}
|
|
|
|
void Whitelist_DeleteAuth(const char[] auth)
|
|
{
|
|
if (g_hWhitelistDB == null)
|
|
return;
|
|
|
|
char query[128];
|
|
g_hWhitelistDB.Format(query, sizeof(query), "DELETE FROM leader_whitelist WHERE steam_id = '%s'", auth);
|
|
g_hWhitelistDB.Query(Whitelist_OnWriteDone, query);
|
|
}
|
|
|
|
public void Whitelist_OnWriteDone(Database db, DBResultSet results, const char[] error, any data)
|
|
{
|
|
if (results == null)
|
|
LogError("[Leader3] Whitelist write failed: %s", error);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Commands
|
|
//----------------------------------------------------------------------------------------------------
|
|
public Action Cmd_AddLeaderWhitelist(int client, int args)
|
|
{
|
|
if (args < 1)
|
|
{
|
|
ReplyToCommand(client, "%s Usage: sm_addleaderwhitelist <target|steamid> [name] - adds a player to the leader whitelist.", PREFIX_PLAIN);
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
char arg[65], targetName[MAX_TARGET_LENGTH];
|
|
int targets[MAXPLAYERS];
|
|
bool tnIsMl;
|
|
GetCmdArg(1, arg, sizeof(arg));
|
|
|
|
int count = ProcessTargetString(arg, client, targets, sizeof(targets),
|
|
COMMAND_FILTER_CONNECTED | COMMAND_FILTER_NO_BOTS, targetName, sizeof(targetName), tnIsMl);
|
|
if (count <= 0)
|
|
{
|
|
// Offline whitelist add by SteamID.
|
|
if (StrContains(arg, "STEAM_", false) == 0)
|
|
{
|
|
char name[MAX_NAME_LENGTH];
|
|
if (args >= 2)
|
|
GetCmdArg(2, name, sizeof(name));
|
|
Whitelist_AddAuth(client, arg, name);
|
|
return Plugin_Handled;
|
|
}
|
|
ReplyToTargetError(client, count);
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
for (int i = 0; i < count; i++)
|
|
Whitelist_Add(client, targets[i]);
|
|
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
public Action Cmd_RemoveLeaderWhitelist(int client, int args)
|
|
{
|
|
if (args < 1)
|
|
{
|
|
ReplyToCommand(client, "%s Usage: sm_removeleaderwhitelist <target|steamid> - removes a player from the leader whitelist.", PREFIX_PLAIN);
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
char arg[65], targetName[MAX_TARGET_LENGTH];
|
|
int targets[MAXPLAYERS];
|
|
bool tnIsMl;
|
|
GetCmdArg(1, arg, sizeof(arg));
|
|
|
|
int count = ProcessTargetString(arg, client, targets, sizeof(targets),
|
|
COMMAND_FILTER_CONNECTED | COMMAND_FILTER_NO_BOTS, targetName, sizeof(targetName), tnIsMl);
|
|
if (count <= 0)
|
|
{
|
|
// Offline whitelist removal by SteamID.
|
|
if (StrContains(arg, "STEAM_", false) == 0)
|
|
{
|
|
Whitelist_RemoveAuth(client, arg);
|
|
return Plugin_Handled;
|
|
}
|
|
ReplyToTargetError(client, count);
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
if (!Whitelist_Remove(client, targets[i]))
|
|
ReplyToCommand(client, "%s %N is not on the leader whitelist.", PREFIX_PLAIN, targets[i]);
|
|
}
|
|
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
public Action Cmd_LeaderWhitelist(int client, int args)
|
|
{
|
|
if (g_hWhitelistDB == null)
|
|
{
|
|
ReplyToCommand(client, "%s The whitelist database is not available.", PREFIX_PLAIN);
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
g_hWhitelistDB.Query(Whitelist_OnListDone,
|
|
"SELECT steam_id, name FROM leader_whitelist ORDER BY added_at DESC",
|
|
client > 0 ? GetClientUserId(client) : 0);
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
public void Whitelist_OnListDone(Database db, DBResultSet results, const char[] error, any userid)
|
|
{
|
|
int client = (userid == 0) ? 0 : GetClientOfUserId(userid);
|
|
if (userid != 0 && client == 0)
|
|
return;
|
|
|
|
if (results == null)
|
|
{
|
|
LogError("[Leader3] Whitelist listing failed: %s", error);
|
|
ReplyToCommand(client, "%s Failed to read the leader whitelist.", PREFIX_PLAIN);
|
|
return;
|
|
}
|
|
|
|
if (results.RowCount == 0)
|
|
{
|
|
ReplyToCommand(client, "%s The leader whitelist is empty.", PREFIX_PLAIN);
|
|
return;
|
|
}
|
|
|
|
ReplyToCommand(client, "%s Leader whitelist (%d):", PREFIX_PLAIN, results.RowCount);
|
|
|
|
char auth[32], name[MAX_NAME_LENGTH];
|
|
while (results.FetchRow())
|
|
{
|
|
results.FetchString(0, auth, sizeof(auth));
|
|
results.FetchString(1, name, sizeof(name));
|
|
ReplyToCommand(client, " %s - %s", auth, name);
|
|
}
|
|
}
|