b913a2bf90
Refs gitea:Adriano/AI-OS#310 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
64 lines
4.9 KiB
Markdown
64 lines
4.9 KiB
Markdown
# Task 15 — Area admin: editor Tiptap, API CRUD, upload immagini
|
|
|
|
Data: 2026-07-02
|
|
Commit: `f0ad162f742179e5154dd0e011345b35f093f119`
|
|
|
|
## Riepilogo
|
|
|
|
Il Task 15 introduce l'area di amministrazione del sito InsanityLab: layout admin dedicato, pagine di login/logout, lista articoli con eliminazione, form di creazione e modifica con editor Tiptap, API REST protette per il CRUD dei post, endpoint di upload immagini con validazione e route di serving dei file caricati con protezione contro il path traversal. La sanitizzazione dell'HTML in ingresso è centralizzata in `src/lib/sanitize.ts` (basata su `sanitize-html`) ed è coperta da test scritti prima dell'implementazione, secondo il flusso TDD richiesto.
|
|
|
|
## File creati
|
|
|
|
- `tests/sanitize.test.ts`
|
|
- `src/lib/sanitize.ts`
|
|
- `src/lib/post-body.ts`
|
|
- `src/layouts/Admin.astro`
|
|
- `src/pages/admin/login.astro`, `src/pages/admin/logout.ts`, `src/pages/admin/index.astro`, `src/pages/admin/new.astro`, `src/pages/admin/edit/[id].astro`
|
|
- `src/components/admin/PostForm.astro`
|
|
- `src/pages/api/admin/posts/index.ts`, `src/pages/api/admin/posts/[id].ts`, `src/pages/api/admin/upload.ts`
|
|
- `src/pages/uploads/[...path].ts`
|
|
|
|
## Esito test (`npm test`)
|
|
|
|
```
|
|
Test Files 6 passed (6)
|
|
Tests 28 passed (28)
|
|
```
|
|
|
|
28/28 test superati: 25 preesistenti (`auth`, `contact`, `posts`, `rate-limit`, `slug`) più i 3 nuovi test di `sanitize`. Il ciclo TDD è stato rispettato: il test è stato creato per primo, la sua esecuzione è fallita con `Cannot find module '../src/lib/sanitize'`, quindi è stata scritta l'implementazione e i test sono passati al primo tentativo.
|
|
|
|
## Verifica end-to-end (dev server su porta 4321)
|
|
|
|
| # | Check | Atteso | Ottenuto | Esito |
|
|
|---|-------|--------|----------|-------|
|
|
| 1 | GET `/admin` senza autenticazione | 302 | 302 | ✓ |
|
|
| 2 | POST `/api/admin/posts` senza autenticazione | 401 | 401 | ✓ |
|
|
| 3 | Login POST `/admin/login` (utente e2e dedicato) | 302 + cookie | 302, cookie `session` impostato | ✓ |
|
|
| 4 | POST nuovo articolo | 201 | 201, `{"id":16,"slug":"test-e2e-task-15"}` | ✓ |
|
|
| 5 | GET `/blog/test-e2e-task-15` | 200 | 200 | ✓ |
|
|
| 6 | PUT aggiornamento articolo | 200 | 200, `{"ok":true}` | ✓ |
|
|
| 7 | Upload PNG (10x10, generato via Python) | 200 | 200, `{"url":"/uploads/1782949642171-10ccb41e.png"}` | ✓ |
|
|
| 8 | GET file caricato | 200 | 200, `Content-Type: image/png` | ✓ |
|
|
| 9 | Path traversal `/uploads/..%2f..%2fpackage.json` | 404 | 404 | ✓ |
|
|
| 10 | DELETE articolo | 200 | 200, `{"ok":true}` | ✓ |
|
|
|
|
Nota sul check 3: il dev server risponde 403 ai POST privi di header `Origin` per via della protezione CSRF integrata di Astro (`security.checkOrigin`). Con `Origin: http://localhost:4321` il login funziona correttamente. Un browser reale invia sempre l'header, quindi il comportamento è quello atteso.
|
|
|
|
Nota sul check 9: la variante `--path-as-is /uploads/../package.json` restituiva 200 in modalità dev, ma la risposta proveniva dal middleware statico di Vite (headers `ETag` e `Cache-Control: no-cache`, assenti nella nostra route), che in sviluppo espone i file di progetto dopo la normalizzazione del path. La verifica è stata ripetuta sul server di produzione (`npm run build` + `node --env-file=.env ./dist/server/entry.mjs`): tutte le varianti di traversal (`../`, `%2e%2e/`, `..%2f`) e l'accesso diretto a `/package.json` restituiscono 404. La route `[...path].ts` è quindi sicura; l'esposizione riguarda esclusivamente l'ambiente di sviluppo locale e non il deploy.
|
|
|
|
## Build
|
|
|
|
`npm run build` completata senza errori: 54 asset generati, sitemap creata, server bundle prodotto in `dist/server`.
|
|
|
|
## Adattamenti al test sanitize
|
|
|
|
Nessuno. `sanitize-html` 2.17.5 preserva l'HTML consentito esattamente com'è, quindi l'asserzione `toBe(html)` del primo test è rimasta invariata. Le asserzioni su `<script>`, handler inline e schema `javascript:` non sono state toccate.
|
|
|
|
## Concern e note
|
|
|
|
1. **Esposizione file in dev**: come descritto sopra, il dev server Vite serve i file della root del progetto (incluso `package.json`) dopo normalizzazione del path. Non riguarda la produzione, ma è bene non esporre mai il dev server su rete pubblica.
|
|
2. **Utente e2e**: per i check è stato creato un utente temporaneo `e2etest` tramite `scripts/create-user.mjs`, poi rimosso dal database (sessioni incluse) al termine. L'utente `admin` preesistente non è stato toccato.
|
|
3. **Pulizia**: il PNG di test caricato in `uploads/` è stato eliminato; l'articolo di prova è stato rimosso tramite l'endpoint DELETE (check 10).
|
|
4. **Dev server Astro 7 come demone**: `astro dev` in questa versione gira come demone (`astro dev stop` per fermarlo). Durante la verifica è stato trovato un demone preesistente sulla porta 4323, fermato e riavviato sulla 4321; al termine dei check il demone è stato fermato.
|
|
5. **`getEnv('UPLOADS_DIR', 'uploads')`**: il fallback relativo `uploads` dipende dalla working directory del processo; il `.env` definisce già `UPLOADS_DIR=uploads`. In produzione conviene valutare un path assoluto.
|