wiregui/wiregui/auth/seed.py
Stefano Bertelli 92554d4089
All checks were successful
CI / test (push) Successful in 1m58s
CI / release (push) Successful in 35s
CI / docker (push) Successful in 35s
fix: make keypair generation async to avoid blocking the event loop
generate_keypair() used synchronous subprocess.run() which blocked
the NiceGUI event loop during wg genkey/pubkey calls. This caused
WebSocket disconnects, page reloads, and the config dialog never
appearing after device creation.

Switched to asyncio.create_subprocess_exec so the event loop stays
responsive while waiting for the wg CLI.
2026-03-30 22:57:00 -05:00

61 lines
2.1 KiB
Python

"""Seed the initial admin user and server keypair on first startup."""
import secrets
from loguru import logger
from sqlmodel import select
from wiregui.auth.passwords import hash_password
from wiregui.config import get_settings
from wiregui.db import async_session
from wiregui.models.configuration import Configuration
from wiregui.models.user import User
async def seed_admin() -> None:
"""Create admin user if no users exist in the database."""
async with async_session() as session:
result = await session.execute(select(User).limit(1))
if result.scalar_one_or_none() is not None:
return # users already exist
settings = get_settings()
password = settings.admin_password or secrets.token_urlsafe(16)
admin = User(
email=settings.admin_email,
password_hash=hash_password(password),
role="admin",
)
session.add(admin)
await session.commit()
logger.info("Admin user created: {}", settings.admin_email)
if settings.admin_password is None:
logger.warning("Generated admin password: {}", password)
async def ensure_server_keypair() -> None:
"""Generate and store the server WireGuard keypair in Configuration if missing."""
from wiregui.utils.crypto import generate_keypair
async with async_session() as session:
result = await session.execute(select(Configuration).limit(1))
config = result.scalar_one_or_none()
if config is None:
config = Configuration()
session.add(config)
if config.server_public_key and config.server_private_key:
return # already have keys
try:
private_key, public_key = await generate_keypair()
config.server_private_key = private_key
config.server_public_key = public_key
session.add(config)
await session.commit()
logger.info("Server WireGuard keypair generated (pubkey: {}...)", public_key[:20])
except Exception as e:
logger.warning("Could not generate server keypair (wg CLI not available?): {}", e)