from lib import config as config_module from lib import logging as logging_lib from lib import background_job from lib import utils import asyncio import json import os import aiofiles.os config = config_module.config log = logging_lib.log dangerous_chars = [';', '|', '&', '`', '$', '>', '<', '(', ')', '\\', '!', '"', '\'', '[', ']', '{', '}'] allowed_commands = ["df"] can_deploy = True async def remove_socket_file(path): try: file_exists = await aiofiles.os.path.exists(path) if file_exists: await aiofiles.os.remove(path) except Exception: pass async def handle_client(reader, writer): global can_deploy try: while True: data = await reader.read(1024*64) try: if not data: break #print("DATA", data, data.decode()) parsed_data = json.loads(data.decode()) if "run_command" in parsed_data and type(parsed_data["run_command"])==str: allowed = False for allowed_command in allowed_commands: if f"{allowed_command} " == parsed_data["run_command"][:len(allowed_command)+1] or allowed_command==parsed_data["run_command"]: allowed = True break if allowed and any(char in parsed_data["run_command"] for char in dangerous_chars): allowed = False log.debug(f"clore_partner_socket | Received \"{parsed_data["run_command"]}\" | {'allowed' if allowed else 'denied'}") if allowed: code, stdout, stderr = await utils.async_run_command( parsed_data["run_command"] ) writer.write(json.dumps({ "code": code, "stderr": stderr, "stdout": stdout }).encode()) else: writer.write(json.dumps({ "code": -1, "stderr": 'Command not allowed', "stdout": 'Command not allowed' }).encode()) elif "can_deploy" in parsed_data: writer.write(json.dumps({ "can_deploy": can_deploy }).encode()) elif "stop_background_job" in parsed_data and "time" in parsed_data: try: if isinstance(parsed_data["time"], int): background_job.temporarly_disable(parsed_data["time"]) except Exception as e: pass else: writer.write('?'.encode()) await writer.drain() except Exception as data_exception: pass break except asyncio.CancelledError: log.debug(f"clore partner socket | Client handler canceled.") finally: log.debug(f"clore partner socket | Closing client connection.") writer.close() await writer.wait_closed() def set_can_deploy(state): global can_deploy can_deploy = state async def socket_service(location): await remove_socket_file(location) server = await asyncio.start_unix_server(handle_client, path=location) log.debug(f"clore partner socket | running at {location}") async with server: await server.serve_forever()