Make install_server handle one-time admin bootstrap prompt

This commit is contained in:
Jage9
2026-02-24 22:11:10 -05:00
parent bf3bc90f2a
commit 404384416e
3 changed files with 74 additions and 2 deletions

View File

@@ -38,6 +38,7 @@ This creates:
- `/home/bestmidi/chgrid/server/.venv`
- `/home/bestmidi/chgrid/server/config.toml` (if missing)
- `/home/bestmidi/chgrid/server/.env` with `CHGRID_AUTH_SECRET` (if missing)
- On first run only, if no admin exists, it prompts to create one immediately.
Edit `/home/bestmidi/chgrid/server/config.toml`:
- `server.bind_ip = "127.0.0.1"`
@@ -48,6 +49,14 @@ Edit `/home/bestmidi/chgrid/server/config.toml`:
- `storage.state_file = "runtime/items.json"`
- `auth.db_file = "runtime/chatgrid.db"`
If you skip first-run admin creation, run later:
```bash
cd /home/bestmidi/chgrid/server
source .env
.venv/bin/python main.py --config config.toml --bootstrap-admin
```
## 4) Build and publish client
```bash

View File

@@ -61,5 +61,63 @@ PY
echo "created $SERVER_DIR/.env with CHGRID_AUTH_SECRET"
fi
# Load generated/shared auth secret for bootstrap checks.
if [[ -f .env ]]; then
set -a
# shellcheck disable=SC1091
source .env
set +a
fi
if [[ -n "${CHGRID_AUTH_SECRET:-}" ]]; then
HAS_ADMIN="$(
.venv/bin/python - <<'PY'
from pathlib import Path
import os
from app.auth_service import AuthService
from app.config import load_config
cfg = load_config(Path("config.toml"))
secret = os.getenv("CHGRID_AUTH_SECRET", "").strip()
if not secret:
print("unknown")
raise SystemExit(0)
db_file = cfg.auth.db_file.strip() or "runtime/chatgrid.db"
db_path = Path(db_file)
if not db_path.is_absolute():
db_path = Path.cwd() / db_path
svc = AuthService(
db_path=db_path,
token_hash_secret=secret,
password_min_length=cfg.auth.password_min_length,
password_max_length=cfg.auth.password_max_length,
username_min_length=cfg.auth.username_min_length,
username_max_length=cfg.auth.username_max_length,
)
try:
print("yes" if svc.has_admin() else "no")
finally:
svc.close()
PY
)"
if [[ "$HAS_ADMIN" == "no" ]]; then
if [[ -t 0 ]]; then
read -r -p "No admin account found. Create one now? [y/N] " CREATE_ADMIN_NOW
case "${CREATE_ADMIN_NOW:-}" in
y|Y|yes|YES)
.venv/bin/python main.py --config config.toml --bootstrap-admin
;;
*)
echo "skipped admin bootstrap (you can run: .venv/bin/python main.py --config config.toml --bootstrap-admin)"
;;
esac
else
echo "no admin account found (non-interactive run)."
echo "run once to bootstrap: .venv/bin/python main.py --config config.toml --bootstrap-admin"
fi
fi
fi
echo "server install complete"
echo "next: edit $SERVER_DIR/config.toml (TLS, bind_ip, port)"

View File

@@ -83,12 +83,17 @@ class AuthService:
def bootstrap_admin(self, username: str, password: str, email: str | None = None) -> AuthUser:
"""Create the first admin account, or fail if one already exists."""
existing = self._conn.execute("SELECT 1 FROM users WHERE role = 'admin' LIMIT 1").fetchone()
if existing is not None:
if self.has_admin():
raise AuthError("An admin account already exists.")
created = self.register(username, password, email=email, role="admin")
return created.user
def has_admin(self) -> bool:
"""Return True when at least one admin account exists."""
existing = self._conn.execute("SELECT 1 FROM users WHERE role = 'admin' LIMIT 1").fetchone()
return existing is not None
def register(
self,
username: str,