Code/components/connexion.py
2025-06-11 14:57:53 +02:00

109 lines
4.3 KiB
Python

import streamlit as st
import requests
import logging
import os
from utils.translations import _
from utils.persistance import get_champ_statut, maj_champ_statut
def initialiser_logger():
LOG_FILE_PATH = "/var/log/fabnum-auth.log"
if not os.path.exists(os.path.dirname(LOG_FILE_PATH)):
os.makedirs(os.path.dirname(LOG_FILE_PATH), exist_ok=True)
logger = logging.getLogger("auth_logger")
logger.setLevel(logging.INFO)
if not logger.hasHandlers():
fh = logging.FileHandler(LOG_FILE_PATH)
formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
fh.setFormatter(formatter)
logger.addHandler(fh)
return logger
def connexion():
login = get_champ_statut("login")
if login == "":
auth_title = str(_("auth.title"))
st.html(f"""
<section role="region" aria-label="region-authentification">
<div role="region" aria-labelledby="Authentification">
<p id="Authentification" class="decorative-heading">{auth_title}</p>
""")
GITEA_URL = "https://fabnum-git.peccini.fr/api/v1"
ORGANISATION = "FabNum"
EQUIPE_CIBLE = "Administrateurs"
logger = initialiser_logger()
if get_champ_statut("login") == "":
with st.form("auth_form"):
# Ajout d'un champ identifiant fictif pour activer l'autocomplétion navigateur
# et permettre de stocker le token comme un mot de passe par le navigateur
# L'identifiant n'est donc pas utilisé par la suite ; il est caché en CSS
identifiant = st.text_input(str(_("auth.username")), value="fabnum-connexion", key="nom_utilisateur")
token = st.text_input(str(_("auth.token")), type="password")
submitted = st.form_submit_button(str(_("auth.login")), icon=":material/login:")
if submitted and token:
erreur = True
headers = {"Authorization": f"token {token}"}
ip = os.environ.get("REMOTE_ADDR", "inconnu")
username = "inconnu"
try:
user_response = requests.get(f"{GITEA_URL}/user", headers=headers, timeout=5)
user_response.raise_for_status()
utilisateur = user_response.json()
username = utilisateur.get("login", "inconnu")
logger.info(f"Tentative par {username} depuis IP {ip}")
teams_url = f"{GITEA_URL}/orgs/{ORGANISATION}/teams"
teams_response = requests.get(teams_url, headers=headers, timeout=5)
teams_response.raise_for_status()
equipes = teams_response.json()
equipe_admin = next((e for e in equipes if e["name"] == EQUIPE_CIBLE), None)
if equipe_admin:
team_id = equipe_admin["id"]
check_url = f"{GITEA_URL}/teams/{team_id}/members/{username}"
check_response = requests.get(check_url, headers=headers, timeout=5)
if check_response.status_code == 200:
erreur = False
maj_champ_statut("login", username)
logger.info(f"Connexion réussie pour {username} depuis IP {ip}")
st.rerun()
except requests.RequestException:
st.error(str(_("auth.gitea_error")))
if erreur:
logger.warning(f"Accès refusé pour tentative avec token depuis IP {ip}")
st.error(str(_("auth.error")))
st.html("""
</div>
</section>
""")
def bouton_deconnexion():
login = get_champ_statut("login")
if not login == "":
auth_title = str(_("auth.title"))
st.html(f"""
<section role="region" aria-label="region-authentification">
<div role="region" aria-labelledby="Authentification">
<p id="Authentification" class="decorative-heading">{auth_title}</p>
""")
st.sidebar.markdown(f"{str(_('auth.logged_as'))} `{login}`")
if st.sidebar.button(str(_("auth.logout")), icon=":material/logout:"):
maj_champ_statut("login", "")
st.success(str(_("auth.success")))
st.rerun()
st.html("""
</div>
</section>
""")