Architecture¶
CreeperCLI is two processes connected by a TCP socket speaking JSON lines.
Your machine Server (Paper 1.21+)
┌─────────────────────┐ ┌──────────────────────────────────┐
│ creepercli (Node) │ TCP / JSON │ CreeperCLI plugin │
│ REPL, transfers, │◄──────────────►│ TcpServer (0.0.0.0:45678) │
│ dashboards │ newline- │ CommandRouter (auth + actions) │
└─────────────────────┘ delimited │ Sandbox (server-root jail) │
│ ExecAllowlist │
│ AuditLogger (append-only) │
└──────────────────────────────────┘
Components¶
TcpServer: accepts sockets, parses NDJSON frames, enforces the connection cap, payload cap, and per-session rate limits. Bindsnetwork.host:network.port, default0.0.0.0:45678.CommandRouter: dispatches actions to handlers. Every action passes session verification and audit logging first.PathSanitizer: resolves every file path against the sandbox root. It normalizes separators, strips NUL bytes and drive letters, and resolves symlinks withtoRealPath()so a link can never escape the jail.ExecAllowlist: pattern-matches console commands before dispatch.BukkitBridge: schedules allowlisted commands on the main thread viaBukkit.getScheduler().runTask()and returns aCompletableFutureto the network thread, so exec never blocks the server tick.LogStreamer: ajava.util.logging.Handlerattached toBukkit.getLogger()broadcasts lines tomonitor.log.startsubscribers.SessionManager,AuthManager(bcrypt + TOTP),RateLimiter(token bucket),Fail2Ban(per-IP),AuditLogger(append-only, rotating).Metrics: bStats 3.x integration, shaded and relocated underdev.demonzdevelopment.creepercli.metrics. Reportsbind_host,debug_log,two_fa_users, anduser_countcharts. See configuration.md.ActionRegistry: public API for third-party plugins to register custom actions.
Threading model¶
- Socket reads and file I/O run off the main thread.
- Anything touching the Bukkit API (console commands, broadcasting) is scheduled onto the main thread.
- Log subscribers receive lines on the logging thread.
Sandbox design¶
- Normalize: backslashes to forward slashes, strip NUL bytes and drive letters.
- Resolve the canonical parent with
toRealPath(). - Verify the canonical path starts with the jail root.
- For non-existent files, resolve the nearest existing parent, check it, then append the new path.
Extension API¶
Third-party plugins register actions with ActionRegistry:
CreeperCLIPlugin creeper = JavaPlugin.getPlugin(CreeperCLIPlugin.class);
creeper.actionRegistry().registerAction("custom.action", (conn, params) -> { ... });
Custom actions inherit session verification, rate limiting, and audit logging. See plugin-api.md.