#pragma newdecls optional #include #pragma newdecls required #include #define SOURCECBL_REQUEST_BAN_ENDPOINT "https://sourcecbl.com/api/steam/" #define SOURCECBL_API_TIMEOUT 5 typedef BanStatusCallback = function void(const char[] steamid64, bool bBanned, any data); /** * Status codes. */ enum APIResponse { Response_Success = 0, Response_NotAuthorized }; /** * Queries the SourceCBL API for a ban on the specified SteamID64. * User-facing function. */ void QueryBanList(const char[] steamid64, BanStatusCallback callback, any data = 0) { // we need to use the steamid64 later on down the line to verify the request even if the // player disconnects DataPack pack = new DataPack(); pack.WriteCell(data); pack.WriteString(steamid64); pack.WriteFunction(callback); HTTPRequestHandle request = Steam_CreateHTTPRequest(HTTPMethod_GET, SOURCECBL_REQUEST_BAN_ENDPOINT); Steam_SetHTTPRequestNetworkActivityTimeout(request, SOURCECBL_API_TIMEOUT); Steam_SetHTTPRequestGetOrPostParameter(request, "steamid", steamid64); Steam_SendHTTPRequest(request, OnAccountStatusReceived, pack); } /** * Called when the response to the API request is received. */ public int OnAccountStatusReceived(HTTPRequestHandle request, bool bSuccess, HTTPStatusCode status, DataPack pack) { if (!bSuccess || status != HTTPStatusCode_OK) { return; } int maxlen = Steam_GetHTTPResponseBodySize(request) + 1; char[] buffer = new char[maxlen]; Steam_GetHTTPResponseBodyData(request, buffer, maxlen); Steam_ReleaseHTTPRequest(request); // they should've just gone with outputting VDF so I could just slap that shit into a buffer and call it a day // also would've preferred SteamID3 so I wouldn't have to use strings pack.Reset(); any data = pack.ReadCell(); char steamid64[64]; pack.ReadString(steamid64, sizeof(steamid64)); Function callback = pack.ReadFunction(); delete pack; /** * The API response (currently) has SteamID64 strings as keys for players that are banned. * It's going to be a painus in the anus if they change the API again. */ JSONObject accountStatus = view_as(json_load(buffer)); if (accountStatus) { JSONInteger response = view_as(accountStatus.Get("response")); APIResponse apiStatus = response? view_as(response.Value) : Response_Success; delete response; JSONObjectIterator iterator; if (apiStatus == Response_Success && (iterator = JSONObjectIterator.From(accountStatus))) { char steamid64Key[64]; bool bBanned; do { iterator.GetKey(steamid64Key, sizeof(steamid64Key)); if (StrEqual(steamid64Key, steamid64)) { bBanned = true; } } while ((iterator.Next(accountStatus))); CallBanStatusCallback(callback, steamid64, bBanned, data); // iterator auto-closes } else if (apiStatus == Response_NotAuthorized) { // TODO shut down everything } delete accountStatus; } } /** * Wrapper to isolate the callback function. */ static void CallBanStatusCallback(Function callback, const char[] steamid64, bool bBanned, any data) { Call_StartFunction(INVALID_HANDLE, callback); Call_PushString(steamid64); Call_PushCell(bBanned); Call_PushCell(data); Call_Finish(); }