Appearance
Backend, API, images et autorisations
Etat du code examine le 2026-10-03. Cette page decrit la configuration et les contrats du depot, pas un audit des conteneurs actifs sur le VPS. Les protections decrites dans la section "Renforcement" doivent etre fusionnees puis deployees avant de pouvoir etre annoncees comme actives en production.
Schema general
text
Application mobile Android / iOS
|
| HTTPS : donnees, actions, photos a identifier
v
Entree HTTPS / reverse proxy du deploiement
|
+--> API Fastify / Node / TypeScript
| |
| +--> PostgreSQL + pgvector
| | comptes, collections, cartes, prix, vecteurs
| |
| +--> Services Python embeddings
| reconnaissance selon le parcours de scan
|
+--> Nginx --> data/images (lecture seule)
| cartes, logos de series, logos de blocs
|
+--> tcg-vision (selon le parcours expose)
DINOv2 + index FAISS
enrichissement via l'API du catalogue
Sources externes --> workers d'import --> PostgreSQL
|
+--> data/images
+--> construction des references de scanLe routage public exact depend du reverse proxy de deploiement. Les ports du reseau Docker ne sont pas une liste de ports a ouvrir sur Internet. La base et les services internes ne doivent pas etre exposes directement aux telephones. Le choix et le nombre de parcours de scan actifs dependent aussi du client et de la configuration ; la presence d'un service dans Compose ne prouve pas que l'app l'utilise, ni qu'il est actuellement en execution.
Trois parcours
- Collection : l'app presente son jeton utilisateur. L'API retrouve le compte et ne lit/modifie que les lignes appartenant a ce compte.
- Visuel : l'API renvoie les donnees de la carte et ses URL. L'app telecharge les fichiers directement depuis Nginx ; l'API Node ne transmet pas chaque image. Les imports alimentent ces fichiers independamment des consultations.
- Scan : la photo est envoyee au parcours de reconnaissance configure. Le moteur compare des references visuelles ; le resultat est enrichi avec les donnees du catalogue. La consultation d'une collection n'est pas un scan.
Ou sont les images et les logos ?
| Element | Stockage / origine | Acces actuel |
|---|---|---|
| Images du catalogue | data/images, references dans card_images | Public via Nginx |
| Logos des series | data/images/set-logos | Public via Nginx |
| Logos des blocs | data/images/series-logos | Public via Nginx |
| Icones UI et certains logos fixes | Assets de l'application | Inclus dans l'app |
| Certains visuels One Piece francais non miroires | Repli vers le site officiel | Externe, public |
| Photos et dossiers Scan Debug | Archive distincte, API /scan-debug-cases | Credential operateur requis |
| Photos personnelles de collection | Aucun service dedie etabli par ce parcours | Ne pas les placer dans data/images |
Un visuel du catalogue represente un produit partage par tous. Il ne revele pas a lui seul quels utilisateurs possedent ce produit. En revanche, le lien entre une carte et son proprietaire, la quantite et le prix d'achat sont des donnees de collection privees.
Nginx sert les assets du catalogue avec un cache d'un an et immutable. L'app utilise Image de React Native et prefere actuellement les images high, meme dans les grilles. Aucun cache disque applicatif explicite ou prechargement generalise n'a ete identifie dans ce parcours. Un logo absent affiche un repli. Les pistes d'optimisation sont les miniatures, le cache mobile et les URL versionnees ; elles ne sont pas implementees par le correctif de securite.
Authentification et autorisation
Ces deux controles ne sont pas interchangeables :
- Authentification : quel compte correspond au jeton presente ?
- Autorisation : ce compte possede-t-il la ligne qu'il veut lire ou modifier ?
Le serveur emet des jetons aleatoires de 32 octets et ne stocke que leur empreinte SHA-256. Un identifiant de compte dans une requete ne remplace jamais ce jeton. Les tokens revoques ne sont plus acceptes. Le modele actuel utilise des jetons opaques longue duree ; ce correctif n'ajoute pas d'expiration ou de rotation automatique qui necessiterait un parcours de renouvellement mobile.
| Surface | Controle |
|---|---|
/me, /collection/**, /alerts/**, /push/** | Session utilisateur et filtrage par proprietaire |
| Ecritures du catalogue et Scan Debug | Credential operateur distinct |
| Catalogue et images communes | Lecture publique |
/public/collections/:slug | Partage volontaire : lien aleatoire, portee, expiration/revocation |
| Demande / verification de code email | Publique pour se connecter, limites IP et budget de tentatives |
Le credential operateur n'est pas une session utilisateur. Les requetes SQL de collection et d'alertes utilisent l'identite resolue cote serveur. Pour une modification de collection, un objet absent et un objet appartenant a un autre compte donnent tous deux 404 : on ne confirme pas son existence au demandeur. Le partage volontaire est une exception explicite ; il n'ouvre pas les routes privees ni les informations exclues de sa portee.
Renforcement du correctif associe
- Controle global en debut de requete sur les espaces prives, meme si une future route oublie son hook local ; refus si la session ne peut etre resolue.
- Identite conservee dans une WeakMap interne a la requete, et non dans un champ libre venant du client. Une requete suivante verifie a nouveau le jeton.
- Reponses privees et de connexion en
private, no-storepour eviter leur conservation dans un cache partage. - Credentials HTTP masques dans les logs ; etiquette d'audit operateur derivee d'une empreinte, sans extrait du secret.
- Format du jeton utilisateur borne a la longueur effectivement emise.
- Delai de renvoi email applique par un upsert conditionnel atomique : deux demandes simultanees ne peuvent pas toutes deux renouveler le code.
- Tests HTTP sans base externe avec deux identites, ainsi que tests des predicates SQL de proprietaire. Ils ne remplacent pas une verification d'integration contre PostgreSQL ni un audit de production.
Decision encore necessaire sur les images
"Uniquement les images des collections" peut designer les photos personnelles ou les visuels communs des cartes possedees. Le correctif ne ferme pas les URL publiques du catalogue pendant que cette distinction reste a clarifier.
Pour des photos personnelles : stockage prive separe, controle du proprietaire avant chaque livraison ou emission d'une URL signee courte, aucune copie publique Nginx, et tests de lecture entre comptes. Ce service n'est pas cree par ce correctif.
Pour interdire aussi les visuels des cartes non possedees : il faudrait fermer le chemin Nginx public et adapter les chargements mobile, Explorer, la recherche, le scan et les partages. Ajouter un controle dans l'API sans fermer le chemin direct ne protegerait rien. Une image deja telechargee ne peut pas etre rendue secrete retroactivement.
Verification avant deploiement
Tester avec deux vrais comptes : lectures privees sans jeton, jeton revoque, identifiant d'objet de l'autre compte en lecture/modification/suppression, portees et revocation des partages, code email rejoue et demandes concurrentes. Verifier aussi le reverse proxy, HTTPS, les limites de requetes, la non-exposition de PostgreSQL et des dossiers de debug. Utiliser un transport email reel en production, pas le transport de developpement console qui journalise le mail.
Sources de code : tcg-collector-backend/src/api/src/auth.ts, collection/session.ts, collection/queries.ts, routes/authEmail.ts, docker/compose.yml, docker/nginx.conf ; mobile src/data/remote/catalogApi.ts, src/ui/CardTile.tsx, src/components/SetLogo.ts.
References : autorisation par objet OWASP, authentification OWASP.