- agent reports the OS user it runs as (enroll + poll header) - per-machine terminal user on the edit page; defaults to the agent's own user (root on Linux) - create a new user from the panel: name, password, optional sudo group - show the reason in the terminal when a shell fails to start - bump version to 0.0.2
165 lines
5.5 KiB
Go
165 lines
5.5 KiB
Go
// Package proto describes the wire messages shared by the server and the agent.
|
|
//
|
|
// All agent<->server traffic is plain JSON over HTTP(S) long-polling so it
|
|
// survives NAT and restrictive egress firewalls: the agent only ever makes
|
|
// outbound requests.
|
|
package proto
|
|
|
|
import "encoding/json"
|
|
|
|
// Control poll message types (server -> agent, returned from /api/agent/poll).
|
|
const (
|
|
// CtrlIdle is returned when the long-poll times out with nothing to do.
|
|
CtrlIdle = "idle"
|
|
// CtrlOpenTerminal tells the agent to spawn a PTY for the session id.
|
|
CtrlOpenTerminal = "open_terminal"
|
|
// CtrlOpenForward tells the agent to dial 127.0.0.1:Port and bridge it to
|
|
// the session id (reverse TCP port-forward).
|
|
CtrlOpenForward = "open_forward"
|
|
// CtrlTask tells the agent to fetch and run the one-shot task TaskID.
|
|
CtrlTask = "task"
|
|
)
|
|
|
|
// EnrollRequest is sent once by a freshly installed agent.
|
|
type EnrollRequest struct {
|
|
Name string `json:"name"`
|
|
Hostname string `json:"hostname"`
|
|
OS string `json:"os"`
|
|
Arch string `json:"arch"`
|
|
Version string `json:"version"`
|
|
User string `json:"user,omitempty"` // OS user the agent runs as
|
|
}
|
|
|
|
// EnrollResponse carries the identity the agent persists and uses from then on.
|
|
type EnrollResponse struct {
|
|
AgentID string `json:"agent_id"`
|
|
Token string `json:"token"`
|
|
}
|
|
|
|
// ControlMessage is the body returned by the control long-poll.
|
|
type ControlMessage struct {
|
|
Type string `json:"type"`
|
|
SessionID string `json:"session_id,omitempty"`
|
|
Port int `json:"port,omitempty"` // CtrlOpenForward: client-side port to dial
|
|
TaskID string `json:"task_id,omitempty"` // CtrlTask
|
|
User string `json:"user,omitempty"` // CtrlOpenTerminal: OS user for the shell ("" = the agent's own)
|
|
}
|
|
|
|
// Terminal / stream frame types on the session "in" channel (server -> agent).
|
|
// Reused for both PTY terminals and raw TCP port-forward streams.
|
|
const (
|
|
FrameStdin = "stdin" // base64 bytes for the PTY / socket
|
|
FrameResize = "resize" // PTY window size (terminal only)
|
|
FrameClose = "close" // tear the stream down
|
|
)
|
|
|
|
// InFrame is one element of the stream downstream batch (server -> agent).
|
|
type InFrame struct {
|
|
Type string `json:"type"`
|
|
Data string `json:"data,omitempty"` // base64 bytes
|
|
Cols uint16 `json:"cols,omitempty"`
|
|
Rows uint16 `json:"rows,omitempty"`
|
|
}
|
|
|
|
// InBatch is the JSON body returned by GET /api/agent/term/{sid}/in.
|
|
type InBatch struct {
|
|
Frames []InFrame `json:"frames"`
|
|
}
|
|
|
|
// OutMessage is POSTed by the agent to /api/agent/term/{sid}/out.
|
|
type OutMessage struct {
|
|
Data string `json:"data,omitempty"` // base64 bytes
|
|
Exit bool `json:"exit,omitempty"`
|
|
}
|
|
|
|
// --- one-shot tasks (file manager, native in the agent) ---
|
|
|
|
const (
|
|
TaskFSList = "fs.list" // list a directory
|
|
TaskFSRead = "fs.read" // read file content (for view/edit)
|
|
TaskFSWrite = "fs.write" // write/overwrite file (edit save, create, upload)
|
|
TaskFSMkdir = "fs.mkdir" // create directory
|
|
TaskFSDelete = "fs.delete" // delete a single file or empty dir
|
|
TaskFSDelTree = "fs.deltree" // recursively delete a directory
|
|
TaskFSUnzip = "fs.unzip" // unzip an archive (needs `unzip` on the client)
|
|
TaskFSZip = "fs.zip" // zip selected paths (native archive/zip)
|
|
TaskFSMove = "fs.move" // move/rename
|
|
TaskFSDownload = "fs.download" // read a whole file (larger cap) for browser download
|
|
|
|
TaskSysUpdate = "sys.update" // download the latest agent binary and restart
|
|
TaskSysUsers = "sys.users" // report the agent's user and the login-capable users
|
|
TaskSysUserAdd = "sys.useradd" // create a new OS user
|
|
)
|
|
|
|
// TaskEnvelope is what the agent fetches for a task id.
|
|
type TaskEnvelope struct {
|
|
Type string `json:"type"`
|
|
Args json.RawMessage `json:"args"`
|
|
}
|
|
|
|
// TaskResult is POSTed back by the agent.
|
|
type TaskResult struct {
|
|
OK bool `json:"ok"`
|
|
Error string `json:"error,omitempty"`
|
|
Data json.RawMessage `json:"data,omitempty"`
|
|
}
|
|
|
|
// fs task argument shapes.
|
|
type FSPathArgs struct {
|
|
Path string `json:"path"`
|
|
}
|
|
type FSWriteArgs struct {
|
|
Path string `json:"path"`
|
|
Data string `json:"data"` // base64 content
|
|
}
|
|
type FSUnzipArgs struct {
|
|
Path string `json:"path"`
|
|
Dest string `json:"dest"`
|
|
}
|
|
type FSZipArgs struct {
|
|
Paths []string `json:"paths"`
|
|
Dest string `json:"dest"`
|
|
}
|
|
type FSMoveArgs struct {
|
|
Src string `json:"src"`
|
|
Dst string `json:"dst"`
|
|
}
|
|
|
|
// FSEntry is one directory entry.
|
|
type FSEntry struct {
|
|
Name string `json:"name"`
|
|
IsDir bool `json:"is_dir"`
|
|
Size int64 `json:"size"`
|
|
Mode string `json:"mode"`
|
|
MTime int64 `json:"mtime"`
|
|
}
|
|
|
|
// FSListResult is returned for TaskFSList.
|
|
type FSListResult struct {
|
|
Path string `json:"path"`
|
|
Entries []FSEntry `json:"entries"`
|
|
}
|
|
|
|
// FSReadResult is returned for TaskFSRead.
|
|
type FSReadResult struct {
|
|
Path string `json:"path"`
|
|
Size int64 `json:"size"`
|
|
Content string `json:"content"` // base64
|
|
Truncated bool `json:"truncated"`
|
|
Binary bool `json:"binary"`
|
|
}
|
|
|
|
// SysUsersResult is returned for TaskSysUsers.
|
|
type SysUsersResult struct {
|
|
Current string `json:"current"` // user the agent runs as
|
|
CanSwitch bool `json:"can_switch"` // agent is root, so it can open shells as (and create) other users
|
|
Users []string `json:"users"`
|
|
}
|
|
|
|
// SysUserAddArgs are the arguments of TaskSysUserAdd.
|
|
type SysUserAddArgs struct {
|
|
Name string `json:"name"`
|
|
Password string `json:"password,omitempty"` // empty leaves the account without a password
|
|
Sudo bool `json:"sudo"` // add to the sudo/wheel group
|
|
}
|