From 1cb2acd647efa5fb36b84aff246cabc9aaad9140 Mon Sep 17 00:00:00 2001 From: Игорь Толмачёв Date: Mon, 22 Apr 2024 12:21:07 +0000 Subject: Initial commit --- server.py | 144 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 server.py (limited to 'server.py') diff --git a/server.py b/server.py new file mode 100644 index 0000000..7edd081 --- /dev/null +++ b/server.py @@ -0,0 +1,144 @@ +import socket +import struct +from http.server import BaseHTTPRequestHandler, HTTPServer +from json import load +from os.path import expanduser +from re import compile +from traceback import print_exc + +import config + + +def rcon_packet(id: int, type: int, body: str) -> bytes: + return ( + struct.pack( + " socket.socket: + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.connect(("127.0.0.1", config.rcon_port)) + s.send(rcon_packet(0, 3, config.rcon_password)) + return s + + +def rcon(command: str) -> None: + rcon_socket.send(rcon_packet(0, 2, command)) + + +def pipe(command: str) -> None: + with open(expanduser(config.pipe_path), "w") as pipe: + pipe.write(f"{command}\n") + + +class HttpHandler(BaseHTTPRequestHandler): + def disabled(self) -> None: + self.send_response(503) + self.send_header("Content-Type", "text/plain") + self.end_headers() + self.wfile.write("Endpoint disabled".encode("utf-8")) + + def do_GET(self): + if "GET" not in config.enabled_endpoints: + self.disabled() + return + + try: + with open(expanduser(config.whitelist_file_path)) as file: + status = 200 + response = file.read() + except Exception: + status = 500 + print_exc() + + self.send_response(status) + self.send_header("Content-Type", "application/json") + self.end_headers() + self.wfile.write(response.encode("utf-8")) + + def do_POST(self) -> None: + if "POST" not in config.enabled_endpoints: + self.disabled() + return + + try: + length = int(self.headers.get("Content-Length", 0)) + username = self.rfile.read(length).decode("utf-8") + + if allowed_usernames_regex.match(username) is None: + status = 400 + response = "Incorrect username" + elif username in whitelist: + status = 409 + response = "Player is already whitelisted" + else: + status = 201 + response = f"Added {username} to the whitelist" + + whitelist.add(username) + console(f"whitelist add {username}") + except Exception: + status = 500 + print_exc() + + self.send_response(status) + self.send_header("Content-Type", "text/plain") + self.end_headers() + self.wfile.write(response.encode("utf-8")) + + def do_DELETE(self) -> None: + if "DELETE" not in config.enabled_endpoints: + self.disabled() + return + + try: + length = int(self.headers.get("Content-Length", 0)) + username = self.rfile.read(length).decode("utf-8") + + if allowed_usernames_regex.match(username) is None: + status = 400 + response = "Incorrect username" + elif username not in whitelist: + status = 409 + response = "Player is not whitelisted" + else: + status = 200 + response = f"Removed {username} from the whitelist" + + whitelist.remove(username) + console(f"whitelist remove {username}") + except Exception: + status = 500 + print_exc() + + self.send_response(status) + self.send_header("Content-Type", "text/plain") + self.end_headers() + self.wfile.write(response.encode("utf-8")) + + +server = HTTPServer(("0.0.0.0", config.http_port), HttpHandler) +allowed_usernames_regex = compile(r"^[a-zA-Z0-9_]+$") + +with open(expanduser(config.whitelist_file_path)) as file: + whitelist = {e["name"] for e in load(file)} + +if config.whitelist_access_type == "pipe": + console = pipe +elif config.whitelist_access_type == "rcon": + rcon_socket = rcon_login() + console = rcon + + +try: + server.serve_forever() +except KeyboardInterrupt: + rcon_socket.close() + server.server_close() -- cgit v1.2.3