Files
greenwood-school-re/tools/extract_endpoints.py
T
Omarchy-Big-PC b6f22ad7c1 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)
2026-09-01 17:29:25 +01:00

64 lines
2.1 KiB
Python
Executable File

#!/usr/bin/env python3
"""Extrait les points d'accès de l'API des apps Boti Education depuis les chunks JS décompilés.
Usage : python3 extract_endpoints.py <dossier-avec-chunks> [--markdown]
Cherche dans les *.js la signature d'appel de l'ApiService Angular :
<http>.post(<payload>, "endpoint") / <http>.get(<payload>, "endpoint")
et produit une table endpoint -> méthodes dédupliquée.
"""
import re
import sys
import glob
import os
import argparse
APPEL = re.compile(
r'\.(post|get|getBlob)\(\s*'
r'(?:"[^"]*"|`[^`]*`|[A-Za-z_$][\w$]*(?:\s*\.\s*[\w$]+)*(?:\([^()]*\))?|\{[^{}]*\})'
r'\s*,\s*"([^"]*)"'
)
def scanner(dossier):
trouves = {} # endpoint -> {méthode: [chunks]}
for chemin in sorted(glob.glob(os.path.join(dossier, '*.js'))):
chunk = os.path.basename(chemin)
src = open(chemin, encoding='utf8', errors='replace').read()
for m in APPEL.finditer(src):
methode, ep = m.group(1), m.group(2)
d = trouves.setdefault(ep, {})
d.setdefault(methode, []).append(chunk)
return trouves
def principal():
ap = argparse.ArgumentParser()
ap.add_argument('dossier')
ap.add_argument('--markdown', action='store_true')
args = ap.parse_args()
trouves = scanner(args.dossier)
if not trouves:
sys.exit('aucun point d\'accès trouvé, mauvais dossier ?')
if args.markdown:
print(f'# Points d\'accès extraits de {os.path.basename(args.dossier)}')
print()
print(f'{len(trouves)} points d\'accès uniques (non filtrés, voir docs/endpoints.md pour la liste nettoyée).')
print()
print('| endpoint | méthodes | chunk(s) |')
print('|---|---|---|')
for ep in sorted(trouves):
methodes = ', '.join(sorted(trouves[ep]))
chunks = ', '.join(sorted({c for ms in trouves[ep].values() for c in ms})[:3])
print(f'| {ep} | {methodes} | {chunks} |')
else:
for ep in sorted(trouves):
print(ep, sorted(trouves[ep]))
print(f'TOTAL points d\'accès : {len(trouves)}', file=sys.stderr)
if __name__ == '__main__':
principal()