# Dépôt de fichiers temporaire + serveur MCP — Document d'exploitation

Ce document est le **document d'exploitation** du projet (installation, configuration, exploitation courante). Le **cahier des charges complet** (contexte, choix techniques, justifications) est dans [`CDC-depot-fichiers-mcp.md`](./CDC-depot-fichiers-mcp.md) — ce README y renvoie et ne le duplique pas sauf pour les parties directement actionnables.

---

## 1. Qu'est-ce que ce projet ?

Un petit programme PHP (3 scripts + 1 script de découverte), exposé directement par Apache, sans aucun service ni daemon, qui sert de **casier temporaire** entre :
- la **sandbox Claude Cowork**, qui y dépose un fichier via `curl` (POST) ;
- un **connecteur MCP externe** (email, xPad, agenda...), qui le récupère via un **tool MCP** (`recuperer_fichier`), ou via un simple GET direct.

Objectif : éviter de faire transiter un fichier binaire par la conversation (base64), ce qui est lent et coûteux en tokens. Détail complet du problème et de la solution : voir `CDC-depot-fichiers-mcp.md` §1.

Ce n'est **pas** un stockage durable : les fichiers sont effacés automatiquement au bout de 10 min d'inactivité ou 1h maximum après dépôt (voir §9 ci-dessous). Ce n'est **pas** adapté à du contenu confidentiel.

---

## 2. Ce qui a été livré (arborescence)

```
/var/www/mcp-depot/                        (racine du projet = docroot Apache)
├── CDC-depot-fichiers-mcp.md              # Cahier des charges complet
├── README.md                              # Ce document
├── config.php                             # Configuration RÉELLE (secrets en clair) — chmod 600, www-data:www-data
├── config.php.exemple                     # Modèle à valeurs factices, partageable
├── upload.php                             # POST — dépôt d'un fichier (token fixe)
├── download.php                           # GET — récupération d'un fichier (token fixe)
├── mcp.php                                # MCP — JSON-RPC over HTTP (OAuth 2.1)
├── well-known-oauth-protected-resource.php # Découverte OAuth (routé par Apache, voir §7)
├── files/                                 # Fichiers déposés — chmod 700, www-data:www-data
│   └── .meta/                             # Sidecars JSON (1 par fichier), chmod 700
└── log/                                   # Journal — chmod 700, www-data:www-data
    └── depot-fichiers.log
```

`files/` et `log/` ont déjà été créés avec les bonnes permissions sur ce serveur (`pc`). Sur un nouveau serveur, les recréer (voir §5.3).

