Update .env.example and README.md for passkey authentication

- .env.example: Add WEBAUTHN_RP_ID, WEBAUTHN_RP_NAME, WEBAUTHN_ORIGIN,
  ENVIRONMENT, and UMBRA_URL with documentation comments
- README.md: Full rewrite — remove outdated PIN/bcrypt references, document
  current auth stack (Argon2id + TOTP + passkeys), all 17 API route groups,
  security features, and Docker deployment

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Kyle 2026-03-17 23:25:27 +08:00
parent 9234880648
commit 57d400c6de
2 changed files with 85 additions and 148 deletions

View File

@ -1,2 +1,14 @@
DATABASE_URL=postgresql+asyncpg://postgres:postgres@localhost:5432/umbra DATABASE_URL=postgresql+asyncpg://postgres:postgres@localhost:5432/umbra
SECRET_KEY=your-secret-key-change-in-production SECRET_KEY=your-secret-key-change-in-production
ENVIRONMENT=development
# Public-facing URL (used for ntfy click links, CORS derivation)
UMBRA_URL=http://localhost
# WebAuthn / Passkey authentication
# RP_ID must be the eTLD+1 domain of the live site (e.g. umbra.ghost6.xyz)
# ORIGIN must include the scheme (https://)
# These defaults work for local development; override in production .env
WEBAUTHN_RP_ID=localhost
WEBAUTHN_RP_NAME=UMBRA
WEBAUTHN_ORIGIN=http://localhost

View File

