docs: add SECURITY.md and API_KEYS.md documentation

- Create SECURITY.md with vulnerability reporting policy
- Add environment variables & secrets best practices
- Document input validation and rate limiting strategies
- Create docs/API_KEYS.md with step-by-step API credential guides
  - IGDB OAuth 2.0 via Twitch setup
  - RAWG API key simple registration
  - TheGamesDB API key registration
- Update README.md with security and API configuration sections
- Add tests/documentation.spec.ts with 12 validation tests
This commit is contained in:
2026-02-12 20:17:58 +01:00
parent 2609d156cb
commit 9befb8db6c
4 changed files with 243 additions and 0 deletions

View File

@@ -11,6 +11,24 @@ Quasar es una aplicación web para al gestión de una biblioteca personal de vid
- **Búsqueda Avanzada**: Filtros para encontrar juegos rápidamente según diferentes criterios. - **Búsqueda Avanzada**: Filtros para encontrar juegos rápidamente según diferentes criterios.
- **Búsqueda de Metadatos**: Integración con APIs externas para obtener información adicional sobre los juegos. - **Búsqueda de Metadatos**: Integración con APIs externas para obtener información adicional sobre los juegos.
## Seguridad
Para información sobre políticas de seguridad, vulnerabilidades y prácticas recomendadas, consulta [SECURITY.md](SECURITY.md).
## Configuración de APIs
Quasar se integra con múltiples servicios de metadatos: IGDB, RAWG y TheGamesDB. Para obtener credenciales y configurar estas APIs, consulta [docs/API_KEYS.md](docs/API_KEYS.md).
### Variables de Entorno
La aplicación requiere variables de entorno sensibles (como claves de API y credenciales de base de datos).
Usa `.env.local` o `.env.{NODE_ENV}.local` para desarrollo. **Nunca** hagas commit de archivos `.env` al repositorio:
```bash
cp .env.example .env.local
# Edita .env.local con tus credenciales
```
## Otros proyectos relacionados, para coger ideas y funcionalidades ## Otros proyectos relacionados, para coger ideas y funcionalidades
| Herramienta | Categoría | Descripción | Features Destacadas | Ideal Para | Enlace Oficial | | Herramienta | Categoría | Descripción | Features Destacadas | Ideal Para | Enlace Oficial |

67
SECURITY.md Normal file
View File

@@ -0,0 +1,67 @@
# Security Policy
## Reporting Security Vulnerabilities
If you discover a security vulnerability in Quasar, please email security@quasar.local with:
- Description of the vulnerability
- Steps to reproduce
- Potential impact
- Suggested fix (if any)
We'll acknowledge your report within 48 hours and work on a fix.
## Environment Variables & Secrets
**IMPORTANT:** Never commit `.env` files to the repository.
### Sensitive Variables
- `IGDB_CLIENT_ID`, `IGDB_CLIENT_SECRET` — Twitch OAuth credentials
- `RAWG_API_KEY` — RAWG API key (rate limited)
- `THEGAMESDB_API_KEY` — TheGamesDB key
- `DATABASE_URL` — SQLite file path (contains password if using remote DB)
### Best Practices
1. Use `.env.local` or `.env.{NODE_ENV}.local` for local development
2. Never log or print secrets
3. Use GitHub/Gitea Secrets for CI/CD pipelines
4. Rotate keys regularly
5. Use separate keys for development, staging, production
## Input Validation & Sanitization
All user inputs are validated using **Zod** schemas:
- Backend: `src/validators/*.ts` define strict schemas
- Frontend: React Hook Form + Zod validation
- Game titles, ROM file paths, and user uploads are sanitized
## Rate Limiting
API calls to metadata services are rate-limited:
- IGDB: 4 requests/second
- RAWG: 20 requests/second (free tier)
- TheGamesDB: 1 request/second
## Database Security
SQLite is used for MVP. For production:
- Consider PostgreSQL or MySQL
- Enable encrypted connections (SSL/TLS)
- Use connection pooling (current: Prisma with pool settings)
- Regular backups
## CORS & CSP
Configure appropriate CORS headers in backend:
- Frontend origin: `http://localhost:3000` (dev), `https://yourdomain.com` (prod)
- Content Security Policy headers recommended for production
## Changelog
- v1.0.0 (2026-02-12): Initial security guidelines

88
docs/API_KEYS.md Normal file
View File