**Le code a déjà été testé fonctionnellement en local** (serveur intégré PHP, sous l'utilisateur `www-data`) le jour de sa rédaction : dépôt, téléchargement, rejet de token invalide, assainissement de nom de fichier (tentative de traversée de chemin réduite à un `basename` inoffensif), nettoyage à la volée d'un fichier expiré, et rejet correct d'un faux token OAuth contre le véritable serveur `oauth.desvigne.org`. Il reste à valider le flux OAuth complet une fois le client FulgurO-Auth réellement enregistré (§8).

---

## 3. Pré-requis serveur (déjà vérifiés sur `pc`)

- PHP-FPM actif (`php8.3-fpm.service`), routé par Apache via `mod_proxy_fcgi` + `/etc/apache2/conf-available/php8.3-fpm.conf` (déjà activé globalement — **aucune configuration PHP spécifique à ajouter dans le vhost**, ça fonctionne automatiquement comme les autres sites PHP du serveur).
- Extension PHP `curl` (utilisée par `mcp.php` pour l'introspection OAuth) — présente par défaut.
- Modules Apache : `rewrite`, `headers`, `ssl` — déjà activés sur ce serveur (`apache2ctl -M`). Sur un nouveau serveur : `a2enmod rewrite headers ssl`.
- `certbot` avec le plugin Apache, déjà utilisé pour tous les autres sous-domaines de `desvigne.org`.

---

## 4. Nom de domaine — un sous-domaine par serveur

Le programme est déployé sur plusieurs machines physiques/virtuelles (`pc`, `v`...). **Chaque serveur a son propre sous-domaine dédié**, à trois niveaux :

| Serveur (`/etc/hostname`) | Sous-domaine du projet |
|---|---|
| `pc` | `depot.pc.desvigne.org` |
| `v` | `depot.v.desvigne.org` |

**Point vérifié le jour de l'installation (important, contredit une inquiétude initiale)** : il n'y a **aucun certificat wildcard** sur ce parc — chaque sous-domaine existant (`mcp.desvigne.org`, `oauth.desvigne.org`, `pc.desvigne.org`...) a son **propre certificat Let's Encrypt individuel**, obtenu via le challenge HTTP-01 (`certbot --apache -d <domaine>`). Ce challenge n'a **aucune limite de profondeur** de sous-domaine (seul le wildcard, non utilisé ici, est limité à un niveau et exige DNS-01). `depot.pc.desvigne.org` obtient donc son certificat exactement comme les 20 autres sous-domaines déjà en place, sans particularité.

**DNS** : sur `pc`, `depot.pc.desvigne.org` **résout déjà** vers ce serveur (`host depot.pc.desvigne.org` → alias de `pc.desvigne.org` → IP du serveur), grâce à un CNAME wildcard `*.pc.desvigne.org` déjà en place côté registrar (OVH). **Aucune action DNS à faire sur `pc`.** Sur un nouveau serveur (`v`), vérifier avec `host depot.v.desvigne.org` que la résolution fonctionne de la même façon avant de lancer certbot — si `v.desvigne.org` n'a pas le même CNAME wildcard, il faudra créer l'enregistrement DNS `depot.v` chez le registrar au préalable.

---

## 5. Installation sur un nouveau serveur (ex: `v`)

### 5.1. Copier les fichiers

Copier l'intégralité du dossier `/var/www/mcp-depot` (ou cloner depuis là où le code est archivé) vers le nouveau serveur, **à l'exception de `config.php`** (secrets propres à `pc`, à ne jamais réutiliser tel quel sur un autre serveur).

### 5.2. Configurer `config.php`

Partir d'une copie de `config.php.exemple`, ou dupliquer `config.php` et changer **impérativement** ces valeurs :

| Constante | Valeur à mettre pour ce nouveau serveur |
|---|---|
| `URL_BASE_SITE` | `https://depot.v.desvigne.org` (adapter au nom du serveur) |
| `TOKEN_ACCES` | Une **nouvelle** valeur, générée avec `openssl rand -hex 32` (ne jamais réutiliser celle de `pc`) |
| `OAUTH_CLIENT_ID` / `OAUTH_CLIENT_SECRET` | Un **nouveau** client FulgurO-Auth, distinct de celui de `pc` (voir §8.2) |

**Sur `pc` aujourd'hui** : `config.php` contient déjà une vraie valeur de `TOKEN_ACCES`, générée automatiquement (`openssl rand -hex 32`), **à changer avant toute mise en production réelle** (elle a servi aux tests locaux du jour). `OAUTH_CLIENT_ID`/`OAUTH_CLIENT_SECRET` sont encore des placeholders (`CHANGER_CETTE_VALEUR`) — étape manuelle obligatoire, voir §8.2.

### 5.3. Permissions

```bash
mkdir -p /var/www/mcp-depot/files/.meta /var/www/mcp-depot/log
chown -R www-data:www-data /var/www/mcp-depot/files /var/www/mcp-depot/log
chmod 700 /var/www/mcp-depot/files /var/www/mcp-depot/files/.meta /var/www/mcp-depot/log
chown www-data:www-data /var/www/mcp-depot/config.php
chmod 600 /var/www/mcp-depot/config.php
```

`config.php` contient des secrets en clair (`TOKEN_ACCES`, `OAUTH_CLIENT_SECRET`) : ne jamais le rendre lisible par d'autres utilisateurs que `www-data`, et ne jamais le versionner (voir §5.4).

### 5.4. Si le projet est un jour versionné (git)

Ce projet n'est **pas** sous git aujourd'hui (choix délibéré). Si cela change un jour :
```
config.php
log/*.log
files/
```
à ajouter dans un `.gitignore`, en gardant `config.php.exemple` versionné.

---

## 6. Configuration Apache

### 6.1. Convention constatée sur ce parc (à respecter)

Chaque sous-domaine a **son propre fichier vhost dédié**, en deux parties (`sites-available/<domaine>.conf` pour le port 80, `sites-available/<domaine>-le-ssl.conf` pour le port 443), exactement comme `mcp.desvigne.org.conf`/`-le-ssl.conf`, `oauth.desvigne.org.conf`/`-le-ssl.conf`, etc. **Aucun `ProxyPass` ni port applicatif** pour ce projet (contrairement à `mcp.desvigne.org` ou `oauth.desvigne.org` qui proxient vers des daemons) : exécution PHP directe, exactement comme `pc.desvigne.org` lui-même.

### 6.2. Workflow réel utilisé sur ce serveur (recommandé, à suivre tel quel)

Tous les vhosts existants portent la signature du plugin `certbot --apache` (bloc `RewriteCond %{SERVER_NAME} ...` généré automatiquement). Procéder de la même façon :

**Étape 1 — créer le vhost HTTP minimal** `/etc/apache2/sites-available/depot.pc.desvigne.org.conf` :

```apache
<VirtualHost *:80>
        ServerAdmin     webmaster@desvigne.org
        ServerName      depot.pc.desvigne.org
        ErrorLog        ${APACHE_LOG_DIR}/depot-pc-error.log
        CustomLog       ${APACHE_LOG_DIR}/depot-pc-access.log combined

        DocumentRoot  /var/www/mcp-depot
        <Directory "/var/www/mcp-depot">
                Options +FollowSymLinks
                AllowOverride None
                Require all granted
        </Directory>
</VirtualHost>
```

**Étape 2 — activer et recharger :**
```bash
a2ensite depot.pc.desvigne.org.conf
apache2ctl configtest
systemctl reload apache2
```

**Étape 3 — obtenir le certificat (certbot génère et complète automatiquement le fichier `-le-ssl.conf`, et ajoute la redirection HTTPS dans le fichier `.conf` du port 80) :**
```bash
certbot --apache -d depot.pc.desvigne.org
```

Après cette étape, `depot.pc.desvigne.org.conf` aura été automatiquement complété par certbot avec le bloc de redirection standard (identique à tous les autres domaines) :
```apache
RewriteEngine on
RewriteCond %{SERVER_NAME} =depot.pc.desvigne.org
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
```
et un nouveau fichier `depot.pc.desvigne.org-le-ssl.conf` aura été créé avec le certificat déjà référencé.

**Étape 4 — compléter manuellement `depot.pc.desvigne.org-le-ssl.conf`** avec les éléments spécifiques à ce projet (headers de sécurité, protection de `files/`/`log/`, réécriture `.well-known`). Contenu final attendu (fusionner avec ce que certbot a généré — `SSLCertificateFile`/`SSLCertificateKeyFile`/`Include options-ssl-apache.conf` sont déjà en place, ne pas les dupliquer) :

```apache
<IfModule mod_ssl.c>
<VirtualHost *:443>
        ServerAdmin     webmaster@desvigne.org
        ServerName      depot.pc.desvigne.org
        ErrorLog        ${APACHE_LOG_DIR}/depot-pc-error.log
        CustomLog       ${APACHE_LOG_DIR}/depot-pc-access.log combined

        DocumentRoot  /var/www/mcp-depot
        <Directory "/var/www/mcp-depot">
                Options +FollowSymLinks
                AllowOverride None
                Require all granted
        </Directory>

        Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
        Header always set X-Content-Type-Options "nosniff"

        # /.well-known/oauth-protected-resource n'a pas d'extension .php :
        # réécriture interne vers le script PHP dédié (RFC 9728).
        RewriteEngine On
        RewriteRule ^\.well-known/oauth-protected-resource$ /well-known-oauth-protected-resource.php [L]

        # files/ et log/ ne doivent JAMAIS être servis directement : tout accès
        # à un fichier déposé DOIT passer par download.php (contrôle du token
        # et de l'expiration). Sans cette règle, un fichier déposé serait
        # accessible en clair via son URL directe.
        <Directory "/var/www/mcp-depot/files">
                Require all denied
        </Directory>
        <Directory "/var/www/mcp-depot/log">
                Require all denied
        </Directory>

        SSLCertificateFile /etc/letsencrypt/live/depot.pc.desvigne.org/fullchain.pem
        SSLCertificateKeyFile /etc/letsencrypt/live/depot.pc.desvigne.org/privkey.pem
        Include /etc/letsencrypt/options-ssl-apache.conf
</VirtualHost>
</IfModule>
```

```bash
apache2ctl configtest
systemctl reload apache2
```

### 6.3. Sur `v.desvigne.org`

Répéter exactement le même processus avec `depot.v.desvigne.org` partout (fichiers, `ServerName`, logs, chemins de certificat). Vérifier au préalable la résolution DNS (§4).

---

## 7. Déclaration du client FulgurO-Auth (étape manuelle obligatoire)

`mcp.php` est un **Resource Server OAuth 2.1** qui s'appuie sur FulgurO-Auth (`https://oauth.desvigne.org`), déjà utilisé pour d'autres MCP (domoticz, wordpress, communication...). Cette étape ne peut pas être scriptée : elle se fait dans l'interface d'admin.

1. Se connecter à `https://oauth.desvigne.org` (interface d'admin).
2. **Clients** → **+ Add Client**.
3. Renseigner :
   - **Client ID** : nom explicite, ex. `depot-fichiers-pc-resource-server` (remplacer `pc` par `v` sur l'autre serveur — un client distinct par serveur).
   - **Name** : « Dépôt de fichiers temporaire — Resource Server (pc) ».
   - **Type** : **Confidential** (obligatoire).
   - **Redirect URIs** : **laisser vide** (ce client ne sert pas à un flux de connexion utilisateur, seulement à l'introspection).
4. **Create**, puis **copier immédiatement le Client Secret affiché** (il ne sera plus jamais montré).
5. Reporter les deux valeurs dans `config.php` :
   ```php
   define('OAUTH_CLIENT_ID', 'depot-fichiers-pc-resource-server');
   define('OAUTH_CLIENT_SECRET', '<valeur copiée>');
   ```

**En cas de perte du secret** : aucune commande ne permet de le retrouver. Retourner sur la page du client dans l'admin FulgurO-Auth, cliquer sur « Régénérer le Secret », mettre à jour `config.php`. L'ancien secret est immédiatement invalidé — toute requête MCP en cours échouera jusqu'à la mise à jour.

**Test de la configuration**, après avoir renseigné les vraies valeurs :
```bash
curl -X POST https://oauth.desvigne.org/introspect \
  -u "OAUTH_CLIENT_ID:OAUTH_CLIENT_SECRET" \
  -d "token=un_faux_token"
# Résultat attendu : {"active": false}
# Si "invalid_client" : le client_id/secret est incorrect.
```
(Ce test a été effectué le jour de la rédaction avec un client_id placeholder : le rejet `invalid_client` a bien été observé, confirmant que le code de `mcp.php` gère correctement ce cas — voir §12.)

---

## 8. Déclaration du connecteur dans Claude Cowork

Nom retenu pour le connecteur MCP : **`MCP-depot-fichiers`**.

Lors de la déclaration dans Claude Cowork, renseigner l'URL du serveur MCP :
```
https://depot.pc.desvigne.org/mcp.php
```
(ou `https://depot.v.desvigne.org/mcp.php` selon le serveur).

L'enregistrement du client **public** OAuth (celui de Claude/Cowork, à ne pas confondre avec le client confidentiel de `mcp.php` créé en §7) se fait automatiquement lors de la première connexion : Claude Cowork découvre le serveur d'autorisation via `GET /.well-known/oauth-protected-resource`, s'enregistre dynamiquement auprès de FulgurO-Auth (RFC 7591), puis ouvre un flux d'autorisation classique (PKCE) dans le navigateur. Aucune action manuelle supplémentaire n'est nécessaire pour ce client-là — voir `CDC-depot-fichiers-mcp.md` §8.1 pour le schéma complet du flux.

---

## 9. Cycle de vie des fichiers (rappel opérationnel)

Un fichier déposé est effacé automatiquement au premier des deux événements :
- **1h après son dépôt** (`DUREE_MAX_DEPOT_SECONDES`), même téléchargé régulièrement ;
- **10 min après son dernier téléchargement** (`DUREE_INACTIVITE_SECONDES`).

**Aucun cron** : le nettoyage se fait à la volée, à chaque requête entrante (peu importe laquelle), par balayage complet de `files/`. Détail du calcul : `CDC-depot-fichiers-mcp.md` §7.

Pour changer ces durées, modifier les constantes correspondantes dans `config.php` (pas besoin de redémarrer quoi que ce soit, PHP relit le fichier à chaque requête).

---

## 10. Journalisation et logrotate

### 10.1. Le fichier de log

Un seul fichier : `/var/www/mcp-depot/log/depot-fichiers.log`. Contrôlé par la constante `DEBUG` dans `config.php` (`false` en production : une ligne par opération significative ; `true` : détails de débogage, secrets toujours tronqués — voir `CDC-depot-fichiers-mcp.md` §10).

### 10.2. Logrotate (à créer manuellement, pas fait aujourd'hui)

Un fichier dédié, cohérent avec le fichier existant `/etc/logrotate.d/zz-custom-logs-scripted` (qui centralise d'autres logs applicatifs du serveur) mais séparé pour rester autonome au projet :

```bash
cat > /etc/logrotate.d/depot-fichiers << 'EOF'
/var/www/mcp-depot/log/depot-fichiers.log {
    rotate 4
    weekly
    missingok
    notifempty
    compress
    delaycompress
    sharedscripts
    create 600 www-data www-data
}
EOF
```

Pas de `postrotate` nécessaire (pas de daemon à recharger, PHP rouvre le fichier à chaque requête). `create 600 www-data www-data` recrée le fichier avec les bonnes permissions après rotation. Tester avec :
```bash
logrotate -d /etc/logrotate.d/depot-fichiers   # simulation, --debug
logrotate -f /etc/logrotate.d/depot-fichiers   # forcer une rotation réelle
```

Sur `v.desvigne.org`, créer le même fichier en adaptant le chemin si le docroot diffère.

---

## 11. Tests de validation

Les 8 premiers tests ci-dessous ont été exécutés avec succès en local le jour de la rédaction (serveur intégré PHP sous `www-data`, avant activation du vrai vhost). Une fois le vhost et le certificat en place (§6), les rejouer contre le vrai domaine :

```bash
TOKEN="<contenu de TOKEN_ACCES dans config.php>"

# 1. Dépôt d'un fichier
curl -X POST https://depot.pc.desvigne.org/upload.php \
  -H "Authorization: Bearer $TOKEN" \
  -F "fichier=@test.docx"
# → 200, JSON avec "url_telechargement"

# 2. Téléchargement direct
curl -o test_recupere.docx "https://depot.pc.desvigne.org/download.php?fichier=test.docx&token=$TOKEN"
# → fichier identique à l'original

# 3. Token invalide → 401 (dépôt et téléchargement)
curl -i -X POST https://depot.pc.desvigne.org/upload.php -H "Authorization: Bearer mauvais" -F "fichier=@test.docx"
curl -i "https://depot.pc.desvigne.org/download.php?fichier=test.docx&token=mauvais"

# 4. Fichier inexistant / nom malicieux → 404 (jamais 200, jamais d'info sur l'historique)
curl -i "https://depot.pc.desvigne.org/download.php?fichier=inexistant.txt&token=$TOKEN"
curl -i "https://depot.pc.desvigne.org/download.php?fichier=../../etc/passwd&token=$TOKEN"

# 5. Découverte OAuth
curl https://depot.pc.desvigne.org/.well-known/oauth-protected-resource
# → JSON avec "authorization_servers": ["https://oauth.desvigne.org"]

# 6. Appel MCP sans token
curl -i -X POST https://depot.pc.desvigne.org/mcp.php \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"tools/list","id":1}'
# → 401, en-tête WWW-Authenticate: Bearer ...

# 7. Appel MCP avec un token OAuth valide (obtenu via un client MCP réel, après §7 et §8)
curl -X POST https://depot.pc.desvigne.org/mcp.php \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"tools/call","id":2,"params":{"name":"recuperer_fichier","arguments":{"nom_fichier":"test.docx","mode":"lien"}}}'
# → 200, JSON avec l'URL de téléchargement

# 8. Expiration
# Déposer un fichier, attendre > 10 min sans le télécharger, refaire une requête
# quelconque sur le programme, vérifier que le fichier et son sidecar ont
# disparu de files/ et files/.meta/.
```

---

## 12. Codes d'erreur — référence rapide

| Situation | `upload.php` | `download.php` | `mcp.php` |
|---|---|---|---|
| Token/Bearer absent ou invalide | `401` | `401` | `401` + `WWW-Authenticate` |
| Fichier absent de la requête (upload) | `400` | — | — |
| Fichier trop volumineux | `413` | — | — |
| Nom de fichier invalide | `400` | `400` | erreur JSON-RPC `-32602` |
| Fichier introuvable ou expiré | — | `404` | erreur JSON-RPC `-32000` |
| Scope OAuth insuffisant | — | — | `403` |
| Méthode JSON-RPC inconnue | — | — | erreur JSON-RPC `-32601` |

---

## 13. Paragraphe à intégrer aux consignes générales de Claude Cowork

*(à copier tel quel dans les instructions permanentes de Claude Cowork)*

> **Dépôt de fichiers temporaire (pont sandbox ↔ extérieur)**
>
> Un fichier présent dans ta sandbox (calcul, conversion, génération de document...) n'est pas directement accessible en dehors de celle-ci : aucun connecteur MCP externe n'a d'accès disque partagé avec ta sandbox. Le faire transiter par la conversation en base64 est possible mais lent et coûteux en tokens au-delà de quelques dizaines de Ko — n'y recours pas si tu peux faire autrement.
>
> Dès que tu as besoin de faire sortir un fichier de ta sandbox vers l'extérieur, et que ce fichier n'est pas trivialement petit (quelques lignes de texte), procède ainsi.
>
> **1. Dans la sandbox, avec `curl`, fais sortir le fichier vers l'extérieur en le déposant sur un site web intermédiaire (le « dépôt »)** :
> ```bash
> curl -X POST https://depot.pc.desvigne.org/upload.php \
>   -H "Authorization: Bearer <TOKEN_ACCES>" \
>   -F "fichier=@/chemin/vers/le/fichier.ext"
> ```
> Cette commande s'exécute entièrement dans la sandbox : elle ne fait pas transiter le fichier par la conversation. Sa sortie (un petit JSON) revient dans ton contexte comme la sortie de n'importe quelle commande shell, par exemple :
> ```json
> {"succes":true,"nom":"fichier.ext","taille_octets":18655,"url_telechargement":"https://depot.pc.desvigne.org/download.php?fichier=fichier.ext&token=xxxxx","expire_au_plus_tard_dans_secondes":3600}
> ```
> Retiens le champ `"nom"` (le nom exact du fichier, à réutiliser tel quel, jamais redéduit du chemin local) et le champ `"url_telechargement"`.
>
> **2. Ensuite, selon ce dont TU as besoin à ce moment-là :**
>
> - **Tu as seulement besoin d'une URL qui pointe vers ce fichier** (par exemple pour la donner en paramètre à un outil ou un connecteur qui ira chercher le fichier lui-même à cette adresse) : utilise directement la valeur `"url_telechargement"` obtenue à l'étape 1, telle quelle, comme un simple paramètre texte. **Pas besoin d'appeler le serveur MCP `MCP-depot-fichiers` dans ce cas** : l'URL est déjà connue. Si tu ne l'as plus sous la main (contexte compacté, trop de temps écoulé) mais que tu connais encore le nom du fichier, appelle alors le tool `recuperer_fichier` du serveur MCP `MCP-depot-fichiers` avec `mode="lien"` pour l'obtenir à nouveau.
>
> - **Un autre outil que tu dois appeler exige le contenu du fichier lui-même, encodé en base64, comme argument texte** (parce qu'il n'accepte pas d'URL) : appelle le tool `recuperer_fichier` du serveur MCP `MCP-depot-fichiers` avec `mode="base64"` :
>   ```json
>   {"name": "recuperer_fichier", "arguments": {"nom_fichier": "fichier.ext", "mode": "base64"}}
>   ```
>   Il te renvoie le contenu encodé en base64 (champ `contenu_base64`) : transmets ce champ tel quel, en argument, à l'outil qui l'exige.
>
>   **N'utilise `mode="base64"` que pour ce cas précis** (fournir le contenu en argument texte à un outil qui l'exige). Si tu as besoin du fichier brut ailleurs — dans la sandbox, ou pour qu'un système tiers le récupère —, n'utilise jamais `mode="base64"` pour ça : reviens au cas précédent (l'URL de téléchargement, éventuellement récupérée via `mode="lien"`), qui donne accès au fichier original sans jamais le faire transiter par ta conversation. Faire un aller-retour par `mode="base64"` puis « décoder » ensuite n'aurait aucun sens : le contenu aurait de toute façon déjà traversé ta conversation en entier, ce qui est précisément ce que ce mécanisme sert à éviter.
>
> Dans tous les cas :
> 1. Ne lis jamais le contenu binaire d'un fichier directement dans la conversation par un autre moyen (ex: `cat` suivi d'un encodage manuel) — c'est précisément ce que ce mécanisme permet d'éviter.
> 2. Un fichier déposé est effacé automatiquement (10 minutes sans téléchargement, ou 1h maximum après le dépôt) — n'y dépose jamais de contenu confidentiel ou sensible.
> 3. Ce mécanisme sert uniquement dans le sens sandbox → extérieur. Pour ramener un fichier de la sandbox vers le dossier local de l'utilisateur, ce n'est **pas nécessaire** : sandbox et dossier local communiquent déjà directement.

**Note pour toi (Manu) — ne fait pas partie du texte ci-dessus** : exemple d'usage du premier cas (URL seule) — envoyer un fichier par email via un connecteur qui accepte une pièce jointe en URL : Cowork pousse le fichier vers le dépôt, récupère `url_telechargement`, et la transmet directement à l'outil d'envoi d'email, sans jamais appeler `recuperer_fichier`. Si un jour ce connecteur n'accepte que du contenu encodé (pas d'URL), c'est le second cas (`mode="base64"`) qu'il faudra utiliser à la place. Cet exemple ne figure pas dans le paragraphe à coller, volontairement : il ne doit pas ancrer Cowork sur un connecteur particulier.

**Autre note** : si Cowork tourne parfois depuis `v` et parfois depuis `pc`, adapter l'URL de l'étape 1 au serveur courant (`depot.pc.desvigne.org` ou `depot.v.desvigne.org`), et le token qui va avec.

---

## 14. Sécurité — récapitulatif

- Assainissement systématique des noms de fichiers (`basename()` + rejet des cas dangereux) sur toutes les entrées.
- `files/` et `log/` protégés par `Require all denied` dans le vhost — aucun accès direct possible en contournant `download.php`.
- `config.php` en `chmod 600`, propriétaire `www-data:www-data`.
- Jamais versionné (`config.php` absent d'un éventuel futur `.gitignore` — c'est `config.php.exemple` qui serait versionné).
- Réponses non-discriminantes : fichier expiré ou inexistant → toujours `404`.
- Aucune information sensible dans les logs en mode `DEBUG=false` ; tokens toujours tronqués même en mode `DEBUG=true`.
- Pas de contenu confidentiel à déposer ici : token fixe simple, expiration courte, pas un contrôle d'accès fin.

---

## 15. Ce que ce projet n'est PAS (rappel)

- Pas de service en tâche de fond (pas de systemd, pas de port applicatif, pas de venv).
- Pas de stockage durable.
- Pas adapté à du contenu sensible ou confidentiel.
- Pas de base de données.
- Pas de fonction de liste des fichiers présents.
- Le MCP ne sert que pour la récupération (pas de dépôt via MCP).

Détail complet et justifications : `CDC-depot-fichiers-mcp.md` §1.4.
