fix: add apikeys

This commit is contained in:
Oleg Proskurin 2025-10-01 21:18:02 +07:00
parent c2b161d71c
commit 35df8a031d
4 changed files with 103 additions and 13 deletions

View File

@ -7,6 +7,8 @@ import {
PromptEnhancementResponse, PromptEnhancementResponse,
} from "../types/api"; } from "../types/api";
import { body, validationResult } from "express-validator"; import { body, validationResult } from "express-validator";
import { validateApiKey } from "../middleware/auth/validateApiKey";
import { rateLimitByApiKey } from "../middleware/auth/rateLimiter";
export const enhanceRouter: RouterType = Router(); export const enhanceRouter: RouterType = Router();
@ -88,6 +90,9 @@ const logEnhanceRequest = (req: Request, _res: Response, next: Function) => {
enhanceRouter.post( enhanceRouter.post(
"/enhance", "/enhance",
// Authentication middleware
validateApiKey,
rateLimitByApiKey,
validateEnhanceRequest, validateEnhanceRequest,
logEnhanceRequest, logEnhanceRequest,

View File

@ -10,6 +10,8 @@ import {
logEnhancementResult, logEnhancementResult,
} from "../middleware/promptEnhancement"; } from "../middleware/promptEnhancement";
import { asyncHandler } from "../middleware/errorHandler"; import { asyncHandler } from "../middleware/errorHandler";
import { validateApiKey } from "../middleware/auth/validateApiKey";
import { rateLimitByApiKey } from "../middleware/auth/rateLimiter";
import { GenerateImageResponse } from "../types/api"; import { GenerateImageResponse } from "../types/api";
export const textToImageRouter: RouterType = Router(); export const textToImageRouter: RouterType = Router();
@ -21,6 +23,10 @@ let imageGenService: ImageGenService;
*/ */
textToImageRouter.post( textToImageRouter.post(
"/text-to-image", "/text-to-image",
// Authentication middleware
validateApiKey,
rateLimitByApiKey,
// JSON validation middleware // JSON validation middleware
logTextToImageRequest, logTextToImageRequest,
validateTextToImageRequest, validateTextToImageRequest,

View File

@ -52,17 +52,47 @@ curl -X POST http://localhost:3000/api/generate \
## Rate Limits ## Rate Limits
All authenticated endpoints (those requiring API keys) are rate limited:
- **Per API Key:** 100 requests per hour - **Per API Key:** 100 requests per hour
- Rate limit information included in response headers: - **Applies to:**
- `POST /api/generate`
- `POST /api/text-to-image`
- `POST /api/enhance`
- **Not rate limited:**
- Public endpoints (`GET /health`, `GET /api/info`)
- Bootstrap endpoint (`POST /api/bootstrap/initial-key`)
- Admin endpoints (require master key, but no rate limit)
- Image serving endpoints (`GET /api/images/*`)
Rate limit information included in response headers:
- `X-RateLimit-Limit`: Maximum requests per window - `X-RateLimit-Limit`: Maximum requests per window
- `X-RateLimit-Remaining`: Requests remaining - `X-RateLimit-Remaining`: Requests remaining
- `X-RateLimit-Reset`: When the limit resets (ISO 8601) - `X-RateLimit-Reset`: When the limit resets (ISO 8601)
- **429 Too Many Requests:** Returned when limit exceeded
**429 Too Many Requests:** Returned when limit exceeded with `Retry-After` header
--- ---
## Endpoints ## Endpoints
### Overview
| Endpoint | Method | Authentication | Rate Limit | Description |
|----------|--------|----------------|------------|-------------|
| `/health` | GET | None | No | Health check |
| `/api/info` | GET | None | No | API information |
| `/api/bootstrap/initial-key` | POST | None (one-time) | No | Create first master key |
| `/api/admin/keys` | POST | Master Key | No | Create new API keys |
| `/api/admin/keys` | GET | Master Key | No | List all API keys |
| `/api/admin/keys/:keyId` | DELETE | Master Key | No | Revoke API key |
| `/api/generate` | POST | API Key | 100/hour | Generate images with files |
| `/api/text-to-image` | POST | API Key | 100/hour | Generate images (JSON only) |
| `/api/enhance` | POST | API Key | 100/hour | Enhance text prompts |
| `/api/images/*` | GET | None | No | Serve generated images |
---
### Authentication & Admin ### Authentication & Admin
#### `POST /api/bootstrap/initial-key` #### `POST /api/bootstrap/initial-key`
@ -227,6 +257,7 @@ Returns API metadata and configuration limits.
Generate images from text prompts with optional reference images. Generate images from text prompts with optional reference images.
**Authentication:** API key required (master or project) **Authentication:** API key required (master or project)
**Rate Limit:** 100 requests per hour per API key
**Content-Type:** `multipart/form-data` **Content-Type:** `multipart/form-data`
@ -302,6 +333,7 @@ curl -X POST http://localhost:3000/api/generate \
Generate images from text prompts only using JSON payload. Simplified endpoint for text-only requests without file uploads. Generate images from text prompts only using JSON payload. Simplified endpoint for text-only requests without file uploads.
**Authentication:** API key required (master or project) **Authentication:** API key required (master or project)
**Rate Limit:** 100 requests per hour per API key
**Content-Type:** `application/json` **Content-Type:** `application/json`
@ -391,6 +423,7 @@ curl -X POST http://localhost:3000/api/text-to-image \
Enhance and optimize text prompts for better image generation results. Enhance and optimize text prompts for better image generation results.
**Authentication:** API key required (master or project) **Authentication:** API key required (master or project)
**Rate Limit:** 100 requests per hour per API key
**Content-Type:** `application/json` **Content-Type:** `application/json`
@ -462,19 +495,26 @@ Enhance and optimize text prompts for better image generation results.
## Common Error Messages ## Common Error Messages
### Authentication Errors ### Authentication Errors (401)
- `"Missing API key"` - No X-API-Key header provided - `"Missing API key"` - No X-API-Key header provided
- `"Invalid API key"` - The provided API key is invalid, expired, or revoked - `"Invalid API key"` - The provided API key is invalid, expired, or revoked
- `"Master key required"` - This endpoint requires a master API key - **Affected endpoints:** `/api/generate`, `/api/text-to-image`, `/api/enhance`, `/api/admin/*`
- `"Bootstrap not allowed"` - API keys already exist, cannot bootstrap again
### Validation Errors ### Authorization Errors (403)
- `"Master key required"` - This endpoint requires a master API key (not project key)
- `"Bootstrap not allowed"` - API keys already exist, cannot bootstrap again
- **Affected endpoints:** `/api/admin/*`, `/api/bootstrap/initial-key`
### Validation Errors (400)
- `"Prompt is required"` - Missing or empty prompt parameter - `"Prompt is required"` - Missing or empty prompt parameter
- `"Reference image validation failed"` - Invalid file format or size - `"Reference image validation failed"` - Invalid file format or size
- `"Validation failed"` - Parameter validation error - `"Validation failed"` - Parameter validation error
### Rate Limiting ### Rate Limiting Errors (429)
- `"Rate limit exceeded"` - Too many requests, retry after specified time - `"Rate limit exceeded"` - Too many requests, retry after specified time
- **Applies to:** `/api/generate`, `/api/text-to-image`, `/api/enhance`
- **Rate limit:** 100 requests per hour per API key
- **Response includes:** `Retry-After` header with seconds until reset
### Server Errors ### Server Errors
- `"Server configuration error"` - Missing GEMINI_API_KEY or database connection - `"Server configuration error"` - Missing GEMINI_API_KEY or database connection

View File

@ -1,4 +1,8 @@
@base = http://localhost:3000 @base = http://localhost:3000
# Replace with your actual API key (e.g., bnt_abc123...)
@apiKey = bnt_d0da2d441cd2f22a0ec13897629b4438cc723f0bcb320d646a41ed05a985fdf8
# Replace with your master key for admin endpoints
@masterKey = bnt_71475a11d69344ff9db2236ff4f10cfca34512b29c7ac1a74f73c156d708e226
### Health ### Health
@ -11,10 +15,42 @@ GET {{base}}/health
GET {{base}}/api/info GET {{base}}/api/info
### enhance ### Bootstrap - Create First Master Key (One-time only)
POST {{base}}/api/bootstrap/initial-key
### Admin - Create New API Key (Requires Master Key)
POST {{base}}/api/admin/keys
Content-Type: application/json
X-API-Key: {{masterKey}}
{
"type": "project",
"projectId": "my-project",
"name": "My Project Key",
"expiresInDays": 90
}
### Admin - List All API Keys (Requires Master Key)
GET {{base}}/api/admin/keys
X-API-Key: {{masterKey}}
### Admin - Revoke API Key (Requires Master Key)
DELETE {{base}}/api/admin/keys/KEY_ID_HERE
X-API-Key: {{masterKey}}
### Enhance Prompt (Requires API Key)
POST {{base}}/api/enhance POST {{base}}/api/enhance
Content-Type: application/json Content-Type: application/json
X-API-Key: {{apiKey}}
{ {
"prompt": "Два мага сражаются в снежном лесу. У одного из них в руках посох, из которого вырывается молния, а другой маг защищается щитом из льда. Вокруг них падают снежинки, и на заднем плане видны заснеженные деревья и горы.", "prompt": "Два мага сражаются в снежном лесу. У одного из них в руках посох, из которого вырывается молния, а другой маг защищается щитом из льда. Вокруг них падают снежинки, и на заднем плане видны заснеженные деревья и горы.",
@ -30,10 +66,11 @@ Content-Type: application/json
} }
### Generate image from text ### Generate Image from Text (Requires API Key)
POST {{base}}/api/text-to-image POST {{base}}/api/text-to-image
Content-Type: application/json Content-Type: application/json
X-API-Key: {{apiKey}}
{ {
"prompt": "A majestic eagle soaring over snow-capped mountains", "prompt": "A majestic eagle soaring over snow-capped mountains",
@ -41,9 +78,11 @@ Content-Type: application/json
} }
### Generate Image with Files ### Generate Image with Files (Requires API Key)
POST {{base}}/api/generate POST {{base}}/api/generate
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary Content-Type: multipart/form-data; boundary=----WebKitFormBoundary
X-API-Key: {{apiKey}}
------WebKitFormBoundary ------WebKitFormBoundary
Content-Disposition: form-data; name="prompt" Content-Disposition: form-data; name="prompt"