diff --git a/WHITELIST_API.md b/WHITELIST_API.md new file mode 100644 index 0000000..526cd3c --- /dev/null +++ b/WHITELIST_API.md @@ -0,0 +1,262 @@ +# Whitelist API Contract + +API endpoints for managing player whitelist in HubMC gateway. + +**Base Path:** `/api/v1/whitelist` + +**Authentication:** All endpoints require `X-API-Key` header. + +--- + +## Endpoints + +### 1. Add Player to Whitelist + +**Endpoint:** `POST /api/v1/whitelist/add` + +**Description:** Add a player to the whitelist. If player exists but is inactive, reactivates them with new data. + +**Request Body:** +```json +{ + "player_name": "string", // 3-16 chars, alphanumeric + underscore only + "added_by": "string", // 1-100 chars, who added the player + "added_at": "datetime", // ISO 8601 format, within 1 hour past to 5 min future + "expires_at": "datetime|null", // Optional, must be after added_at, max 2 years future + "is_active": "boolean", // Default: true + "reason": "string|null" // Optional, max 500 chars, whitespace trimmed +} +``` + +**Validation Rules:** +- `player_name`: Must match regex `^[a-zA-Z0-9_]{3,16}$` +- `added_by`: Cannot be empty or whitespace +- `added_at`: Must be between (now - 1 hour) and (now + 5 minutes) +- `expires_at`: Must be after `added_at` and before (now + 2 years) +- `reason`: Trimmed, null if empty after trim + +**Response:** `201 Created` +```json +{ + "id": "uuid", + "player_name": "string", + "added_by": "string", + "added_at": "datetime", + "expires_at": "datetime|null", + "is_active": true, + "reason": "string|null" +} +``` + +**Errors:** +- `401 Unauthorized`: Invalid API key +- `400 Bad Request`: Validation error (invalid username format, date constraints, etc.) +- `409 Conflict`: Player already exists and is active (`AlreadyExistsError`) + +**Behavior:** +- Creates LuckPerms player entry (logs error if fails, continues anyway) +- If player exists and is inactive: reactivates with new data +- If player exists and is active: returns 409 error +- Handles race conditions with IntegrityError retry logic + +--- + +### 2. Remove Player from Whitelist + +**Endpoint:** `POST /api/v1/whitelist/remove` + +**Description:** Permanently delete a player from the whitelist. + +**Request Body:** +```json +{ + "player_name": "string" // 3-16 chars, alphanumeric + underscore only +} +``` + +**Validation Rules:** +- `player_name`: Must match regex `^[a-zA-Z0-9_]{3,16}$` + +**Response:** `204 No Content` + +**Errors:** +- `401 Unauthorized`: Invalid API key +- `400 Bad Request`: Invalid username format +- `404 Not Found`: Player not found in whitelist (`NotFoundError`) + +**Behavior:** +- Hard deletes the entry from database +- Does NOT check if player is active/inactive + +--- + +### 3. Check Player Whitelist Status + +**Endpoint:** `POST /api/v1/whitelist/check` + +**Description:** Check if a player is currently whitelisted and active. + +**Request Body:** +```json +{ + "player_name": "string" // 3-16 chars, alphanumeric + underscore only +} +``` + +**Validation Rules:** +- `player_name`: Must match regex `^[a-zA-Z0-9_]{3,16}$` + +**Response:** `200 OK` +```json +{ + "is_whitelisted": true // true if exists AND is_active=true +} +``` + +**Errors:** +- `401 Unauthorized`: Invalid API key +- `400 Bad Request`: Invalid username format + +**Behavior:** +- Returns `true` only if entry exists AND `is_active = true` +- Returns `false` if player not found OR `is_active = false` + +--- + +### 4. List All Whitelisted Players + +**Endpoint:** `GET /api/v1/whitelist/` + +**Description:** Get all whitelist entries (both active and inactive). + +**Query Parameters:** None + +**Response:** `200 OK` +```json +{ + "entries": [ + { + "id": "uuid", + "player_name": "string", + "added_by": "string", + "added_at": "datetime", + "expires_at": "datetime|null", + "is_active": true, + "reason": "string|null" + } + ], + "total": 42 // Count of entries array +} +``` + +**Errors:** +- `401 Unauthorized`: Invalid API key + +**Behavior:** +- Returns ALL entries (active and inactive) +- Sorted by `added_at` descending (newest first) +- No pagination implemented + +--- + +### 5. Get Whitelist Count + +**Endpoint:** `GET /api/v1/whitelist/count` + +**Description:** Get total count of all whitelist entries. + +**Query Parameters:** None + +**Response:** `200 OK` +```json +{ + "total": 42 // Total count of all entries (active + inactive) +} +``` + +**Errors:** +- `401 Unauthorized`: Invalid API key + +**Behavior:** +- Counts ALL entries regardless of `is_active` status + +--- + +## Data Types + +**datetime:** ISO 8601 format with timezone +``` +2024-01-15T10:30:00+00:00 +2024-01-15T10:30:00Z +``` + +**uuid:** UUID v4 format +``` +550e8400-e29b-41d4-a716-446655440000 +``` + +--- + +## Common Headers + +**Request:** +``` +X-API-Key: your-api-key-here +Content-Type: application/json +``` + +**Response:** +``` +Content-Type: application/json +``` + +--- + +## Error Response Format + +All errors follow FastAPI standard format: + +```json +{ + "detail": "Error message description" +} +``` + +**Status Codes:** +- `200 OK`: Success (GET) +- `201 Created`: Resource created (POST add) +- `204 No Content`: Success with no body (POST remove) +- `400 Bad Request`: Validation error +- `401 Unauthorized`: Invalid/missing API key +- `404 Not Found`: Resource not found +- `409 Conflict`: Resource already exists +- `500 Internal Server Error`: Unexpected server error + +--- + +## Implementation Notes + +### Database Model +- Table: `hub_whitelist` +- Primary Key: `id` (UUID, auto-generated) +- Unique Constraint: `player_name` +- Indexes: `player_name`, `is_active`, `expires_at` +- Auto-timestamps: `created_at`, `updated_at` + +### Race Condition Handling +The `add` endpoint handles concurrent requests for the same `player_name`: +1. Checks if player exists +2. Attempts to create/update +3. On `IntegrityError` (race condition), retries check +4. Returns appropriate error if now active + +### LuckPerms Integration +The `add` endpoint creates a LuckPerms player entry with: +- `username`: from `player_name` +- `primary_group`: "default" + +Failures are logged but do NOT block whitelist creation. + +### Soft Delete +Currently NOT implemented. The `remove` endpoint performs hard delete. +Inactive entries are kept until explicitly removed.