No description
Find a file
James Trotter 6e9d525654 feat(portal): let users change their account password
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>
2026-10-09 19:38:50 -04:00
cmd/shells-dashboard deploy: Logto stack + portal service/Traefik; portal.4evr.sh + id.4evr.sh 2026-06-20 19:10:01 -04:00
deploy fix(ui): readable login button + no logout when logged out; deploy notes 2026-06-20 19:56:41 -04:00
internal feat(portal): let users change their account password 2026-10-09 19:38:50 -04:00
web feat(portal): let users change their account password 2026-10-09 19:38:50 -04:00
.gitignore deploy: Logto runs on the ircforever-vps (separate instance) at id.4evr.sh 2026-06-20 19:28:36 -04:00
build.sh shells-dashboard: self-service portal for 4evr.sh shells (Go + embedded SvelteKit SPA) 2026-06-20 16:12:28 -04:00
go.mod shells-dashboard: self-service portal for 4evr.sh shells (Go + embedded SvelteKit SPA) 2026-06-20 16:12:28 -04:00
go.sum shells-dashboard: self-service portal for 4evr.sh shells (Go + embedded SvelteKit SPA) 2026-06-20 16:12:28 -04:00
README.md deploy: Logto stack + portal service/Traefik; portal.4evr.sh + id.4evr.sh 2026-06-20 19:10:01 -04:00

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 via bun, //go:embed). No Node at runtime.
  • Reuses the ircforever/website Tailwind 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 — OIDC
  • GET /api/me, GET /api/shell — identity + the caller's shell
  • POST /api/shell/subdomain /sshkey /rebuild /upgrade — manage (session-scoped)
  • everything else → the embedded SPA