Traduction française complète + courriel de divulgation responsable

- README, PROTOCOL, FINDINGS, endpoints, rapport et outils traduits en français
- docs/DISCLOSURE.md : courriel prêt à envoyer à hello@boti.education
  (compte démo codé en dur, transmission en clair, logging de production)
- extract_endpoints.py vérifié après traduction (100 points d'accès toujours extraits)
This commit is contained in:
2026-09-01 17:29:25 +01:00
parent 358027bf27
commit b6f22ad7c1
8 changed files with 329 additions and 224 deletions
+61 -54
View File
@@ -1,94 +1,101 @@
# Boti Education app API protocol (Green Wood School variant)
# Boti Education app API : protocole (variante Green Wood School)
Reverse engineered statically from com.botieducation.greenwood 2.4.14
(Capacitor/Ionic/Angular bundle) and verified with one live login call on 2026-09-01.
Rétro-ingénierie statique à partir de com.botieducation.greenwood 2.4.14
(bundle Capacitor/Ionic/Angular), vérifiée avec un seul appel de connexion
réel le 2026-09-01.
## Base URL
## URL de base
https://boti.education/p/greenwood/botiapi/
Pattern per school: https://boti.education/p/<school-slug>/botiapi/
All Boti Education schools share one backend. Media host: media.boti.education
(signed expiring URLs, token appended to path).
Motif par école : https://boti.education/p/<slug-école>/botiapi/
Tous les établissements Boti Education partagent un même backend. Hôte
média : media.boti.education (URLs signées à durée limitée, token dans le
chemin).
## Authentication
## Authentification
### Login
### Connexion
POST {base}/login Content-Type: multipart/form-data
Fields:
- login phone number, e.g. 06xxxxxxxx
- password plaintext
- privacy bool ("true"/"false")
Champs :
- login numéro de téléphone, ex. 06xxxxxxxx
- password en clair
- privacy booléen ("true"/"false")
- remembreMe bool
Response (HTTP 200, application/json):
Réponse (HTTP 200, application/json) :
{
"status": 200, "msg": "Bienvenue !", "error": false,
"keyToken": "<40 hex chars>", // session key
"keyToken": "<40 caractères hex>", // clé de session
"userId": "20887",
"parentId": "1376", // when role=parent
"parentId": "1376", // quand role=parent
"eleveId": "1739",
"_acces": "parent", "role": "parent",
"eleves": [ { id, nomcomplet, prenom, nom, datenaissance, sexe,
niveau, img, parent_nom, parent_image } ],
"parent": { id, nomcomplet, tel, email, sexe, image },
"accessToken": "<jwt>", // present on some accounts, may be empty
"accessToken": "<jwt>", // présent sur certains comptes, peut être vide
"refreshToken": "<jwt>"
}
Errors: {"error": true, "msg": "..."} with HTTP 200.
Erreurs : {"error": true, "msg": "..."} avec HTTP 200.
### Session use on every subsequent call
### Utilisation de la session sur chaque appel suivant
- GET: query params, plus key=<keyToken> and user_id=<userId>
- POST: multipart/form-data fields, plus key=<keyToken>
- Optional modern path (supported by the ApiService, may be empty for parent
accounts): headers Authorization: Bearer <accessToken> and
- GET : paramètres d'URL, plus key=<keyToken> et user_id=<userId>
- POST : champs multipart/form-data, plus key=<keyToken>
- Voie moderne optionnelle (prise en charge par l'ApiService, souvent vide
pour les comptes parents) : en-têtes Authorization: Bearer <accessToken> et
X-refresh-token: Bearer <refreshToken>
### Server-side session control
### Contrôle de session côté serveur
- Any response containing "disconnect": true means the session was killed
client-side (app navigates to login).
- "redirect": "<path>" makes the app navigate there.
- "showSLides": "<key>" pops a slider modal (onboarding/news screens).
- Toute réponse contenant "disconnect": true signifie que la session a été
tuée (l'app navigue vers la page de connexion).
- "redirect": "<chemin>" fait naviguer l'app vers ce chemin.
- "showSLides": "<clé>" ouvre une modale de diapositives (écrans d'accueil ou
d'actualités).
## Request envelope
## Enveloppe des requêtes
GET params observed in the bundle (per feature, subset applies):
user_id, key, acces, versionCode, versionNumber, paltform (sic, typo is in the
app), eleveId, lang, date, startDate, endDate, classe, id, search, page
Paramètres GET observés dans le bundle (par fonctionnalité, sous-ensemble) :
user_id, key, acces, versionCode, versionNumber, paltform (sic, la faute de
frappe est dans l'app), eleveId, lang, date, startDate, endDate, classe, id,
search, page
POST FormData conventions:
- flat fields appended as key=value
- nested object -> key[subkey]=value
- array -> key[0]=..., key[1]=...
- File/Blob -> appended raw under the field name
- key=<keyToken> auto-appended by the ApiService
Conventions POST (FormData) :
- champs plats ajoutés comme clé=valeur
- objet imbriqué -> clé[sous-clé]=valeur
- tableau -> clé[0]=..., clé[1]=...
- File/Blob -> ajouté brut sous le nom du champ
- key=<keyToken> ajouté automatiquement par l'ApiService
## Push notifications
## Notifications push
POST {base}/device_token fields: token=<fcm token>, user_id, key, uid=<device uuid>
POST {base}/device_token champs : token=<jeton fcm>, user_id, key, uid=<uuid appareil>
## Endpoint inventory
## Inventaire des points d'accès
See endpoints.md (100 app endpoints, get/post flags, source chunk per endpoint).
Endpoint names are stable Pascal/snake identifiers appended to the base URL.
Voir endpoints.md (100 points d'accès de l'app, méthodes get/post et chunk
source par point d'accès). Les noms sont stables et ajoutés tels quels à
l'URL de base.
## Media / files
## Médias / fichiers
- Files and images are fetched from media.boti.education with a signed,
expiring path (base64url token + timestamp appended).
- PDFs opened in-app via pdf.js (chunk 7482.js).
- getBlob(path, params, absolute) downloads raw blobs for attachments.
- Fichiers et images servis par media.boti.education avec un chemin signé à
durée limitée (token base64url + horodatage ajoutés).
- Les PDF sont ouverts en interne via pdf.js (chunk 7482.js).
- getBlob(path, params, absolute) télécharge les blobs bruts pour les pièces
jointes.
## Quirks
## Particularités
- The ApiService appends the endpoint as a raw string, so endpoint names in the
table are the complete server route (no /api prefix, no .php).
- Param typo "paltform" is sent by the app; server accepts it, do not "fix" it
blindly.
- Detailed console.log of params and headers ships in production.
- L'ApiService ajoute le nom du point d'accès comme chaîne brute : les noms
du tableau sont la route serveur complète (pas de préfixe /api, pas de .php).
- La coquille de paramètre « paltform » est envoyée par l'app ; le serveur
l'accepte, ne pas la « corriger » aveuglément.
- Des console.log détaillés (paramètres, en-têtes) subsistent dans la version
de production.