From adf44ca2fe06ab252288dafd676b5260fbd3d14d Mon Sep 17 00:00:00 2001 From: Olivier <1+olivier@noreply.raspot.in> Date: Tue, 18 Aug 2026 14:33:45 +0200 Subject: [PATCH] Actualiser modules/yubikey-first-login.nix --- modules/yubikey-first-login.nix | 490 ++++++++++++++++++-------------- 1 file changed, 279 insertions(+), 211 deletions(-) diff --git a/modules/yubikey-first-login.nix b/modules/yubikey-first-login.nix index e2d9407..52c7efd 100644 --- a/modules/yubikey-first-login.nix +++ b/modules/yubikey-first-login.nix @@ -1,24 +1,16 @@ { pkgs, ... }: let - # ============================================================ - # Assistant interactif de changement du PIN YubiKey - # ============================================================ - - yubikeyPinChange = pkgs.writeShellScript "yubikey-pin-change" '' + firstLoginSetup = pkgs.writeShellScript "first-login-setup" '' set -u state_dir="$HOME/.local/state/nixos-workstations" - marker="$state_dir/yubikey-pin-initialized" + + password_marker="$state_dir/password-initialized" + yubikey_marker="$state_dir/yubikey-pin-initialized" runtime_dir="''${XDG_RUNTIME_DIR:-/tmp}" - active_file="$runtime_dir/nixos-workstations-yubikey-first-login.active" - - # ---------------------------------------------------------- - # Déclare l'assistant comme actif. - # On stocke son PID pour permettre au superviseur - # de savoir s'il tourne réellement. - # ---------------------------------------------------------- + active_file="$runtime_dir/nixos-workstations-first-login.active" printf '%s\n' "$$" > "$active_file" @@ -28,22 +20,13 @@ let trap cleanup EXIT HUP INT TERM - # ---------------------------------------------------------- - # Si l'initialisation a déjà été effectuée, rien à faire. - # ---------------------------------------------------------- - - if [ -e "$marker" ]; then - exit 0 - fi - - # ---------------------------------------------------------- + # ========================================================== # Couleurs - # ---------------------------------------------------------- + # ========================================================== RESET="\033[0m" BOLD="\033[1m" - BLUE="\033[38;5;39m" CYAN="\033[38;5;45m" GREEN="\033[38;5;82m" YELLOW="\033[38;5;220m" @@ -51,286 +34,371 @@ let GREY="\033[38;5;245m" WHITE="\033[38;5;255m" - separator() { - printf "''${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━''${RESET}\n" + line() { + printf "''${GREY}────────────────────────────────────────────────────────────''${RESET}\n" } - # ---------------------------------------------------------- - # Nettoyage de l'écran - # ---------------------------------------------------------- - - printf "\033[2J\033[H" + clear echo - separator echo - printf " ''${BOLD}''${CYAN}🔐 INITIALISATION DE VOTRE YUBIKEY''${RESET}\n" + printf " ''${BOLD}''${CYAN}CONFIGURATION DE VOTRE COMPTE''${RESET}\n" echo - separator + line echo - printf " ''${WHITE}Bienvenue.''${RESET}\n" + printf " Bienvenue ''${BOLD}Alice''${RESET}.\n" echo - - printf " Pour sécuriser votre accès au poste, vous devez maintenant\n" - printf " personnaliser le ''${BOLD}PIN de votre YubiKey''${RESET}.\n" - echo - - printf " ''${YELLOW}⚠ Cette opération est obligatoire.''${RESET}\n" - echo - - # ---------------------------------------------------------- - # Étapes - # ---------------------------------------------------------- - - printf " ''${BOLD}''${CYAN}[1/3]''${RESET} ''${WHITE}Saisissez votre PIN temporaire.''${RESET}\n" - printf " ''${GREY}Il vous a été communiqué avec votre poste.''${RESET}\n" - echo - - printf " ''${BOLD}''${CYAN}[2/3]''${RESET} ''${WHITE}Choisissez votre nouveau PIN personnel.''${RESET}\n" - printf " ''${GREY}Ne réutilisez pas le PIN temporaire.''${RESET}\n" - echo - - printf " ''${BOLD}''${CYAN}[3/3]''${RESET} ''${WHITE}Confirmez votre nouveau PIN.''${RESET}\n" - echo - - separator - echo - - printf " ''${GREY}Votre nouveau PIN est enregistré directement dans la YubiKey.''${RESET}\n" - printf " ''${GREY}Il n'est pas enregistré dans la configuration du poste.''${RESET}\n" + printf " Cette procédure termine la préparation de votre poste.\n" + printf " Elle ne sera effectuée qu'une seule fois.\n" echo - separator + line echo - printf " ''${BOLD}''${YELLOW}IMPORTANT''${RESET}\n" - echo - printf " • Ne fermez pas cette fenêtre pendant l'opération.\n" - printf " • Vérifiez l'état de ''${BOLD}Verr Num''${RESET} si vous utilisez le pavé numérique.\n" - printf " • En cas de doute, utilisez les chiffres situés au-dessus du clavier.\n" + # ========================================================== + # ÉTAPE 1 : MOT DE PASSE LOCAL + # ========================================================== - echo - separator - echo - - printf " ''${BOLD}''${WHITE}Suivez maintenant les instructions ci-dessous.''${RESET}\n" - echo - - # ---------------------------------------------------------- - # Changement du PIN - # ---------------------------------------------------------- - - if ${pkgs.yubikey-manager}/bin/ykman fido access change-pin; then - - # -------------------------------------------------------- - # Succès - # - # IMPORTANT : - # le marqueur est créé immédiatement après le succès - # confirmé par ykman. - # -------------------------------------------------------- - - ${pkgs.coreutils}/bin/mkdir -p "$state_dir" - ${pkgs.coreutils}/bin/touch "$marker" + if [ ! -e "$password_marker" ]; then + printf " ''${BOLD}''${CYAN}ÉTAPE 1 / 2''${RESET}\n" echo - separator + printf " ''${BOLD}Choisissez votre mot de passe de secours''${RESET}\n" echo - printf " ''${BOLD}''${GREEN}✔ INITIALISATION TERMINÉE''${RESET}\n" + printf " Ce mot de passe permet notamment d'accéder au poste\n" + printf " si votre YubiKey est indisponible.\n" echo - separator + printf " ''${YELLOW}Vous allez saisir :''${RESET}\n" echo - - printf " ''${GREEN}Votre nouveau PIN est maintenant actif.''${RESET}\n" - echo - - printf " Utilisez désormais ce nouveau PIN pour vous\n" - printf " connecter avec votre YubiKey.\n" + printf " ① votre mot de passe temporaire actuel\n" + printf " ② votre nouveau mot de passe personnel\n" + printf " ③ une confirmation du nouveau mot de passe\n" echo - printf " ''${GREY}Cette procédure ne sera plus affichée.''${RESET}\n" - - echo - separator + line echo - printf " Fermeture automatique" + if ${pkgs.shadow}/bin/passwd; then - for i in 1 2 3 4 5; do - printf "." - ${pkgs.coreutils}/bin/sleep 1 - done + ${pkgs.coreutils}/bin/mkdir -p "$state_dir" + ${pkgs.coreutils}/bin/touch "$password_marker" - echo - exit 0 + echo + printf " ''${GREEN}✓ Mot de passe modifié avec succès.''${RESET}\n" + echo - else + ${pkgs.coreutils}/bin/sleep 2 - # -------------------------------------------------------- - # Échec / annulation - # - # Aucun marqueur n'est créé. - # Le superviseur relancera automatiquement l'assistant. - # -------------------------------------------------------- + else - echo - separator - echo + echo + printf " ''${RED}✗ Le changement du mot de passe a échoué.''${RESET}\n" + echo + printf " La procédure sera automatiquement reproposée.\n" - printf " ''${BOLD}''${RED}✖ INITIALISATION NON TERMINÉE''${RESET}\n" + ${pkgs.coreutils}/bin/sleep 3 - echo - separator - echo + exit 1 + fi - printf " ''${RED}Le PIN n'a pas été modifié.''${RESET}\n" - echo - - printf " La fenêtre va être fermée puis l'assistant\n" - printf " sera automatiquement relancé.\n" - - echo - printf " ''${YELLOW}Vous devez terminer cette procédure''${RESET}\n" - printf " ''${YELLOW}pour finaliser l'initialisation de votre YubiKey.''${RESET}\n" - - echo - separator - echo - - ${pkgs.coreutils}/bin/sleep 4 - - exit 1 fi + + # ========================================================== + # ÉTAPE 2 : PIN YUBIKEY + # ========================================================== + + clear + + echo + echo + printf " ''${BOLD}''${CYAN}CONFIGURATION DE VOTRE COMPTE''${RESET}\n" + echo + line + echo + + printf " ''${BOLD}''${CYAN}ÉTAPE 2 / 2''${RESET}\n" + echo + printf " ''${BOLD}Personnalisez le PIN de votre YubiKey''${RESET}\n" + echo + + printf " Votre clé utilise actuellement le PIN temporaire fourni\n" + printf " lors de la préparation du poste.\n" + + echo + printf " ''${YELLOW}Vous allez saisir :''${RESET}\n" + echo + printf " ① votre PIN temporaire actuel\n" + printf " ② votre nouveau PIN personnel\n" + printf " ③ une confirmation du nouveau PIN\n" + + echo + printf " ''${GREY}Le nouveau PIN reste enregistré uniquement dans la YubiKey.''${RESET}\n" + + echo + printf " ''${YELLOW}⚠ Vérifiez Verr Num si vous utilisez le pavé numérique.''${RESET}\n" + printf " En cas de doute, utilisez les chiffres situés au-dessus du clavier.\n" + + echo + line + echo + + if [ ! -e "$yubikey_marker" ]; then + + if ${pkgs.yubikey-manager}/bin/ykman fido access change-pin; then + + ${pkgs.coreutils}/bin/mkdir -p "$state_dir" + ${pkgs.coreutils}/bin/touch "$yubikey_marker" + + echo + printf " ''${GREEN}✓ PIN YubiKey modifié avec succès.''${RESET}\n" + + ${pkgs.coreutils}/bin/sleep 2 + + else + + echo + printf " ''${RED}✗ Le changement du PIN n'a pas été terminé.''${RESET}\n" + echo + printf " Votre mot de passe déjà modifié sera conservé.\n" + printf " Seule cette étape sera reproposée.\n" + + ${pkgs.coreutils}/bin/sleep 3 + + exit 1 + fi + + fi + + # ========================================================== + # TERMINÉ + # ========================================================== + + clear + + echo + echo + line + echo + + printf " ''${BOLD}''${GREEN}✓ CONFIGURATION TERMINÉE''${RESET}\n" + + echo + line + echo + + printf " Votre compte est maintenant prêt.\n" + echo + + printf " ''${GREEN}✓''${RESET} Mot de passe personnel configuré\n" + printf " ''${GREEN}✓''${RESET} PIN personnel YubiKey configuré\n" + + echo + echo + + printf " Pour vos prochaines connexions :\n" + echo + printf " ''${BOLD}YubiKey + votre PIN personnel''${RESET}\n" + + echo + printf " Votre mot de passe local reste disponible comme solution\n" + printf " de secours.\n" + + echo + line + echo + + printf " Fermeture automatique" + + for i in 1 2 3 4 5; do + printf "." + ${pkgs.coreutils}/bin/sleep 1 + done + + echo + exit 0 ''; - # ============================================================ - # Superviseur de première connexion - # ============================================================ - - yubikeyFirstLoginSupervisor = - pkgs.writeShellScript "yubikey-first-login-supervisor" '' + firstLoginSupervisor = + pkgs.writeShellScript "first-login-supervisor" '' set -u current_user="$(${pkgs.coreutils}/bin/id -un)" - # -------------------------------------------------------- - # Pour le moment, uniquement Alice. - # -------------------------------------------------------- - + # Pour le moment uniquement Alice. if [ "$current_user" != "alice" ]; then exit 0 fi state_dir="$HOME/.local/state/nixos-workstations" - marker="$state_dir/yubikey-pin-initialized" + + password_marker="$state_dir/password-initialized" + yubikey_marker="$state_dir/yubikey-pin-initialized" runtime_dir="''${XDG_RUNTIME_DIR:-/tmp}" - active_file="$runtime_dir/nixos-workstations-yubikey-first-login.active" - supervisor_lock="$runtime_dir/nixos-workstations-yubikey-first-login.lock" + active_file="$runtime_dir/nixos-workstations-first-login.active" + supervisor_lock="$runtime_dir/nixos-workstations-first-login.lock" + + KDIALOG="${pkgs.kdePackages.kdialog}/bin/kdialog" + KONSOLE="${pkgs.kdePackages.konsole}/bin/konsole" - # -------------------------------------------------------- # Une seule instance du superviseur. - # -------------------------------------------------------- - exec 9>"$supervisor_lock" if ! ${pkgs.util-linux}/bin/flock -n 9; then exit 0 fi - # -------------------------------------------------------- - # Initialisation déjà terminée. - # -------------------------------------------------------- - - if [ -e "$marker" ]; then + # Les deux opérations sont déjà terminées. + if [ -e "$password_marker" ] && [ -e "$yubikey_marker" ]; then exit 0 fi # Laisse Plasma terminer son démarrage. - ${pkgs.coreutils}/bin/sleep 4 + ${pkgs.coreutils}/bin/sleep 3 - # -------------------------------------------------------- - # Boucle de supervision - # -------------------------------------------------------- + # ======================================================== + # Présentation + # ======================================================== - while [ ! -e "$marker" ]; do + while \ + [ ! -e "$password_marker" ] || \ + [ ! -e "$yubikey_marker" ] + do - assistant_running=0 + "$KDIALOG" \ + --title "Finalisation de votre poste" \ + --warningcontinuecancel \ + "Bienvenue Alice. + +Votre poste est presque prêt. + +Pour terminer sa configuration, vous devez personnaliser deux éléments de sécurité : + + 🔑 Votre mot de passe local de secours + + 🔐 Le PIN de votre YubiKey + +Ces informations deviennent personnelles. + +Elles ne sont pas enregistrées dans Git et ne sont pas transmises au service informatique. + +La procédure prend seulement quelques instants." + + result=$? + + if [ "$result" -ne 0 ]; then + + "$KDIALOG" \ + --title "Configuration requise" \ + --sorry \ + "La configuration initiale de votre compte n'est pas terminée. + +L'assistant va être reproposé." + + ${pkgs.coreutils}/bin/sleep 1 + continue + fi # ------------------------------------------------------ - # Vérifie si l'assistant précédemment lancé tourne - # réellement toujours. + # Lance l'assistant interactif # ------------------------------------------------------ - if [ -s "$active_file" ]; then + "$KONSOLE" \ + --separate \ + --fullscreen \ + --hide-menubar \ + --hide-tabbar \ + -e ${firstLoginSetup} \ + >/dev/null 2>&1 & - assistant_pid="$(${pkgs.coreutils}/bin/cat "$active_file" 2>/dev/null || true)" + ${pkgs.coreutils}/bin/sleep 1 - if [ -n "$assistant_pid" ] \ - && ${pkgs.coreutils}/bin/kill -0 "$assistant_pid" 2>/dev/null; then + # ------------------------------------------------------ + # Attend la fin réelle du script. + # ------------------------------------------------------ - assistant_running=1 - - else - - # Fichier devenu obsolète. - rm -f "$active_file" + while true; do + if [ \ + -e "$password_marker" \ + ] && [ \ + -e "$yubikey_marker" \ + ]; then + break fi - fi + + if [ ! -s "$active_file" ]; then + break + fi + + assistant_pid="$( + ${pkgs.coreutils}/bin/cat "$active_file" 2>/dev/null || true + )" + + if [ -z "$assistant_pid" ]; then + break + fi + + if ! ${pkgs.coreutils}/bin/kill -0 "$assistant_pid" 2>/dev/null; then + rm -f "$active_file" + break + fi + + ${pkgs.coreutils}/bin/sleep 1 + done # ------------------------------------------------------ - # Aucun assistant actif : - # on en ouvre un. + # Tout est terminé. # ------------------------------------------------------ - if [ "$assistant_running" -eq 0 ]; then + if [ \ + -e "$password_marker" \ + ] && [ \ + -e "$yubikey_marker" \ + ]; then - ${pkgs.kdePackages.konsole}/bin/konsole \ - --separate \ - --fullscreen \ - --hide-menubar \ - --hide-tabbar \ - -e ${yubikeyPinChange} \ - >/dev/null 2>&1 & + "$KDIALOG" \ + --title "Poste configuré" \ + --msgbox \ + "✓ Votre poste est prêt. - # Laisse le temps à Konsole et au script de démarrer. - ${pkgs.coreutils}/bin/sleep 2 +Votre mot de passe personnel et le PIN de votre YubiKey ont été configurés. - else +Pour vos prochaines connexions, utilisez votre YubiKey et votre nouveau PIN. - ${pkgs.coreutils}/bin/sleep 2 +Votre mot de passe local reste disponible comme solution de secours." + exit 0 fi + "$KDIALOG" \ + --title "Configuration incomplète" \ + --sorry \ + "La configuration n'a pas été entièrement terminée. + +Les étapes déjà réalisées sont conservées. + +L'assistant va reprendre uniquement les étapes restantes." + + ${pkgs.coreutils}/bin/sleep 1 + done - # -------------------------------------------------------- - # Le marqueur existe : - # l'initialisation est terminée. - # - # On ne touche PAS à la session KDE. - # -------------------------------------------------------- - exit 0 ''; in { - # ============================================================ - # Lancement automatique à l'ouverture de KDE - # ============================================================ - environment.etc."xdg/autostart/yubikey-first-login.desktop".text = '' [Desktop Entry] Type=Application - Name=Initialisation de la YubiKey - Comment=Configuration obligatoire de votre PIN personnel - Exec=${yubikeyFirstLoginSupervisor} + Name=Finalisation du poste + Comment=Configuration initiale du compte utilisateur + Exec=${firstLoginSupervisor} OnlyShowIn=KDE; NoDisplay=true StartupNotify=false