# Contract pinned from MythicMeta/Mythic_Scripting master @ 2026-06-10 (raw.githubusercontent.com/MythicMeta/Mythic_Scripting/master/mythic/mythic.py) """Mythic 3.x C2 adapter. M1 implements test_connection() only. All other methods raise NotImplementedError("M2") — they land in milestone M2/M3. Transport: POST https://:7443/graphql Header: apitoken: Backend: Hasura-proxied Postgres behind nginx. """ from __future__ import annotations import requests from backend.app.services.c2.adapter import ( C2Adapter, C2Callback, C2Health, C2TaskPage, C2TaskStatus, ) _HEALTH_QUERY = '{ __typename }' class MythicAdapter(C2Adapter): """Real Mythic 3.x adapter using GraphQL over HTTP.""" def __init__(self, url: str, api_token: str, verify_tls: bool = True) -> None: self._url = url.rstrip("/") + "/graphql" self._token = api_token self._verify = verify_tls def _headers(self) -> dict[str, str]: return { "Content-Type": "application/json", "apitoken": self._token, } def test_connection(self) -> C2Health: """POST a trivial introspection query to verify reachability and token validity.""" try: resp = requests.post( self._url, json={"query": _HEALTH_QUERY}, headers=self._headers(), verify=self._verify, timeout=10, ) if resp.status_code == 200: return C2Health(ok=True) return C2Health(ok=False, error=f"HTTP {resp.status_code}") except requests.RequestException as exc: return C2Health(ok=False, error=str(exc)) def list_callbacks(self) -> list[C2Callback]: raise NotImplementedError("M2") def create_task( self, callback_display_id: int, command: str, params: str | None = None, ) -> int: raise NotImplementedError("M2") def get_task(self, task_display_id: int) -> C2TaskStatus: raise NotImplementedError("M2") def get_task_output(self, task_display_id: int) -> str: raise NotImplementedError("M3") def list_callback_tasks( self, callback_display_id: int, page: int = 1, page_size: int = 25, ) -> C2TaskPage: raise NotImplementedError("M4")