alpinux-static/app/CHANGELOG.md
Alpinux a6d7bc2c8a feat: v2.0.0 — 14 tickets implémentés
#53 résumé req/IPs par statut dans Erreurs 404
#54 titre onglet avec compteur non résolus
#2  Tout/Aucun dans resize (tailles + formats)
#7  backup filename affiché dans résultats resize
#8  flash message résumé après upload
#6  renommage inline sur preview_text + preview_other
#23 filtre + tri par nom/taille/date dans corbeille
#20 sélection multiple + batch restore/delete corbeille
#45 /sitemap.xml (assets publics)
#52 ignoreip fail2ban sync sur Ignorer/Retirer une IP
#1  cairosvg>=2.7 dans requirements.txt
#51 ignored_ips.json exclu du rsync --delete
#48 as_cache/ exclu du rsync --delete

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 21:04:03 +02:00

10 KiB
Raw Blame History

Changelog — Alpinux Static

[2.0.0] — 2026-05-06

Ajouté

  • Erreurs 404 (#53) : barre de résumé rouge/verte affichant le total requêtes·IPs ventilé entre erreurs actives et résolues (calculé après vérification batch)
  • Erreurs 404 (#54) : titre de l'onglet navigateur mis à jour avec le nombre d'erreurs non résolues (Erreurs 404 (12) — Static Alpinux)
  • Resize (#2) : boutons « Tout / Aucun » pour les groupes Tailles et Formats
  • Resize (#7) : nom du fichier backup affiché dans les résultats de génération
  • Upload (#8) : message de résumé après upload (X envoyé(s), Y sauvegardé(s), Z ignoré(s)…)
  • Renommage (#6) : bouton ✏️ disponible sur les pages preview_text et preview_other (idem preview_image)
  • Corbeille (#23) : filtre texte + tri par nom / taille / date
  • Corbeille (#20) : sélection multiple — cases à cocher, « Tout sélectionner », restaurer/supprimer en lot
  • Sitemap (#45) : route /sitemap.xml listant les assets publics (logo/, wiki/, error/)
  • Ignorer IP (#52) : « Ignorer cette IP » ajoute/retire automatiquement l'IP dans fail2ban ignoreip global-blacklist
  • SVG (#1) : cairosvg>=2.7 ajouté à requirements.txt (libcairo2 disponible sur le serveur)

Corrigé

  • Déploiement (#51) : ignored_ips.json exclu du rsync --delete — les IPs ignorées ne sont plus effacées au déploiement
  • Déploiement (#48) : as_cache/ exclu du rsync --delete — le cache RIPE local est préservé entre déploiements

[1.10.0] — 2026-05-06

Modifié

  • Erreurs 404 : les pastilles de statut (●) rouges sont désormais vérifiées automatiquement au chargement de la page — elles passent en vert si le fichier existe maintenant, sans nécessiter un clic
  • Nouveau endpoint POST /errors/status-batch : vérifie jusqu'à 200 chemins en une seule requête (simple os.path.exists côté serveur)

[1.9.1] — 2026-05-06

Corrigé

  • Onglet Bannis affichait « Aucune IP bannie » après le premier chargement : le timeout de fail2ban-client était de 5 s (trop court sous charge) — porté à 30 s
  • Les exceptions dans _get_banned_ips() étaient silencieuses et mettaient en cache un résultat vide pendant 60 s ; elles sont désormais loguées (returncode, stderr, message)

[1.9.0] — 2026-05-06

Ajouté

  • Onglet Bannis : blocs AS repliables par défaut (▶/▼), bouton « Tout déplier / Tout replier »
  • La recherche dynamique déplie automatiquement les blocs contenant un résultat
  • Résolution ASN en triple fallback : ip-api.com → ipinfo.io → Team Cymru whois (TCP port 43, fonctionne même si HTTPS sortant bloqué)

Corrigé

  • Onglet Bannis trop lent / Internal Server Error : les lookups ASN se faisaient de façon synchrone au chargement de la page pour chaque CIDR banni
    • Le tab est désormais chargé en AJAX (lazy, à la première activation seulement)
    • Nouveau endpoint GET /errors/banned-groups : un seul SELECT ANY() PostgreSQL au lieu de N requêtes individuelles
    • Les entrées avec asn vide ne sont plus utilisées depuis le cache (AND asn != '') — elles sont automatiquement re-tentées avec le fallback
  • Résolution des « AS inconnu » : les CIDRs bannis via « Ban AS » sont résolus depuis as_cache/*.json (index local RIPE, zéro appel API) puis nom/pays récupérés en 1 requête PostgreSQL DISTINCT ON (asn)
  • 17 172 entrées ASN résolues en base via batch Team Cymru (les CIDRs précédemment bannis sans lookup individuel)

[1.8.0] — 2026-05-06

Modifié

  • Fusion des pages Erreurs 404 et Bannis en une seule page avec deux onglets (URL /errors/)
  • L'onglet actif est mémorisé dans le hash d'URL (#errors / #banned)
  • Suppression du lien « Bannis » dans la navigation (accessible via l'onglet de la page Erreurs)
  • Route /errors/banned/ redirige vers /errors/#banned

[1.7.0] — 2026-05-06

Ajouté

  • Page Bannis (/errors/banned/) : liste tous les bannissements fail2ban (global-blacklist) groupés par AS, avec nom de l'opérateur et pays
  • Débloquer une IP/CIDR individuelle ou tout un AS d'un seul clic
  • Filtre de recherche dynamique par IP, CIDR ou nom d'AS
  • Mise à jour en temps réel des lignes après déblocage (pas de rechargement)
  • Sudoers static-cdn : ajout de la permission unbanip

[1.6.1] — 2026-05-06

Modifié

  • Cache IP→ASN migré de la mémoire process vers PostgreSQL (ip_asn_cache) — TTL 30 jours, partagé entre tous les workers gunicorn, pas de lock SQLite
  • Pool de connexions ThreadedConnectionPool (13 conns par worker), schéma créé automatiquement au premier démarrage
  • Graceful degradation : si DATABASE_URL absent ou PostgreSQL indisponible, l'app appelle ip-api.com sans cache

[1.6.0] — 2026-05-06

Ajouté

  • Erreurs 404 : clic sur 🔨 affiche l'AS de l'IP (via ip-api.com) avec le nom, le pays et le nombre de préfixes IPv4
  • Bannir l'IP seule ou bannir tout l'AS d'un coup (tous ses préfixes CIDR via RIPE Stat, cache 30 jours)
  • Erreurs 404 : les IPs déjà bannies dans fail2ban (global-blacklist) sont masquées de la liste et du détail

Modifié

  • fail2ban ignoreip : ton IP publique (82.65.88.34) protégée sur toutes les jails
  • Sudoers static-cdn : ajout de la permission fail2ban-client status global-blacklist

[1.5.2] — 2026-05-06

Ajouté

  • Erreurs 404 : champ de recherche dynamique — filtre les lignes par chemin ou adresse IP à chaque frappe, avec compteur de résultats

[1.5.1] — 2026-05-06

Corrigé

  • Ignorer une IP : /opt/static-cdn/ appartenait à abonnelc alors que le service tourne sous static-cdn — écriture de ignored_ips.json silencieusement impossible ; corrigé par chown -R static-cdn + script de déploiement mis à jour
  • Ignorer une IP : invalidation du cache multi-worker gunicorn basée sur le mtime de ignored_ips.json (chaque worker re-parse dès que le fichier change)
  • Bannir une IP : règle sudoers créée pour static-cdn (compte de service réel, pas abonnelc) avec chemins absolus /usr/bin/sudo et /usr/bin/fail2ban-client

[1.5.0] — 2026-05-06

Ajouté

  • Onglet Erreurs dans la navigation : analyse des logs Apache des 7 derniers jours (fichiers .gz inclus)
  • Tableau des erreurs 404 trié par fréquence, avec badge statut coloré (✗ actif / ✓ résolu) cliquable
  • Détail par chemin (AJAX) : liste des IPs avec compteur, dernière date, referers
  • Ignorer une IP (devs, tests, IPs internes) — persisté dans ignored_ips.json, cache invalidé
  • Bannir une IP directement depuis l'interface via fail2ban-client set global-blacklist banip
  • Section des IPs ignorées avec suppression individuelle

[1.4.2] — 2026-05-06

Corrigé

  • Statistiques : la page affichait une erreur de génération alors qu'ISPConfig génère déjà le rapport GoAccess chaque nuit — STATS_FILE pointe maintenant directement sur le fichier ISPConfig

[1.4.1] — 2026-05-06

Corrigé

  • Changelog : TypeError au rendu — clé items du dict en conflit avec la méthode Python dict.items() en Jinja2 (renommée entries)
  • Sélecteur de largeur : boutons L et ∞ sans effet — max-width:none + margin:auto sur flex child rétrécissait <main> ; remplacé par data-cw sur <html> + sélecteurs CSS d'attribut

[1.4.0] — 2026-05-06

Ajouté

  • Sélecteur de largeur du contenu dans le header : Étroit (900 px), Normal (1 200 px), Large (1 600 px), Plein — préférence mémorisée dans le navigateur
  • Changelog avec numéro de version sémantique, accessible depuis le footer

Corrigé

  • Décalage de largeur entre les pages dû à l'apparition/disparition de la scrollbar (scrollbar-gutter: stable)
  • Labels EXIF non traduits : ResolutionUnit, XResolution, YResolution
  • Valeur numérique brute pour ColorSpace → libellé lisible (sRGB, Adobe RGB, Non calibré)

Modifié

  • Contenu principal en pleine largeur (suppression du max-width fixe sur <main>)

[1.3.0] — 2026-05-06

Ajouté

  • Prévisualisation des fichiers depuis la corbeille (propriétés, métadonnées, téléchargement)
  • Footer sur toutes les pages avec liens de navigation et numéro de version
  • Stats corbeille dans le tableau de bord (nombre de fichiers, taille totale, date du plus ancien)

Modifié

  • Header compact : avatar initiale + prénom + icône déconnexion (suppression du bouton texte)
  • Suppression du lien « Tableau de bord » dans la navigation (doublon avec le logo)
  • user, humansize, trash_count centralisés dans le context processor Flask (disponibles sur toutes les pages)

[1.2.0] — 2026-05-06

Ajouté

  • Corbeille : mise à la corbeille depuis /browse, restauration avec gestion des conflits (écraser / renommer), suppression définitive
  • Purge automatique des éléments en corbeille depuis plus de 30 jours
  • Badge dans la navigation indiquant le nombre d'éléments en corbeille
  • Page /trash avec tableau partagé (mode browse / trash) et bouton « Vider la corbeille »

[1.1.0] — 2026-05-06

Ajouté

  • Redimensionnement d'images depuis la prévisualisation : tailles prédéfinies, dimension libre, formats PNG/JPG/ICO
  • Gestion des conflits lors du redimensionnement (backup, écraser, renommer, ignorer)
  • Renommage de fichiers inline dans /browse et la page de prévisualisation
  • Affichage des métadonnées image (dimensions, format, mode couleur, DPI, EXIF)
  • Dimension libre avec contrainte de proportions (mode « carré »)

Corrigé

  • Échec du redimensionnement sur les fichiers ICO en mode palette (conversion RGBA avant LANCZOS)
  • Aucune sélection de taille ou format → copie à l'identique (comportement par défaut)

[1.0.0] — 2026-05-03

Ajouté

  • Upload de fichiers par glisser-déposer avec gestion des conflits (écraser, backup, renommer, ignorer)
  • Parcourir les assets CDN depuis /browse avec fil d'Ariane
  • Statistiques de consultation via GoAccess (/stats), générées à la demande
  • Authentification SSO via AlpID (Keycloak / OpenID Connect)
  • Recherche dans les fichiers
  • Scripts rsync push-assets.sh et pull-assets.sh pour la synchronisation locale ↔ serveur
  • Script deploy-app.sh pour le déploiement de l'application Flask