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

207 lines
10 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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