# HTTP API Reference ## Endpoints ### GET /api/health - **Description:** Health check endpoint. - **Auth:** None - **Query params:** None - **Response:** `{"status":"ok"}` --- ### GET /api/content/:cxid - **Description:** Get content metadata (files, view limits, password status, etc.). - **Auth:** - None if the content has no password. - Password required if the content has a password. Provide via query param `sc` **or** cookie `cgcx_pw`. - **Path params:** - `cxid` — Content ID string. - **Query params:** - `sc` (optional) — Password as a query string parameter. - **Response formats:** - `200 OK` — JSON metadata object: ```json { "cxid": "string", "files": [ { "idx": 0, "name": "string", "mime": "string", "size": 12345, "render_flags": 0 } ], "has_password": true, "max_views": 10, "current_views": 3, "allow_download": true, "created_at": "2024-01-01T00:00:00+00:00" } ``` - `401 Unauthorized` — Password required but missing or invalid. - `404 Not Found` — Content does not exist or has been deleted/blacklisted. - `410 Gone` — Content has reached its maximum view count. - **Notes:** - If authentication succeeds via the `sc` query parameter, the server sets an HMAC-signed `cgcx_pw` cookie on the response (`Max-Age=3600; SameSite=Strict; HttpOnly; Path=/`). --- ### GET /api/content/:cxid/file/:file_idx - **Description:** Serve a decrypted file. Supports HTTP Range requests for video/audio streaming. Returns the file with `Content-Disposition: inline` by default, or `attachment` when downloading. - **Auth:** - None if the content has no password. - Password required if the content has a password. Provide via query param `sc` **or** cookie `cgcx_pw`. - **Path params:** - `cxid` — Content ID string. - `file_idx` — Zero-based file index within the content bundle. - **Query params:** - `sc` (optional) — Password as a query string parameter. - `download` (optional) — If truthy (`1`, `true`, `yes`), requests a download (`Content-Disposition: attachment`). Ignored if `allow_download` is `false` for the content. - **Response formats:** - `200 OK` — File stream with appropriate `Content-Type`. - `206 Partial Content` — Byte-range response (if `Range` header is present and valid). - `401 Unauthorized` — Password required but missing or invalid. - `403 Forbidden` — Download requested but not allowed, or path traversal blocked. - `404 Not Found` — Content or file index does not exist, or content deleted/blacklisted. - `410 Gone` — Content has reached its maximum view count. - `416 Range Not Satisfiable` — Invalid `Range` header. - **Notes:** - The server increments the view counter on successful full-file responses. Range requests and `If-None-Match` (ETag) matches do **not** increment the counter. - If the incremented view count reaches `max_views`, the server may delete content files (depending on `keep_content` config) and mark the content as `Deleted`, returning `410 Gone`. - `Accept-Ranges: bytes` is included for `video/*` and `audio/*` MIME types. - Cache-Control is `private, max-age=60` for unprotected content and `private, no-store, max-age=0` for password-protected content. - If authentication succeeds via the `sc` query parameter, the server sets an HMAC-signed `cgcx_pw` cookie on the response. --- ### GET /api/content/:cxid/file/:file_idx/raw - **Description:** Serve the fully decrypted file as raw plain text (`text/plain; charset=utf-8`). The entire file is decrypted into memory before being returned. No Range support. - **Auth:** - None if the content has no password. - Password required if the content has a password. Provide via query param `sc` **or** cookie `cgcx_pw`. - **Path params:** - `cxid` — Content ID string. - `file_idx` — Zero-based file index within the content bundle. - **Query params:** - `sc` (optional) — Password as a query string parameter. - **Response formats:** - `200 OK` — Plain text body. - `401 Unauthorized` — Password required but missing or invalid. - `403 Forbidden` — Path traversal blocked. - `404 Not Found` — Content or file index does not exist, or content deleted/blacklisted. - `410 Gone` — Content has reached its maximum view count. - **Notes:** - The server performs BLAKE3 integrity verification after full decryption. - If authentication succeeds via the `sc` query parameter, the server sets an HMAC-signed `cgcx_pw` cookie on the response. --- ### POST /api/content/:cxid/verify-password - **Description:** Explicitly verify a password for password-protected content and receive an authentication cookie. - **Auth:** None (this is the endpoint used to *obtain* auth). - **Path params:** - `cxid` — Content ID string. - **Body:** JSON object: ```json { "password": "string" } ``` - **Response formats:** - `204 No Content` — Password is correct. The response includes a `Set-Cookie` header with `cgcx_pw`. - `401 Unauthorized` — Password is incorrect. - `404 Not Found` — Content does not exist. - **Notes:** - If the content has no password, the endpoint returns `204 No Content` without setting a cookie. - This endpoint has a separate, stricter rate limit than the general API. --- ## General Behavior ### CORS The server allows cross-origin requests from its configured `base_url` and common local development origins (`http://127.0.0.1:5173`, `http://localhost:5173`, `http://127.0.0.1:8090`, `http://localhost:8090`). ### Rate Limiting - General API routes (`/api/health`, `/api/content/...`) share a per-IP rate limit configured by `requests_per_minute` and `burst`. - `POST /api/content/:cxid/verify-password` has its own rate limit with a burst of 3 and a separate `password_attempts_per_minute` setting. ### Fallback / Static Assets - `/assets/*` — Serves static files from `frontend/dist/assets`. - All other non-`/api` paths — Serves `frontend/dist/index.html` (SPA fallback). - `/api/*` paths with no matching route — Return `404 Not Found` JSON.