2026-03-31 21:27:46 -05:00
|
|
|
"""Tests for authentication modules — seed logic and JWT edge cases."""
|
feat: initial WireGUI implementation — full VPN management platform
Complete Python/NiceGUI rewrite of the Wirezone (Elixir/Phoenix) VPN
management platform. All 10 implementation phases delivered.
Core stack:
- NiceGUI reactive UI with SQLModel ORM on PostgreSQL (asyncpg)
- Alembic migrations, Valkey/Redis cache, pydantic-settings config
- WireGuard management via subprocess (wg/ip/nft CLIs)
- 164 tests passing, 35% code coverage
Features:
- User/device/rule CRUD with admin and unprivileged roles
- Full device config form with per-device WG overrides
- WireGuard client config generation with QR codes
- REST API (v0) with Bearer token auth for all resources
- TOTP MFA with QR registration and challenge flow
- OIDC SSO with authlib (provider registry, auto-create users)
- Magic link passwordless sign-in via email
- SAML SP-initiated SSO with IdP metadata parsing
- WebAuthn/FIDO2 security key registration
- nftables firewall with per-user chains and masquerade
- Background tasks: WG stats polling, VPN session expiry,
OIDC token refresh, WAN connectivity checks
- Startup reconciliation (DB ↔ WireGuard state sync)
- In-memory notification system with header badge
- Admin UI: users, devices, rules, settings (3 tabs), diagnostics
- Loguru logging with optional timestamped file output
Deployment:
- Multi-stage Dockerfile (python:3.13-slim)
- Docker Compose prod stack (bridge networking, NET_ADMIN, nftables)
- Forgejo CI: tests → semantic versioning → Docker registry push
- Health endpoint at /api/health
2026-03-30 16:53:46 -05:00
|
|
|
|
|
|
|
|
from sqlmodel import select
|
|
|
|
|
|
|
|
|
|
from wiregui.auth.jwt import create_access_token, decode_access_token
|
|
|
|
|
from wiregui.auth.passwords import hash_password, verify_password
|
|
|
|
|
from wiregui.auth.seed import seed_admin
|
|
|
|
|
from wiregui.models.user import User
|
|
|
|
|
|
|
|
|
|
|
2026-03-31 21:27:46 -05:00
|
|
|
# --- Password hashing (format guard) ---
|
feat: initial WireGUI implementation — full VPN management platform
Complete Python/NiceGUI rewrite of the Wirezone (Elixir/Phoenix) VPN
management platform. All 10 implementation phases delivered.
Core stack:
- NiceGUI reactive UI with SQLModel ORM on PostgreSQL (asyncpg)
- Alembic migrations, Valkey/Redis cache, pydantic-settings config
- WireGuard management via subprocess (wg/ip/nft CLIs)
- 164 tests passing, 35% code coverage
Features:
- User/device/rule CRUD with admin and unprivileged roles
- Full device config form with per-device WG overrides
- WireGuard client config generation with QR codes
- REST API (v0) with Bearer token auth for all resources
- TOTP MFA with QR registration and challenge flow
- OIDC SSO with authlib (provider registry, auto-create users)
- Magic link passwordless sign-in via email
- SAML SP-initiated SSO with IdP metadata parsing
- WebAuthn/FIDO2 security key registration
- nftables firewall with per-user chains and masquerade
- Background tasks: WG stats polling, VPN session expiry,
OIDC token refresh, WAN connectivity checks
- Startup reconciliation (DB ↔ WireGuard state sync)
- In-memory notification system with header badge
- Admin UI: users, devices, rules, settings (3 tabs), diagnostics
- Loguru logging with optional timestamped file output
Deployment:
- Multi-stage Dockerfile (python:3.13-slim)
- Docker Compose prod stack (bridge networking, NET_ADMIN, nftables)
- Forgejo CI: tests → semantic versioning → Docker registry push
- Health endpoint at /api/health
2026-03-30 16:53:46 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_hash_is_not_plaintext():
|
|
|
|
|
hashed = hash_password("plaintext")
|
|
|
|
|
assert hashed != "plaintext"
|
|
|
|
|
assert hashed.startswith("$2b$")
|
|
|
|
|
|
|
|
|
|
|
2026-03-31 21:27:46 -05:00
|
|
|
# --- JWT edge cases ---
|
feat: initial WireGUI implementation — full VPN management platform
Complete Python/NiceGUI rewrite of the Wirezone (Elixir/Phoenix) VPN
management platform. All 10 implementation phases delivered.
Core stack:
- NiceGUI reactive UI with SQLModel ORM on PostgreSQL (asyncpg)
- Alembic migrations, Valkey/Redis cache, pydantic-settings config
- WireGuard management via subprocess (wg/ip/nft CLIs)
- 164 tests passing, 35% code coverage
Features:
- User/device/rule CRUD with admin and unprivileged roles
- Full device config form with per-device WG overrides
- WireGuard client config generation with QR codes
- REST API (v0) with Bearer token auth for all resources
- TOTP MFA with QR registration and challenge flow
- OIDC SSO with authlib (provider registry, auto-create users)
- Magic link passwordless sign-in via email
- SAML SP-initiated SSO with IdP metadata parsing
- WebAuthn/FIDO2 security key registration
- nftables firewall with per-user chains and masquerade
- Background tasks: WG stats polling, VPN session expiry,
OIDC token refresh, WAN connectivity checks
- Startup reconciliation (DB ↔ WireGuard state sync)
- In-memory notification system with header badge
- Admin UI: users, devices, rules, settings (3 tabs), diagnostics
- Loguru logging with optional timestamped file output
Deployment:
- Multi-stage Dockerfile (python:3.13-slim)
- Docker Compose prod stack (bridge networking, NET_ADMIN, nftables)
- Forgejo CI: tests → semantic versioning → Docker registry push
- Health endpoint at /api/health
2026-03-30 16:53:46 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_decode_invalid_token():
|
|
|
|
|
assert decode_access_token("garbage.token.value") is None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_decode_tampered_token():
|
|
|
|
|
token = create_access_token(user_id="user-123", role="admin")
|
|
|
|
|
tampered = token[:-4] + "XXXX"
|
|
|
|
|
assert decode_access_token(tampered) is None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# --- Admin seed ---
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async def test_seed_admin_creates_user(session, monkeypatch):
|
|
|
|
|
"""seed_admin should create an admin when no users exist."""
|
|
|
|
|
from contextlib import asynccontextmanager
|
|
|
|
|
|
|
|
|
|
@asynccontextmanager
|
|
|
|
|
async def mock_session():
|
|
|
|
|
yield session
|
|
|
|
|
|
|
|
|
|
monkeypatch.setattr("wiregui.auth.seed.async_session", mock_session)
|
|
|
|
|
monkeypatch.setattr("wiregui.auth.seed.get_settings", lambda: type("S", (), {
|
|
|
|
|
"admin_email": "seed-test@example.com",
|
|
|
|
|
"admin_password": "seed-pass-123",
|
|
|
|
|
})())
|
|
|
|
|
|
|
|
|
|
await seed_admin()
|
|
|
|
|
|
|
|
|
|
result = await session.execute(select(User).where(User.email == "seed-test@example.com"))
|
|
|
|
|
admin = result.scalar_one()
|
|
|
|
|
assert admin.role == "admin"
|
|
|
|
|
assert verify_password("seed-pass-123", admin.password_hash)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async def test_seed_admin_skips_when_users_exist(session, monkeypatch):
|
|
|
|
|
"""seed_admin should not create a second admin if users already exist."""
|
|
|
|
|
from contextlib import asynccontextmanager
|
|
|
|
|
|
|
|
|
|
existing = User(email="existing@example.com", role="unprivileged")
|
|
|
|
|
session.add(existing)
|
|
|
|
|
await session.flush()
|
|
|
|
|
|
|
|
|
|
@asynccontextmanager
|
|
|
|
|
async def mock_session():
|
|
|
|
|
yield session
|
|
|
|
|
|
|
|
|
|
monkeypatch.setattr("wiregui.auth.seed.async_session", mock_session)
|
|
|
|
|
|
|
|
|
|
await seed_admin()
|
|
|
|
|
|
|
|
|
|
result = await session.execute(select(User))
|
|
|
|
|
users = result.scalars().all()
|
|
|
|
|
assert len(users) == 1
|
|
|
|
|
assert users[0].email == "existing@example.com"
|