- 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)
95 lines
3.3 KiB
Markdown
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.
|