Connexion : formulaire utilisable sans JavaScript, refus expliqués dans le Terminal, rtg mot-de-passe --tester ; nginx : location ^~ /admin/

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mf2kATMtqVABHSYdxJMnim
This commit is contained in:
FabriceandClaude Opus 5.5 committed 2026-10-09 16:43:26 +00:00
1 parent 2c2530a3dc
commit 4852361ea6
6 files changed
+46 -11

No files matched your search

+2 -2
View File
@@ -20,12 +20,12 @@
elle contient la clé d'accès de cette session{% if mdp %}, ou entrez le mot de passe{% endif %}.</p>
{% endif %}
{% if mdp %}
<form hx-post="{{ base }}/connexion" hx-target="#retour-connexion">
<form method="post" action="{{ base }}/connexion" hx-post="{{ base }}/connexion" hx-target="#retour-connexion">
<label>Mot de passe
<input type="password" name="mot_de_passe" autocomplete="current-password" required autofocus>
</label>
<button class="principal">Entrer</button>
<div id="retour-connexion">{% if attente %}<div class="erreur">Trop d'essais : réessayez dans {{ attente }} s.</div>{% endif %}</div>
<div id="retour-connexion">{% if message %}<div class="erreur">{{ message }}</div>{% elif attente %}<div class="erreur">Trop d'essais : réessayez dans {{ attente }} s.</div>{% endif %}</div>
</form>
{% elif not distant %}
<p class="aide">Pour entrer aussi avec un mot de passe (depuis un autre navigateur ou une autre machine) :
+29 -7
View File
@@ -696,14 +696,18 @@ def creer_gestionnaire(app, port, gardien=None):
connecte = gardien.session_valide(self.session())
form = {}
if methode == "POST":
if self.headers.get("HX-Request") != "true":
# La connexion marche aussi sans JavaScript (formulaire classique),
# à condition de venir d'une page de ce site.
if self.headers.get("HX-Request") != "true" and not (
chemin == "/connexion" and self.meme_origine()):
raise Erreur(403, "Requête refusée")
n = int(self.headers.get("Content-Length") or 0)
if n > 2_000_000:
raise Erreur(413, "Requête trop grosse")
form = parse_qs(self.rfile.read(n).decode("utf-8"), keep_blank_values=True)
if chemin in PUBLIQUES:
return self.envoyer(self.connexion(methode, form, connecte), tete)
rep = self.connexion(methode, form, connecte)
return self.envoyer(rep, tete) if rep else None
if not connecte:
if self.headers.get("HX-Request") == "true":
return self.envoyer(Reponse("", entetes={"HX-Redirect": P + "/connexion"}), tete)
@@ -741,18 +745,36 @@ def creer_gestionnaire(app, port, gardien=None):
def https(self):
return gardien.https or (gardien.proxy and self.headers.get("X-Forwarded-Proto") == "https")
def meme_origine(self):
origine = self.headers.get("Origin")
if not origine:
return True # navigateurs anciens : pas d'en-tête Origin
hote = self.headers.get("X-Forwarded-Host") if gardien.proxy else None
return urlsplit(origine).netloc in {hote or self.headers.get("Host", ""), *hotes}
def connexion(self, methode, form, connecte):
ip = self.ip()
htmx = self.headers.get("HX-Request") == "true"
message = ""
if methode == "POST":
ok, message = gardien.essayer(ip, _valeur(form, "mot_de_passe", ""))
mdp = _valeur(form, "mot_de_passe", "")
ok, message = gardien.essayer(ip, mdp)
if ok:
print(f"🔓 Connexion à l'interface depuis {ip}")
sid = gardien.ouvrir_session()
return Reponse("", entetes={"HX-Redirect": P + "/",
"Set-Cookie": gardien.entete_cookie(sid, self.https())})
return Reponse(f'<div class="erreur">{_echapper(message)}</div>')
cookie = gardien.entete_cookie(sid, self.https())
if htmx:
return Reponse("", entetes={"HX-Redirect": P + "/", "Set-Cookie": cookie})
self.rediriger(P + "/", cookie)
return None
# Dans le Terminal, pour comprendre un refus (jamais le mot de passe).
raison = "champ vide (formulaire mal transmis ?)" if not mdp else message
print(f"🔒 Connexion refusée depuis {ip} : {raison}")
if htmx:
return Reponse(f'<div class="erreur">{_echapper(message)}</div>')
return page("connexion.html", mdp=acces.defini(), connecte=connecte,
distant=gardien.distant or gardien.proxy, attente=gardien.attente(ip),
site=self.adresse_site())
site=self.adresse_site(), message=message)
def adresse_site(self):
"""Lien « Retour au site » de la page de connexion, derrière le serveur web."""