source_cbl.sp 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. /**
  2. * [CSRD] SourceCBL Integration
  3. *
  4. * An optimized version of the SourceCBL plugin.
  5. */
  6. #pragma semicolon 1
  7. #include <sourcemod>
  8. #include <steamtools>
  9. #pragma newdecls required
  10. #include <newdecl-handles/smjansson>
  11. #define PLUGIN_VERSION "0.1.0"
  12. public Plugin myinfo = {
  13. name = "[CSRD] SourceCBL Integration",
  14. author = "nosoop",
  15. description = "Personal integartion of the SourceCBL API.",
  16. version = PLUGIN_VERSION,
  17. url = "https://git.csrd.science/"
  18. }
  19. #define INVALID_USERID -1
  20. #define SOURCECBL_REQUEST_BAN_ENDPOINT "https://sourcecbl.com/api/steam/"
  21. #define SOURCECBL_API_TIMEOUT 5
  22. enum APIResponse {
  23. Response_Success = 0,
  24. Response_NotAuthorized
  25. };
  26. char g_CommunityKickLog[PLATFORM_MAX_PATH];
  27. public void OnPluginStart() {
  28. CreateConVar("sm_scbl_enabled", "1",
  29. "Teamwork.TF convar for A2S_RULES's sake. Does absolutely nothing else.",
  30. FCVAR_NOTIFY);
  31. // really though, does this actually matter? we're just going to skip the thing anyways
  32. int port = FindConVar("hostport").IntValue;
  33. char portString[6];
  34. IntToString(port, portString, sizeof(portString));
  35. RegAdminCmd("cbl_check_steamid", CheckCBLStatus, ADMFLAG_ROOT);
  36. BuildPath(Path_SM, g_CommunityKickLog, sizeof(g_CommunityKickLog), "logs/sourcecbl.log");
  37. }
  38. public void OnClientAuthorized(int client) {
  39. if (!IsFakeClient(client) && !SkipCommunityBanListCheck(client)) {
  40. RequestClientBanStatus(client);
  41. }
  42. }
  43. bool SkipCommunityBanListCheck(int client) {
  44. // TODO check if account is whitelisted (command group / keyvalues / clientprefs cache, etc.)
  45. return CheckCommandAccess(client, "cbl_whitelist", 0);
  46. }
  47. void RequestClientBanStatus(int client) {
  48. char steamid64[64];
  49. if (GetClientAuthId(client, AuthId_SteamID64, steamid64, sizeof(steamid64))) {
  50. QueryBanList(steamid64, GetClientUserId(client));
  51. }
  52. }
  53. public Action CheckCBLStatus(int client, int argc) {
  54. char steamid64[64];
  55. GetCmdArgString(steamid64, sizeof(steamid64));
  56. StripQuotes(steamid64);
  57. // TODO make sure this is a valid steamid
  58. QueryBanList(steamid64);
  59. }
  60. void QueryBanList(const char[] steamid64, int userid = INVALID_USERID) {
  61. // we need to use the steamid64 later on down the line to verify the request even if the
  62. // player disconnects
  63. DataPack pack = new DataPack();
  64. pack.WriteCell(userid);
  65. pack.WriteString(steamid64);
  66. HTTPRequestHandle request = Steam_CreateHTTPRequest(HTTPMethod_GET,
  67. SOURCECBL_REQUEST_BAN_ENDPOINT);
  68. Steam_SetHTTPRequestNetworkActivityTimeout(request, SOURCECBL_API_TIMEOUT);
  69. Steam_SetHTTPRequestGetOrPostParameter(request, "steamid", steamid64);
  70. Steam_SendHTTPRequest(request, OnAccountStatusReceived, pack);
  71. }
  72. public int OnAccountStatusReceived(HTTPRequestHandle request, bool bSuccess,
  73. HTTPStatusCode status, DataPack pack) {
  74. if (!bSuccess || status != HTTPStatusCode_OK) {
  75. return;
  76. }
  77. int maxlen = Steam_GetHTTPResponseBodySize(request);
  78. char[] buffer = new char[maxlen];
  79. Steam_GetHTTPResponseBodyData(request, buffer, maxlen);
  80. Steam_ReleaseHTTPRequest(request);
  81. // they should've just gone with outputting VDF so I could just slap that shit into a buffer and call it a day
  82. // also would've preferred SteamID3 so I wouldn't have to use strings
  83. pack.Reset();
  84. int userid = pack.ReadCell();
  85. char steamid64[64];
  86. pack.ReadString(steamid64, sizeof(steamid64));
  87. delete pack;
  88. /**
  89. * The API response (currently) has SteamID64 strings as keys for players that are banned.
  90. * It's going to be a painus in the anus if they change the API again.
  91. */
  92. JSONObject accountStatus = view_as<JSONObject>(json_load(buffer));
  93. if (accountStatus) {
  94. APIResponse apiStatus = view_as<APIResponse>(
  95. accountStatus.GetInt("response", view_as<int>(Response_Success)) );
  96. JSONObjectIterator iterator;
  97. if (apiStatus == Response_Success &&
  98. (iterator = JSONObjectIterator.From(accountStatus))) {
  99. char steamid64Key[64];
  100. do {
  101. iterator.GetKey(steamid64Key, sizeof(steamid64Key));
  102. if (StrEqual(steamid64Key, steamid64)) {
  103. // player in banlist, request ban
  104. if (userid != INVALID_USERID) {
  105. int client = GetClientOfUserId(userid);
  106. if (client) {
  107. KickClient(client,
  108. "You have been banned by SourceCBL for hacking / cheating."
  109. ... "\nVisit www.SourceCBL.com for more information.");
  110. LogToFile(g_CommunityKickLog, "Kicked \"%L\" from server.", client);
  111. }
  112. }
  113. }
  114. } while ((iterator.Next(accountStatus)));
  115. // iterator auto-closes
  116. } else if (apiStatus == Response_NotAuthorized) {
  117. // TODO shut down everything
  118. }
  119. delete accountStatus;
  120. }
  121. }