Spaces:
Sleeping
Sleeping
File size: 5,932 Bytes
fe4792e |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
import streamlit as st
from datetime import datetime, timedelta
import pytz
import secrets
import bcrypt
from supabase import create_client
import os
from dotenv import load_dotenv
from utils.email_utils import send_email
from urllib.parse import urljoin, urlparse
from utils.logging_utils import log_to_file # remplace "import logging" car maintenat les logging sont définis et importés depuis le fichier dédié: logging_utils.py
load_dotenv()
supabase = create_client(os.getenv("SUPABASE_URL"), os.getenv("SUPABASE_KEY"))
# Fonction pour générer un token de réinitialisation de mot de passe
def generate_reset_token() -> str:
"""Génère un token sécurisé pour la réinitialisation de mot de passe."""
return secrets.token_urlsafe(32)
# Fonction pour créer un token de réinitialisation de mot de passe pour un utilisateur spécifique
def create_reset_token(user_id: int) -> tuple[bool, str]:
"""
Crée un token de réinitialisation de mot de passe.
"""
try:
token = generate_reset_token()
expires_at = datetime.now(pytz.UTC) + timedelta(hours=24)
# Invalider les tokens précédents
supabase.table("user_tokens").update({
"used": True
}).eq("user_id", user_id).eq("type", "reset_password").execute()
# Créer un nouveau token
supabase.table("user_tokens").insert({
"user_id": user_id,
"token": token,
"type": "reset_password",
"expires_at": expires_at.isoformat()
}).execute()
return True, token
except Exception as e:
log_to_file(f"Erreur lors de la création du token : {str(e)}")
return False, ""
# Fonction pour envoyer l'email de réinitialisation
def send_reset_email(email: str, reset_url: str) -> bool:
"""
Envoie l'email de réinitialisation.
"""
subject = "Réinitialisation de votre mot de passe"
html_content = f"""
<html>
<body>
<h2>Réinitialisation de votre mot de passe</h2>
<p>Vous avez demandé la réinitialisation de votre mot de passe.</p>
<p>Cliquez sur le lien ci-dessous pour définir un nouveau mot de passe :</p>
<p><a href="{reset_url}">Réinitialiser mon mot de passe</a></p>
<p>Ce lien est valable pendant 24 heures.</p>
<p>Si vous n'avez pas demandé cette réinitialisation, ignorez cet email.</p>
</body>
</html>
"""
return send_email(email, subject, html_content)
# Fonction pour initier le processus de réinitialisation du mot de passe
def initiate_password_reset(email: str) -> tuple[bool, str]:
"""
Initie le processus de réinitialisation de mot de passe.
"""
try:
# Vérifier si l'utilisateur existe
user = supabase.table("users").select("id").eq("email", email).execute()
if not user.data:
return False, "Aucun compte associé à cet email."
user_id = user.data[0]['id']
success, token = create_reset_token(user_id)
if not success:
return False, "Erreur lors de la création du token."
# Construire l'URL de réinitialisation de manière sécurisée
base_url = os.getenv('APP_URL', '').rstrip('/')
# Nettoyer l'URL de base
if base_url.startswith('http://'):
base_url = base_url[7:]
elif base_url.startswith('https://'):
base_url = base_url[8:]
base_url = base_url.strip('/')
reset_url = f"http://{base_url}/reset_password?token={token}"
# Envoyer l'email
if send_reset_email(email, reset_url):
return True, "Instructions envoyées par email."
return False, "Erreur lors de l'envoi de l'email."
except Exception as e:
log_to_file(f"Erreur lors de l'initiation de la réinitialisation : {str(e)}")
return False, "Une erreur est survenue."
# Fonction pour vérifier la validité d'un token de réinitialisation
def verify_reset_token(token: str) -> tuple[bool, int]:
"""
Vérifie la validité d'un token de réinitialisation.
"""
try:
response = supabase.table("user_tokens").select("*").eq(
"token", token
).eq("type", "reset_password").eq("used", False).execute()
if not response.data:
return False, 0
token_data = response.data[0]
expires_at = datetime.fromisoformat(token_data['expires_at'].replace('Z', '+00:00'))
if expires_at < datetime.now(pytz.UTC):
return False, 0
return True, token_data['user_id']
except Exception as e:
log_to_file(f"Erreur lors de la vérification du token : {str(e)}")
return False, 0
# Fonction pour réinitialiser le mot de passe avec le token de réinitialisation
def reset_password(token: str, new_password: str) -> tuple[bool, str]:
"""
Réinitialise le mot de passe avec le token.
"""
try:
valid, user_id = verify_reset_token(token)
if not valid:
return False, "Token invalide ou expiré."
# Hasher le nouveau mot de passe
hashed_password = bcrypt.hashpw(new_password.encode(), bcrypt.gensalt()).decode()
# Mettre à jour le mot de passe
supabase.table("users").update({
"password": hashed_password
}).eq("id", user_id).execute()
# Marquer le token comme utilisé
supabase.table("user_tokens").update({
"used": True
}).eq("token", token).execute()
return True, "Mot de passe mis à jour avec succès."
except Exception as e:
log_to_file(f"Erreur lors de la réinitialisation du mot de passe : {str(e)}")
return False, "Une erreur est survenue." |