@ -1,39 +1,37 @@
# UMBRA Backend # UMBRA Backend
A complete FastAPI backend for the UMBRA application with async SQLAlchemy, PostgreSQL, authentication, and comprehensive CRUD operations. FastAPI backend for the UMBRA life management application with async SQLAlchemy, PostgreSQL, multi-user RBAC, and comprehensive security.
## Features ## Features
- **FastAPI** with async/await support - **FastAPI** with async/await and Pydantic v2
- **SQLAlchemy 2.0** with async engine - **SQLAlchemy 2.0** async engine with `Mapped[]` types
- **PostgreSQL** with asyncpg driver - **PostgreSQL 16** via asyncpg
- **Alembic** for database migrations - **Alembic** database migrations (001-061)
- **bcrypt** for password hashing - **Authentication**: Argon2id passwords + signed httpOnly cookies + optional TOTP MFA + passkey (WebAuthn/FIDO2)
- **itsdangerous** for session management - **Multi-user RBAC**: admin/standard roles, per-user resource scoping
- **PIN-based authentication** with secure session cookies - **Session management**: DB-backed sessions, sliding window expiry, concurrent session cap
- **Full CRUD operations** for all entities - **Account security**: Account lockout (10 failures = 30-min lock), CSRF protection, rate limiting
- **Dashboard** with aggregated data - **APScheduler** for background notification dispatch
- **CORS enabled** for frontend integration
## Project Structure ## Project Structure
``` ```
backend/ backend/
├── alembic/ # Database migrations ├── alembic/versions/ # 61 database migrations
│ ├── versions/ # Migration files
│ ├── env.py # Alembic environment
│ └── script.py.mako # Migration template
├── app/ ├── app/
│ ├── models/ # SQLAlchemy models │ ├── models/ # 21 SQLAlchemy 2.0 models
│ ├── schemas/ # Pydantic schemas │ ├── schemas/ # 14 Pydantic v2 schema modules
│ ├── routers/ # API route handlers │ ├── routers/ # 17 API routers
│ ├── config.py # Configuration │ ├── services/ # Auth, session, passkey, TOTP, audit, recurrence, etc.
│ ├── database.py # Database setup │ ├── jobs/ # APScheduler notification dispatch
│ └── main.py # FastAPI application │ ├── config.py # Pydantic Settings (env vars)
├── requirements.txt # Python dependencies │ ├── database.py # Async engine + session factory
├── Dockerfile # Docker configuration │ └── main.py # FastAPI app + CSRF middleware
├── alembic.ini # Alembic configuration ├── requirements.txt
└── start.sh # Startup script ├── Dockerfile
├── alembic.ini
└── start.sh
``` ```
## Setup ## Setup
@ -41,160 +39,87 @@ backend/
### 1. Install Dependencies ### 1. Install Dependencies
```bash ```bash
cd backend
pip install -r requirements.txt pip install -r requirements.txt
``` ```
### 2. Configure Environment ### 2. Configure Environment
Create a `.env` file: Copy `.env.example` to `.env` and configure:
```bash ```bash
DATABASE_URL=postgresql+asyncpg://postgres:postgres@localhost:5432/umbra DATABASE_URL=postgresql+asyncpg://postgres:postgres@db:5432/umbra
SECRET_KEY=your-secret-key-change-in-production SECRET_KEY=generate-a-strong-random-key
ENVIRONMENT=production
# WebAuthn / Passkeys (required for passkey auth)
WEBAUTHN_RP_ID=your-domain.com
WEBAUTHN_RP_NAME=UMBRA
WEBAUTHN_ORIGIN=https://your-domain.com
``` ```
### 3. Create Database ### 3. Run Migrations
```bash
createdb umbra
```
### 4. Run Migrations
```bash ```bash
alembic upgrade head alembic upgrade head
``` ```
### 5. Start Server ### 4. Start Server
```bash ```bash
# Using the start script uvicorn app.main:app --host 0.0.0.0 --port 8000
chmod +x start.sh
./start.sh
# Or directly with uvicorn
uvicorn app.main:app --reload
``` ```
The API will be available at `http://localhost:8000` ## API Routes
## API Documentation All routes require authentication (signed session cookie) except `/api/auth/*` and `/health`.
Interactive API documentation is available at: | Prefix | Description |
- **Swagger UI**: http://localhost:8000/docs |--------|-------------|
- **ReDoc**: http://localhost:8000/redoc | `/api/auth` | Login, logout, register, setup, status, password, TOTP, passkeys |
| `/api/admin` | User management, system config, audit logs (admin only) |
| `/api/todos` | Task management with categories and priorities |
| `/api/events` | Calendar events with recurrence support |
| `/api/event-invitations` | Event invitation RSVP and management |
| `/api/event-templates` | Reusable event templates |
| `/api/calendars` | Calendar CRUD |
| `/api/shared-calendars` | Calendar sharing with permission levels |
| `/api/reminders` | Reminder management with snooze |
| `/api/projects` | Projects with tasks, comments, and collaboration |
| `/api/people` | Contact management |
| `/api/locations` | Location management |
| `/api/connections` | User connections (friend requests) |
| `/api/notifications` | In-app notification centre |
| `/api/settings` | User preferences and ntfy configuration |
| `/api/dashboard` | Aggregated dashboard data |
| `/api/weather` | Weather widget data |
## API Endpoints ## Authentication
### Authentication UMBRA supports three authentication methods:
- `POST /api/auth/setup` - Initial PIN setup
- `POST /api/auth/login` - Login with PIN
- `POST /api/auth/logout` - Logout
- `GET /api/auth/status` - Check auth status
### Todos 1. **Password** (Argon2id) - Primary login method
- `GET /api/todos` - List todos (with filters) 2. **TOTP MFA** - Optional second factor via authenticator apps
- `POST /api/todos` - Create todo 3. **Passkeys** (WebAuthn/FIDO2) - Optional passwordless login via biometrics, security keys, or password managers
- `GET /api/todos/{id}` - Get todo
- `PUT /api/todos/{id}` - Update todo
- `DELETE /api/todos/{id}` - Delete todo
- `PATCH /api/todos/{id}/toggle` - Toggle completion
### Calendar Events Passkey login bypasses TOTP (a passkey is inherently two-factor: possession + biometric/PIN).
- `GET /api/events` - List events (with date range)
- `POST /api/events` - Create event
- `GET /api/events/{id}` - Get event
- `PUT /api/events/{id}` - Update event
- `DELETE /api/events/{id}` - Delete event
### Reminders ## Security
- `GET /api/reminders` - List reminders (with filters)
- `POST /api/reminders` - Create reminder
- `GET /api/reminders/{id}` - Get reminder
- `PUT /api/reminders/{id}` - Update reminder
- `DELETE /api/reminders/{id}` - Delete reminder
- `PATCH /api/reminders/{id}/dismiss` - Dismiss reminder
### Projects - CSRF protection via `X-Requested-With` header middleware
- `GET /api/projects` - List projects - All Pydantic schemas use `extra="forbid"` (mass-assignment prevention)
- `POST /api/projects` - Create project - Nginx rate limiting on auth, registration, and admin endpoints
- `GET /api/projects/{id}` - Get project - DB-backed account lockout after 10 failed attempts
- `PUT /api/projects/{id}` - Update project - Timing-safe dummy hash for non-existent users (prevents enumeration)
- `DELETE /api/projects/{id}` - Delete project - SSRF validation on ntfy webhook URLs
- `GET /api/projects/{id}/tasks` - List project tasks - Naive datetimes throughout (Docker runs UTC)
- `POST /api/projects/{id}/tasks` - Create project task
- `PUT /api/projects/{id}/tasks/{task_id}` - Update task
- `DELETE /api/projects/{id}/tasks/{task_id}` - Delete task
### People
- `GET /api/people` - List people (with search)
- `POST /api/people` - Create person
- `GET /api/people/{id}` - Get person
- `PUT /api/people/{id}` - Update person
- `DELETE /api/people/{id}` - Delete person
### Locations
- `GET /api/locations` - List locations (with category filter)
- `POST /api/locations` - Create location
- `GET /api/locations/{id}` - Get location
- `PUT /api/locations/{id}` - Update location
- `DELETE /api/locations/{id}` - Delete location
### Settings
- `GET /api/settings` - Get settings
- `PUT /api/settings` - Update settings
- `PUT /api/settings/pin` - Change PIN
### Dashboard
- `GET /api/dashboard` - Get dashboard data
- `GET /api/upcoming?days=7` - Get upcoming items
## Database Schema
The application uses the following tables:
- `settings` - Application settings and PIN
- `todos` - Task items
- `calendar_events` - Calendar events
- `reminders` - Reminders
- `projects` - Projects
- `project_tasks` - Tasks within projects
- `people` - Contacts/people
- `locations` - Physical locations
## Docker ## Docker
Build and run with Docker: The backend runs as non-root `appuser` in `python:3.12-slim`:
```bash ```bash
docker build -t umbra-backend . docker build -t umbra-backend .
docker run -p 8000:8000 -e DATABASE_URL=... -e SECRET_KEY=... umbra-backend docker run -p 8000:8000 --env-file .env umbra-backend
``` ```
## Development In production, use Docker Compose (see root `docker-compose.yaml`).
### Create New Migration
```bash
alembic revision --autogenerate -m "Description of changes"
```
### Apply Migrations
```bash
alembic upgrade head
```
### Rollback Migration
```bash
alembic downgrade -1
```
## Security Notes
- Change `SECRET_KEY` in production
- Use strong PINs (minimum 4 digits recommended)
- Session cookies are httpOnly and last 30 days
- All API endpoints (except auth) require authentication
- PINs are hashed with bcrypt before storage