Make install_server handle one-time admin bootstrap prompt
This commit is contained in:
@@ -38,6 +38,7 @@ This creates:
|
|||||||
- `/home/bestmidi/chgrid/server/.venv`
|
- `/home/bestmidi/chgrid/server/.venv`
|
||||||
- `/home/bestmidi/chgrid/server/config.toml` (if missing)
|
- `/home/bestmidi/chgrid/server/config.toml` (if missing)
|
||||||
- `/home/bestmidi/chgrid/server/.env` with `CHGRID_AUTH_SECRET` (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`:
|
Edit `/home/bestmidi/chgrid/server/config.toml`:
|
||||||
- `server.bind_ip = "127.0.0.1"`
|
- `server.bind_ip = "127.0.0.1"`
|
||||||
@@ -48,6 +49,14 @@ Edit `/home/bestmidi/chgrid/server/config.toml`:
|
|||||||
- `storage.state_file = "runtime/items.json"`
|
- `storage.state_file = "runtime/items.json"`
|
||||||
- `auth.db_file = "runtime/chatgrid.db"`
|
- `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
|
## 4) Build and publish client
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -61,5 +61,63 @@ PY
|
|||||||
echo "created $SERVER_DIR/.env with CHGRID_AUTH_SECRET"
|
echo "created $SERVER_DIR/.env with CHGRID_AUTH_SECRET"
|
||||||
fi
|
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 "server install complete"
|
||||||
echo "next: edit $SERVER_DIR/config.toml (TLS, bind_ip, port)"
|
echo "next: edit $SERVER_DIR/config.toml (TLS, bind_ip, port)"
|
||||||
|
|||||||
@@ -83,12 +83,17 @@ class AuthService:
|
|||||||
def bootstrap_admin(self, username: str, password: str, email: str | None = None) -> AuthUser:
|
def bootstrap_admin(self, username: str, password: str, email: str | None = None) -> AuthUser:
|
||||||
"""Create the first admin account, or fail if one already exists."""
|
"""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 self.has_admin():
|
||||||
if existing is not None:
|
|
||||||
raise AuthError("An admin account already exists.")
|
raise AuthError("An admin account already exists.")
|
||||||
created = self.register(username, password, email=email, role="admin")
|
created = self.register(username, password, email=email, role="admin")
|
||||||
return created.user
|
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(
|
def register(
|
||||||
self,
|
self,
|
||||||
username: str,
|
username: str,
|
||||||
|
|||||||
Reference in New Issue
Block a user