- Vidéo piégée : l'expression régulière de position était quadratique, un faux MP4 de 2 Mo figeait l'API (bornée, linéaire)
- Sessions émises avant le 01/10/2026 refusées (SESSIONS_NOT_BEFORE) : des sessions ont fuité dans les annotations et les journaux jusqu'à la 1.0
- Contributions : l'« avant » montré au propriétaire vient de la base ; une suppression approuvée part en cascade (unions, liens, souvenirs, portrait, fichiers)
- Mot de passe de partage : essai compté avant bcrypt, comparaisons une par une, changement et rattachement dans une transaction
- Quota mesuré sur le disque, 10 arbres par compte, corps à 1 Mo hors envois, bornes sur annotations, contributions et GEDCOM
- GIF réencodés ; anciennes propositions d'annotation sans adresse stockée ; clé d'exemple refusée sans NODE_ENV
- Déploiement du commit validé par la CI, clé d'hôte obligatoire ; nginx : X-Forwarded-For écrasé, version masquée, journal sans query string
- PostHog verrouillé dans le code, sans script externe ; CSP sans *.posthog.com ; sauvegardes hors serveur chiffrées par défaut
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Reprend la PR Dependabot #30. La 7.0 adopte les défauts de la 6.0 et rend fatales ses options dépréciées : rien de cela ne touche tsconfig.json, qui fixait déjà rootDir (src), types (["node"]), module et moduleResolution NodeNext, target ES2022, strict, esModuleInterop à true. Le JavaScript produit dans dist/ est identique octet pour octet à celui de TypeScript 5.9.3 (diff -r vide sur les 27 fichiers). La 7.0 n'a plus d'API JavaScript, mais aucun outil du backend ne s'en sert : vitest et tsx ne passent pas par tsc, Prisma ne lit que le numéro de version et tolère son absence. Binaires natifs dans le package-lock pour Linux x64 (CI, Docker, VPS) et Windows. 113 tests.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Reprend la PR Dependabot #34 (18.0.5, correctif publié depuis). Depuis la 17.0.0, config() écrit « ◇ injected env (N) from .env » à chaque démarrage, même sans fichier .env (vu avec la 18.0.5 : « injected env (0) »), ce qui glisse une ligne hors format dans les journaux JSON de production : config({ quiet: true }). Les autres ruptures de la 18.0.0 (préchargement -r dotenv/config retiré, .env.vault retiré) ne touchent pas Parenthèse, qui n'appelle que config() dans config/env.ts. La CLI Prisma garde sa propre copie de dotenv 16. 113 tests.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Reprend la PR Dependabot #32. Rupture de la 11.0.0 : la pré-vérification CORS n'annonce plus par défaut que GET, HEAD et POST, un navigateur d'une autre origine aurait refusé les PUT, PATCH et DELETE de l'API. La liste d'avant est maintenant écrite dans app.ts, et un test vérifie la réponse à un OPTIONS d'une origine autorisée (il échoue sans la ligne). Option origin inchangée. Les ajouts de la 11.x (logLevel du préflight, cors par route dans config.cors) ne sont pas utilisés. 113 tests.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Reprend la PR Dependabot #29. La 11.2.0 corrige GHSA-grpc-p53c-r64v : la clé par défaut était l'adresse IP telle quelle, un client IPv6 changeait d'adresse dans son /64 (ou réécrivait la même autrement) et repartait à zéro. La clé est maintenant l'adresse normalisée, IPv4 mappée ramenée en IPv4, IPv6 regroupée par /64. Rupture de la 11.0.0 : option whitelist retirée au profit d'allowList, que Parenthèse n'utilise pas. Aucun changement de code (global: false, limites par route dans config.rateLimit, clé par défaut sur request.ip calculée par Fastify avec TRUST_PROXY). 112 tests.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Reprend le groupe Dependabot backend-minor-patch (#27). vitest arrive en 5.0.3, correctif publié depuis la PR (5.0.2). Aucun changement de code. Compilation propre, 112 tests.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Les versions de sharp antérieures à 0.35.0 sont touchées quand elles décodent des images non fiables (GHSA-f88m-g3jw-g9cj, libvips), et antérieures à 0.35.4 pour libheif (GHSA-rgj7-g3m4-5g8c). Parenthèse décode les photos envoyées par la famille : montée en 0.35.5 (libvips 8.18.7). Aucun changement d'API utilisé ici (Node 24, failOn, rotate, sorties JPEG/PNG/WebP). 112 tests, recette sécurité et comparaison de rotation relues.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Un nom GEDCOM piégé bloquait l'API plusieurs secondes (expression régulière quadratique) : lu par indexOf, lignes et fiches plafonnées. L'export n'injecte plus de lignes. Deux relectures simultanées appliquaient deux fois les ajouts : la session est verrouillée dans la transaction. Au plus 200 changements par envoi, photos refusées effacées du disque.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Les annotations se lisaient avec n'importe quel compte, et une annotation photo enregistrait l'adresse de l'image avec la session de son auteur. Accès vérifié, adresse retirée à l'écriture comme à la lecture. Les images portent un jeton de lecture des médias (12 h, un arbre) au lieu de la session du compte. trustProxy ne croit plus que nginx (TRUST_PROXY), l'API peut n'écouter que la boucle locale (HOST), plafond de 30 échecs par arbre sur le mot de passe de partage, changer ce mot de passe coupe les comptes rattachés, connexion à durée constante, secrets d'exemple refusés en production.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Un SVG ou du HTML déclaré « photo » passait et s'exécutait sur app.parenthese.io à l'ouverture (vol de session du propriétaire). Le type vient maintenant des premiers octets, les photos sont réencodées par sharp (rotation appliquée, EXIF et GPS retirés), les vidéos de téléphone perdent leur position, et chaque fichier est servi avec nosniff et une CSP sandbox (téléchargement pour tout ce qui n'est pas image, son, vidéo ou PDF). Fichiers supprimés effacés du disque, quota par arbre, limite de débit sur les envois.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Visites : chaque ouverture de l'arbre est notée (prénom facultatif demandé avec le mot de passe, appareil, compte), sans adresse IP, effacée après un an ; onglet Visites dans les paramètres, réservé aux administrateurs
- Recherche : un résultat choisi recentre l'arbre sur la personne, la liste se replie
- Écran de compte ouvert depuis l'arbre : croix pour y revenir
- Enfant presque sous l'union : trait direct au lieu d'un petit S
- Page vie privée : paragraphe sur les visites
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Le panneau du propriétaire affichait la copie gardée par le navigateur où le
mot de passe avait été défini : changé depuis un autre appareil, il montrait
l'ancien. Le serveur garde maintenant le mot de passe de partage chiffré
(AES-256-GCM, clé dérivée de JWT_SECRET) dans une table à part, pour ne pas
toucher la version des accès déjà ouverts.
- GET /trees/:id/access/passwords : le mot de passe en vigueur, admin seulement
- POST .../remember : arbres d'avant, le propriétaire saisit celui déjà donné,
vérifié contre les hash, retenu sans rien changer aux accès
- rotation à deux mots de passe distincts : plus de valeur lisible
- anciennes copies locales effacées à l'ouverture du panneau
- message d'invitation (lien, mot de passe, une phrase) modifiable et à copier
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Prénom demandé à l'envoi d'une contribution et d'un souvenir, retenu
sur l'appareil pour la fois suivante (submittedByLabel). Le propriétaire
lit « par Camille » au lieu de « par Contributeur ».
- Mot d'accompagnement enregistré (ContributionSession.comment, migration
additive) et affiché à la relecture.
- Une personne ajoutée par la famille garde ses liens : identifiant
provisoire « tmp:… » remplacé par le vrai id à l'application ; un lien
vers une personne refusée est écarté au lieu de faire échouer la
relecture. Frère ou sœur : parents calculés aussi pour la famille.
- Soumission et relecture en transaction, appliquées dans l'ordre
personnes, unions, liens : tout ou rien.
- Bouton « Ajouter une personne » pour la famille sur ordinateur ; après
l'ajout, le panneau se ferme et un message confirme que la personne est
dans les modifications ; il ne réapparaît plus au retour en édition.
- Relecture : les liens se lisent « Léon, enfant de Marc ».
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Un membre de la famille (lien de partage ou membre non administrateur)
peut maintenant envoyer une photo, une vidéo, une voix ou une citation.
Le serveur la stocke « en attente » et crée une contribution d'une ligne,
qui arrive dans « Propositions à relire » avec l'aperçu de la photo.
Accepter la rend visible, refuser la masque. En mode « application
immédiate », elle est visible tout de suite.
- Migration additive : MediaItem.status (approved par défaut, tout
l'existant reste visible), MediaItem.contributionSessionId, valeur
« media » dans ContributionEntityType.
- Graphe, statistiques, ordre des souvenirs : souvenirs acceptés seuls.
- Relecture d'une session contenant un dessin : ne plante plus
(l'annotation tombait dans la branche des liens).
- App : message « Merci, c'est envoyé » après un envoi en attente ;
réordonner, supprimer et changer la photo de profil réservés au
propriétaire (le serveur les refuse aux autres).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Le déverrouillage ouvre toujours en contributeur, quel que soit le mot de
passe tapé : les deux mots de passe déjà envoyés aux familles continuent
de marcher. Les jetons et accès « visitor » existants peuvent proposer
sans rien ressaisir. La rotation accepte un mot de passe unique, écrit
dans les deux colonnes (pas de migration). Côté app, un nouvel arbre
reçoit un seul mot de passe, gardé dans le navigateur du propriétaire,
et le panneau de partage n'affiche plus qu'un champ, avec Copier.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
npm audit fix sur les trois paquets, @fastify/jwt 9 → 10 (fast-jwt 6,
faille critique), ignoreTrailingSlash passé dans routerOptions
(avertissement FSTDEP022 à chaque démarrage).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
La clé étrangère et l'index sur le dernier arbre ouvert, et la valeur par défaut de
user_tree_accesses.updatedAt, existaient en base sans être déclarés dans le schéma.
Aucune migration : le schéma décrit désormais la base telle que les migrations la créent.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Utilisateurs
- Suppression de compte depuis l'écran « Votre compte », confirmée par mot de passe :
arbres possédés et médias effacés, email retiré des contributions, sessions fermées partout.
- Suppression d'arbre définitive, en base et sur le disque.
- Ajout d'un frère ou d'une sœur relié aux parents existants ; relations parent et enfant
corrigées en mode démo.
- Liste d'attente retirée (route, envoi d'emails, dépendance Resend).
Projet ouvert
- CI : front, landing, backend avec vérification des migrations, test Docker de bout en bout.
- Déploiement lancé seulement après une CI réussie sur main.
- Image API : CLI Prisma installée à part pour que les migrations tournent au démarrage.
- SECURITY.md, CONTRIBUTING.md, modèles d'issue et de pull request.
- Migration renommée avec un nom descriptif, contenu identique.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Galaxie familiale : personnes, unions et filiations, photos, vidéos et voix sur chaque personne,
partage par lien avec consultation sans compte et contributions validées par le propriétaire.
Auto-hébergeable avec Docker. Licence PolyForm Noncommercial 1.0.0.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>