Commit graph

54 commits

Author SHA1 Message Date
Alpinux
9835caa3d9 v1.9.0 — Perf bannissements, AS inconnus résolus, blocs repliables
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 15:42:33 +02:00
Alpinux
94f75dc59c ASN lookup : ajout fallback Team Cymru whois (port 43)
3e service de résolution après ip-api.com et ipinfo.io.
Cymru whois utilise TCP port 43 (pas HTTPS), ce qui fonctionne même
quand les sorties HTTPS sont bloquées côté serveur.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 15:38:54 +02:00
Alpinux
d272b3e8b7 Bannis : résolution AS via reverse-index RIPE Stat local + fallback ipinfo.io
- CIDRs bannis via "Ban AS" : résolus depuis as_cache/*.json (0 appel API)
  + nom/pays récupérés en 1 seule requête PostgreSQL (DISTINCT ON asn)
- IPs/CIDRs bannis individuellement : _batch_lookup_ip_asn avec fallback
  ipinfo.io (résout les cas où ip-api.com retourne vide, ex: 103.51.13.0)
- Entrées avec asn='' exclues du cache (AND asn != '') → re-tentée à chaque fois

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 15:10:26 +02:00
Alpinux
e0a3dd42f4 ASN lookup : fallback ipinfo.io + pas de cache pour AS inconnus
Si ip-api.com ne retourne pas d'AS, on retente sur ipinfo.io (champ org).
Les entrées sans ASN ne sont plus mises en cache (AND asn != '' sur les
lectures), donc les IP inconnues sont automatiquement re-tentées au prochain
chargement du tab Bannis.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 14:19:01 +02:00
Alpinux
a01976cbe8 Bannis : blocs AS repliables par défaut (fixes #47)
Chaque AS est replié au chargement (▶). Clic sur la ligne titre pour
déplier/replier. Bouton "Tout déplier / Tout replier". La recherche
dynamique déplie automatiquement les blocs qui contiennent un résultat.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 14:14:06 +02:00
Alpinux
259e8d5f3f Perf : tab Bannis chargé en AJAX, batch SQL pour les ASN
La route /errors/ ne calculait plus les groupes ASN au chargement (N×SQL
pour chaque CIDR banni). Le tab Bannissements est désormais lazy-chargé via
/errors/banned-groups avec un unique SELECT ANY() en PostgreSQL.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 14:09:12 +02:00
Alpinux
785a4639af v1.8.0 — Fusion pages Bannis et Erreurs en un seul onglet
La page /errors/ intègre désormais deux onglets (Erreurs 404 et Bannissements)
activés via hash URL (#errors / #banned). Le lien "Bannis" disparaît de la nav,
la route /errors/banned/ redirige vers /errors/#banned.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 13:53:11 +02:00
Alpinux
5ff97d50b5 feat: page Bannis — liste et déblocage fail2ban par IP ou AS entier
- /errors/banned/ : bannissements groupés par AS (nom, pays, nb entrées)
- Déblocage IP seule ou AS entier via POST /errors/unban
- Filtre dynamique par IP/CIDR/nom AS, mise à jour DOM sans rechargement
- Nav header + sudoers unbanip

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 13:46:13 +02:00
Alpinux
d4fe8614c2 feat(cache): IP→ASN cache PostgreSQL + fix deploy venv permissions
- psycopg2-binary ajouté aux dépendances
- Cache ip-api.com dans table ip_asn_cache (PostgreSQL, TTL 30 j)
- ThreadedConnectionPool partagé par worker, schéma auto-créé au démarrage
- Graceful degradation si DATABASE_URL absent
- deploy-app.sh : pip tourne sous static-cdn (sudo -u) pour respecter les droits

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 13:39:14 +02:00
Alpinux
5d2a4ab430 feat(erreurs): ban AS entier + masquer IPs bannies (#43, #44)
- Clic 🔨 : lookup AS via ip-api.com, propose 🔨 IP ou 🔨 AS (N préfixes)
- Ban AS : récupère les CIDRs via RIPE Stat, cache 30 j dans as_cache/
- IPs déjà bannies (global-blacklist) masquées du tableau et du détail AJAX
- ignoreip fail2ban : 82.65.88.34 protégée sur toutes les jails
- Sudoers : permission status global-blacklist pour static-cdn

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 13:31:35 +02:00
Alpinux
3a6f363e1d feat(erreurs): recherche dynamique par chemin ou IP (#42)
Champ de filtre en temps réel au-dessus du tableau des 404 ;
ferme le panneau de détail des lignes masquées.
Corrige aussi rsync via sudo pour préserver les droits static-cdn.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 13:21:02 +02:00
Alpinux
abf13db0e6 chore: changelog v1.5.1 — détail des corrections ignore/ban IP
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 13:18:43 +02:00
Alpinux
827fbc869b fix(deploy): chown static-cdn au lieu de abonnelc
Le service tourne sous static-cdn — il ne pouvait pas écrire ignored_ips.json.
Corrige aussi /var/log/static-cdn.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 13:16:52 +02:00
Alpinux
7b9024ab05 fix(erreurs): cache multi-worker + sudo service account pour fail2ban
- Invalidation du cache 404 basée sur mtime de ignored_ips.json (tous les workers gunicorn voient la mise à jour)
- Chemins complets /usr/bin/sudo et /usr/bin/fail2ban-client pour éviter les erreurs PATH dans systemd
- Version 1.5.1

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 13:12:54 +02:00
Alpinux
a94bf12e4d chore: version 1.5.0 — page Erreurs 404
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 12:57:37 +02:00
Alpinux
0513afdbb4 feat: page Erreurs 404 — logs, détail IP/date/referer, ignore, ban fail2ban
- Onglet "Erreurs" dans la navigation
- Analyse des logs Apache des 7 derniers jours (.gz inclus)
- Tableau trié par nombre de requêtes avec badge statut (résolu/actif)
- Détail AJAX par chemin : IPs, compteurs, referers
- Vérification live au clic sur le point de statut
- Ignorer une IP (persisté dans ignored_ips.json, cache invalidé)
- Bannir une IP via fail2ban-client (global-blacklist)
- Section IPs ignorées avec suppression depuis la page

Closes #37 #38 #39 #40 #41

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 12:57:13 +02:00
Alpinux
11a3ae72ee chore: version 1.4.2 — fix stats ISPConfig
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 12:03:42 +02:00
Alpinux
c0f3e43e35 fix: stats — utiliser le rapport ISPConfig au lieu de générer manuellement
STATS_FILE pointe vers /stats/goaindex.html généré chaque nuit par ISPConfig.
STATS_GENERATE_CMD et STATS_JSON vidés (génération déléguée à ISPConfig).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 12:01:43 +02:00
Alpinux
d81acf2b19 chore: version 1.4.1 — correctifs changelog et sélecteur de largeur
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 11:57:36 +02:00
Alpinux
46a8a0b75f fix: sélecteur largeur — data-cw sur <html> au lieu de CSS variable
max-width:none + margin:auto sur flex child causait le rétrécissement
de main. Remplacé par width:100% + sélecteurs d'attribut html[data-cw].

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 11:53:25 +02:00
Alpinux
ec3284873a fix: renommer items→entries dans _parse_changelog (conflit méthode dict)
grp.items en Jinja2 résolvait la méthode dict.items() au lieu de la clé.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 11:49:02 +02:00
Alpinux
b18db0646c fix: sélecteur de largeur — type=button + init CSS dans <head>
- Ajout de type="button" sur les boutons du sélecteur (évite le submit)
- Initialisation de --content-width dans <head> pour éviter le flash
- Séparation init CSS (head) / gestion active (body)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 11:44:31 +02:00
Alpinux
6d25cab295 feat: changelog + versioning sémantique
- Fichier VERSION (1.4.0) lu par l'app au démarrage
- CHANGELOG.md versionné (v1.0.0 → v1.4.0)
- Route /changelog avec parsing du markdown et rendu structuré
- Lien cliquable sur le numéro de version dans le footer

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 11:43:26 +02:00
Alpinux
7f5d86449e feat: sélecteur de largeur du contenu (S/M/L/∞)
Ajoute 4 boutons dans le header pour choisir la largeur du contenu :
- S : ~900 px  M : ~1200 px  L : ~1600 px  ∞ : plein écran
La préférence est mémorisée en localStorage et appliquée instantanément
via la CSS custom property --content-width sur <main>.

Closes #33

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 11:36:53 +02:00
Alpinux
857539725f style: contenu pleine largeur — supprimer max-width sur main
Les cards occupent maintenant toute la largeur disponible avec juste
1.5rem de marge sur les côtés, quelle que soit la taille d'écran.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 11:22:55 +02:00
Alpinux
1ba1b65283 style: élargir la zone de contenu de 1100px à 1400px
Header, contenu principal et footer alignés à 1400px pour mieux
utiliser l'espace horizontal sur les écrans larges.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 11:19:33 +02:00
Alpinux
6ea8785038 fix: stabiliser largeur pages + traduire labels EXIF
- CSS: scrollbar-gutter stable pour éviter le décalage de largeur entre
  pages avec/sans scrollbar
- EXIF: ajouter labels XResolution, YResolution, ResolutionUnit
- EXIF: afficher ColorSpace 1→sRGB, 2→Adobe RGB, 65535→Non calibré
- EXIF: afficher ResolutionUnit 2→pouces, 3→cm

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 11:16:40 +02:00
Alpinux
0bfe6336f0 fix: scrollbar permanente pour éviter le décalage de largeur entre pages
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 11:04:38 +02:00
Alpinux
8627bb1143 Revert "style: responsive mobile/tablette/PC (2 breakpoints)"
This reverts commit 1280af1af8.
2026-05-06 11:02:48 +02:00
Alpinux
1280af1af8 style: responsive mobile/tablette/PC (2 breakpoints)
Tablette ≤ 768px : nav scrollable horizontalement, date masquée,
  stat boxes 2 par ligne, padding réduit, footer réorganisé.
Mobile ≤ 480px : colonnes taille/hits/origin masquées, stat boxes
  empilées, grille dossiers 2 colonnes, header compact,
  preview-meta en colonne, chips resize plus petits.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 10:59:54 +02:00
Alpinux
9ffb055e92 feat: footer sur toutes les pages + layout flex body
Footer sombre (même couleur que le header) avec logo, liens nav et
version git (commit court). Body en flex-column + main flex:1
garantit que le footer reste en bas même sur les pages courtes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 10:54:35 +02:00
Alpinux
937433c0e5 feat: prévisualisation depuis la corbeille + suppression doublon nav
- Route /trash/preview/<path> : réutilise preview_image/text/other.html
  avec from_trash=True (← Corbeille, pas de rename ni de resize)
- Nom de fichier cliquable dans la liste corbeille → aperçu
- Suppression du lien "Tableau de bord" du header (doublon avec le logo)
- Ferme #25

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 10:53:07 +02:00
Alpinux
b85056a2fb refactor: centraliser user, humansize et trash_count dans le context processor
user et humansize injectés via _inject_globals() pour toutes les pages.
Supprime les 8 injections manuelles redondantes dans les routes.
Corrige le bug : /trash n'avait pas user → header incomplet.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 10:51:10 +02:00
Alpinux
4442022982 style: compacter le header — prénom + avatar initiale + icône logout
Réduit le padding nav (wrap évité sur "Tableau de bord"), remplace
"Nom complet + bouton Déconnexion" par un avatar cercle + prénom +
icône ⎋ avec tooltip, libérant ~120px horizontaux.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 10:46:18 +02:00
Alpinux
d2683a02e0 feat: stats corbeille dans le tableau de bord
Nouvelle stat box cliquable (→ /trash) affichant le nombre de fichiers,
la taille totale et la date du plus ancien fichier en corbeille.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 10:43:54 +02:00
Alpinux
b3af420d36 feat: corbeille avec purge automatique 30 jours
- Suppression déplace dans .trash/ (arborescence préservée + .trashinfo)
- /trash : liste, restauration (conflit overwrite/rename), suppression
  définitive, vidage complet
- Purge automatique des fichiers > 30 jours à chaque visite /trash
- Badge rouge dans la nav avec le nombre de fichiers en corbeille
- Extraction du tableau de fichiers en partial _file_table.html
  partagé entre browse et trash

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 10:40:35 +02:00
Alpinux
dd83e6f36e fix: resize ICO et comportement sans sélection
- Convertit le mode palette (ICO, GIF) en RGBA avant LANCZOS pour
  éviter l'erreur de resampling sur les sources ICO
- Sans dimension sélectionnée : conserve les dimensions d'origine
- Sans format sélectionné : conserve le format d'origine
- Bouton toujours actif, texte dynamique "Générer la copie / N copies"

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 10:11:17 +02:00
Alpinux
3e8b18b127 feat: dimension libre pour le redimensionnement d'images
Ajout d'un champ W×H dans la carte resize, contraint à la résolution
source. Option "carré" synchronise les deux valeurs. Le bouton Générer
s'active si au moins un format est sélectionné et une taille valide
(prédéfinie ou libre) est renseignée.

Supprime le code mort dans la route /resize (errors_pre).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 10:03:48 +02:00
Alpinux
8f6aa292ef feat: conflit resize à la demande + nommage sans suffixe dimensions
- Route POST /check-resize : pre-check des fichiers cibles avant génération
  (utilise déjà le strip _NxN sur le stem)
- Route /resize : strip du suffixe _NxN dans le stem source
  (logo_1024x1024.png → 500x500 = logo_500x500.png)
- preview_image.html : bloc conflit masqué par défaut
  Au clic Générer → pre-check AJAX → si conflit : panneau jaune identique
  à l'upload avec Backup/Écraser/Renommer/Ignorer puis Confirmer
  Sans conflit → génération directe sans interruption

Ferme #10.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 09:54:39 +02:00
Alpinux
31ddff2a75 feat: affichage des métadonnées image dans la page de prévisualisation
Ajoute une carte de propriétés au-dessus de l'image :
- Dimensions (largeur × hauteur), format, mode couleur, résolution DPI
- Données EXIF complètes si présentes (appareil, exposition, ISO, focale,
  balance des blancs, auteur, copyright…)
- Coordonnées GPS avec lien OpenStreetMap si le champ est renseigné

Nouvelle fonction _image_meta() et _parse_gps() dans app.py (Pillow).
Grille CSS responsive, n'apparaît pas si aucune métadonnée disponible.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 09:41:31 +02:00
Alpinux
fa5408bb03 refactor: vérification des conflits upload à la soumission (AJAX)
Au lieu d'un sélecteur statique pré-affiché, le formulaire d'upload
vérifie maintenant les conflits côté serveur au clic sur Envoyer :
- Aucun conflit → envoi immédiat sans interruption
- Conflits détectés → panneau jaune avec la liste des fichiers existants
  et un sélecteur segmenté Écraser / Backup / Renommer / Ignorer
- L'utilisateur confirme ou annule avant que le formulaire parte

Ajout de la route POST /check-upload (retourne {"conflicts": [...]}).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 09:31:53 +02:00
Alpinux
130a901be7 feat: gestion des conflits lors de l'upload de fichiers
Ajoute un sélecteur de stratégie dans le formulaire de dépôt CDN,
identique à celui du redimensionnement :
- Écraser (défaut) : comportement précédent, écrase silencieusement
- Backup : renomme l'existant en {stem}_bak_{timestamp}{ext} avant dépôt
- Renommer : auto-incrémente le nom du fichier uploadé ({stem}_1, _2…)
- Ignorer : ne dépose pas si le fichier existe déjà

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 09:29:29 +02:00
Alpinux
14259c59f1 feat: renommage de fichiers + gestion des conflits dans le redimensionnement
- Route POST /rename : renomme un fichier CDN avec validation sécurité,
  retourne JSON (name, path, browse_url)
- Route /resize : accepte param `conflict` (backup | overwrite | rename | skip)
  backup  → renomme l'existant en {stem}_bak_{timestamp}{ext} avant création
  rename  → auto-incrémente le nom de la copie ({stem}_1, _2…)
  overwrite → écrase silencieusement
  skip    → ignore (signalé dans les erreurs)
- browse.html : bouton ✏️ par fichier, renommage inline avec Entrée/Échap
- preview_image.html : bouton ✏️ dans l'en-tête, champ inline + redirect
  après validation ; radio segmenté pour la stratégie de conflit
- app.css : styles btn-rename, rename-inline, radio-chips segmentés

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 09:26:26 +02:00
Alpinux
c503f5e074 feat: redimensionnement d'images depuis la prévisualisation CDN
Ajoute une carte interactive sous chaque aperçu d'image permettant de
générer des copies redimensionnées directement dans le même dossier CDN.

- Route POST /resize avec Pillow (PNG, JPG, ICO) et cairosvg optionnel (SVG)
- Tailles disponibles : 32, 64, 100, 128, 200, 300, 500, 600, 1024 px (carré)
- Formats : png, jpg, ico (svg uniquement si la source est déjà SVG)
- Nommage automatique : {nom}_{taille}x{taille}.{ext}
- UI chips cliquables, soumission AJAX, retour avec liens directs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 08:26:51 +02:00
Alpinux
0079c9297a Ajouter référence au README principal de l'espace de travail
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-03 21:00:07 +02:00
Alpinux
b1020062b0 fix: logout SSO — redirige vers l'endpoint end_session d'AlpID
session.clear() seul ne déconnectait pas la session Keycloak,
provoquant une reconnexion automatique immédiate.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-03 20:43:10 +02:00
Alpinux
16c1af4143 feat: génération GoAccess à la demande + README complet
- stats.html : bouton "Générer et ouvrir" avec polling async ; supprime
  le window.open automatique (bloqué par les navigateurs)
- app.py : routes POST /stats/generate et GET /stats/status ; exécution
  GoAccess en thread daemon, verrou anti-doublon
- .env.example : documente STATS_LOG_FILE et STATS_GENERATE_CMD
- README.md : flux de publication local→git→serveur, variables d'env,
  procédure première installation

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-03 20:39:25 +02:00
Alpinux
25b68df5ec docs: documente l'upload et les variables d'env de l'app Flask
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-03 20:36:35 +02:00
Alpinux
64989e83c8 feat: upload de fichiers dans l'app Flask CDN
Ajoute la route POST /upload (admin uniquement) et la zone de dépôt
dans browse.html — glisser-déposer ou sélection multiple, destination
= dossier courant du navigateur.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-03 20:35:29 +02:00
Alpinux
7c70e904f3 fix: supprime --delete, exclut wiki/ et fichiers ISPConfig
Push : additive uniquement (pas de suppression sur le serveur)
Pull : idem, wiki/ exclu des deux côtés
Excludes communs : .git/, scripts/, README.md, .env*, .gitignore, wiki/
Correction bug bash set -e avec ((VAR++)) → VAR=$(( VAR + 1 ))

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-03 18:22:45 +02:00