mirror of
https://github.com/TronoSfera/backup_service.git
synced 2026-05-18 10:03:32 +03:00
Merge pull request #6 from TronoSfera/codex/fix-admin-login-unauthorized-error
Honor .env ADMIN credentials and seed initial admin on startup
This commit is contained in:
commit
41f8430bb4
5 changed files with 48 additions and 4 deletions
|
|
@ -10,6 +10,12 @@
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
SECRET_KEY=mysecretkey
|
SECRET_KEY=mysecretkey
|
||||||
|
|
||||||
|
# Initial admin credentials (created on first startup if no users exist).
|
||||||
|
# If omitted, the server falls back to USERNAME/PASSWORD for backward
|
||||||
|
# compatibility with older compose files.
|
||||||
|
ADMIN_USERNAME=admin
|
||||||
|
ADMIN_PASSWORD=adminpass
|
||||||
|
|
||||||
# Use Postgres instead of SQLite. This DSN is used by SQLAlchemy. If you
|
# Use Postgres instead of SQLite. This DSN is used by SQLAlchemy. If you
|
||||||
# leave it empty or omit it, the server will fall back to a local SQLite
|
# leave it empty or omit it, the server will fall back to a local SQLite
|
||||||
# database stored in `/app/backup.db`.
|
# database stored in `/app/backup.db`.
|
||||||
|
|
|
||||||
|
|
@ -133,6 +133,10 @@ by supplying a `.env` file, or via the built‑in web interface on port 8080.
|
||||||
browser, authenticate using a token from `/api/login`, and use the “Create
|
browser, authenticate using a token from `/api/login`, and use the “Create
|
||||||
User” form. Alternatively, you can call the `/api/register_user` endpoint
|
User” form. Alternatively, you can call the `/api/register_user` endpoint
|
||||||
directly using a bearer token from an existing admin.
|
directly using a bearer token from an existing admin.
|
||||||
|
* On first startup, the server will create an initial admin user if the
|
||||||
|
database is empty. Configure `ADMIN_USERNAME` and `ADMIN_PASSWORD` (or
|
||||||
|
`USERNAME`/`PASSWORD` for backward compatibility) in your environment or
|
||||||
|
`.env` file to control these credentials.
|
||||||
* Ensure that the retention policies set on each user reflect your backup
|
* Ensure that the retention policies set on each user reflect your backup
|
||||||
strategy. For example, specifying `retention_versions=5` keeps the five
|
strategy. For example, specifying `retention_versions=5` keeps the five
|
||||||
most recent versions of each file; specifying `retention_days=30` retains
|
most recent versions of each file; specifying `retention_days=30` retains
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,9 @@ services:
|
||||||
environment:
|
environment:
|
||||||
# Change SECRET_KEY in production
|
# Change SECRET_KEY in production
|
||||||
SECRET_KEY: "mysecretkey"
|
SECRET_KEY: "mysecretkey"
|
||||||
|
# Initial admin user (created on first startup if no users exist)
|
||||||
|
ADMIN_USERNAME: "${ADMIN_USERNAME:-admin}"
|
||||||
|
ADMIN_PASSWORD: "${ADMIN_PASSWORD:-adminpass}"
|
||||||
# Use Postgres instead of SQLite. The DATABASE_URL uses the same
|
# Use Postgres instead of SQLite. The DATABASE_URL uses the same
|
||||||
# credentials defined in the db service below.
|
# credentials defined in the db service below.
|
||||||
DATABASE_URL: "postgresql+psycopg2://backup:backup@db:5432/backup"
|
DATABASE_URL: "postgresql+psycopg2://backup:backup@db:5432/backup"
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,9 @@ services:
|
||||||
environment:
|
environment:
|
||||||
# Change SECRET_KEY in production
|
# Change SECRET_KEY in production
|
||||||
SECRET_KEY: "mysecretkey"
|
SECRET_KEY: "mysecretkey"
|
||||||
|
# Initial admin user (created on first startup if no users exist)
|
||||||
|
ADMIN_USERNAME: "${ADMIN_USERNAME:-admin}"
|
||||||
|
ADMIN_PASSWORD: "${ADMIN_PASSWORD:-adminpass}"
|
||||||
# Use Postgres instead of SQLite. The DATABASE_URL uses the same
|
# Use Postgres instead of SQLite. The DATABASE_URL uses the same
|
||||||
# credentials defined in the db service below.
|
# credentials defined in the db service below.
|
||||||
DATABASE_URL: "postgresql+psycopg2://backup:backup@db:5432/backup"
|
DATABASE_URL: "postgresql+psycopg2://backup:backup@db:5432/backup"
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,32 @@ templates = Jinja2Templates(directory=os.path.join(os.path.dirname(__file__), "t
|
||||||
storage = storage_module.get_storage()
|
storage = storage_module.get_storage()
|
||||||
|
|
||||||
|
|
||||||
|
def ensure_default_admin() -> None:
|
||||||
|
"""Seed an initial admin user when the database is empty.
|
||||||
|
|
||||||
|
Uses ADMIN_USERNAME/ADMIN_PASSWORD, falling back to USERNAME/PASSWORD for
|
||||||
|
backward compatibility with existing compose files and .env settings.
|
||||||
|
"""
|
||||||
|
username = os.getenv("ADMIN_USERNAME") or os.getenv("USERNAME")
|
||||||
|
password = os.getenv("ADMIN_PASSWORD") or os.getenv("PASSWORD")
|
||||||
|
if not username or not password:
|
||||||
|
return
|
||||||
|
db = database.SessionLocal()
|
||||||
|
try:
|
||||||
|
existing_user = db.query(models.User).first()
|
||||||
|
if existing_user:
|
||||||
|
return
|
||||||
|
admin = models.User(
|
||||||
|
username=username,
|
||||||
|
hashed_password=auth.hash_password(password),
|
||||||
|
is_admin=True,
|
||||||
|
)
|
||||||
|
db.add(admin)
|
||||||
|
db.commit()
|
||||||
|
finally:
|
||||||
|
db.close()
|
||||||
|
|
||||||
|
|
||||||
@app.exception_handler(HTTPException)
|
@app.exception_handler(HTTPException)
|
||||||
async def custom_http_exception_handler(request: Request, exc: HTTPException) -> Response:
|
async def custom_http_exception_handler(request: Request, exc: HTTPException) -> Response:
|
||||||
if (
|
if (
|
||||||
|
|
@ -77,6 +103,8 @@ async def on_startup() -> None:
|
||||||
# Column already exists or migration failed; ignore
|
# Column already exists or migration failed; ignore
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
ensure_default_admin()
|
||||||
|
|
||||||
|
|
||||||
@app.post("/api/register_user", response_model=schemas.UserOut)
|
@app.post("/api/register_user", response_model=schemas.UserOut)
|
||||||
async def register_user(
|
async def register_user(
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue