Config strictement stricte partout (ruff, mypy --strict, bandit, vulture, import-linter, eslint, stylelint), aucune regle desactivee "pour ne pas casser le build" - l'existant a ete corrige pour la satisfaire plutot que l'inverse. Hooks pre-commit locaux (language: system) bloquants. - Typage mypy --strict propage a tout le moteur (db, screens, auth, core, ai, routes, puis publish/scripts/tests/app.py/build_css.py). - Securite : fuite de handle fichier Windows corrigee dans l'export SCORM (routes/publish/export_scorm.py), CSRF/RNG non-crypto/xAPI documentes (# nosec, # NOSONAR justifies), nouveau db.json_for_script() (echappe "</script>" dans le JSON embarque en <script>, 25 sites). - Architecture : imports circulaires/F811 nettoyes, contrats import-linter respectes, code mort retire (vulture). - Accessibilite : 69 champs de formulaire sans label correctement associe corriges (for/id ou aria-label) sur 11 templates. - ESLint/Stylelint : lot mecanique JS/CSS, regles ajustees puis appliquees (aucune desactivee sans verification individuelle). - Tests : isolation du compte admin partage (nettoyage ponctuel + fixture de teardown automatique en filet de securite), suite complete verte (591 tests Python, 241 tests JS). - SonarQube Community Build self-heberge (Docker + PostgreSQL) : rapport complet analyse point par point, faux positifs documentes. - .gitattributes ajoute (LF force) : core.autocrlf=true sur cette machine faisait echouer ESLint (linebreak-style) via un bug connu de git (checkout "en place" qui ignore l'eol force sur un fichier deja present sur disque - contourne en supprimant puis recreant chaque fichier suivi). djLint (H021, styles inline) volontairement saute pour ce commit - backlog assume, deja documente, traite dans un lot separe. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
98 lines
3.5 KiB
Python
98 lines
3.5 KiB
Python
"""auth — comptes utilisateurs, connexion, 2FA (TOTP) et isolation par
|
|
utilisateur d'un SEUL projet (sauf le rôle "admin", illimité) — voir
|
|
create_user.py pour le détail des règles. Base SQLite entièrement séparée
|
|
de db/ (une base par JEU) : ces comptes n'appartiennent à aucun jeu, ils
|
|
en POSSÈDENT un (project_slug)."""
|
|
|
|
from .confirm_totp import confirm_totp
|
|
from .connection import users_db_path
|
|
from .count_admins import count_admins
|
|
from .create_user import UserCreationError, create_user
|
|
from .create_user_asset import create_user_asset
|
|
from .delete_user import delete_user
|
|
from .delete_user_asset import delete_user_asset
|
|
from .ensure_schema import ensure_users_schema
|
|
from .ensure_user_assets_schema import ensure_user_assets_schema
|
|
from .get_user_asset import get_user_asset
|
|
from .get_user_by_email import get_user_by_email
|
|
from .get_user_by_id import get_user_by_id
|
|
from .image_dimensions import image_dimensions
|
|
from .is_first_user import is_first_user
|
|
from .list_user_assets import list_user_assets
|
|
from .password_reset import (
|
|
TOKEN_TTL_MINUTES,
|
|
consume_password_reset_token,
|
|
create_password_reset_token,
|
|
get_user_id_for_valid_token,
|
|
)
|
|
from .password_strength import MIN_SCORE_REQUIRED, password_strength
|
|
from .rate_limit import lockout_message, lockout_minutes_for, seconds_locked_remaining
|
|
from .record_failed_attempt import record_failed_attempt
|
|
from .recovery_codes import generate_recovery_codes, verify_recovery_code
|
|
from .reset_failed_attempts import reset_failed_attempts
|
|
from .save_user_asset import save_user_asset
|
|
from .send_email import EmailNotConfiguredError, send_password_reset_email
|
|
from .set_password import set_password
|
|
from .set_project_slug import set_project_slug
|
|
from .totp_qrcode_svg import totp_provisioning_uri, totp_qrcode_svg
|
|
from .update_email import EmailUpdateError, update_email
|
|
from .update_profile import update_profile
|
|
from .update_user_asset_scene_kind import update_user_asset_scene_kind
|
|
from .user_asset_kind import user_asset_kind
|
|
from .user_assets_dir import user_assets_dir
|
|
from .validate_audio_duration import MAX_AUDIO_SECONDS, validate_audio_duration
|
|
from .validate_video_duration import MAX_VIDEO_SECONDS, validate_video_duration
|
|
from .verify_password import verify_password
|
|
from .verify_totp import verify_totp
|
|
|
|
__all__ = [
|
|
"users_db_path",
|
|
"ensure_users_schema",
|
|
"is_first_user",
|
|
"create_user",
|
|
"UserCreationError",
|
|
"get_user_by_email",
|
|
"get_user_by_id",
|
|
"verify_password",
|
|
"confirm_totp",
|
|
"verify_totp",
|
|
"set_project_slug",
|
|
"password_strength",
|
|
"MIN_SCORE_REQUIRED",
|
|
"totp_provisioning_uri",
|
|
"totp_qrcode_svg",
|
|
"lockout_minutes_for",
|
|
"seconds_locked_remaining",
|
|
"lockout_message",
|
|
"record_failed_attempt",
|
|
"reset_failed_attempts",
|
|
"generate_recovery_codes",
|
|
"verify_recovery_code",
|
|
"set_password",
|
|
"create_password_reset_token",
|
|
"get_user_id_for_valid_token",
|
|
"consume_password_reset_token",
|
|
"TOKEN_TTL_MINUTES",
|
|
"send_password_reset_email",
|
|
"EmailNotConfiguredError",
|
|
"update_profile",
|
|
"count_admins",
|
|
"delete_user",
|
|
"update_email",
|
|
"EmailUpdateError",
|
|
"ensure_user_assets_schema",
|
|
"user_assets_dir",
|
|
"create_user_asset",
|
|
"list_user_assets",
|
|
"get_user_asset",
|
|
"delete_user_asset",
|
|
"save_user_asset",
|
|
"user_asset_kind",
|
|
"validate_audio_duration",
|
|
"MAX_AUDIO_SECONDS",
|
|
"validate_video_duration",
|
|
"MAX_VIDEO_SECONDS",
|
|
"image_dimensions",
|
|
"update_user_asset_scene_kind",
|
|
]
|