"""Émission de jetons d'auto-inscription (flux "kubeadm join", voir ROADMAP.md et banevents/views.py::join_node) — factorisé pour être appelé à la fois par `manage.py create_join_token` (CLI, décision humaine directe) et par `EnrollmentRequestAdmin.approve_and_send_token` (validation d'une demande soumise via /communaute/) : un seul endroit qui touche le hachage/l'expiration du jeton. """ import datetime import hashlib import os import secrets from django.utils import timezone from .models import JoinToken DEFAULT_TTL_MINUTES = 60 def issue_join_token(node_name: str, ttl_minutes: int = DEFAULT_TTL_MINUTES) -> tuple[str, JoinToken]: """Génère un jeton en clair (jamais persisté tel quel) + l'objet JoinToken correspondant (seul le hash SHA-256 est stocké).""" token = secrets.token_urlsafe(32) token_hash = hashlib.sha256(token.encode('utf-8')).hexdigest() expires_at = timezone.now() + datetime.timedelta(minutes=ttl_minutes) join_token = JoinToken.objects.create(node_name=node_name, token_hash=token_hash, expires_at=expires_at) return token, join_token def join_command(node_name: str, token: str) -> str: """Commande complète à communiquer (CLI ou email) — DASHBOARD_DOMAIN déjà chargé dans os.environ par python-dotenv (cf. settings/base.py).""" master_url = os.environ.get('DASHBOARD_DOMAIN', '') master_url = f'https://{master_url}' if master_url else '' return f'sudo make join MASTER={master_url} NODE={node_name} TOKEN={token}'