# Revue de code complète — Office Translator

**Date** : Mars 2026  
**Périmètre** : Backend FastAPI (Python) + Frontend Next.js (TypeScript/React)  
**Méthode** : Exploration du codebase, recherche bonnes pratiques 2025, audits pip-audit / npm audit, analyse ciblée frontend.

---

## 1. Synthèse exécutive

| Priorité | Thème | Impact |
|----------|--------|--------|
| **Critique** | Path traversal sur `/download/{filename}` et `/cleanup/{filename}` | Lecture/suppression de fichiers hors répertoire |
| **Critique** | Vulnérabilités connues (pip + npm) | RCE, DoS, fuites (Next.js, Starlette, Pillow, etc.) |
| **Haute** | Pas de normalisation `session_id` / chemins dans legacy extract/reconstruct | Risque d’accès à des fichiers non prévus |
| **Haute** | Token JWT en `localStorage` sans refresh | Expiration = déconnexion brute ; risque XSS |
| **Haute** | CORS `*` si `CORS_ORIGINS` vide | En prod, exposition à toutes origines |
| **Moyenne** | Config dispersée (`os.getenv` partout) | Erreurs de config, pas de validation au démarrage |
| **Moyenne** | Jobs de traduction en mémoire | Pas de partage entre workers (scale horizontal) |
| **Moyenne** | Duplication API_BASE / fetch+token côté frontend | Maintenance et incohérences |

---

## 2. Architecture (rapport agent)

- **Backend** : `main.py` → CORS, middlewares (rate limit, security, error, cleanup), router unique `/api/v1` (translate, auth, admin, api-keys, legacy, glossary, prompt).
- **Auth** : JWT (access 15 min, refresh 7 j), blocklist JTI (Redis/mémoire), admin par token opaque (Redis/mémoire), API Key (X-API-Key, Pro).
- **Traduction** : POST `/translate` → validation fichier/URL → job `tr_*` → `asyncio.to_thread` + excel/word/pptx_translator + provider (OpenRouter, etc.) ; clés/modèles depuis admin settings + env.
- **Fichiers** : Upload avec nom unique ; download v1 par `job_id` + ownership ; legacy `/download/{filename}` et `/cleanup/{filename}` **sans normalisation du chemin**.

---

## 3. Sécurité

### 3.1 Path traversal (critique)

**Fichiers** : `routes/legacy_routes.py`

- **`GET /api/v1/download/{filename}`** (L.299–311) : `file_path = config.OUTPUT_DIR / filename`. Si `filename = "../../../etc/passwd"`, le chemin peut sortir de `OUTPUT_DIR`.
- **`DELETE /api/v1/cleanup/{filename}`** (L.314–325) : même construction.

**Recommandation** :  
- Normaliser : `safe_name = Path(filename).name` (pas de `..`).  
- Résoudre : `resolved = (config.OUTPUT_DIR / safe_name).resolve()`.  
- Vérifier : `resolved.is_relative_to(config.OUTPUT_DIR.resolve())` (Python 3.9+) ou équivalent.  
- Sinon 400/404.

### 3.2 Session / extract-texts / reconstruct-document

- **`session_id`** (UUID généré côté serveur) : utilisé pour `session_{session_id}.json` et chemins. Vérifier que tout `session_id` reçu en form est bien un UUID strict.  
- **`session_data["input_path"]`** : s’assurer que le chemin résolu reste sous `UPLOAD_DIR` avant toute lecture.

### 3.3 Authentification

- **JWT** : si `JWT_SECRET_KEY` absent, clé éphémère au démarrage → tous les tokens invalidés au redémarrage (log CRITICAL). À corriger en prod.
- **Admin** : `ADMIN_PASSWORD` en clair à éviter ; utiliser uniquement `ADMIN_PASSWORD_HASH` (bcrypt) en production.
- **Frontend** : token et refresh en `localStorage` → exposés au XSS. Bonnes pratiques 2025 : cookies HTTP-only pour le token (ou au minimum documenter le risque et privilégier des pages à faible exposition XSS).

### 3.4 CORS

- **`main.py`** : si `CORS_ORIGINS` vide ou `*`, `allowed_origins = ["*"]` avec warning. En production, définir des origines explicites.

### 3.5 Stripe webhook

- **`services/payment_service.py`** : `stripe.Webhook.construct_event(payload, sig_header, STRIPE_WEBHOOK_SECRET)` → **signature bien vérifiée**. Rien à changer côté vérification.

### 3.6 SSRF / Webhook URL

- **Translate** : `download_from_url` et validation webhook limitent schéma, DNS et IP privées/loopback. Cohérent avec les bonnes pratiques.

---

## 4. Vulnérabilités connues (dépendances)

### 4.1 Backend (pip-audit)

| Package | Version | Problème | Correction |
|---------|---------|----------|------------|
| deep-translator | 1.11.4 | PYSEC-2022-252 | Mettre à jour |
| fastapi | 0.109.0 | PYSEC-2024-38 | 0.109.1+ |
| pillow | 10.2.0 | CVE-2024-28219 | 10.3.0+ |
| python-multipart | 0.0.9 | CVE-2024-53981, CVE-2026-24486 | 0.0.18+ / 0.0.22+ |
| starlette | 0.35.1 | CVE-2024-47874, CVE-2025-54121 | 0.40.0+ / 0.47.2+ |

**Action** : Exécuter `pip-audit` puis mettre à jour les paquets (tests de non-régression après mise à jour).

### 4.2 Frontend (npm audit)

| Package | Problème | Action |
|---------|----------|--------|
| next | RCE (flight), DoS, exposition Server Actions, etc. | `npm audit fix` ou mise à jour ciblée (ex. next@16.1.6) |
| minimatch | ReDoS | `npm audit fix` |
| ajv | ReDoS ($data) | `npm audit fix` |

