Files
Omarchy-Big-PC 358027bf27 Document full static RE of Greenwood School (Boti Education) app 2.4.14
- PROTOCOL.md: base URL, login/session auth, request envelope, push, media
- endpoints.md: 100 app endpoints extracted from the Capacitor JS bundle
- FINDINGS.md: security findings incl. hardcoded dev account in build
- tools: endpoint extractor + credential-safe login script
- results: original analysis report (IDs redacted)
2026-09-01 15:13:28 +01:00

95 lines
3.3 KiB
Markdown

# Boti Education app API protocol (Green Wood School variant)
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.
## Base URL
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).
## Authentication
### Login
POST {base}/login Content-Type: multipart/form-data
Fields:
- login phone number, e.g. 06xxxxxxxx
- password plaintext
- privacy bool ("true"/"false")
- remembreMe bool
Response (HTTP 200, application/json):
{
"status": 200, "msg": "Bienvenue !", "error": false,
"keyToken": "<40 hex chars>", // session key
"userId": "20887",
"parentId": "1376", // when 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
"refreshToken": "<jwt>"
}
Errors: {"error": true, "msg": "..."} with HTTP 200.
### Session use on every subsequent call
- 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
X-refresh-token: Bearer <refreshToken>
### Server-side session control
- 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).
## Request envelope
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
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
## Push notifications
POST {base}/device_token fields: token=<fcm token>, user_id, key, uid=<device uuid>
## Endpoint inventory
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.
## Media / files
- 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.
## Quirks
- 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.