No description
Adds an "Account password" card (shown with or without a shell) backed by POST /api/account/password. The portal acts as the signed-in user through Logto's Account API with that user's own access token (now kept in the session), so it holds no admin credential: Logto verifies the current password, enforces its password policy and can only change that user's password. The endpoint only accepts same-origin JSON, refuses after 5 wrong current passwords per user in 15 minutes, never logs either password, and asks the user to sign in again when their access token has expired. Requires Logto's account center enabled with the password field editable. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|---|---|---|
| cmd/shells-dashboard | ||
| deploy | ||
| internal | ||
| web | ||
| .gitignore | ||
| build.sh | ||
| go.mod | ||
| go.sum | ||
| README.md | ||
shells-dashboard
Self-service web portal for 4evr.sh shells. A shell owner logs in with their
IRCforever account (Logto / OIDC) and manages their own shell: change their
subdomain, rotate their SSH key, see status / connection details, and
rebuild / upgrade. Shell creation stays in IRC (!shell); this portal manages
an existing shell.
Runs on the shells host, calls shellsd over loopback, and is fronted by Traefik.
Design
- Single Go binary = JSON API + an embedded SvelteKit SPA (
web/, static build viabun,//go:embed). No Node at runtime. - Reuses the
ircforever/websiteTailwind v4 design system (web/src/app.css). - Auth: OIDC (Logto) — auth-code + PKCE, signed session cookie
(
internal/auth, adapted from managebot). - Shells: HMAC client to shellsd
/v1/list,/v1/set-subdomain,/v1/rekey,/v1/rebuild,/v1/upgrade(internal/shellsapi). Never deprovision. - Identity → shell: the logged-in user's Logto username == their shell username. Every operation is scoped to the session's username (never taken from the request body).
Build
./build.sh # bun build SPA -> go build (single binary)
# or cross-compile for the host:
( cd web && bun install && bun run build )
GOOS=linux GOARCH=amd64 go build -o shells-dashboard ./cmd/shells-dashboard
(web/build is committed so go build works without a frontend build; regenerate it
with bun run build when the SPA changes.)
Run / config (env)
| var | default | purpose |
|---|---|---|
PORTAL_LISTEN |
127.0.0.1:8095 |
listen address (behind Traefik) |
SHELLSD_URL |
http://127.0.0.1:8090 |
shellsd base URL (loopback) |
SHELLSD_HMAC_SECRET |
— (required) | shared with /etc/shellsd/env |
OIDC_ISSUER |
— | Logto issuer URL |
OIDC_CLIENT_ID / OIDC_CLIENT_SECRET |
— | Logto application creds |
OIDC_REDIRECT_URL |
https://portal.4evr.sh/auth/callback |
OIDC callback |
OIDC_POST_LOGOUT_URL |
https://portal.4evr.sh/ |
post-logout |
OIDC_SESSION_SECRET |
— | signs the session cookie |
PORTAL_DEV_AUTH |
— | 1 = bypass OIDC with a stub user (local dev only) |
Local dev: cd web && bun run dev (proxies /api+/auth to :8095); run the Go
binary with PORTAL_DEV_AUTH=1 SHELLSD_HMAC_SECRET=x.
Routes
GET /auth/login/auth/callback/auth/logout— OIDCGET /api/me,GET /api/shell— identity + the caller's shellPOST /api/shell/subdomain/sshkey/rebuild/upgrade— manage (session-scoped)- everything else → the embedded SPA