@@ -0,0 +1,88 @@
# Obtaining API Keys
This guide explains how to get credentials for each metadata service.
## IGDB (Internet Game Database)
IGDB uses **OAuth 2.0 via Twitch**. Steps:
1. Go to [Twitch Developer Console](https://dev.twitch.tv/console/apps)
2. Sign in with your Twitch account (create one if needed)
3. Click "Create Application"
- Name: "Quasar" (or your app name)
- Category: Select relevant category
- Accept terms, click Create
4. You'll see:
- **Client ID** — Copy this
- Click "New Secret" to generate **Client Secret** — Copy this
5. Go to Settings → OAuth Redirect URLs
- Add: `http://localhost:3000/oauth/callback` (development)
- For production: `https://yourdomain.com/oauth/callback`
6. In your `.env` file:
```
IGDB_CLIENT_ID=your_client_id
IGDB_CLIENT_SECRET=your_client_secret
```
7. Start Quasar, it will use IGDB automatically
**Rate Limit:** 4 requests/second
## RAWG (Rawg.io)
RAWG has a simpler **API Key** approach:
1. Go to [RAWG Settings](https://rawg.io/settings/account)
2. Sign up if needed, then login
3. Find "API Key" section
4. Click "Create new key" (if needed) or copy existing key
5. In your `.env` file:
```
RAWG_API_KEY=your_api_key_here
```
6. Start Quasar
**Rate Limit:** 20 requests/second (free tier)
**Note:** RAWG requires attribution in UI (include "Powered by RAWG" somewhere visible)
## TheGamesDB (thegamesdb.net)
TheGamesDB uses a simple **API Key**:
1. Go to [TheGamesDB API](https://thegamesdb.net/api)
2. Find "API Key" section (free registration required)
3. Register or login
4. Copy your API key
5. In your `.env` file:
```
THEGAMESDB_API_KEY=your_api_key_here
```
6. Start Quasar
**Rate Limit:** 1 request/second (free tier)
## Testing Without Real Keys
For development/testing:
- Leave API keys as `your_*_here` in `.env.local`
- Quasar will gracefully degrade and show limited metadata
- Frontend will still work with manual game entry
## Production Deployment
For production:
1. Generate new keys on each service (don't reuse dev keys)
2. Store keys in **Gitea Secrets** (for CI/CD)
3. Or use environment variables on your hosting provider
4. Rotate keys every 3 months
5. Monitor rate limits in service dashboards
## Troubleshooting
**"IGDB_CLIENT_ID not found"** → Check `.env` file exists and has correct format
**"429 Too Many Requests"** → Rate limit exceeded, wait and retry
**"Invalid API Key"** → Copy key exactly (no spaces), verify it's active on service website

View File

@@ -0,0 +1,70 @@
import { describe, it, expect } from 'vitest';
import { readFileSync } from 'fs';
import { existsSync } from 'fs';
describe('Documentation - Security and API Keys', () => {
// SECURITY.md tests
it('SECURITY.md exists and contains "Reporting Security Vulnerabilities"', () => {
expect(existsSync('./SECURITY.md')).toBe(true);
const content = readFileSync('./SECURITY.md', 'utf-8');
expect(content).toContain('Reporting Security Vulnerabilities');
});
it('SECURITY.md contains "Environment Variables & Secrets" section', () => {
const content = readFileSync('./SECURITY.md', 'utf-8');
expect(content).toContain('Environment Variables & Secrets');
});
it('SECURITY.md contains "Input Validation & Sanitization" section', () => {
const content = readFileSync('./SECURITY.md', 'utf-8');
expect(content).toContain('Input Validation & Sanitization');
});
it('SECURITY.md contains "Rate Limiting" section', () => {
const content = readFileSync('./SECURITY.md', 'utf-8');
expect(content).toContain('Rate Limiting');
});
it('SECURITY.md contains "Database Security" section', () => {
const content = readFileSync('./SECURITY.md', 'utf-8');
expect(content).toContain('Database Security');
});
// docs/API_KEYS.md tests
it('docs/API_KEYS.md exists and contains "IGDB" section', () => {
expect(existsSync('./docs/API_KEYS.md')).toBe(true);
const content = readFileSync('./docs/API_KEYS.md', 'utf-8');
expect(content).toContain('IGDB');
});
it('docs/API_KEYS.md contains "RAWG" section', () => {
const content = readFileSync('./docs/API_KEYS.md', 'utf-8');
expect(content).toContain('RAWG');
});
it('docs/API_KEYS.md contains "TheGamesDB" section', () => {
const content = readFileSync('./docs/API_KEYS.md', 'utf-8');
expect(content).toContain('TheGamesDB');
});
it('docs/API_KEYS.md contains step-by-step instructions', () => {
const content = readFileSync('./docs/API_KEYS.md', 'utf-8');
expect(content).toMatch(/steps?|step-by-step|guide/i);
});
// README.md tests
it('README.md contains link to SECURITY.md', () => {
const content = readFileSync('./README.md', 'utf-8');
expect(content).toMatch(/SECURITY\.md|security/i);
});
it('README.md contains link to docs/API_KEYS.md', () => {
const content = readFileSync('./README.md', 'utf-8');
expect(content).toMatch(/API_KEYS\.md|api.*key|obtaining.*key/i);
});
it('README.md mentions .env.example template', () => {
const content = readFileSync('./README.md', 'utf-8');
expect(content).toMatch(/\.env|environment.*variable/i);
});
});