fix: require client secrets and sanitize uploaded images

This commit is contained in:
vasily committed 2026-10-16 14:24:02 +08:00
1 parent 1f43b2d065
commit a07c178fda
7 files changed
+78 -24

No files matched your search

+6 -6
View File
@@ -10,7 +10,7 @@ Provide a small single-host service that routes image-generation requests from i
- Photobooth/installation clients submit a prompt, model, optional parameters, and zero or more images.
- An administrator provisions clients and manages access.
- A client may manage its own upstream keys when it has a client secret.
- Every client must have a secret. Generation, job polling, and client-managed key operations require that secret.
- The initial service runs as one Uvicorn process against a local SQLite database on persistent disk.
## Requirements
@@ -31,7 +31,7 @@ Provide a small single-host service that routes image-generation requests from i
### Non-functional and security
- Use async HTTP for all upstream network I/O and a shared bounded connection pool.
- Bound aggregate uploaded bytes and image count. Allow only configured raster image MIME types.
- Bound aggregate uploaded bytes, image count, and decoded pixel dimensions. Accept only valid JPEG, PNG, and WebP images; re-encode before forwarding to strip metadata and trailing payloads.
- Require an explicit administrator secret at startup; never ship a default secret.
- Store client secrets hashed. Store provider keys only because they are needed for upstream requests; restrict database file access and redact keys from API responses.
- Scope job reads and client key operations to the authenticated owning client.
@@ -51,7 +51,7 @@ Provide a small single-host service that routes image-generation requests from i
- `provider` (optional: `google` or `openrouter`)
- `params` (optional JSON object string)
- `images` (repeated image upload fields)
- `x-client-secret` header when a secret is configured for that client
- `x-client-secret` header (required)
Success is `200` with `provider_used`, `model_used`, `images`, `text`, elapsed time, and failover attempt count. With `?async_mode=true`, success is `200` with `job_id`, status, and poll URL.
@@ -69,7 +69,7 @@ Validation errors use FastAPI's `detail` format; upstream failures return `502`
## Data model
- `clients`: client ID primary key, name, optional client-secret hash, activation flag, creation timestamp.
- `clients`: client ID primary key, name, required client-secret hash, activation flag, creation timestamp.
- `provider_keys`: owned by a client with cascading deletion; provider constrained to `google`/`openrouter`; key, priority, activation and failure metadata.
- `jobs`: owned by a client with cascading deletion; status, serialized request/result/error and timestamps. On startup, interrupted jobs are marked failed.
@@ -78,7 +78,7 @@ SQLite connections enable foreign keys and busy timeout; WAL is initialized once
## Architecture and flow
1. FastAPI validates the multipart request and client authentication.
2. Uploaded images are bounded and encoded for the provider's JSON API.
2. Uploaded images are bounded, decoded, re-encoded to an allowlisted raster format, then encoded for the provider's JSON API.
3. A route loads the active client's provider keys from SQLite.
4. The adapter translates the request to Google or OpenRouter format and sends through shared async `httpx`.
5. A retryable upstream failure advances to the next configured key; success is normalized into a provider-neutral response.
@@ -88,7 +88,7 @@ SQLite connections enable foreign keys and busy timeout; WAL is initialized once
1. Install Python dependencies and set a unique `ADMIN_SECRET`.
2. Mount a persistent local volume at the configured database path with restrictive permissions.
3. Run one Uvicorn worker. Put TLS and request-size enforcement at Nginx; keep port 8000 private.
3. Run one Uvicorn worker as `www-data`, bound to `127.0.0.1:8081`. Put TLS and request-size enforcement at Nginx; keep the application port private.
4. Create clients, add provider credentials, then call `/healthz` and verify one small generation using the intended account/model.
5. Back up the database securely. Treat backups and job records as secrets and apply retention appropriate to the installation.