Le cookie user_id était lu tel quel depuis la requête, ce qui permettait à
n'importe qui de forger `user_id=victime` dans DevTools/curl et d'accéder à
toutes les routes "authentifiées" (lecture/écriture des pointages, export,
régénération des tokens Tasker, etc.). Le mot de passe bcrypt ne servait
donc à rien.
Le cookie est maintenant au format `<user_id>.<hmac_sha256_hex>` signé avec
une clé persistée dans /data/secret.key (auto-générée, stable entre
redémarrages). La vérification utilise hmac.compare_digest pour éviter les
fuites par timing. Toutes les routes appellent _get_user qui valide la
signature à chaque requête.
Les tests de test_logs.py récupèrent désormais le cookie réellement signé
par le serveur, et un nouveau module test_security.py couvre le rejet des
cookies forgés/tamponnés/rejoués.
Le DATA_DIR temporaire des tests est centralisé dans conftest.py pour éviter
les collisions entre modules de test.
💘 Generated with Crush
Assisted-by: Crush:glm-5.2
Toute modification des paramètres (topic/serveur/jeton ntfy, plages
horaires, régénération du token de présence Tasker) est désormais
enregistrée dans /logs sous un nouveau type "Réglages", avec un onglet
dédié. Chaque entrée résume ce qui a changé (valeurs des plages, plage
des rappels, topic, jeton défini/vide, URLs invalidées), pour aider à
diagnostiquer a posteriori un problème de configuration.
💘 Generated with Crush
Assisted-by: Crush:glm-5.2
Le bouton "Régénérer le token" de la carte Tasker crée un nouveau token
secret et invalide immédiatement les anciennes URLs, au cas où elles
auraient fuité. La fonction regenerate_presence_token préserve les
autres réglages notif (topic, serveur, jeton d'accès, plage). Au passage
le message de retour du bouton de test ntfy occupe désormais toute la
largeur de la carte au lieu d'être limité à 420px.
💘 Generated with Crush
Assisted-by: Crush:glm-5.2
Certains serveurs ntfy auto-hébergés (ex: ntfy.arkel.fr) renvoient
403 Forbidden sans authentification. Un nouveau champ "Jeton d'accès"
(optionnel, type password) sur /settings permet de renseigner un token
qui sera envoyé comme "Authorization: Bearer ..." à chaque publication,
pour les rappels réels comme pour le bouton de test. La page /aide
documente le cas 403 et la marche à suivre.
💘 Generated with Crush
Assisted-by: Crush:glm-5.2
Chaque utilisateur a désormais son propre fichier logs.json dans son
dossier users/<id>/, alimenté automatiquement quand un rappel ntfy est
envoyé (ou échoue) et quand Tasker signale une arrivée ou un départ.
Une nouvelle page /logs, accessible depuis la nav, affiche ces entrées
avec filtres (Tout / Notifications / Présence), et le journal tourne à
500 entrées pour rester compact.
💘 Generated with Crush
Assisted-by: Crush:glm-5.2
Chaque compte a désormais son propre data/users/<user>/plages.json, réglable
depuis une nouvelle carte "Plages horaires" sur /settings (avec validation
HH:MM et ordre matin < aprem). Le calcul, les stats de conformité et les
avertissements de saisie lisent la config de l'utilisateur courant au lieu
du plages global. La valeur globale de data/config.json reste lue comme
valeur de repli tant qu'un utilisateur n'a rien personnalisé.
classement, ajoute une suite de tests pytest
- calcul.py: matin_debut/fin, aprem_debut/fin et pause_dejeuner_fin sont
paramétrables via config.json > plages (moteur de calcul de l'heure de
sortie optimale inclus, pas seulement l'affichage). Défauts identiques
à l'ancien comportement, validé par la suite de tests.
- stats.py: les seuils de conformité utilisent la même config.
- main.py/templates: warn de saisie et suffixes de cible dynamiques.
- Rappels ntfy: serveur, topic et plage horaire (rappel_debut_h/fin_h)
configurables par utilisateur depuis /settings, plus en dur dans le code.
- Page classement supprimée (pas de compétition entre utilisateurs).
- Nouvelle suite pytest (app/tests/), à lancer via
`docker compose run --rm pointeuse pytest -v`.
réduit le score spam des emails, et rend le niveau de log configurable
- Les styles .login-* étaient définis uniquement dans login.html, donc
set_password.html s'affichait sans aucun style. Déplacé dans base.html.
- La nav affichait les liens même sans session active.
- mail.py ajoute Message-ID/Date et encode en quoted-printable (au lieu
de base64) pour réduire le score spam (MISSING_MID, MISSING_DATE,
MIME_BASE64_TEXT).
- log_level devient une directive de config.json plutôt qu'une variable
d'environnement.
- README: section démarrage rapide (copie de config.example.json,
compose.override.yml pour les surcharges locales).
Niveau configurable via LOG_LEVEL (défaut DEBUG). Les erreurs de config
JSON invalide remontent maintenant un message clair (fichier + position)
au lieu d'un JSONDecodeError brut.
Ajoute le bloc "smtp" (host, port, identifiants, TLS) dans config.json,
plus fiable et plus simple à opérer qu'une livraison directe au MX du
destinataire. data/config.json n'est plus versionné (secrets), remplacé
par data/config.example.json.
- Auth cookie simple (SSO-ready) : login/logout, redirection si non authentifié
- Données isolées par utilisateur dans /data/users/{user_id}/
- Migration automatique des données legacy au premier login
- Page classement avec podium et tableau comparatif (score, précision zéro, conformité)
- Nav mise à jour : Classement, affichage utilisateur courant, déconnexion
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Nouvelles colonnes : Δ sem. (solde cumulé semaine) et Fin cible (heure de
sortie aprem optimale pour 0h suppl. en fin de semaine)
- Δ sem. n'est affiché que quand la journée est complète et la chaîne de jours
ininterrompue (pas de saut de jour non saisi)
- Fin cible disparaît quand la journée est validée (passée/complète)
- Delta = "—" pour les jours non travaillés (futur ou congé jour)
- Indicateur warn (fond rouge) sur matin/aprem si horaires < minimum
(matin 09:00→12:00, aprem 14:00→17:00) ; mise à jour live via JS
- Suppression du solde global (3 cartes au lieu de 4)
- Tableau sans largeurs fixes + container 1100 px pour éviter scroll
horizontal sur écrans normaux ; touch-scroll conservé sur mobile
- Base reste 39h/semaine (7h48/jour)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
App web de suivi des heures de travail (FastAPI + HTMX + JSON plats).
- Saisie inline par semaine avec bouton ✓ par ligne
- Congés MA/AM/J avec coloration cellule et mise à jour live via OOB HTMX
- Import fichier ODS badgeuse
- Solde semaine et solde global recalculés à la volée
- Design "ledger" écru, DM Mono, zéro border-radius
- Déploiement Docker sur port 8000
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>