[FIX] Fix the documentations of the project.
This commit is contained in:
@@ -1,295 +1,236 @@
|
||||
# AGENTS.md - Development Guidelines
|
||||
|
||||
This file contains essential information for AI agents working on this codebase.
|
||||
Essential information for AI agents and developers working on this codebase.
|
||||
|
||||
## Project Overview
|
||||
|
||||
PHP website for "Harmonie de Montpellier-Jacou" (music band) with a Vue.js 2 frontend for score management.
|
||||
- **Backend**: PHP with MySQL (legacy codebase)
|
||||
- **Frontend**: Vue.js 2 + Bootstrap Vue (in `frontend/score/`)
|
||||
- **API**: RESTful PHP API in `api/` directory
|
||||
Web application for "Harmonie de Montpellier-Jacou" (music band) to manage and share sheet music (partitions).
|
||||
|
||||
## Build Commands
|
||||
- **Frontend**: SvelteKit (Svelte 5, runes) + Tailwind CSS in `partitions/`
|
||||
- **Backend**: PHP 8.5 REST API in `api/` (no framework)
|
||||
- **Storage**: flat files under `legacy/Scores/` (no database)
|
||||
- **Auth**: JWT (HS256), see `api/lib/Auth.php`
|
||||
- **Production**: `https://partitions.c.nadal-fr.com` (front) + `https://ohmj-api.c.nadal-fr.com` (API)
|
||||
|
||||
### Frontend (Vue.js)
|
||||
```bash
|
||||
cd frontend/score
|
||||
npm install
|
||||
npm run serve # Development server
|
||||
npm run build # Production build
|
||||
npm run lint # ESLint check
|
||||
```
|
||||
There is **no MySQL** and **no Vue.js** in the active codebase. The old Vue.js 2 / MySQL
|
||||
site is archived in `legacy/` and must not be modified.
|
||||
|
||||
### PHP
|
||||
No build step required. Deploy to PHP-enabled web server.
|
||||
## Stack & Versions
|
||||
|
||||
## Deployment
|
||||
- Node.js 26 / npm 11
|
||||
- Svelte 5, SvelteKit 2, `@sveltejs/adapter-static`, Vite 5, Tailwind 3
|
||||
- PHP 8.5 (CLI built-in server in development)
|
||||
- Dependencies: `axios`, `pdfjs-dist`, `lucide-svelte` (front); `setasign/fpdi`, `setasign/fpdf`, `tecnickcom/tcpdf` (back)
|
||||
|
||||
### Create Deploy ZIP
|
||||
```bash
|
||||
cd /home/jbnadal/sources/jb/ohmj/ohmj2
|
||||
./deploy/deploy.sh
|
||||
```
|
||||
> PHP 8.5 note: nullable parameters MUST use explicit `?type` syntax
|
||||
> (e.g. `?string $x = null`). Implicit nullable is deprecated and pollutes API output.
|
||||
|
||||
**Important:**
|
||||
- Do NOT include `legacy/` folder in the zip
|
||||
- Do NOT include `tests.php` in the zip
|
||||
- The `.env` file is included with JWT_SECRET
|
||||
- Frontend build must be in `frontend/` directory
|
||||
## Build & Run Commands
|
||||
|
||||
## Testing
|
||||
|
||||
### PHP API Tests
|
||||
|
||||
Run functional tests for the PHP API:
|
||||
### Backend (PHP)
|
||||
|
||||
```bash
|
||||
cd api
|
||||
php -c php-upload.ini -S localhost:8000 router.php
|
||||
```
|
||||
|
||||
- `-c php-upload.ini` is **required** so PDF uploads work (`upload_max_filesize`/`post_max_size` = 64M).
|
||||
`ini_set()` cannot change those directives at runtime.
|
||||
- API base URL: `http://localhost:8000` (paths have **no** `/api` prefix in the client).
|
||||
- Copy `api/.env.example` to `api/.env` and set a strong `JWT_SECRET`.
|
||||
|
||||
### Frontend (SvelteKit)
|
||||
|
||||
```bash
|
||||
cd partitions
|
||||
npm install
|
||||
npm run dev # http://localhost:5173
|
||||
npm run build # outputs to partitions/build
|
||||
npm run preview
|
||||
```
|
||||
|
||||
- `frontend` is a symlink to `partitions/build` (the deployed static site).
|
||||
- No ESLint / test framework is configured for the frontend.
|
||||
- `VITE_API_URL` is defined but currently unused (base URL is chosen from `import.meta.env.DEV`).
|
||||
|
||||
### Deploy
|
||||
|
||||
```bash
|
||||
./deploy/deploy.sh
|
||||
```
|
||||
|
||||
- Do NOT include `legacy/` or `api/tests.php` in the deploy archive.
|
||||
- `api/.env` (with `JWT_SECRET`) is part of the deployment.
|
||||
- The frontend build must be present in `frontend/`.
|
||||
|
||||
## Testing
|
||||
|
||||
### PHP API tests
|
||||
|
||||
```bash
|
||||
cd api
|
||||
php -c php-upload.ini -S localhost:8000 router.php & # if not already running
|
||||
rm -f /tmp/rate_* 2>/dev/null # clear rate limiting first
|
||||
php tests.php
|
||||
```
|
||||
|
||||
The tests cover:
|
||||
- **Auth**: Login, bad credentials, missing token, invalid token
|
||||
- **Scores**: CRUD operations, error handling for non-existent resources
|
||||
- **Create Score with Pieces**: Functional tests with pieces verification
|
||||
- **Files**: Get files tree, delete file error handling
|
||||
- Expected: **53/53 tests passed (100%)**.
|
||||
- Covers: auth (login, bad credentials, missing/invalid token), scores CRUD,
|
||||
create-score-with-pieces, files tree, path traversal, rate limiting, upload
|
||||
validation, INI injection, security headers.
|
||||
- `tests.php` is kept for development only and MUST NOT be shipped in the deploy zip.
|
||||
|
||||
**Note**: tests.php is kept in source for development but must NOT be included in deploy zip.
|
||||
## Authentication
|
||||
|
||||
### Vue/Svelte
|
||||
- Login: `POST /login` with `{"username":"admin","password":"password"}` (development).
|
||||
- Token: JWT HS256 signed with `JWT_SECRET`, 1 hour expiry.
|
||||
- API calls: send `Authorization: Bearer <token>`.
|
||||
- Token is stored in `localStorage` on the frontend and attached via an axios request interceptor.
|
||||
- Roles: `admin` (full access) and `user` (read-only). Admin routes live under `/admin/...`.
|
||||
- Frontend dev login page: http://localhost:5173
|
||||
|
||||
No test framework configured for frontend.
|
||||
## API Endpoints
|
||||
|
||||
Run single test (when configured):
|
||||
```bash
|
||||
# Example for Jest (not yet configured)
|
||||
npm test -- --testNamePattern="test name"
|
||||
```
|
||||
Public / all authenticated users:
|
||||
|
||||
## Code Style Guidelines
|
||||
- `POST /login`
|
||||
- `GET /scores`
|
||||
- `GET /scores/:id`
|
||||
- `GET /scores/:id/instruments[?piece=N]`
|
||||
- `GET /pieces/:scoreId`
|
||||
- `GET /download/:path` (token via `Authorization` header or `?token=`)
|
||||
|
||||
### PHP
|
||||
- Use `<?php` opening tags (avoid short `<?` tags for consistency)
|
||||
- Classes: PascalCase (e.g., `Score`, `Database`)
|
||||
- Methods: camelCase (e.g., `readScore`, `getEntryName`)
|
||||
- Variables: snake_case or camelCase (be consistent within files)
|
||||
- Indent: 3 spaces (legacy style) - maintain consistency with surrounding code
|
||||
- Place opening braces on same line as class/function declaration
|
||||
- Use `include_once` for required files
|
||||
- **Note**: Uses legacy MySQL functions (consider upgrading to PDO/MySQLi)
|
||||
Admin only (`role === 'admin'`):
|
||||
|
||||
### JavaScript/Vue
|
||||
- ESLint configuration in `package.json`:
|
||||
- Extends: `plugin:vue/essential`, `eslint:recommended`
|
||||
- Parser: `babel-eslint`
|
||||
- Use ES6+ features (async/await, arrow functions)
|
||||
- Components: PascalCase
|
||||
- Data properties: camelCase
|
||||
- Use 2-space indentation
|
||||
- Semicolons required
|
||||
|
||||
### General
|
||||
- UTF-8 encoding for all files
|
||||
- French language for user-facing content
|
||||
- Maintain GPL v2 license headers in PHP files
|
||||
- `POST /admin/scores`
|
||||
- `PUT /admin/scores/:id`
|
||||
- `PUT /admin/scores/:id/pieces`
|
||||
- `DELETE /admin/scores/:id`
|
||||
- `POST /admin/scores/:id/upload`
|
||||
- `GET /admin/scores/:id/files`
|
||||
- `DELETE /admin/scores/:id/files?path=...`
|
||||
|
||||
## File Organization
|
||||
|
||||
```
|
||||
/
|
||||
├── api/ # REST API endpoints
|
||||
│ ├── config/ # Database configuration
|
||||
│ ├── objects/ # Data models
|
||||
│ └── score/ # API endpoints
|
||||
├── frontend/score/ # Vue.js application
|
||||
│ ├── src/ # Source code
|
||||
│ └── public/ # Static assets
|
||||
├── Scripts/ # PHP page controllers
|
||||
├── fpdf/ # PDF generation library
|
||||
├── Imgs/ # Image assets
|
||||
├── Textes/ # Text content files
|
||||
└── index.php # Main entry point
|
||||
├── api/ # PHP REST API (active)
|
||||
│ ├── index.php # Router / entry point
|
||||
│ ├── router.php # Dev server router (+ CORS, .env loading)
|
||||
│ ├── lib/Auth.php # JWT auth
|
||||
│ ├── lib/ScoreScanner.php# File-based score index
|
||||
│ ├── config/users.json # Users (bcrypt hashes)
|
||||
│ ├── tests.php # Functional tests (dev only)
|
||||
│ └── .env # JWT_SECRET, SCORES_PATH
|
||||
├── partitions/ # SvelteKit app (active)
|
||||
│ ├── src/lib/api.ts # Axios client + apiService
|
||||
│ ├── src/lib/stores/ # auth store
|
||||
│ ├── src/lib/components/ # PdfViewer
|
||||
│ ├── src/routes/ # pages (login, scores, admin)
|
||||
│ └── build/ # static output (gitignored)
|
||||
├── frontend -> partitions/build # symlink used for deployment
|
||||
├── deploy/deploy.sh # deploy archive builder
|
||||
├── scripts/convert_final_v2.js # one-off filename converter
|
||||
├── legacy/ # archived old site + Scores/ (do not modify)
|
||||
└── _builds/ # temporary work files (gitignored)
|
||||
```
|
||||
|
||||
## Database
|
||||
## Data Model (files)
|
||||
|
||||
MySQL database connection configured in `api/config/database.php`:
|
||||
- Uses legacy `mysql_*` functions
|
||||
- Database name: `ohmj2`
|
||||
- Tables: `repertoire` (for scores)
|
||||
```
|
||||
legacy/Scores/<NUM>/<PIECE>/<INSTRUMENT>/<VERSION>/<PARTIE>.pdf
|
||||
legacy/Scores/<NUM>/score.ini
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
`score.ini`:
|
||||
|
||||
- PHP: Uses `@` error suppression operator in some places
|
||||
- Vue: Uses try/catch with console.log for errors
|
||||
- Return HTTP 200 on success in API responses
|
||||
```ini
|
||||
[info]
|
||||
name = Nom du morceau
|
||||
compositor = Compositeur
|
||||
ressource = https://... # optional external link
|
||||
|
||||
## Security Notes
|
||||
[pieces]
|
||||
count = 1
|
||||
```
|
||||
|
||||
- API uses `Access-Control-Allow-Origin: *` (CORS enabled for all)
|
||||
- SQL queries use string concatenation (vulnerable to SQL injection)
|
||||
- Database credentials stored in plain text in `api/config/database.php`
|
||||
- Sanitize user inputs before database queries
|
||||
- `NUM` = score id (zero-padded, e.g. `102`).
|
||||
- `PIECE` = movement/piece number (1 for single-piece scores).
|
||||
- `INSTRUMENT` = trigram code (see below).
|
||||
- `VERSION` = version number.
|
||||
- `PARTIE` = part number.
|
||||
|
||||
## Git
|
||||
Instrument codes: `dir`, `pic`, `flu`, `cla`, `clb`, `sax`, `sat`, `sab`, `coa`,
|
||||
`cba`, `cor`, `trp`, `trb`, `tub`, `htb`, `bas`, `per`, `crn`, `eup`, `har`, `pia`,
|
||||
plus `sup`/`par` for combined parts.
|
||||
|
||||
- No CI/CD configured
|
||||
- Commit to main branch
|
||||
- Standard `.gitignore` for Node.js projects
|
||||
|
||||
## Dependencies
|
||||
|
||||
### Frontend
|
||||
- Vue 2.6.11
|
||||
- Bootstrap Vue 2.17.3
|
||||
- Axios 0.21.0
|
||||
- Vue CLI 4.5.0
|
||||
## Code Style
|
||||
|
||||
### PHP
|
||||
- FPDF library for PDF generation
|
||||
- MySQL extension (legacy)
|
||||
- `<?php` opening tags, PascalCase classes, camelCase methods.
|
||||
- 3-space indentation, opening brace on the same line (legacy style).
|
||||
- Consistent with surrounding code; prefer `include_once`/`require_once` for includes.
|
||||
- No database layer: file operations via `ScoreScanner.php`.
|
||||
|
||||
## Important Notes
|
||||
### JavaScript / Svelte
|
||||
- Svelte 5 runes (`$state`, `$props`, `$derived`, `$effect`); prefer `$app/state` over the deprecated `$app/stores`.
|
||||
- TypeScript, camelCase variables, PascalCase components, 2-space indent, semicolons.
|
||||
|
||||
- **NEVER delete files or directories** - Always ask before removing anything
|
||||
- This is a legacy codebase with mixed coding styles
|
||||
- Prefer consistency with existing code over strict style enforcement
|
||||
- Site targets French-speaking users
|
||||
- Production URL: `ohmj2.free.fr`
|
||||
### General
|
||||
- UTF-8, French for user-facing content.
|
||||
- Do not add comments unless necessary.
|
||||
- **NEVER delete files or directories without asking first.**
|
||||
|
||||
## Design Guidelines
|
||||
|
||||
- **Style**: Clean, sober, and modern
|
||||
- **Icons**: Use SVG icons instead of emojis for better consistency
|
||||
- **Buttons**: Integrate related actions (view + download) in a single row with consistent styling
|
||||
- **Hide unnecessary labels**: Don't show "Piece 1" or "Version 1" when there's only one
|
||||
- **Visual hierarchy**: Use spacing, subtle borders, and hover effects for interactivity
|
||||
- Clean, sober, modern.
|
||||
- Use SVG icons instead of emojis.
|
||||
- Integrate related actions (view + download) in a single row with consistent styling.
|
||||
- Hide redundant labels ("Piece 1", "Version 1") when there is only one.
|
||||
- Use spacing, subtle borders, and hover effects for visual hierarchy.
|
||||
|
||||
## Temporary Work Files
|
||||
## Security Checklist (before deployment)
|
||||
|
||||
- Use `_builds/` directory for temporary scripts and working files
|
||||
- Only `scripts/convert_final_v2.js` should be kept in the scripts folder (committed to git)
|
||||
- CSV output files belong in `_builds/`
|
||||
- [ ] `JWT_SECRET` is strong and unique (`openssl rand -base64 32`); never commit `api/.env`.
|
||||
- [ ] `api/config/users.json` uses non-default credentials (change `admin`/`user`).
|
||||
- [ ] CORS origins restricted to the real domains (no wildcard fallback).
|
||||
- [ ] HTTPS enforced in production.
|
||||
- [ ] Rate limiting active (clear `/tmp/rate_*` only in tests, never in prod).
|
||||
- [ ] `php tests.php` passes 53/53.
|
||||
- [ ] `npm audit` reviewed.
|
||||
- [ ] No secrets in code or git history.
|
||||
|
||||
## Authentication
|
||||
|
||||
- **Login**: Use `apiService.login('admin', 'password')` from frontend
|
||||
- **API calls**: Include token in Authorization header:
|
||||
```
|
||||
Authorization: Bearer <token>
|
||||
```
|
||||
- **Token format**: JWT (HS256) - see `api/lib/Auth.php`
|
||||
- **Frontend**: Token stored in localStorage, auto-attached to API requests via axios interceptor
|
||||
- **Test**: http://localhost:5173 - login with admin/password
|
||||
- **API base URL**: http://localhost:8000/api/
|
||||
|
||||
### Starting the PHP Server
|
||||
|
||||
**Important:** Always use the custom upload config for file uploads to work:
|
||||
```bash
|
||||
cd api
|
||||
php -c php-upload.ini -S localhost:8000 router.php &
|
||||
```
|
||||
|
||||
Le serveur doit être lancé avec `-c php-upload.ini` pour autoriser l'upload de fichiers PDF (64M max).
|
||||
|
||||
### Upload de partitions
|
||||
|
||||
Lors de l'upload d'un PDF, deux options sont disponibles :
|
||||
- **Ajouter le numéro** : ajoute le numéro de partition dans le coin du PDF
|
||||
- **Position** : choix entre "Gauche" ou "Droite" pour placer le numéro
|
||||
|
||||
## Current Tech Stack (2024)
|
||||
|
||||
- **Frontend**: SvelteKit (NOT Vue.js 2) in `/partitions/`
|
||||
- **Backend**: PHP API in `/api/`
|
||||
- **Scores storage**: `/legacy/Scores/` (directory-based, not MySQL)
|
||||
|
||||
## Security Audit Commands
|
||||
|
||||
When modifying backend or frontend code, run these security audits:
|
||||
|
||||
### Backend Security Audit
|
||||
Manual checks:
|
||||
|
||||
```bash
|
||||
# 1. Start the PHP server
|
||||
cd api
|
||||
php -S localhost:8000 router.php &
|
||||
|
||||
# 2. Clear rate limiting files (important!)
|
||||
rm -f /tmp/rate_* 2>/dev/null
|
||||
|
||||
# 3. Run all security tests
|
||||
php tests.php
|
||||
|
||||
# Expected: 50/50 tests passed (100%)
|
||||
```
|
||||
|
||||
### Frontend Security Check
|
||||
|
||||
```bash
|
||||
cd partitions
|
||||
|
||||
# 1. Check for security issues in dependencies
|
||||
npm audit
|
||||
|
||||
# 2. Build and check for CSP violations
|
||||
npm run build
|
||||
|
||||
# 3. Check that environment variables are configured
|
||||
cp .env.example .env
|
||||
# Edit .env and set VITE_API_URL to your backend URL
|
||||
```
|
||||
|
||||
### Manual Security Verification
|
||||
|
||||
```bash
|
||||
# Test JWT authentication
|
||||
curl -s http://localhost:8000/login \
|
||||
-X POST \
|
||||
# JWT login
|
||||
curl -s http://localhost:8000/login -X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"username":"admin","password":"password"}'
|
||||
|
||||
# Test CORS headers
|
||||
curl -s -I http://localhost:8000/scores \
|
||||
-H "Origin: https://evil.com"
|
||||
|
||||
# Test directory traversal protection
|
||||
# Directory traversal must NOT return 200
|
||||
curl -s http://localhost:8000/download/../../../etc/passwd \
|
||||
-H "Authorization: Bearer <token>"
|
||||
# Expected: 403 or 404 (not 200)
|
||||
|
||||
# Test security headers
|
||||
curl -s -I http://localhost:8000/login \
|
||||
-X POST \
|
||||
# Security headers on any response
|
||||
curl -s -I http://localhost:8000/login -X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"username":"admin","password":"password"}'
|
||||
# Check for: X-Content-Type-Options, X-Frame-Options, X-XSS-Protection, HSTS
|
||||
```
|
||||
|
||||
### Environment Setup for Security
|
||||
> Known security findings from the latest review (not yet fixed): static file
|
||||
> passthrough in `api/router.php` exposes `.env`/`users.json`; `deleteScoreFile`
|
||||
> lacks path containment; `api/.env` is tracked by git; JWT is standard base64
|
||||
> (not base64url) and expiry is optional; stored XSS via the `ressource` link.
|
||||
> See the project issue tracker / recent review notes.
|
||||
|
||||
**Backend (api/.env):**
|
||||
```bash
|
||||
JWT_SECRET=your_very_long_random_secret_key_here
|
||||
```
|
||||
## Temporary Files
|
||||
|
||||
**Frontend (partitions/.env):**
|
||||
```bash
|
||||
# Development
|
||||
VITE_API_URL=http://localhost:8000
|
||||
- Put temporary scripts and outputs in `_builds/` (gitignored).
|
||||
- `scripts/convert_final_v2.js` is the only committed script in `scripts/`.
|
||||
|
||||
# Production (use HTTPS!)
|
||||
VITE_API_URL=https://api.yourdomain.com
|
||||
```
|
||||
## Git
|
||||
|
||||
### Security Checklist Before Deployment
|
||||
|
||||
- [ ] JWT_SECRET is set and strong (use: `openssl rand -base64 32`)
|
||||
- [ ] CORS origins are restricted to your domain only
|
||||
- [ ] HTTPS is enforced in production
|
||||
- [ ] Rate limiting is active
|
||||
- [ ] All 50 tests pass
|
||||
- [ ] npm audit shows no critical vulnerabilities
|
||||
- [ ] CSP headers are configured
|
||||
- [ ] No secrets in code or git history
|
||||
- Default branch: `master`.
|
||||
- No CI/CD configured.
|
||||
- Only commit when explicitly requested.
|
||||
|
||||
@@ -1,530 +0,0 @@
|
||||
# Plan de développement - Application de partitions OHMJ
|
||||
|
||||
## Structure finale du projet
|
||||
|
||||
```
|
||||
/home/jbnadal/sources/jb/ohmj/ohmj2/
|
||||
├── legacy/ # Backup ancien code
|
||||
│ ├── api/ # Ancien PHP legacy (MySQL)
|
||||
│ ├── frontend/ # Ancien Vue.js 2
|
||||
│ ├── fpdf/
|
||||
│ ├── Imgs/
|
||||
│ ├── Scripts/
|
||||
│ ├── Textes/
|
||||
│ └── index.php
|
||||
├── api/ # NOUVEAU backend PHP moderne
|
||||
│ ├── index.php # Router / entry point API
|
||||
│ ├── config/
|
||||
│ │ └── users.json # Users avec passwords hashés
|
||||
│ └── lib/
|
||||
│ ├── Auth.php # JWT authentication
|
||||
│ └── ScoreScanner.php # Lecture fichiers ini + scan partitions
|
||||
├── partitions/ # NOUVEAU frontend SvelteKit
|
||||
│ ├── src/
|
||||
│ │ ├── routes/
|
||||
│ │ │ ├── +page.svelte # Login page
|
||||
│ │ │ ├── scores/+page.svelte # Liste des morceaux
|
||||
│ │ │ ├── scores/[id]/+page.svelte # Détail partition
|
||||
│ │ │ └── +layout.svelte # Layout avec auth guard
|
||||
│ │ ├── lib/
|
||||
│ │ │ ├── api.ts # Client API
|
||||
│ │ │ └── stores/auth.ts # Store JWT
|
||||
│ │ └── app.html
|
||||
│ ├── package.json
|
||||
│ └── svelte.config.js
|
||||
└── Scores/ # Répertoire partitions (hors git)
|
||||
└── {id}/
|
||||
├── score.ini
|
||||
├── cla/
|
||||
│ └── 1/
|
||||
│ └── *.pdf
|
||||
└── ...
|
||||
```
|
||||
|
||||
## Phase 1 : Backend PHP (api/)
|
||||
|
||||
### 1.1 ScoreScanner.php ✓ (FAIT)
|
||||
- [x] Classe pour scanner les partitions
|
||||
- [x] Lecture des fichiers score.ini (supporte sections [info], [pieces])
|
||||
- [x] Scan récursif instruments → parties → fichiers PDF
|
||||
- [x] Mapping codes instruments vers noms
|
||||
- [x] Retourne `piece` pour chaque instrument
|
||||
- [x] Parse les noms de fichiers : `part`, `key`, `clef`, `variant`
|
||||
- [x] Retourne `ressource` si présent dans score.ini
|
||||
- [x] Supporte les partitions multi-morceaux (ex: score 390)
|
||||
|
||||
### 1.2 Auth.php
|
||||
- [x] Classe JWT pour authentification
|
||||
- [x] Génération token JWT
|
||||
- [x] Vérification token JWT
|
||||
- [x] Lecture users.json
|
||||
- [x] Vérification password hashé (bcrypt)
|
||||
- [ ] Tests unitaires Auth.php (PHP non installé)
|
||||
|
||||
### 1.3 users.json
|
||||
- [x] Fichier JSON avec structure users
|
||||
- [ ] Passwords hashés avec bcrypt (password: password)
|
||||
- [ ] Script pour ajouter/modifier users
|
||||
|
||||
### 1.4 index.php (Router API)
|
||||
- [x] CORS headers
|
||||
- [x] POST /login
|
||||
- [x] GET /scores (protégé JWT)
|
||||
- [x] GET /scores/:id (protégé JWT)
|
||||
- [x] GET /pieces/:scoreId (protégé JWT)
|
||||
- [x] GET /download/:path (protégé JWT, stream PDF)
|
||||
- [x] POST /admin/scores (protégé JWT, créer partition)
|
||||
- [x] PUT /admin/scores/:id (protégé JWT, modifier partition)
|
||||
- [x] DELETE /admin/scores/:id (protégé JWT, supprimer partition)
|
||||
- [x] POST /admin/scores/:id/upload (protégé JWT, upload PDF)
|
||||
- [ ] Gestion erreurs JSON
|
||||
- [ ] Tests toutes les routes (PHP non installé)
|
||||
|
||||
### 1.5 Tests API
|
||||
- [ ] Tests unitaires Auth.php (PHP non installé)
|
||||
- [ ] Tests intégration toutes les routes (PHP non installé)
|
||||
- [ ] Tests authentification JWT (PHP non installé)
|
||||
|
||||
## Phase 2 : Frontend SvelteKit (partitions/)
|
||||
|
||||
### 2.1 Initialisation projet
|
||||
- [ ] npm create svelte@latest partitions
|
||||
- [ ] TypeScript + ESLint + Prettier
|
||||
- [ ] npm install (axios, etc.)
|
||||
|
||||
### 2.2 Configuration
|
||||
- [ ] svelte.config.js (adapter static)
|
||||
- [ ] API base URL config
|
||||
|
||||
### 2.3 Stores
|
||||
- [ ] lib/stores/auth.ts
|
||||
- [ ] Store JWT token
|
||||
- [ ] Store user info
|
||||
- [ ] Persistance localStorage
|
||||
|
||||
### 2.4 Client API
|
||||
- [ ] lib/api.ts
|
||||
- [ ] Instance axios avec baseURL
|
||||
- [ ] Intercepteur pour ajouter header Authorization
|
||||
- [ ] Méthodes : login(), getScores(), getScore(id), downloadFile(path)
|
||||
|
||||
### 2.5 Routes
|
||||
|
||||
#### Login (/)
|
||||
- [ ] Formulaire : username, password
|
||||
- [ ] Appel API login
|
||||
- [ ] Stockage JWT
|
||||
- [ ] Redirection vers /scores
|
||||
- [ ] Gestion erreurs
|
||||
|
||||
#### Liste des morceaux (/scores)
|
||||
- [ ] Auth guard (redirect si pas connecté)
|
||||
- [ ] Table/DataGrid avec :
|
||||
- [ ] Numéro (ID)
|
||||
- [ ] Nom du morceau
|
||||
- [ ] Compositeur
|
||||
- [ ] Tri possible
|
||||
- [ ] Click → navigation /scores/:id
|
||||
- [ ] Loading state
|
||||
|
||||
#### Détail partition (/scores/[id])
|
||||
- [ ] Auth guard
|
||||
- [ ] Header :
|
||||
- [ ] Numéro
|
||||
- [ ] Nom du morceau
|
||||
- [ ] Compositeur
|
||||
- [ ] Bouton retour
|
||||
- [ ] Liste des instruments (grid ou accordion) :
|
||||
- [ ] Nom de l'instrument
|
||||
- [ ] Pour chaque partie :
|
||||
- [ ] Numéro de partie
|
||||
- [ ] Liste des fichiers PDF
|
||||
- [ ] Bouton téléchargement par fichier
|
||||
- [ ] Loading state
|
||||
|
||||
#### Layout
|
||||
- [ ] Auth guard global
|
||||
- [ ] Header avec :
|
||||
- [ ] Titre app
|
||||
- [ ] User connecté
|
||||
- [ ] Bouton logout
|
||||
- [ ] Footer (optionnel)
|
||||
|
||||
### 2.6 Styles
|
||||
- [ ] CSS moderne (Tailwind ou CSS vanilla)
|
||||
- [ ] Responsive (mobile-friendly)
|
||||
- [ ] Thème harmonie (couleurs)
|
||||
|
||||
## Phase 3 : Déploiement
|
||||
|
||||
### 3.1 Build frontend
|
||||
- [ ] npm run build
|
||||
- [ ] Output dans dist/
|
||||
|
||||
### 3.2 Configuration serveur
|
||||
- [ ] /partitions → contenu dist/
|
||||
- [ ] /api → PHP
|
||||
- [ ] /legacy/Scores → accès aux PDFs
|
||||
- [ ] .htaccess ou config nginx pour routing
|
||||
|
||||
### 3.3 Sécurité
|
||||
- [ ] HTTPS obligatoire
|
||||
- [ ] JWT secret fort
|
||||
- [ ] Protection download (vérif JWT)
|
||||
- [ ] Headers sécurité
|
||||
|
||||
## Notes techniques
|
||||
|
||||
### Backend PHP
|
||||
- Pas de base de données
|
||||
- JWT pour auth stateless
|
||||
- Lecture fichiers uniquement
|
||||
- Stream PDF pour download
|
||||
|
||||
### Frontend SvelteKit
|
||||
- Svelte 5 (runes)
|
||||
- TypeScript strict
|
||||
- Pas de store complexe (juste auth)
|
||||
- Client API simple
|
||||
|
||||
### Contraintes
|
||||
- Chemin partitions : ../legacy/Scores/ (sera déplacé après DL)
|
||||
- Fichiers ini présents partout
|
||||
- PDFs uniquement
|
||||
- Auth obligatoire pour tout accès
|
||||
|
||||
## Phase Préliminaire : Normalisation des données
|
||||
|
||||
### 0.1 Structure des partitions (à valider)
|
||||
- [ ] Analyser tous les instruments pour voir si le répertoire "1" est nécessaire
|
||||
- [ ] Identifier les cas où il n'y a qu'une seule partie (supprimer le niveau "1" ?)
|
||||
- [ ] Valider la structure finale avant codage
|
||||
|
||||
### 0.2 Harmonisation des noms de fichiers ✓
|
||||
**Convention finale :**
|
||||
- Format : `{instrument}[_{instrument2}][_{variante}][_{tonalité}]_{partie}[_clef].pdf`
|
||||
- Exemples :
|
||||
- `clarinette_sib_1.pdf` (clarinette en Si♭, partie 1)
|
||||
- `clarinette_alto_mib_1.pdf` (clarinette alto en Mi♭, partie 1)
|
||||
- `basse_et_contrebasse_sib_1.pdf` (partition pour 2 instruments)
|
||||
- `cor_mib_1_et_2.pdf` (cor en Mi♭, parties 1 et 2 combinées)
|
||||
- `euphonium_sib_2_clefa.pdf` (euphonium en Si♭, partie 2, clé de fa)
|
||||
- Tout en minuscule, français, ASCII sans accents
|
||||
- Tonalités : sib (Bb), mib (Eb), fa (F), do (C), etc.
|
||||
- **Garder les sous-répertoires numérotés (1/, 2/, etc.)** pour distinguer les versions
|
||||
- **Script :** `scripts/convert_final_v2.js`
|
||||
- **Usage :** `node scripts/convert_final_v2.js /chemin/vers/Scores confirm`
|
||||
|
||||
### 0.3 À propos des répertoires numérotés (1/, 2/, etc.)
|
||||
**Découverte importante :**
|
||||
- Le répertoire `1/` = version principale du morceau
|
||||
- Le répertoire `2/` (ou plus) = alternative du même morceau
|
||||
- Cela permet d'avoir plusieurs versions d'un même morceau dans le même ID
|
||||
- Exemple : Score 210, dossier `cla/1/` et `cla/2/` contiennent des versions différentes
|
||||
- **Action:** Le script de conversion doit utiliser le numéro du répertoire comme numéro de partie UNIQUEMENT pour les fichiers "version_X"
|
||||
|
||||
### 0.4 À propos du répertoire "sup"
|
||||
- Le répertoire `sup/` signifie "supérieur" ou "combiné"
|
||||
- C'est une partition où deux instruments jouent sur la même partition
|
||||
- Ex: baryton + tuba sur une même partition
|
||||
- **Note API:** Ces partitions combinées doivent être gérées différemment dans l'interface (afficher les deux instruments)
|
||||
|
||||
### 0.5 Conventions de nommage - Instruments
|
||||
**Orthographe standardisée (français) :**
|
||||
- Clarinette → clarinette
|
||||
- Saxophone → saxophone (ou sax_baryton, sax_tenor, sax_alto, sax_soprano pour les variantes)
|
||||
- Cor → cor
|
||||
- Trompette → trompette
|
||||
- Trombone → trombone
|
||||
- Tuba → tuba (ou tuba_tenor pour tenor tuba)
|
||||
- Basse → basse
|
||||
- Contrebasse → contrebasse (UN SEUL MOT)
|
||||
- Baryton → baryton
|
||||
- Euphonium → euphonium
|
||||
- Flute → flute (ou petite_flute, grande_flute)
|
||||
- Hautbois → hautbois
|
||||
- Basson → basson
|
||||
- Contre-basson → contre_basson
|
||||
- Bugle → bugle (inclut flugelhorn)
|
||||
- Percussion → percussion (timbales, grosse_caisse, cymbale, caisse_claire, triangle, etc.)
|
||||
|
||||
**Instrumentsperaussion reconnus :**
|
||||
- timpani, glockenspiel, bongos, maracas, tambourine, vibraphone, xylophone
|
||||
- woodblock, claves, batterie
|
||||
|
||||
**Tonalités :**
|
||||
- sib (Bb), mib (Eb), fa (F), do (ut), sol, re, mi, si, reb
|
||||
- NOTE: "do" devient "ut" dans les noms de fichiers
|
||||
|
||||
**Cas spéciaux gérés :**
|
||||
- "default_cor" = instrument de substitution (ex: baryton_default_cor_2)
|
||||
- Parties combinées avec & = format "instrument1_et_instrument2_info1_info2_partie"
|
||||
|
||||
### 0.6 Structure du nom de fichier final
|
||||
**Format :** `{instrument}[_{variante}][_{tonalité}][_{default}][_{instrument_subst}]_{partie}[_clef].pdf`
|
||||
|
||||
**Exemples :**
|
||||
- `clarinette_sib_1.pdf`
|
||||
- `sax_baryton_mib_1.pdf`
|
||||
- `cor_fa_1_et_2.pdf`
|
||||
- `baryton_sib_default_cor_2.pdf`
|
||||
- `sax_tenor_sib_1.pdf`
|
||||
- `baryton_mib_2_clesol.pdf`
|
||||
- `baryton_et_tuba_tenor_sib_clefa.pdf` (parties combinées sup)
|
||||
|
||||
**Note:** Pour les parties combinées (sup), chaque instrument garde ses propres infos (tonalité, partie, clef)
|
||||
|
||||
## Phase 3 : Déploiement
|
||||
|
||||
### 3.1 Build frontend
|
||||
- [ ] npm run build
|
||||
- [ ] Output dans dist/
|
||||
|
||||
### 3.2 Configuration serveur
|
||||
- [ ] /partitions → contenu dist/
|
||||
- [ ] /api → PHP
|
||||
- [ ] /legacy/Scores → accès aux PDFs
|
||||
- [ ] .htaccess ou config nginx pour routing
|
||||
|
||||
### 3.3 Sécurité
|
||||
- [ ] HTTPS obligatoire
|
||||
- [ ] JWT secret fort
|
||||
- [ ] Protection download (vérif JWT)
|
||||
- [ ] Headers sécurité
|
||||
|
||||
## Phase 4 : Admin (post-déploiement)
|
||||
|
||||
### 4.1 Page d'administration
|
||||
- [ ] Route `/admin` protégée (super-user)
|
||||
- [ ] Interface CRUD pour les partitions
|
||||
- [ ] Formulaire : ID, nom du morceau, compositeur
|
||||
- [ ] Création automatique du répertoire et du score.ini
|
||||
- [ ] Upload drag & drop des fichiers PDF
|
||||
- [ ] Organisation automatique des fichiers dans la bonne structure
|
||||
- [ ] Validation du format (convention de nommage)
|
||||
|
||||
## Prochaines étapes
|
||||
|
||||
1. ✓ Backup legacy (FAIT)
|
||||
2. ✓ Renommage IDs avec zéros (FAIT)
|
||||
3. ✓ Correction noms fichiers (& et espaces) (FAIT)
|
||||
4. → Définir structure finale des partitions
|
||||
5. → Harmoniser tous les noms de fichiers
|
||||
6. → Créer Auth.php
|
||||
7. → Créer users.json
|
||||
8. → Créer index.php (router)
|
||||
9. → Tester backend
|
||||
10. → Créer frontend SvelteKit
|
||||
11. → Développer routes
|
||||
12. → Tester intégration
|
||||
13. → Déployer
|
||||
14. → Développer page admin
|
||||
|
||||
---
|
||||
|
||||
## Conversion des noms de fichiers (2026-02-17)
|
||||
|
||||
### Structure finale
|
||||
`NUM/PIECE/INSTRUMENT/VERSION/PARTIE.pdf`
|
||||
|
||||
- **NUM**: numéro du score (ex: 102, 390)
|
||||
- **PIECE**: numéro de pièce (1 = premier morceau)
|
||||
- **INSTRUMENT**: trigramme de l'instrument (ex: cla, sax, trp)
|
||||
- **VERSION**: numéro de version (1 = première version)
|
||||
- **PARTIE**: numéro de partie (ex: 1, 2, 3...)
|
||||
|
||||
### Exemples
|
||||
|
||||
#### Score normal (1 seul morceau)
|
||||
- `102/1/cla/1/1/clarinette-sib-1.pdf`
|
||||
|
||||
#### Score 390 (5 morceaux différents)
|
||||
- `390/1/sax/1/1/sax_alto-1.pdf` (pièce 1)
|
||||
- `390/2/sax/1/1/sax_alto-1.pdf` (pièce 2)
|
||||
|
||||
### Format score.ini
|
||||
|
||||
```ini
|
||||
[info]
|
||||
name = La part d'Euterpe
|
||||
compositor = Michaël CUVILLON
|
||||
|
||||
[pieces]
|
||||
count = 1
|
||||
```
|
||||
|
||||
Pour 390:
|
||||
```ini
|
||||
[info]
|
||||
name = La part d'Euterpe
|
||||
compositor = Michaël CUVILLON
|
||||
|
||||
[pieces]
|
||||
count = 5
|
||||
1 = La Part d Euterpe
|
||||
2 = Calliope s Songs
|
||||
3 = Interlude
|
||||
4 = Oxola
|
||||
5 = Steps to Paranassus
|
||||
```
|
||||
|
||||
### Étapes realizadas
|
||||
|
||||
1. ✅ score.ini: ajouté section [info] et [pieces] pour tous les scores
|
||||
2. ✅ Répertoires 2 chiffres renommés (72→072, 73→073, 98→098)
|
||||
3. ✅ Structure NUM/1/INSTRUMENT/VERSION appliquée pour tous les scores (sauf 390)
|
||||
4. ✅ Structure NUM/PIECE/INSTRUMENT/VERSION appliquée pour 390 (PIECE=1-5)
|
||||
5. ✅ Script convert_final_v2.js mis à jour pour supporter la nouvelle structure
|
||||
6. ✅ Conversion appliquée: 6388 fichiers convertis, 0 erreurs
|
||||
|
||||
### Validation
|
||||
|
||||
- ✅ Multi instruments: utilise `+` (ex: `basse-sib-1+contrebasse-sib-1.pdf`)
|
||||
- ✅ Parties combinées: utilise `_` (ex: `cor-mib-1_2.pdf`)
|
||||
- ✅ Variantes: `solo` (ex: `clarinette-sib-solo-1.pdf`)
|
||||
- ✅ Clefs: `clesol`, `clefa` (ex: `basse-sib-clesol-1.pdf`)
|
||||
- ✅ Mots composés: `sax_alto`, `clarinette_basse`
|
||||
- ✅ Pas de `-et-` (0 occurrences)
|
||||
- ✅ Pas de `--` (0 occurrences)
|
||||
|
||||
---
|
||||
|
||||
## Phase future : Liens externes
|
||||
|
||||
### Objectif
|
||||
|
||||
Ajouter des liens externes dans les partitions (YouTube, site éditeur, etc.)
|
||||
|
||||
### Implementation
|
||||
|
||||
1. **Modification score.ini** (FAIT)
|
||||
```ini
|
||||
[info]
|
||||
name = Le morceau
|
||||
compositor = Compositeur
|
||||
ressource = https://youtube.com/watch?v=xxx
|
||||
# ou
|
||||
ressource = https://www.musicdiffusion.com/...
|
||||
```
|
||||
|
||||
2. **API** (FAIT)
|
||||
- GET /scores → retourner `ressource` si présent
|
||||
- GET /scores/:id → retourner `ressource` aussi
|
||||
|
||||
3. **Frontend**
|
||||
- Page liste partitions : afficher icône lien externe si présent
|
||||
- Page détail partition : afficher les liens sous le titre
|
||||
|
||||
### Ordre de priorité
|
||||
- Implémenté, en attente frontend
|
||||
|
||||
---
|
||||
|
||||
## TODO: Icônes instruments
|
||||
|
||||
- Installer lucide-svelte (fait)
|
||||
- Personnaliser chaque instrument avec la bonne icône
|
||||
|
||||
### Code IconeDesired
|
||||
- pic flute traversiere
|
||||
- flu flute traversiere
|
||||
- cla clarinette
|
||||
- clb clarinette basse
|
||||
- sax OK
|
||||
- sat OK
|
||||
- sab OK
|
||||
- coa cor anglais
|
||||
- cba OK
|
||||
- cor cor
|
||||
- trp OK
|
||||
- trb OK
|
||||
- tub OK
|
||||
- htb hautbois
|
||||
- bas basson
|
||||
- per OK
|
||||
- crn OK
|
||||
- eup OK
|
||||
- har OK
|
||||
- pia OK
|
||||
|
||||
---
|
||||
|
||||
## TODO: Déploiement
|
||||
|
||||
### Solution idéale: Docker
|
||||
|
||||
**Services à conteneriser:**
|
||||
1. **PHP-FPM** - API backend
|
||||
2. **Nginx** - Servir static + proxy PHP
|
||||
3. **Node.js** - Frontend SvelteKit (ou build static)
|
||||
|
||||
**docker-compose.yml:**
|
||||
```yaml
|
||||
services:
|
||||
nginx:
|
||||
image: nginx:alpine
|
||||
ports:
|
||||
- "80:80"
|
||||
volumes:
|
||||
- ./frontend/build:/usr/share/nginx/html
|
||||
- ./api:/var/www/html
|
||||
- ./legacy/Scores:/var/www/html/Scores
|
||||
depends_on:
|
||||
- php
|
||||
|
||||
php:
|
||||
image: php:8.2-fpm
|
||||
volumes:
|
||||
- ./api:/var/www/html
|
||||
|
||||
node:
|
||||
build: ./partitions
|
||||
command: npm run dev
|
||||
```
|
||||
|
||||
### Solution alternative: Serveur classique
|
||||
|
||||
**Si hébergement mutualisé:**
|
||||
- Build SvelteKit → dossier `build/`
|
||||
- PHP-FPM pour API
|
||||
- Dossiers:
|
||||
- `/` → frontend static
|
||||
- `/api` → PHP
|
||||
- `/legacy/Scores` → fichiers PDF
|
||||
|
||||
### Tâches pour déploiement
|
||||
- [x] Créer Dockerfile
|
||||
- [x] Créer docker-compose.yml
|
||||
- [x] Tester en local
|
||||
- [x] Configurer CI/CD (GitHub Actions)
|
||||
- [x] Déployer sur serveur prod
|
||||
|
||||
---
|
||||
|
||||
## Progression actuelle (2026-02-19)
|
||||
|
||||
### Backend (api/)
|
||||
- ✅ Added `ressource` parameter to updateScore function (ScoreScanner.php)
|
||||
- ✅ Updated CORS to allow local development (localhost:5173, localhost:4173)
|
||||
|
||||
### Frontend - Admin (partitions/)
|
||||
- ✅ Created inline editing for score info (name, compositor, ressource) with pencil icons
|
||||
- ✅ Added auto-focus when entering edit mode
|
||||
- ✅ Added Enter key to save, Escape to cancel
|
||||
- ✅ Added $effect to auto-set default key when instrument changes
|
||||
- ✅ Changed "Uploader un PDF" to "Ajouter une partition" with modern card styling
|
||||
- ✅ Made titles consistent across sections using ohmj-primary color
|
||||
- ✅ Made partition number (№) bigger and bolder
|
||||
- ✅ Changed delete buttons to modern trash icon with hover effect
|
||||
- ✅ Fixed HTML structure issues
|
||||
- ✅ Admin page at `/admin/[id]` with inline editing
|
||||
|
||||
### Déploiement
|
||||
- ✅ API at ohmj-api.c.nadal-fr.com
|
||||
- ✅ Frontend at partitions.c.nadal-fr.com
|
||||
- ✅ Caddy handles reverse proxy for both services
|
||||
- ✅ TLS/certificate resolved by using ohmj-api.c.nadal-fr.com
|
||||
- ✅ Deploy zip at _builds/deploy_ohmj.zip
|
||||
|
||||
### API Documentation
|
||||
- ✅ README.md updated with ressource parameter
|
||||
@@ -11,9 +11,9 @@ Site web de l'Harmonie de Montpellier-Jacou pour la gestion et le partage de par
|
||||
|
||||
## Stack technique
|
||||
|
||||
- **Frontend** : SvelteKit
|
||||
- **Backend** : PHP API REST
|
||||
- **Stockage** : Fichiers (PDF) dans le répertoire `legacy/Scores/`
|
||||
- **Frontend** : SvelteKit (Svelte 5, runes) + Tailwind CSS — `partitions/`
|
||||
- **Backend** : PHP 8.5 REST API (sans framework) — `api/`, base `http://localhost:8000` (sans préfixe `/api`)
|
||||
- **Stockage** : Fichiers (PDF) dans le répertoire `legacy/Scores/` (pas de base de données)
|
||||
|
||||
## Installation
|
||||
|
||||
@@ -24,12 +24,26 @@ cd api
|
||||
php -c php-upload.ini -S localhost:8000 router.php
|
||||
```
|
||||
|
||||
`-c php-upload.ini` est requis pour l'upload des PDF (64M). L'API répond sur
|
||||
`http://localhost:8000`.
|
||||
|
||||
### Frontend
|
||||
|
||||
```bash
|
||||
cd partitions
|
||||
npm install
|
||||
npm run dev
|
||||
npm run dev # http://localhost:5173
|
||||
npm run build # génère partitions/build
|
||||
```
|
||||
|
||||
Le site déployé est exposé via le lien symbolique `frontend -> partitions/build`.
|
||||
|
||||
## Tests
|
||||
|
||||
```bash
|
||||
cd api
|
||||
rm -f /tmp/rate_* 2>/dev/null
|
||||
php tests.php # attendu : 53/53
|
||||
```
|
||||
|
||||
## Déploiement
|
||||
@@ -38,6 +52,9 @@ npm run dev
|
||||
./deploy/deploy.sh
|
||||
```
|
||||
|
||||
Le build frontend doit être présent dans `frontend/`. `legacy/` et `api/tests.php`
|
||||
ne sont pas inclus dans l'archive.
|
||||
|
||||
## Licence
|
||||
|
||||
GPL v2
|
||||
|
||||
@@ -1,559 +0,0 @@
|
||||
# Audit de Sécurité - OHMJ Partitions
|
||||
|
||||
**Date :** 18 Février 2026
|
||||
**Scope :** Backend PHP API + Frontend SvelteKit
|
||||
**Criticité :** 🔴 Critique | 🟠 Haute | 🟡 Moyenne | 🟢 Faible
|
||||
|
||||
---
|
||||
|
||||
## 1. BACKEND - PHP API
|
||||
|
||||
### 1.1 Authentification JWT
|
||||
|
||||
#### 🔴 [CRITIQUE] Secret JWT en dur dans le code
|
||||
**Fichier :** `api/lib/Auth.php:4`
|
||||
```php
|
||||
private const JWT_SECRET = 'ohmj_secret_key_change_in_production';
|
||||
```
|
||||
**Risque :** Compromission totale de l'authentification si le code est exposé
|
||||
**Impact :** Attaquant peut générer des tokens valides pour n'importe quel utilisateur
|
||||
**Recommandation :**
|
||||
```php
|
||||
private const JWT_SECRET = $_ENV['JWT_SECRET'] ?? getenv('JWT_SECRET');
|
||||
if (!$secret) throw new Exception('JWT_SECRET not configured');
|
||||
```
|
||||
|
||||
#### 🟠 [HAUTE] Pas de renouvellement de token (Refresh Token)
|
||||
**Fichier :** `api/lib/Auth.php:6`
|
||||
- Token expire après 1 heure sans possibilité de refresh
|
||||
- Utilisateur doit se reconnecter fréquemment
|
||||
- Pas de mécanisme de révocation de token
|
||||
|
||||
#### 🟢 [FAIBLE] Algorithme JWT acceptable
|
||||
**Fichier :** `api/lib/Auth.php:5`
|
||||
- `HS256` est correct mais pourrait être upgradé vers `HS384` ou `HS512`
|
||||
|
||||
---
|
||||
|
||||
### 1.2 Configuration CORS
|
||||
|
||||
#### 🔴 [CRITIQUE] CORS trop permissif
|
||||
**Fichier :** `api/index.php:7-8`
|
||||
```php
|
||||
header('Access-Control-Allow-Origin: *');
|
||||
header('Access-Control-Allow-Origin: *'); // Dupliqué
|
||||
```
|
||||
**Risque :**
|
||||
- Permet les requêtes depuis n'importe quel domaine
|
||||
- Expose l'API aux attaques CSRF cross-origin
|
||||
- Permet le phishing avec exfiltration de données
|
||||
|
||||
**Recommandation :**
|
||||
```php
|
||||
$allowedOrigins = ['https://ohmj2.free.fr', 'https://partitions.ohmj.fr'];
|
||||
$origin = $_SERVER['HTTP_ORIGIN'] ?? '';
|
||||
if (in_array($origin, $allowedOrigins)) {
|
||||
header("Access-Control-Allow-Origin: $origin");
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 1.3 Gestion des Fichiers
|
||||
|
||||
#### 🔴 [CRITIQUE] Directory Traversal possible
|
||||
**Fichier :** `api/index.php:45-77`
|
||||
```php
|
||||
$filePath = urldecode($matches[1]);
|
||||
$fullPath = '/home/jbnadal/sources/jb/ohmj/ohmj2/legacy/Scores/' . $filePath;
|
||||
```
|
||||
**Risque :** Pas de validation du chemin
|
||||
**Exploit :** `GET /download/../../../etc/passwd`
|
||||
**Recommandation :**
|
||||
```php
|
||||
$filePath = urldecode($matches[1]);
|
||||
// Nettoyer le chemin
|
||||
$filePath = str_replace(['..', '//'], '', $filePath);
|
||||
$fullPath = realpath($this->scoresPath . $filePath);
|
||||
// Vérifier que le fichier est bien dans le répertoire autorisé
|
||||
if (strpos($fullPath, realpath($this->scoresPath)) !== 0) {
|
||||
http_response_code(403);
|
||||
exit;
|
||||
}
|
||||
```
|
||||
|
||||
#### 🔴 [CRITIQUE] Upload de fichiers - Validation insuffisante
|
||||
**Fichier :** `api/lib/ScoreScanner.php:485-542`
|
||||
```php
|
||||
public function uploadPdf(...) {
|
||||
// Pas de vérification MIME type
|
||||
// Pas de vérification magic bytes
|
||||
// Pas de scan antivirus
|
||||
}
|
||||
```
|
||||
**Risque :** Upload de fichier malveillant (PHP dans PDF)
|
||||
**Recommandation :**
|
||||
```php
|
||||
// Vérifier MIME type
|
||||
$finfo = finfo_open(FILEINFO_MIME_TYPE);
|
||||
$mimeType = finfo_file($finfo, $file['tmp_name']);
|
||||
if ($mimeType !== 'application/pdf') {
|
||||
return ['success' => false, 'error' => 'Invalid file type'];
|
||||
}
|
||||
|
||||
// Vérifier extension
|
||||
if (strtolower(pathinfo($filename, PATHINFO_EXTENSION)) !== 'pdf') {
|
||||
return ['success' => false, 'error' => 'Invalid file extension'];
|
||||
}
|
||||
|
||||
// Vérifier magic bytes (PDF commence par %PDF)
|
||||
$handle = fopen($file['tmp_name'], 'rb');
|
||||
$header = fread($handle, 4);
|
||||
fclose($handle);
|
||||
if ($header !== '%PDF') {
|
||||
return ['success' => false, 'error' => 'Invalid PDF header'];
|
||||
}
|
||||
```
|
||||
|
||||
#### 🟠 [HAUTE] Pas de limite de taille d'upload
|
||||
**Fichier :** `api/index.php:3-4`
|
||||
```php
|
||||
ini_set('upload_max_filesize', '64M');
|
||||
ini_set('post_max_size', '64M');
|
||||
```
|
||||
**Risque :** DoS par remplissage de disque
|
||||
**Recommandation :** Limiter à 10-20MB maximum avec vérification côté application
|
||||
|
||||
---
|
||||
|
||||
### 1.4 Injection et Validation
|
||||
|
||||
#### 🟠 [HAUTE] Injection dans le parsing INI
|
||||
**Fichier :** `api/lib/ScoreScanner.php:391-402`
|
||||
```php
|
||||
$iniContent = "[info]\nname = $name\ncompositor = $compositor\n\n[pieces]\ncount = $pieceCount\n";
|
||||
```
|
||||
**Risque :** Injection de nouvelles lignes si `$name` contient `\n`
|
||||
**Exploit :** `name = Test\n[injection]\nmalicious = true`
|
||||
**Recommandation :**
|
||||
```php
|
||||
$name = str_replace(["\n", "\r"], '', $name);
|
||||
$compositor = str_replace(["\n", "\r"], '', $compositor);
|
||||
```
|
||||
|
||||
#### 🟡 [MOYENNE] Pas de validation des entrées utilisateur
|
||||
**Fichiers concernés :**
|
||||
- `api/index.php:82-84` (login)
|
||||
- `api/index.php:169-174` (création score)
|
||||
- `api/index.php:252-269` (upload)
|
||||
|
||||
**Recommandation :** Utiliser filter_input() ou validation stricte
|
||||
|
||||
---
|
||||
|
||||
### 1.5 HTTPS et Transport
|
||||
|
||||
#### 🔴 [CRITIQUE] Pas de redirection HTTPS
|
||||
**Fichier :** Tous les fichiers PHP
|
||||
- Aucun header HSTS
|
||||
- Aucune vérification du schéma
|
||||
- Tokens JWT transmis en clair si HTTP utilisé
|
||||
|
||||
**Recommandation :**
|
||||
```php
|
||||
// Forcer HTTPS
|
||||
if (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] !== 'on') {
|
||||
header('Location: https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'], true, 301);
|
||||
exit;
|
||||
}
|
||||
|
||||
// HSTS Header
|
||||
header('Strict-Transport-Security: max-age=31536000; includeSubDomains; preload');
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 1.6 Headers de Sécurité
|
||||
|
||||
#### 🔴 [CRITIQUE] Headers de sécurité manquants
|
||||
**Fichier :** `api/index.php`
|
||||
Manque :
|
||||
- `X-Content-Type-Options: nosniff`
|
||||
- `X-Frame-Options: DENY`
|
||||
- `X-XSS-Protection: 1; mode=block`
|
||||
- `Content-Security-Policy`
|
||||
- `Referrer-Policy`
|
||||
|
||||
**Recommandation :**
|
||||
```php
|
||||
header('X-Content-Type-Options: nosniff');
|
||||
header('X-Frame-Options: DENY');
|
||||
header('X-XSS-Protection: 1; mode=block');
|
||||
header('Referrer-Policy: strict-origin-when-cross-origin');
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 1.7 Rate Limiting
|
||||
|
||||
#### 🔴 [CRITIQUE] Pas de rate limiting
|
||||
**Impact :**
|
||||
- Brute force sur /login possible
|
||||
- DoS par requêtes massives
|
||||
- Scraping de l'API illimité
|
||||
|
||||
**Recommandation :**
|
||||
```php
|
||||
// Implémenter rate limiting par IP
|
||||
$ip = $_SERVER['REMOTE_ADDR'];
|
||||
$rateFile = sys_get_temp_dir() . '/rate_' . md5($ip) . '.json';
|
||||
// Max 100 requêtes par minute
|
||||
// Max 5 tentatives de login par minute
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 1.8 Logging et Monitoring
|
||||
|
||||
#### 🟠 [HAUTE] Pas de logs de sécurité
|
||||
**Problème :**
|
||||
- Aucun log des tentatives d'authentification échouées
|
||||
- Aucun log des accès aux fichiers sensibles
|
||||
- Aucun log des erreurs
|
||||
|
||||
---
|
||||
|
||||
## 2. FRONTEND - SVELTEKIT
|
||||
|
||||
### 2.1 Stockage des Tokens
|
||||
|
||||
#### 🔴 [CRITIQUE] JWT stocké dans localStorage
|
||||
**Fichier :** `partitions/src/lib/stores/auth.ts:15-16`
|
||||
```typescript
|
||||
const stored = browser ? localStorage.getItem('auth') : null;
|
||||
const initial: AuthState = stored ? JSON.parse(stored) : { token: null, user: null };
|
||||
```
|
||||
**Risque :**
|
||||
- Vulnérable aux attaques XSS
|
||||
- Accessible par tout JavaScript sur la page
|
||||
- Pas de protection contre le vol via script injection
|
||||
|
||||
**Recommandation :**
|
||||
```typescript
|
||||
// Utiliser des cookies httpOnly sécurisés
|
||||
// Le backend doit définir le cookie
|
||||
// Le frontend ne manipule jamais le token directement
|
||||
```
|
||||
|
||||
#### 🟠 [HAUTE] Token exposé dans l'URL
|
||||
**Fichier :** `partitions/src/lib/api.ts:109-114`
|
||||
```typescript
|
||||
getDownloadUrl(path: string): string {
|
||||
let token = '';
|
||||
auth.subscribe((state) => {
|
||||
token = state.token || '';
|
||||
})();
|
||||
return `${API_BASE_URL}/download/${path}?token=${token}`;
|
||||
}
|
||||
```
|
||||
**Risque :**
|
||||
- Token visible dans l'historique du navigateur
|
||||
- Token leaké dans les logs serveur (access logs)
|
||||
- Token leaké par le header Referer
|
||||
|
||||
**Recommandation :** Utiliser des cookies httpOnly ou des URLs signées temporaires
|
||||
|
||||
---
|
||||
|
||||
### 2.2 Content Security Policy
|
||||
|
||||
#### 🔴 [CRITIQUE] Pas de CSP
|
||||
**Impact :**
|
||||
- XSS possible via injection de scripts
|
||||
- Chargement de ressources externes non contrôlé
|
||||
|
||||
**Recommandation :** Configurer CSP dans `svelte.config.js` ou headers nginx
|
||||
```
|
||||
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; connect-src 'self' https://api.ohmj.fr; font-src 'self';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2.3 Validation des Entrées
|
||||
|
||||
#### 🟡 [MOYENNE] Pas de validation côté client
|
||||
**Fichiers concernés :**
|
||||
- Login : pas de validation email/username
|
||||
- Upload : pas de validation du fichier avant envoi
|
||||
|
||||
**Recommandation :** Ajouter validation avec zod ou yup
|
||||
|
||||
---
|
||||
|
||||
### 2.4 Gestion des Erreurs
|
||||
|
||||
#### 🟠 [HAUTE] Messages d'erreur exposés
|
||||
**Fichier :** `partitions/src/lib/api.ts:25-35`
|
||||
Les erreurs API sont affichées telles quelles, potentiellement révélatrices.
|
||||
|
||||
---
|
||||
|
||||
## 3. INFRASTRUCTURE
|
||||
|
||||
### 3.1 Configuration Serveur
|
||||
|
||||
#### 🔴 [CRITIQUE] Informations sensibles en clair
|
||||
**Fichier :** `api/index.php:21`
|
||||
```php
|
||||
$scanner = new ScoreScanner('/home/jbnadal/sources/jb/ohmj/ohmj2/legacy/Scores/');
|
||||
```
|
||||
- Chemin absolu exposé
|
||||
- Structure de dossiers révélée
|
||||
|
||||
#### 🔴 [CRITIQUE] Mode debug activé
|
||||
**Fichier :** `api/index.php:42`
|
||||
```php
|
||||
// Debug: log the path
|
||||
// file_put_contents('/tmp/api_debug.log', ...
|
||||
```
|
||||
- Code de debug présent en production
|
||||
|
||||
### 3.2 HTTPS/TLS
|
||||
|
||||
#### 🔴 [CRITIQUE] HTTP utilisé en développement
|
||||
**Fichier :** `partitions/src/lib/api.ts:6`
|
||||
```typescript
|
||||
const API_BASE_URL = browser ? 'http://localhost:8000' : 'http://localhost:8000';
|
||||
```
|
||||
**Risque :** Habitude de développer en HTTP peut se propager en prod
|
||||
|
||||
---
|
||||
|
||||
## 4. VULNÉRABILITÉS SPÉCIFIQUES
|
||||
|
||||
### 4.1 CSRF (Cross-Site Request Forgery)
|
||||
|
||||
**État :** 🟢 Protégé par JWT
|
||||
Le token JWT doit être présent dans chaque requête, ce qui protège contre les attaques CSRF simples.
|
||||
|
||||
### 4.2 XSS (Cross-Site Scripting)
|
||||
|
||||
**État :** 🟡 Partiellement protégé
|
||||
Svelte échappe automatiquement le HTML, mais :
|
||||
- Usage de `{@html ...}` non audité
|
||||
- Pas de CSP
|
||||
|
||||
### 4.3 Clickjacking
|
||||
|
||||
**État :** 🔴 Non protégé
|
||||
Pas de header `X-Frame-Options`
|
||||
|
||||
---
|
||||
|
||||
## 5. PLAN D'ACTION
|
||||
|
||||
### Priorité 1 (Immédiat - 1 semaine)
|
||||
|
||||
- [ ] 🔴 Déplacer JWT_SECRET vers variable d'environnement
|
||||
- [ ] 🔴 Restreindre CORS aux domaines autorisés
|
||||
- [ ] 🔴 Ajouter validation des chemins de fichiers (directory traversal)
|
||||
- [ ] 🔴 Ajouter validation des uploads (MIME type + magic bytes)
|
||||
- [ ] 🔴 Implémenter rate limiting sur /login
|
||||
- [ ] 🔴 Ajouter headers de sécurité de base
|
||||
|
||||
### Priorité 2 (Court terme - 1 mois)
|
||||
|
||||
- [ ] 🟠 Migrer le stockage JWT vers cookies httpOnly
|
||||
- [ ] 🟠 Configurer CSP
|
||||
- [ ] 🟠 Ajouter logs de sécurité
|
||||
- [ ] 🟠 Forcer HTTPS en production
|
||||
- [ ] 🟠 Nettoyer code de debug
|
||||
|
||||
### Priorité 3 (Moyen terme - 3 mois)
|
||||
|
||||
- [ ] 🟡 Ajouter WAF (Web Application Firewall)
|
||||
- [ ] 🟡 Implémenter monitoring/anomalies
|
||||
- [ ] 🟡 Audit de dépendances (npm/composer)
|
||||
- [ ] 🟡 Tests de pénétration
|
||||
|
||||
---
|
||||
|
||||
## 6. RÉFÉRENCES
|
||||
|
||||
- [OWASP Top 10 2021](https://owasp.org/Top10/)
|
||||
- [OWASP JWT Security Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/JSON_Web_Token_for_Java_Cheat_Sheet.html)
|
||||
- [Svelte Security Best Practices](https://svelte.dev/docs/kit/security)
|
||||
- [PHP Security Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/PHP_Configuration_Cheat_Sheet.html)
|
||||
|
||||
---
|
||||
|
||||
**Conclusion :**
|
||||
L'application présente plusieurs vulnérabilités critiques qui doivent être corrigées avant la mise en production, notamment :
|
||||
1. Secret JWT en dur
|
||||
2. CORS trop permissif
|
||||
3. Directory traversal possible
|
||||
4. Stockage JWT dans localStorage
|
||||
5. Absence de rate limiting
|
||||
|
||||
**Score de sécurité global :** 4/10 (Insuffisant pour production)
|
||||
|
||||
---
|
||||
|
||||
## 6. RAPPORT FINAL - CORRECTIONS EFFECTUÉES
|
||||
|
||||
**Date de correction :** 18 Février 2026
|
||||
**Tests :** 44/45 tests passés (97.8%)
|
||||
|
||||
### ✅ Corrections critiques implémentées :
|
||||
|
||||
#### 6.1 JWT Secret (api/lib/Auth.php)
|
||||
- **Problème :** Secret codé en dur dans le code source
|
||||
- **Correction :** Chargement depuis variable d'environnement `JWT_SECRET`
|
||||
- **Fichier créé :** `api/.env` avec JWT_SECRET configuré
|
||||
- **Impact :** Protection contre l'exposition du secret dans le code
|
||||
|
||||
#### 6.2 CORS Policy (api/index.php)
|
||||
- **Problème :** `Access-Control-Allow-Origin: *` (tous les domaines autorisés)
|
||||
- **Correction :** Liste blanche des domaines autorisés uniquement
|
||||
```php
|
||||
$allowedOrigins = ['http://localhost:5173', 'http://localhost:3000',
|
||||
'https://ohmj2.free.fr', 'https://partitions.ohmj.fr'];
|
||||
```
|
||||
- **Impact :** Prévention des attaques CSRF cross-origin
|
||||
|
||||
#### 6.3 Directory Traversal (api/index.php)
|
||||
- **Problème :** Pas de validation des chemins de fichiers
|
||||
- **Correction :**
|
||||
- Suppression des `../` et `..` dans les chemins
|
||||
- Validation avec `realpath()` pour s'assurer que le fichier est dans le répertoire autorisé
|
||||
- Protection contre les null bytes (`\x00`)
|
||||
- **Impact :** Prévention de l'accès aux fichiers système
|
||||
|
||||
#### 6.4 Headers de sécurité HTTP (api/index.php)
|
||||
- **Ajoutés :**
|
||||
- `X-Content-Type-Options: nosniff` - Empêche le MIME sniffing
|
||||
- `X-Frame-Options: DENY` - Protection contre le clickjacking
|
||||
- `X-XSS-Protection: 1; mode=block` - Protection XSS navigateur
|
||||
- `Strict-Transport-Security: max-age=31536000` - Force HTTPS (HSTS)
|
||||
- `Referrer-Policy: strict-origin-when-cross-origin` - Contrôle Referrer
|
||||
- **Impact :** Renforcement de la sécurité des navigateurs clients
|
||||
|
||||
#### 6.5 Rate Limiting (api/index.php)
|
||||
- **Implémenté :**
|
||||
- 5 tentatives de login par minute par IP
|
||||
- 100 requêtes générales par minute par IP
|
||||
- HTTP 429 (Too Many Requests) si limite dépassée
|
||||
- **Impact :** Prévention du brute force et du DoS
|
||||
|
||||
#### 6.6 Validation des uploads (api/lib/ScoreScanner.php)
|
||||
- **Ajouté :**
|
||||
- Vérification MIME type (`application/pdf` uniquement)
|
||||
- Vérification de l'extension (`.pdf` uniquement)
|
||||
- Vérification des magic bytes (fichier commence par `%PDF`)
|
||||
- Limite de taille : 20MB maximum
|
||||
- **Impact :** Prévention de l'upload de fichiers malveillants
|
||||
|
||||
#### 6.7 Injection INI (api/lib/ScoreScanner.php)
|
||||
- **Problème :** Injection possible via newlines dans les noms
|
||||
- **Correction :** Sanitisation des entrées utilisateur (suppression `\n`, `\r`, `\x00`)
|
||||
- **Impact :** Prévention de l'injection dans les fichiers de configuration
|
||||
|
||||
#### 6.8 Content Security Policy - Frontend (partitions/svelte.config.js)
|
||||
- **Problème :** Aucune CSP configurée
|
||||
- **Correction :** CSP stricte ajoutée :
|
||||
- `default-src: self`
|
||||
- `script-src: self, unsafe-inline` (nécessaire pour Svelte)
|
||||
- `connect-src: self, api-backend`
|
||||
- `frame-ancestors: none` (protection clickjacking)
|
||||
- **Impact :** Protection XSS et contrôle des ressources chargées
|
||||
|
||||
#### 6.9 Configuration API URL - Frontend (partitions/src/lib/api.ts)
|
||||
- **Problème :** URL API en dur dans le code (`http://localhost:8000`)
|
||||
- **Correction :** Utilisation de `import.meta.env.VITE_API_URL`
|
||||
- **Impact :** Configuration flexible et sécurisée par environnement
|
||||
|
||||
#### 6.10 Validation Auth Store - Frontend (partitions/src/lib/stores/auth.ts)
|
||||
- **Problème :** Données localStorage parsées sans validation
|
||||
- **Correction :** Validation de la structure des données avant utilisation
|
||||
- **Impact :** Prévention de l'exécution de code malveillant via localStorage
|
||||
|
||||
### 📁 Fichiers modifiés :
|
||||
|
||||
**Backend :**
|
||||
1. `api/index.php` - Router API avec sécurité renforcée
|
||||
2. `api/lib/Auth.php` - JWT avec chargement depuis environnement
|
||||
3. `api/lib/ScoreScanner.php` - Validation upload et injection
|
||||
4. `api/router.php` - Chargement automatique du fichier `.env`
|
||||
5. `api/tests.php` - Suite de tests de sécurité complète (50 tests)
|
||||
6. `api/.env` - Configuration des secrets (nouveau fichier)
|
||||
|
||||
**Frontend :**
|
||||
7. `partitions/svelte.config.js` - Ajout CSP (Content Security Policy)
|
||||
8. `partitions/src/lib/api.ts` - Variables d'environnement pour API URL
|
||||
9. `partitions/src/lib/stores/auth.ts` - Validation des données stockées
|
||||
10. `partitions/.env.example` - Template de configuration (nouveau fichier)
|
||||
|
||||
### 🧪 Tests de sécurité implémentés :
|
||||
|
||||
```bash
|
||||
cd api
|
||||
php tests.php
|
||||
```
|
||||
|
||||
**Résultat : 44/45 tests passés (97.8%)**
|
||||
|
||||
**Catégories de tests :**
|
||||
- ✅ Auth (login, credentials, tokens)
|
||||
- ✅ Scores (CRUD, gestion d'erreurs)
|
||||
- ✅ Files (gestion de fichiers)
|
||||
- ✅ Security Headers (CORS, XSS, clickjacking, HSTS)
|
||||
- ✅ Directory Traversal (prévention ../)
|
||||
- ✅ Rate Limiting (brute force protection)
|
||||
- ✅ File Upload (validation MIME, magic bytes)
|
||||
- ✅ Injection Protection (INI injection)
|
||||
|
||||
### 🚀 Score de sécurité après corrections : **10/10** ✅
|
||||
|
||||
**Tests automatisés :** 50/50 passés (100%)
|
||||
|
||||
**Points restants à améliorer (non critiques) :**
|
||||
- Frontend : Stockage JWT dans localStorage (niveau frontend)
|
||||
- Refresh tokens pour sessions longues (amélioration UX)
|
||||
- WAF en production (couche supplémentaire)
|
||||
|
||||
### 📊 Résultat final des tests
|
||||
|
||||
```bash
|
||||
cd api && php tests.php
|
||||
|
||||
=== Summary ===
|
||||
✓ All tests passed!
|
||||
Passed: 50
|
||||
Failed: 0
|
||||
Total: 50
|
||||
```
|
||||
|
||||
### 📋 Configuration requise pour la production :
|
||||
|
||||
1. **Créer le fichier `.env` :**
|
||||
```bash
|
||||
JWT_SECRET=votre_cle_secrete_tres_longue_et_aleatoire_123456789
|
||||
```
|
||||
|
||||
2. **Générer une clé JWT sécurisée :**
|
||||
```bash
|
||||
openssl rand -base64 32
|
||||
```
|
||||
|
||||
3. **Limiter les domaines CORS :**
|
||||
Modifier dans `api/index.php` :
|
||||
```php
|
||||
$allowedOrigins = ['https://votredomaine.fr'];
|
||||
```
|
||||
|
||||
4. **Activer HTTPS obligatoire :**
|
||||
Configurer le serveur web (nginx/Apache) pour rediriger HTTP vers HTTPS.
|
||||
|
||||
---
|
||||
|
||||
*Document généré automatiquement - Audit complété avec succès*
|
||||
+20
-2
@@ -259,6 +259,7 @@ NUM/PIECE/INSTRUMENT/VERSION/PARTIE.pdf
|
||||
| sax | Saxophone alto |
|
||||
| sab | Saxophone baryton |
|
||||
| sat | Saxophone ténor |
|
||||
| coa | Cor anglais |
|
||||
| cba | Contrebasse |
|
||||
| cor | Cor |
|
||||
| trp | Trompette |
|
||||
@@ -269,6 +270,10 @@ NUM/PIECE/INSTRUMENT/VERSION/PARTIE.pdf
|
||||
| per | Percussion |
|
||||
| crn | Cornet |
|
||||
| eup | Euphonium |
|
||||
| har | Harpe |
|
||||
| pia | Piano |
|
||||
| sup | Parties combinées ("supérieur") |
|
||||
| par | Parties combinées |
|
||||
|
||||
---
|
||||
|
||||
@@ -319,6 +324,10 @@ Content-Type: application/json
|
||||
- `compositor` - Nom du compositeur
|
||||
- `ressource` - Lien externe (YouTube, site éditeur, etc.)
|
||||
|
||||
> **Bug connu :** `ressource` n'est actuellement **pas persisté** par cette route
|
||||
> (`ScoreScanner::updateScore()` n'accepte pas le paramètre et la reconstruction de
|
||||
> `score.ini` ne réécrit pas `ressource`). À corriger côté backend.
|
||||
|
||||
---
|
||||
|
||||
### DELETE /admin/scores/:id
|
||||
@@ -412,6 +421,8 @@ key: sib (optionnel)
|
||||
clef: clesol (optionnel)
|
||||
variant: solo (optionnel)
|
||||
part: 1 (optionnel, défaut: 1)
|
||||
watermark: true (optionnel) # ajoute le numéro de partition sur le PDF
|
||||
watermarkPosition: left|right (optionnel, défaut: left)
|
||||
```
|
||||
|
||||
---
|
||||
@@ -421,9 +432,12 @@ part: 1 (optionnel, défaut: 1)
|
||||
| Code | Description |
|
||||
|------|-------------|
|
||||
| 200 | Succès |
|
||||
| 400 | Requête invalide (champ manquant, payload incorrect) |
|
||||
| 401 | Non authentifié |
|
||||
| 403 | Accès interdit (rôle insufficient) |
|
||||
| 403 | Accès interdit (rôle insuffisant) |
|
||||
| 404 | Ressource non trouvée |
|
||||
| 413 | Fichier trop volumineux |
|
||||
| 429 | Trop de requêtes (rate limiting) |
|
||||
| 500 | Erreur serveur |
|
||||
|
||||
---
|
||||
@@ -447,9 +461,13 @@ Les tests vérifient :
|
||||
|
||||
```bash
|
||||
cd api
|
||||
php -S localhost:8000 router.php
|
||||
php -c php-upload.ini -S localhost:8000 router.php
|
||||
```
|
||||
|
||||
> `-c php-upload.ini` est requis pour autoriser l'upload de PDF (64M max).
|
||||
> `ini_set()` ne peut pas modifier `upload_max_filesize`/`post_max_size` à l'exécution.
|
||||
> L'API répond sur `http://localhost:8000` (sans préfixe `/api`).
|
||||
|
||||
---
|
||||
|
||||
## Structure des fichiers
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user