Ctrl K
ComunidadGuías…

TESTING.md

Rama master · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# TESTING — Authentification avancée

Plan de tests manuels pour les passkeys, la vérification email, la 2FA et
l'approbation de connexion multi-appareils. À dérouler après déploiement (ou en
local avec une base de test).

## ⚙️ Configuration requise (Vercel + local)

Les variables suivantes doivent exister (cf. [`.env.example`](.env.example)) :

| Variable | Requis | Notes |
|---|---|---|
| `AUTH_RESEND_KEY` | ✅ | Clé API Resend (déjà présente). Sans elle, aucun email n'est envoyé. |
| `EMAIL_FROM` | ✅ | Expéditeur, domaine vérifié sur Resend. |
| `RP_ID` | ⬜ | `drivecord.vercel.app` en prod, `localhost` en dev. **Fallback auto** sur l'hôte de la requête. |
| `RP_NAME` | ⬜ | `Drivecord` (défaut). |
| `WEBAUTHN_ORIGIN` | ⬜ | `https://drivecord.vercel.app` en prod. **Fallback auto** sur l'origine. |
| `TOTP_ISSUER` | ⬜ | `Drivecord` (défaut), affiché dans l'app d'authentification. |

> ⚠️ Pour les **passkeys sur l'app iOS** (WebView chargeant `drivecord.vercel.app`),
> définis explicitement `RP_ID=drivecord.vercel.app` et
> `WEBAUTHN_ORIGIN=https://drivecord.vercel.app` sur Vercel — le fallback host
> peut différer dans certaines WebViews.

La migration `20260626131000_add_advanced_auth` est **déjà appliquée** sur la base
(additive, sans perte). Aucune action DB supplémentaire.

## 1. Vérification email

- [ ] **Inscription email + mot de passe** : créer un compte → redirigé vers
  `/auth/challenge` → un code à 6 chiffres arrive par email → saisir → accès au drive.
- [ ] **Inscription Google / Discord (1re fois)** : la 1re connexion déclenche un
  code email (règle « 1re connexion / 24h ») → vérifier → accès.
- [ ] **Renvoi** : bouton « Renvoyer le code » grisé 60 s (cooldown).
- [ ] **Erreurs** : code faux → message ; 5 essais → blocage ; code expiré (10 min) → message.
- [ ] **Règle 24h** : se reconnecter dans les 24 h → pas de code. Forcer `lastLoginAt`
  à > 24 h en base → un code est de nouveau exigé.

## 2. Passkeys (WebAuthn)

- [ ] **Ajouter** : Réglages → Sécurité → Passkeys → « Ajouter » → Face/Touch ID →
  le passkey apparaît dans la liste.
- [ ] **Renommer** (inline) et **supprimer** (avec confirmation).
- [ ] **Garde du dernier facteur** : sur un compte sans mot de passe ni OAuth, la
  suppression du dernier passkey est refusée.
- [ ] **Connexion** : `/login` → « Se connecter avec un passkey » → sélection →
  session ouverte.
- [ ] **Anti-rejeu** : le `counter` est mis à jour (pas d'erreur à la 2e connexion).

## 3. 2FA (TOTP + email + recovery)

- [ ] **Activer TOTP** : Réglages → Sécurité → « Configurer » → scanner le QR →
  saisir le code → 2FA activée + **10 codes de récupération affichés une fois**.
- [ ] **Login TOTP** : déconnexion/reconnexion → écran 2FA → code de l'app → accès.
  Tolérance ±1 fenêtre (30 s).
- [ ] **Login recovery** : « Utiliser un code de récupération » → un code → accès →
  le code est consommé (réutilisation refusée).
- [ ] **2FA email** : activer la méthode email → au login, un code arrive par email.
- [ ] **Régénérer** les codes (invalide les anciens).
- [ ] **Désactiver** : exige un code 2FA ou de récupération.

## 4. Approbation multi-appareils

- [ ] **Appareil A** (déjà connecté, full) reste sur l'app. **Appareil B** (ou autre
  navigateur) se connecte → écran challenge → « Approuver depuis un autre appareil ».
