fix(server): require gateway secrets
This commit is contained in:
parent
84a9aeea25
commit
96efe21b50
@ -80,7 +80,10 @@ MCP endpoint (OpenCode connects here): http://127.0.0.1:4445
|
|||||||
|
|
||||||
The MCP endpoint stays bound to `127.0.0.1` on purpose: `exec-lua` / `write-file` are
|
The MCP endpoint stays bound to `127.0.0.1` on purpose: `exec-lua` / `write-file` are
|
||||||
as powerful as the linked computer, so only local processes (your OpenCode) reach them.
|
as powerful as the linked computer, so only local processes (your OpenCode) reach them.
|
||||||
Set `TRAPOS_SERVER_PASSWORD` in `.env` to require a shared secret on the gateway connection.
|
`TRAPOS_SERVER_PASSWORD` (and `OPENCODE_SERVER_PASSWORD`) must be set in `.env`: the
|
||||||
|
gateway connection requires this shared secret, and the server refuses to start if either
|
||||||
|
is empty (run `just install` to generate them). An empty password would expose the gateway
|
||||||
|
unauthenticated, so it is never allowed.
|
||||||
|
|
||||||
## 5. Link The Computer To The Gateway
|
## 5. Link The Computer To The Gateway
|
||||||
|
|
||||||
@ -88,7 +91,7 @@ On the ComputerCraft computer, point it at the gateway and reboot:
|
|||||||
|
|
||||||
```sh
|
```sh
|
||||||
set cloud.url ws://<public-host>:4444
|
set cloud.url ws://<public-host>:4444
|
||||||
set cloud.password secret # only if TRAPOS_SERVER_PASSWORD is set on the host
|
set cloud.password secret # must match TRAPOS_SERVER_PASSWORD on the host
|
||||||
reboot
|
reboot
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@ -1,17 +1,21 @@
|
|||||||
# Serve the trapos-server gateway (port 4444) for remote/in-game attachment using
|
# Serve the trapos-server gateway (port 4444) for remote/in-game attachment using
|
||||||
# repo-local .env secrets. Mirrors `opencode-serve`, but auth is optional: an unset
|
# repo-local .env secrets. Mirrors `opencode-serve`. Both TRAPOS_SERVER_PASSWORD and
|
||||||
# TRAPOS_SERVER_PASSWORD means the gateway runs with auth disabled (warn, do not fail).
|
# OPENCODE_SERVER_PASSWORD are required: an empty one would run the gateway
|
||||||
|
# unauthenticated, so a missing secret is a fatal error (see also the guard in index.ts).
|
||||||
[positional-arguments]
|
[positional-arguments]
|
||||||
serve *args:
|
serve *args:
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
repo='{{justfile_directory()}}'
|
repo='{{justfile_directory()}}'
|
||||||
if [ -f "$repo/.env" ]; then set -a; . "$repo/.env"; set +a; fi
|
if [ -f "$repo/.env" ]; then set -a; . "$repo/.env"; set +a; fi
|
||||||
if [ -z "${TRAPOS_SERVER_PASSWORD:-}" ]; then
|
for var in TRAPOS_SERVER_PASSWORD OPENCODE_SERVER_PASSWORD; do
|
||||||
printf '%s\n' 'serve: TRAPOS_SERVER_PASSWORD unset in .env — gateway auth disabled' >&2
|
if [ -z "${!var:-}" ]; then
|
||||||
|
printf '%s\n' "serve: $var is empty or unset in .env — refusing to start (run \`just install\` to generate secrets)" >&2
|
||||||
|
exit 1
|
||||||
fi
|
fi
|
||||||
export TRAPOS_SERVER_PASSWORD="${TRAPOS_SERVER_PASSWORD:-}"
|
done
|
||||||
export OPENCODE_SERVER_PASSWORD="${OPENCODE_SERVER_PASSWORD:-}"
|
export TRAPOS_SERVER_PASSWORD
|
||||||
|
export OPENCODE_SERVER_PASSWORD
|
||||||
export OPENCODE_URL="${OPENCODE_URL:-http://127.0.0.1:4242}"
|
export OPENCODE_URL="${OPENCODE_URL:-http://127.0.0.1:4242}"
|
||||||
export TRAPOS_SERVER_HOST="${TRAPOS_SERVER_HOST:-0.0.0.0}"
|
export TRAPOS_SERVER_HOST="${TRAPOS_SERVER_HOST:-0.0.0.0}"
|
||||||
export TRAPOS_SERVER_PORT="${TRAPOS_SERVER_PORT:-4444}"
|
export TRAPOS_SERVER_PORT="${TRAPOS_SERVER_PORT:-4444}"
|
||||||
|
|||||||
@ -3,11 +3,14 @@ import { createApp, type Config } from "./app.js";
|
|||||||
const config: Config = {
|
const config: Config = {
|
||||||
host: process.env.TRAPOS_SERVER_HOST ?? "0.0.0.0",
|
host: process.env.TRAPOS_SERVER_HOST ?? "0.0.0.0",
|
||||||
port: readPort(process.env.TRAPOS_SERVER_PORT, 4444),
|
port: readPort(process.env.TRAPOS_SERVER_PORT, 4444),
|
||||||
serverPassword: process.env.TRAPOS_SERVER_PASSWORD,
|
serverPassword: requireSecret("TRAPOS_SERVER_PASSWORD", process.env.TRAPOS_SERVER_PASSWORD),
|
||||||
requestTimeoutMs: readPositiveInt(process.env.TRAPOS_SERVER_REQUEST_TIMEOUT_MS, 600_000),
|
requestTimeoutMs: readPositiveInt(process.env.TRAPOS_SERVER_REQUEST_TIMEOUT_MS, 600_000),
|
||||||
opencodeUrl: process.env.OPENCODE_URL ?? "http://127.0.0.1:4242",
|
opencodeUrl: process.env.OPENCODE_URL ?? "http://127.0.0.1:4242",
|
||||||
opencodeUsername: process.env.OPENCODE_USERNAME ?? "opencode",
|
opencodeUsername: process.env.OPENCODE_USERNAME ?? "opencode",
|
||||||
opencodeServerPassword: process.env.OPENCODE_SERVER_PASSWORD,
|
opencodeServerPassword: requireSecret(
|
||||||
|
"OPENCODE_SERVER_PASSWORD",
|
||||||
|
process.env.OPENCODE_SERVER_PASSWORD,
|
||||||
|
),
|
||||||
// MCP endpoint: on by default, bound to localhost. exec-lua / write-file are as
|
// MCP endpoint: on by default, bound to localhost. exec-lua / write-file are as
|
||||||
// powerful as the linked computer, so the listener stays off the public gateway port.
|
// powerful as the linked computer, so the listener stays off the public gateway port.
|
||||||
mcpEnabled: process.env.MCP_ENABLED !== "0",
|
mcpEnabled: process.env.MCP_ENABLED !== "0",
|
||||||
@ -53,6 +56,22 @@ function buildLogger(): Config["logger"] {
|
|||||||
return { level };
|
return { level };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A non-empty password is mandatory: an empty TRAPOS_SERVER_PASSWORD disables auth
|
||||||
|
// on the public gateway (resolveAccount maps any secret to "local"), and an empty
|
||||||
|
// OPENCODE_SERVER_PASSWORD drops the outbound Basic-auth header. Refuse to start
|
||||||
|
// rather than run silently unauthenticated.
|
||||||
|
function requireSecret(name: string, value: string | undefined): string {
|
||||||
|
const secret = value?.trim();
|
||||||
|
if (!secret) {
|
||||||
|
process.stderr.write(
|
||||||
|
`\n[trapos-server] ${name} is empty or unset. Set it in .env ` +
|
||||||
|
`(run \`just install\` to generate secrets). Refusing to start.\n\n`,
|
||||||
|
);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
return secret;
|
||||||
|
}
|
||||||
|
|
||||||
function readPort(value: string | undefined, fallback: number): number {
|
function readPort(value: string | undefined, fallback: number): number {
|
||||||
return readPositiveInt(value, fallback);
|
return readPositiveInt(value, fallback);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user