**Action** : `npm audit` puis `npm audit fix` (ou `--force` avec prudence et tests).

---

## 5. Fiabilité et bonnes pratiques

### 5.1 Gestion d’erreurs

- Middleware global + handlers dédiés (TranslationError, ValidationError, etc.) → correct.
- OpenRouter : retry 429 + levée d’exception en cas d’échec (plus de retour silencieux du texte original) → bon.

### 5.2 Configuration

- **Config** : tout en `os.getenv()` dans `config.py` et ailleurs. Risque : valeurs manquantes ou incohérentes au démarrage.
- **Recommandation** : centraliser dans un module type **Pydantic BaseSettings** (validation, typage, valeurs par défaut) et charger une seule fois au démarrage.

### 5.3 Jobs de traduction

- **`_translation_jobs`** en mémoire : en multi-workers (plusieurs processus uvicorn), les jobs ne sont pas partagés.
- **Recommandation** : pour un scale horizontal, stocker l’état des jobs dans Redis (ou autre store partagé).

### 5.4 Legacy

- **`/translate-batch`**, **`/download/{filename}`**, **`/cleanup/{filename}`**, **`/extract-texts`**, **`/reconstruct-document`** : peu ou pas d’auth, exposition de chemins/fichiers.
- **Recommandation** : renforcer l’auth et la validation des paramètres, ou déprécier au profit des endpoints v1 (translate + download par `job_id`).

---

## 6. Frontend (rapport agent)

### 6.1 Types et erreurs

- **`any`** : `app/(app)/ollama-setup/page.tsx` (models, error), `app/(app)/settings/subscription/page.tsx` (PLAN_ICONS), `app/pricing/page.tsx` (PLAN_ICONS). Remplacer par des types précis.
- **Error boundary** : aucun au niveau racine (`app/layout.tsx`). Ajouter un ErrorBoundary pour éviter des écrans blancs.

### 6.2 Validation et timeout

- **Login / Admin login** : pas de validation explicite (email, mot de passe) avant submit.
- **Translate** : pas de validation centralisée de `file` / `config` (taille, type, champs requis) avant l’appel API.
- **Fetch** : plusieurs appels sans timeout (pricing, subscription, admin verify, settings, translate, polling, download). Ajouter `AbortController` + timeout (ex. 8–30 s selon l’endpoint).

### 6.3 Auth et stockage

- **Token** : `localStorage` ("token", "refresh_token", "user"). Risque XSS ; en production privilégier cookies HTTP-only si possible.
- **Refresh** : `refresh_token` stocké mais **jamais utilisé** ; aucun appel `/auth/refresh`. Quand l’access token expire, l’utilisateur est déconnecté. Implémenter un refresh automatique (intercepteur ou hook) pour améliorer l’UX.

### 6.4 Duplication et centralisation

- **API_BASE** : répété dans plusieurs fichiers (useTranslationSubmit, useTranslationConfig, TranslationComplete, settings/services, lib/api). Utiliser une seule source : `@/lib/config` ou `apiClient`.
- **Pattern fetch + token** : répété partout. Utiliser systématiquement **apiClient** (déjà en place pour auth, glossaries, api-keys) pour tous les appels authentifiés.
- **URL en dur** : `app/(app)/ollama-setup/page.tsx` L.85 `"http://localhost:8000/api/auth/settings"` → remplacer par `API_BASE + "/api/v1/..."` (et vérifier le chemin exact de l’API).

---

## 7. Plan d’action priorisé

### Immédiat (sécurité)

1. **Path traversal** : normaliser `filename` et vérifier `resolved.is_relative_to(OUTPUT_DIR)` dans `legacy_routes.py` pour `/download/{filename}` et `/cleanup/{filename}`.
2. **Dépendances** : mettre à jour FastAPI, Starlette, Pillow, python-multipart, deep-translator ; puis Next.js, minimatch, ajv (avec tests après chaque vague).

### Court terme (sécurité / robustesse)

3. **Session / reconstruct** : valider `session_id` (UUID) et s’assurer que tout chemin dérivé reste sous `UPLOAD_DIR`.
4. **CORS** : en prod, définir `CORS_ORIGINS` explicitement (pas `*`).
5. **Admin** : en prod, n’utiliser que `ADMIN_PASSWORD_HASH` (bcrypt).
6. **Frontend** : ajouter un ErrorBoundary racine et des timeouts sur les fetch critiques (translate, download, polling, auth verify).

### Moyen terme (qualité / maintenabilité)

7. **Config** : migrer vers Pydantic BaseSettings pour la config backend.
8. **Frontend** : centraliser API_BASE et utiliser apiClient partout ; implémenter le refresh token.
9. **Jobs** : si scale horizontal prévu, stocker l’état des jobs dans Redis (ou équivalent).
10. **Legacy** : protéger ou déprécier les routes legacy (auth + validation des paramètres).

### Long terme (bonnes pratiques)

11. **Auth frontend** : étudier le passage à des cookies HTTP-only pour le token (avec adaptation du backend).
12. **Validation** : validation explicite login/admin et validation centralisée des paramètres de traduction avant appel API.
13. **Types** : supprimer les `any` et renforcer les types (discriminated unions, type predicates) côté TypeScript.

---

## 8. Références

- FastAPI & Next.js security (TurboStarter, Next.js Data Security, Mikul Gohil).
- Python code review (DeepSource, Kodus, Medium).
- TypeScript security & quality (Krython, Kodus).
- Exploration et revue frontend par agents (explore + generalPurpose) sur le dépôt.

---

*Document généré dans le cadre d’une revue de code complète. Aucune modification n’a été appliquée automatiquement ; les changements sont à planifier et à tester.*