- [ ] B affiche un **code à 4 chiffres** et « En attente… ». A reçoit une **fenêtre**
  d'approbation avec le **même code**, l'appareil et la localisation (best-effort).
- [ ] **Approuver** sur A → B ouvre la session (≤ ~3 s de polling).
- [ ] **Refuser** sur A → B affiche « Connexion refusée ».
- [ ] **Expiration** : ne rien faire 2 min → B affiche « expiré » ; fallback code email.
- [ ] **Sans appareil de confiance** : l'option n'apparaît pas (seul le code email).
- [ ] **Révocation** : Réglages → Appareils de confiance → révoquer un appareil.

## 5. E2EE non cassé (critique)

Après **chaque** nouveau moyen de login (passkey, OAuth, cross-device, 2FA) :

- [ ] Ouvrir un drive, **uploader** un fichier, le **télécharger** → contenu déchiffré OK.
- [ ] Le **coffre-fort** (PIN) se déverrouille et déchiffre normalement.

> La clé de chiffrement par drive est récupérée du serveur après authentification
> (modèle inchangé), donc indépendante du facteur de login : aucun moyen de
> connexion ne casse le déchiffrement.

## 6. Compte Cord (OIDC)

Variables : `AUTH_CORD_ISSUER`, `AUTH_CORD_ID`, `AUTH_CORD_SECRET`,
`NEXT_PUBLIC_CORD_ACCOUNT_URL` (sans elles, le bouton et la carte Réglages sont masqués).
En local, lancer `cordlauncher/account-service` (`CORD_ISSUER=http://localhost:4319`,
`CORD_CLIENTS` avec le retour `http://localhost:3000/api/auth/callback/cord`).

- [ ] **1re connexion Cord** : `/login` → « Continuer avec Cord » → consentement →
  compte créé (nom + photo Cord, email déjà vérifié) → code de connexion (règle 24 h) → drive.
- [ ] **Déjà consenti** : reconnexion sans écran de consentement, même compte (pas de doublon).
- [ ] **Refus sur Cord** → `/login` : « Connexion avec Cord annulée ».
- [ ] **Email déjà utilisé par un compte Drivecord** → `/login` : « Cet email a déjà un
  compte Drivecord… associe Cord dans Réglages ». Aucune association silencieuse.
- [ ] **Association** : connecté (session complète) → Réglages › Compte Cord › Associer →
  retour `/settings` « Compte Cord associé ». Nom manuel conservé (proposition « Utiliser ce
  nom »), avatar rempli seulement s'il était vide.
- [ ] **Compte Cord déjà associé à un autre compte** → message dans la carte Cord.
- [ ] **Dissocier** : possible seulement s'il reste mot de passe / passkey / Google / Discord.
- [ ] **App iOS** : « Continuer avec Cord » ouvre Safari → retour `drivecord://auth` → connecté.
- [ ] **Drivecord Desktop** : login Cord dans la fenêtre → bascule dans l'app (jeton desktop).
- [ ] **Raccourcis** Sécurité / Appareils et Passcord / Apps connectées → bonnes ancres du portail.

## Limites connues / TODO

- **Push iOS native** pour l'approbation cross-device : non implémentée ; le
  polling web (3–5 s) couvre le cas. Hook à ajouter si une infra push existe.
- **2FA** : une seule méthode active à la fois (TOTP **ou** email).
- **Modale post-login « ajouter un passkey »** : non implémentée (l'ajout se fait
  dans Réglages → Sécurité + bouton de login).
- L'E2EE des fichiers normaux n'est **pas** zero-knowledge (le serveur détient la
  clé du drive) — choix produit assumé, inchangé par cette feature.

## Portes de qualité

```bash
npx tsc --noEmit   # 0 erreur
npm run lint       # 0 erreur (warnings préexistants tolérés)
npm test           # tests unitaires (node --test)
npm run build      # build de production OK
```