def unblacklist_player(request): data = _get_data(request) res = {} try: remove_player_from_blacklist(data["steam_id_64"]) audit("unblacklist", request, data) if get_config()["BANS"]["unblacklist_does_unban"]: ctl.do_unban(data["steam_id_64"]) # also remove bans if get_config()["MULTI_SERVERS"]["broadcast_unbans"]: forward_command( "/api/do_unban", json=data, sessionid=request.COOKIES.get("sessionid"), ) failed = False except: logger.exception("Unable to unblacklist player") failed = True return JsonResponse({ "result": res, "command": "unblacklist_player", "arguments": data, "failed": failed, })
def unban(request): data = _get_data(request) res = {} results = None try: ctl.do_unban(data["steam_id_64"]) # also remove bans audit("unban", request, data) if get_config()["MULTI_SERVERS"]["broadcast_unbans"]: results = forward_command( "/api/do_unban", json=data, sessionid=request.COOKIES.get("sessionid")) if get_config()["BANS"]["unban_does_unblacklist"]: try: remove_player_from_blacklist(data["steam_id_64"]) except CommandFailedError: logger.warning("Player %s was not on blacklist", data["steam_id_64"]) failed = False except: logger.exception("Unable to unban player") failed = True return JsonResponse({ "result": res, "command": "unban_player", "arguments": data, "failed": failed, "forward_results": results, })
def live_scoreboard(request): stats = LiveStats() config = get_config() try: result = stats.get_cached_stats() result = { "snapshot_timestamp": result["snapshot_timestamp"], "refresh_interval_sec": config.get('LIVE_STATS', {}).get('refresh_stats_seconds', 30), "stats": list(result["stats"].values()), } error = (None, ) failed = False except Exception as e: logger.exception("Unable to produce live stats") result = {} error = "" failed = True return api_response(result=result, error=error, failed=failed, command="live_scoreboard")
def auto_kick(_, log): try: config = get_config().get('NAME_KICKS') except KeyError: logger.error("Invalid configuration file, NAME_KICKS key is missing") return for r in config['regexps']: name = log["player"] info = recorded_rcon.get_player_info(name) try: profile = get_player_profile(info["steam_id_64"], 0) for f in config.get("whitelist_flags", []): if player_has_flag(profile, f): logger.debug( "Not checking nickname validity for whitelisted player %s (%s)", name, info["steam_id_64"]) return except: logger.exception("Unable to check player profile") if re.match(r, name): logger.info("%s matched player %s", r, name) recorded_rcon.do_kick(player=name, reason=config["reason"], by="NAME_KICK") try: send_to_discord_audit( f"`{name}` kicked from regexp `{r}`", by="NAME_KICK", webhookurl=config.get("discord_webhook_url")) except Exception: logger.error("Unable to send to audit_log") return
def from_config(cls, server_number=None): server_number = server_number or os.getenv("SERVER_NUMBER") config = get_config() config = config.get("GTX").get(f"server_{server_number}") return cls( ip=config["ip"], port=config["port"], username=config["username"], password=config["password"], )
def live_stats_loop(): live = LiveStats() config = get_config() sleep_seconds = config.get("LIVE_STATS", {}).get("refresh_stats_seconds", 30) while True: try: live.set_live_stats() logger.debug("Refreshed") except Exception: logger.exception("Error while producing stats") time.sleep(sleep_seconds)
def wrapper(request): logger = logging.getLogger("rconweb") arguments = {} data = {} failure = False others = None error = "" data = _get_data(request) for pname, param in parameters.items(): if pname == "by": arguments[pname] = request.user.username elif param.default != inspect._empty: arguments[pname] = data.get(pname, param.default) else: try: arguments[pname] = data[pname] except KeyError: # TODO raise 400 raise try: logger.debug("%s %s", func.__name__, arguments) res = func(**arguments) audit(func.__name__, request, arguments) except CommandFailedError as e: failure = True error = e.args[0] if e.args else None res = None response = JsonResponse( dict( result=res, command=func.__name__, arguments=data, failed=failure, error=error, forward_results=others, )) if data.get("forward"): if command_name == "do_temp_ban" and not get_config().get( "MULTI_SERVERS", {}).get("broadcast_temp_bans", True): logger.debug("Not broadcasting temp ban due to settings") return response try: others = forward_request(request) except: logger.exception("Unexpected error while forwarding request") # logger.debug("%s %s -> %s", func.__name__, arguments, res) return response
def live_stats_loop(): live = LiveStats() config = get_config() last_loop_session = datetime.datetime(year=2020, month=1, day=1) last_loop_game = datetime.datetime(year=2020, month=1, day=1) live_session_sleep_seconds = config.get("LIVE_STATS", {}).get("refresh_stats_seconds", 30) live_game_sleep_seconds = config.get("LIVE_STATS", {}).get( "refresh_current_game_stats_seconds", 5) logger.debug( "live_session_sleep_seconds: {}".format(live_session_sleep_seconds)) logger.debug("live_game_sleep_seconds: {}".format(live_game_sleep_seconds)) red = get_redis_client() while True: # Keep track of session and game timers seperately last_loop_session_seconds = (datetime.datetime.now() - last_loop_session).total_seconds() last_loop_game_seconds = (datetime.datetime.now() - last_loop_game).total_seconds() if last_loop_session_seconds >= live_session_sleep_seconds: last_loop_session = datetime.datetime.now() try: live.set_live_stats() logger.debug("Refreshed set_live_stats") except Exception: logger.exception("Error while producing stats") if last_loop_game_seconds >= live_game_sleep_seconds: last_loop_game = datetime.datetime.now() try: snapshot_ts = datetime.datetime.now().timestamp() stats = current_game_stats() logger.debug("Refreshed current_game_stats") red.set( "LIVE_GAME_STATS", pickle.dumps( dict(snapshot_timestamp=snapshot_ts, stats=list(stats.values()), refresh_interval_sec=live_game_sleep_seconds)), ) except Exception: logger.exception("Failed to compute live game stats") time.sleep(0.1)
def auto_ban_if_tks_right_after_connection(rcon: RecordedRcon, log): config = get_config() config = config.get("BAN_TK_ON_CONNECT") if not config or not config.get("enabled"): return player_name = log["player"] player_steam_id = log["steam_id_64_1"] player_profile = None vips = {} try: player_profile = get_player_profile(player_steam_id, 0) except: logger.exception("Unable to get player profile") try: vips = set(v['steam_id_64'] for v in rcon.get_vip_ids()) except: logger.exception("Unable to get VIPS") last_logs = get_recent_logs(end=500, player_search=player_name, exact_player_match=True) logger.debug("Checking TK from %s", player_name) author = config.get("author_name", "Automation") reason = config.get("message", "No reasons provided") discord_msg = config.get("discord_webhook_message", "No message provided") webhook = config.get("discord_webhook_url") max_time_minute = config.get("max_time_after_connect_minutes", 5) excluded_weapons = [w.lower() for w in config.get("exclude_weapons", [])] ignore_after_kill = config.get("ignore_tk_after_n_kills", 1) ignore_after_death = config.get("ignore_tk_after_n_death", 1) whitelist_players = config.get("whitelist_players", {}) tk_tolerance_count = config.get("teamkill_tolerance_count", 1) if player_profile: if whitelist_players.get('is_vip') and player_steam_id in vips: logger.debug("Not checking player because he's VIP") return if whitelist_players.get('has_at_least_n_sessions') and player_profile[ 'sessions_count'] >= whitelist_players.get( 'has_at_least_n_sessions'): logger.debug("Not checking player because he has %s sessions", player_profile['sessions_count']) return flags = whitelist_players.get('has_flag', []) if not isinstance(flags, list): flags = [flags] for f in flags: if player_has_flag(player_profile, f): logger.debug("Not checking player because he has flag %s", f) return last_action_is_connect = False last_connect_time = None kill_counter = 0 death_counter = 0 tk_counter = 0 for log in reversed(last_logs["logs"]): logger.debug(log) if log["action"] == "CONNECTED": last_action_is_connect = log last_connect_time = log["timestamp_ms"] kill_counter = 0 death_counter = 0 continue if log["action"] == "TEAM KILL" and log[ 'player'] == player_name and last_action_is_connect: if excluded_weapons and log["weapon"].lower() in excluded_weapons: logger.debug( "Not counting TK as offense due to weapon exclusion") continue if log['timestamp_ms'] - last_connect_time > max_time_minute * 60 * 1000: logger.debug( "Not counting TK as offense due to elapsed time exclusion, last connection time %s, tk time %s", datetime.datetime.fromtimestamp(last_connect_time / 1000), datetime.datetime.fromtimestamp(log["timestamp_ms"])) continue logger.info("Banning player %s for TEAMKILL after connect %s", player_name, log) tk_counter += 1 if tk_counter > tk_tolerance_count: rcon.do_perma_ban( player=player_name, reason=reason, by=author, ) send_to_discord_audit(discord_msg.format(player=player_name), by=author, webhookurl=webhook) elif is_player_death(player_name, log): death_counter += 1 if death_counter >= ignore_after_death: last_action_is_connect = False elif is_player_kill(player_name, log): kill_counter += 1 if kill_counter >= ignore_after_kill: last_action_is_connect = False
import time from logging.config import dictConfig from sqlite3.dbapi2 import connect from urllib.parse import urljoin import discord import requests from discord.embeds import Embed from discord.errors import HTTPException from requests.exceptions import ConnectionError, RequestException from rcon.config import get_config logger = logging.getLogger(__name__) SERVER_CONFIG = get_config()['SCOREBOT'][f'SERVER_{os.getenv("SERVER_NUMBER")}'] CONFIG = get_config()['SCOREBOT']['COMMON'] STATS_URL = SERVER_CONFIG["STATS_URL"] INFO_URL = SERVER_CONFIG["INFO_URL"] SCOREBOARD_PUBLIC_URL = SERVER_CONFIG["SCOREBOARD_PUBLIC_URL"] SCORBOARD_BASE_PATH = SERVER_CONFIG["SCORBOARD_BASE_PATH"] PAST_GAMES_URL = SERVER_CONFIG["PAST_GAMES_URL"] WEBHOOK_URL = SERVER_CONFIG["WEBHOOK_URL"] ALL_STATS_TEXT = CONFIG["ALL_STATS_TEXT"] AUTHOR_NAME = CONFIG["AUTHOR_NAME"] AUTHOR_ICON_URL = CONFIG["AUTHOR_ICON_URL"] ELAPSED_TIME = CONFIG["ELAPSED_TIME"] TOP_LIMIT = CONFIG["TOP_LIMIT"]