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

3.3 KiB

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//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= and user_id=
  • POST: multipart/form-data fields, plus key=
  • Optional modern path (supported by the ApiService, may be empty for parent accounts): headers Authorization: Bearer and X-refresh-token: Bearer

Server-side session control

  • Any response containing "disconnect": true means the session was killed client-side (app navigates to login).
  • "redirect": "" makes the app navigate there.
  • "showSLides": "" 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= 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.