From 3564d24a45fe838075e680c49c22798e6862236d Mon Sep 17 00:00:00 2001 From: Dylan Garvis Date: Sat, 8 Aug 2026 08:06:11 -0400 Subject: [PATCH] feat(rcon): refine server console --- README.md | 2 +- .../web/src/app/admin/(console)/rcon/page.tsx | 4 +- apps/web/src/components/rcon-console.test.tsx | 7 ++- apps/web/src/components/rcon-console.tsx | 51 ++++++++++++------- design/index.md | 2 +- design/log.md | 1 + design/us-021-rcon-connections.md | 8 +-- design/us-022-rcon-console.md | 14 ++--- docs/architecture.md | 2 +- docs/rcon.md | 4 +- 10 files changed, 58 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index 465a87b..f0791b3 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@ The token is displayed once and stored only as a SHA-256 hash. - PostgreSQL and Drizzle ORM - Keycloak OIDC for admin access with the `minecraft-account-manager-admin` role -- Admin user search, account management, event exploration, DAU and confirmed-connection metrics, toggleable Natural Earth/OpenStreetMap user-location views, internal RCON connection management and command proxying, and automatic Discord nickname synchronization +- Admin user search, account management, event exploration, DAU and confirmed-connection metrics, toggleable Natural Earth/OpenStreetMap user-location views, RCON server-address management and command proxying, and automatic Discord nickname synchronization - Exclusive group admission: unassigned users fall back to protected `everyone`, and administrators manage effective membership, access, recurring UTC login windows, and VPN/proxy/Tor exceptions through confirmed group workflows - Deployment-managed Discord guild ID and invite URL - discord.js bot with `/register` and `/account` diff --git a/apps/web/src/app/admin/(console)/rcon/page.tsx b/apps/web/src/app/admin/(console)/rcon/page.tsx index 142994e..23bde28 100644 --- a/apps/web/src/app/admin/(console)/rcon/page.tsx +++ b/apps/web/src/app/admin/(console)/rcon/page.tsx @@ -60,7 +60,7 @@ export default async function RconPage({

Server operations

RCON

-

Run commands through the portal backend. RCON endpoints remain internal and credentials are never sent to the browser.

+

Run commands through the portal backend to internal or external server addresses. Credentials are never sent to the browser.

{saved &&

{savedMessages[saved] ?? "RCON settings saved."}

} @@ -139,7 +139,7 @@ function ConnectionFields({ return ( <> - + diff --git a/apps/web/src/components/rcon-console.test.tsx b/apps/web/src/components/rcon-console.test.tsx index b4e25e4..3f0561e 100644 --- a/apps/web/src/components/rcon-console.test.tsx +++ b/apps/web/src/components/rcon-console.test.tsx @@ -8,12 +8,15 @@ vi.mock("@/app/admin/(console)/rcon/actions", () => ({ import { RconConsole } from "./rcon-console"; describe("RconConsole", () => { - it("renders labelled keyboard-operable controls without history", () => { + it("renders a labelled keyboard-operable terminal without persisted history", () => { const markup = renderToStaticMarkup(); + expect(markup).toContain('aria-label="RCON terminal"'); expect(markup).toContain('for="rcon-console-server"'); expect(markup).toContain('for="rcon-command"'); expect(markup).toContain("Season 4"); - expect(markup).toContain("Run command"); + expect(markup).toContain("server://"); + expect(markup).toContain("Awaiting command"); + expect(markup).toContain("Enter ↵"); expect(markup).not.toContain("Latest response"); }); diff --git a/apps/web/src/components/rcon-console.tsx b/apps/web/src/components/rcon-console.tsx index 495059c..b27ed97 100644 --- a/apps/web/src/components/rcon-console.tsx +++ b/apps/web/src/components/rcon-console.tsx @@ -16,24 +16,41 @@ export function RconConsole({ servers }: { servers: ServerOption[] }) { } return ( -
- - - - {state.status !== "idle" && ( -
-

Latest response{responseServer ? ` — ${responseServer.name}` : ""}

-
{state.message}
+ +
+
+
- )} + +
+ +
+ {pending ? ( +

Executing command…

+ ) : state.status === "idle" ? ( +

Awaiting command

+ ) : ( + <> +

+ {state.status === "error" ? "Error" : "Response"}{responseServer ? ` — ${responseServer.name}` : ""} +

+
{state.message}
+ + )} +
+ +
+ + + + +
); } diff --git a/design/index.md b/design/index.md index 72a6ca5..4d38e05 100644 --- a/design/index.md +++ b/design/index.md @@ -34,7 +34,7 @@ This OKF bundle is the product record for implemented and proposed behavior. Sto * [US-018 — Monitor community account activity](us-018-admin-dashboard.md) - Administrators review daily users, confirmed connections, locations, denials, and risky networks. * [US-019 — Manage groups efficiently](us-019-admin-group-management.md) - Administrators manage group identity, policies, membership, and creation through focused confirmed workflows. * [US-020 — Schedule group access in UTC](us-020-scheduled-group-access.md) - Enabled groups may be restricted to recurring weekly UTC windows with static denial-message templates. -* [US-021 — Manage RCON server connections](us-021-rcon-connections.md) - Administrators manage encrypted internal Minecraft RCON endpoints. +* [US-021 — Manage RCON server connections](us-021-rcon-connections.md) - Administrators manage encrypted Minecraft RCON server addresses. * [US-022 — Operate servers through an RCON console](us-022-rcon-console.md) - Administrators execute bounded commands through the server-side portal proxy. # Tracking diff --git a/design/log.md b/design/log.md index babadac..c751ce8 100644 --- a/design/log.md +++ b/design/log.md @@ -6,6 +6,7 @@ * **Implement**: Added a bounded server-side RCON command console with safe output and error handling; internal-only deployment verification remains pending. * **Refine**: Removed deployment-managed RCON endpoint allowlisting so administrators may configure any valid DNS hostname and port, while retaining IP-literal rejection and documenting the outbound-connectivity trust boundary. * **Verify**: Confirmed the RCON console uses an authenticated internal ClusterIP deployment with secret-backed credentials and no public RCON exposure. +* **Refine**: Renamed RCON host configuration to server addresses, documented internal and external targets, and redesigned the console as a portal-colored terminal with a target bar, command prompt, and latest-response viewport. ## 2026-08-07 diff --git a/design/us-021-rcon-connections.md b/design/us-021-rcon-connections.md index 408fd65..ef60a69 100644 --- a/design/us-021-rcon-connections.md +++ b/design/us-021-rcon-connections.md @@ -1,9 +1,9 @@ --- type: User Story title: Manage RCON server connections -description: Administrators manage encrypted connection settings for internal Minecraft RCON endpoints. +description: Administrators manage encrypted connection settings for Minecraft RCON server addresses. tags: [admin, rcon, minecraft, security, operations] -timestamp: 2026-08-08T11:44:59Z +timestamp: 2026-08-08T12:05:37Z story_id: US-021 status: verified --- @@ -15,7 +15,7 @@ As an administrator, I want to manage one or more Minecraft RCON connections, so # Acceptance Criteria - [x] Existing account-manager administrators can list, add, edit, test, enable or disable, and delete RCON server connections. -- [x] Each connection has a unique display name, internal hostname, port, enabled state, and write-only password. +- [x] Each connection has a unique display name, server address, port, enabled state, and write-only password. - [x] RCON passwords are encrypted with an authenticated cipher using a deployment-managed master key and are never returned to the browser, audit events, or application logs. - [x] Updating a connection preserves its password unless an administrator explicitly supplies a replacement. - [x] Administrators can save any syntactically valid DNS hostname and port without deployment-managed endpoint configuration; IP literals remain rejected. @@ -30,7 +30,7 @@ The administrator RCON page and server actions manage endpoints without deployme # Validation -Verified with RCON validation, encryption, gateway, component, and server-action tests; full workspace tests and type checks; web lint; OKF validation; Semgrep; dependency audit; and a production Next.js build on 2026-08-08. Validation confirms arbitrary valid DNS hostname and port pairs no longer require deployment configuration while IP literals and malformed hostnames remain rejected. Action tests confirm independent authorization, password preservation, enabled-state rechecks, safe failures, and command audit redaction. +Verified with RCON validation, encryption, gateway, component, and server-action tests; full workspace tests and type checks; web lint; OKF validation; Semgrep; dependency audit; and a production Next.js build on 2026-08-08. Validation confirms arbitrary valid internal or external DNS server addresses and ports no longer require deployment configuration while IP literals and malformed hostnames remain rejected. Action tests confirm independent authorization, password preservation, enabled-state rechecks, safe failures, and command audit redaction. # Related Stories diff --git a/design/us-022-rcon-console.md b/design/us-022-rcon-console.md index 0e05fa8..ed8d472 100644 --- a/design/us-022-rcon-console.md +++ b/design/us-022-rcon-console.md @@ -3,34 +3,34 @@ type: User Story title: Operate servers through an RCON console description: Administrators execute bounded RCON commands through the server-side portal proxy. tags: [admin, rcon, minecraft, console, security] -timestamp: 2026-08-08T11:44:59Z +timestamp: 2026-08-08T12:05:37Z story_id: US-022 status: verified --- # User Story -As an administrator, I want an RCON console in the portal, so that I can operate internal Minecraft servers without exposing RCON publicly. +As an administrator, I want an RCON console in the portal, so that I can operate configured Minecraft servers without exposing credentials to the browser. # Acceptance Criteria - [x] Existing account-manager administrators can select an enabled connection and execute an RCON command from the admin UI. -- [x] Browsers never connect to RCON directly; commands pass through the authenticated Next.js server runtime to an internal endpoint. +- [x] Browsers never connect to RCON directly; commands pass through the authenticated Next.js server runtime to the configured endpoint. - [x] Every command independently rechecks administrator authorization and the selected connection's enabled state. - [x] Commands are length-limited, reject control characters, execute with bounded concurrency and a timeout, and return bounded output. - [x] Command responses are displayed safely and are not persisted in console history, audit data, or application logs. - [x] Audit events record the administrator, connection, command verb and digest, success, and duration without recording complete commands or responses. - [x] Authentication, timeout, and connection failures return safe operator-facing messages without credentials or stack traces. -- [x] The console is keyboard accessible and clearly identifies the selected server. -- [x] RCON remains internal to the cluster and is not exposed through public ingress or a load balancer. +- [x] The console uses the portal color palette to present a terminal-style server header, single keyboard-accessible prompt, pending state, and scrollable latest-response viewport. +- [x] Configured server addresses may be internal or external, and operators receive guidance that RCON network exposure and transport security remain their responsibility. # Implementation -The client console invokes an authenticated server action that revalidates the enabled connection, decrypts its credential only in the server runtime, and executes one bounded command. The gateway limits each process to one operation per server and eight total operations, applies a five-second end-to-end deadline plus bounded cleanup, sanitizes and truncates output, and records keyed command lifecycle audits without command or response content. +The portal-colored terminal interface identifies the selected server in its header, accepts one command through a keyboard-focused prompt, and displays only the latest bounded response in a scrollable viewport. The client invokes an authenticated server action that revalidates the enabled connection, decrypts its credential only in the server runtime, and executes one bounded command. The gateway limits each process to one operation per server and eight total operations, applies a five-second end-to-end deadline plus bounded cleanup, sanitizes and truncates output, and records keyed command lifecycle audits without command or response content. # Validation -Application behavior is verified with gateway, validation, component, credential, and server-action tests; full workspace tests and type checks; web lint; OKF validation; Semgrep; dependency audit; and a production Next.js build on 2026-08-08. The SoMC GitOps deployment verifies Season 4 RCON through an authenticated internal ClusterIP Service backed by a Kubernetes Secret, with no public ingress or load balancer exposure. +Application behavior is verified with gateway, validation, component, credential, and server-action tests; full workspace tests and type checks; web lint; OKF validation; Semgrep; dependency audit; and a production Next.js build on 2026-08-08. Component validation confirms labelled server and command controls, terminal semantics, an idle output viewport, and an accessible no-server state. The SoMC GitOps deployment verifies Season 4 RCON through an authenticated internal ClusterIP Service backed by a Kubernetes Secret while product guidance also covers external server addresses. # Related Stories diff --git a/docs/architecture.md b/docs/architecture.md index d90cd68..74943a2 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -10,7 +10,7 @@ User authentication begins with an opaque, short-lived, single-use token created ### RCON administration -The administrator console stores one or more RCON endpoints with write-only AES-GCM-encrypted passwords. Browser requests invoke authenticated server actions; only the Next.js runtime opens RCON TCP connections. Administrators may configure any syntactically valid DNS hostname and port without deployment-managed endpoint configuration; IP literals remain rejected. Commands and responses are bounded and ephemeral, while credential-safe audit events retain the operator, server, command verb, keyed digest, outcome, and duration. Production Minecraft RCON is exposed only through internal cluster services and never through public ingress. +The administrator console stores one or more RCON server addresses with write-only AES-GCM-encrypted passwords. Browser requests invoke authenticated server actions; only the Next.js runtime opens RCON TCP connections. Administrators may configure any syntactically valid internal or external DNS hostname and port without deployment-managed endpoint configuration; IP literals remain rejected. Commands and responses are bounded and ephemeral, while credential-safe audit events retain the operator, server, command verb, keyed digest, outcome, and duration. Operators remain responsible for endpoint exposure and transport security. ### Discord bot diff --git a/docs/rcon.md b/docs/rcon.md index e72da8c..33c7b61 100644 --- a/docs/rcon.md +++ b/docs/rcon.md @@ -12,7 +12,7 @@ Saved passwords are encrypted with AES-256-GCM and connection-bound authenticate ## Minecraft server configuration -Enable RCON with a high-entropy password supplied through the deployment secret. Expose its port only on an internal `ClusterIP` service. Do not add RCON to an Ingress, NodePort, or public LoadBalancer. +Enable RCON with a high-entropy password supplied through the deployment secret. Server addresses may resolve internally or externally. Prefer private networking, a VPN, or an encrypted tunnel; do not expose plaintext RCON directly to the public internet. The password entered in the administrator connection form must match the server password. Existing passwords are write-only; leave the replacement field blank when editing unrelated connection settings. @@ -26,7 +26,7 @@ The password entered in the administrator connection form must match the server - Full commands and responses are not persisted or logged. Audit events contain the command verb and a domain-separated HMAC digest. - Connection passwords are never selected by page queries or returned to the browser. -RCON is plaintext TCP. Keep it on the cluster network and use network policy or an encrypted tunnel when the network trust model requires stronger isolation. +RCON is plaintext TCP. Internal deployments should use network policy; external connections should use private routing, a VPN, or an encrypted tunnel rather than direct public exposure. ## Migration