diff --git a/modules/yubikey-first-login.nix b/modules/yubikey-first-login.nix index ad979c7..e2d9407 100644 --- a/modules/yubikey-first-login.nix +++ b/modules/yubikey-first-login.nix @@ -11,8 +11,33 @@ let state_dir="$HOME/.local/state/nixos-workstations" marker="$state_dir/yubikey-pin-initialized" + runtime_dir="''${XDG_RUNTIME_DIR:-/tmp}" + active_file="$runtime_dir/nixos-workstations-yubikey-first-login.active" + # ---------------------------------------------------------- - # Couleurs ANSI + # Déclare l'assistant comme actif. + # On stocke son PID pour permettre au superviseur + # de savoir s'il tourne réellement. + # ---------------------------------------------------------- + + printf '%s\n' "$$" > "$active_file" + + cleanup() { + rm -f "$active_file" + } + + 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" @@ -26,121 +51,71 @@ let GREY="\033[38;5;245m" WHITE="\033[38;5;255m" - # ---------------------------------------------------------- - # Fonctions d'affichage - # ---------------------------------------------------------- - separator() { printf "''${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━''${RESET}\n" } - header() { - printf "\033[2J\033[H" - - echo - separator - echo - printf " ''${BOLD}''${CYAN}🔐 INITIALISATION DE VOTRE YUBIKEY''${RESET}\n" - echo - separator - echo - } - - step() { - number="$1" - text="$2" - - printf " ''${BOLD}''${CYAN}[%s]''${RESET} ''${WHITE}%s''${RESET}\n" \ - "$number" "$text" - } - - info() { - printf " ''${GREY}%s''${RESET}\n" "$1" - } - - success() { - echo - separator - echo - printf " ''${BOLD}''${GREEN}✔ INITIALISATION TERMINÉE''${RESET}\n" - echo - separator - echo - } - - failure() { - echo - separator - echo - printf " ''${BOLD}''${RED}✖ INITIALISATION NON TERMINÉE''${RESET}\n" - echo - separator - echo - } - # ---------------------------------------------------------- - # Déjà initialisé + # Nettoyage de l'écran # ---------------------------------------------------------- - if [ -e "$marker" ]; then - exit 0 - fi + printf "\033[2J\033[H" - # ---------------------------------------------------------- - # Annulation / interruption - # ---------------------------------------------------------- - - trap ' - printf "\n\n" - printf "''${RED}Initialisation interrompue.''${RESET}\n" - exit 130 - ' INT TERM - - # ---------------------------------------------------------- - # Écran d'accueil - # ---------------------------------------------------------- - - header + echo + separator + echo + printf " ''${BOLD}''${CYAN}🔐 INITIALISATION DE VOTRE YUBIKEY''${RESET}\n" + echo + separator + echo printf " ''${WHITE}Bienvenue.''${RESET}\n" echo - printf " Pour sécuriser votre accès au poste, vous devez personnaliser\n" - printf " le ''${BOLD}PIN de votre YubiKey''${RESET}.\n" + + 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 - step "1/3" "Munissez-vous du PIN temporaire fourni par le service informatique." + # ---------------------------------------------------------- + # É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 - step "2/3" "Choisissez un nouveau PIN personnel." - info "Ne réutilisez pas le PIN temporaire." + 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 - step "3/3" "Confirmez votre nouveau PIN." + printf " ''${BOLD}''${CYAN}[3/3]''${RESET} ''${WHITE}Confirmez votre nouveau PIN.''${RESET}\n" echo separator echo - printf " ''${GREY}Le PIN est enregistré directement dans votre YubiKey.''${RESET}\n" - printf " ''${GREY}Il n'est ni enregistré sur le poste, ni envoyé au service informatique.''${RESET}\n" + 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" echo separator echo - printf " ''${BOLD}''${WHITE}Insérez votre YubiKey et suivez les instructions.''${RESET}\n" + printf " ''${BOLD}''${YELLOW}IMPORTANT''${RESET}\n" echo - printf " ''${YELLOW}Ne fermez pas cette fenêtre.''${RESET}\n" + 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" echo separator echo - # Petite pause pour que l'utilisateur lise l'écran - ${pkgs.coreutils}/bin/sleep 2 + printf " ''${BOLD}''${WHITE}Suivez maintenant les instructions ci-dessous.''${RESET}\n" + echo # ---------------------------------------------------------- # Changement du PIN @@ -148,25 +123,42 @@ let if ${pkgs.yubikey-manager}/bin/ykman fido access change-pin; then + # -------------------------------------------------------- + # Succès + # # IMPORTANT : - # le marqueur n'est créé qu'après retour positif de ykman. + # 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" - success + echo + separator + echo + + printf " ''${BOLD}''${GREEN}✔ INITIALISATION TERMINÉE''${RESET}\n" + + echo + separator + echo printf " ''${GREEN}Votre nouveau PIN est maintenant actif.''${RESET}\n" echo - printf " Utilisez désormais ce PIN pour vous connecter\n" - printf " avec votre YubiKey.\n" + + printf " Utilisez désormais ce nouveau PIN pour vous\n" + printf " connecter avec votre YubiKey.\n" + echo printf " ''${GREY}Cette procédure ne sera plus affichée.''${RESET}\n" - echo + echo separator echo printf " Fermeture automatique" + for i in 1 2 3 4 5; do printf "." ${pkgs.coreutils}/bin/sleep 1 @@ -177,33 +169,45 @@ let else - failure + # -------------------------------------------------------- + # Échec / annulation + # + # Aucun marqueur n'est créé. + # Le superviseur relancera automatiquement l'assistant. + # -------------------------------------------------------- - printf " ''${RED}Le PIN de la YubiKey n'a pas été modifié.''${RESET}\n" echo - printf " Votre session va être fermée afin de protéger\n" - printf " l'accès au poste.\n" - echo - printf " ''${YELLOW}La procédure sera automatiquement reproposée''${RESET}\n" - printf " ''${YELLOW}à votre prochaine connexion.''${RESET}\n" - echo - separator echo - printf " Fermeture de la session" - for i in 1 2 3; do - printf "." - ${pkgs.coreutils}/bin/sleep 1 - done + printf " ''${BOLD}''${RED}✖ INITIALISATION NON TERMINÉE''${RESET}\n" echo + separator + echo + + 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 ''; # ============================================================ - # Superviseur + # Superviseur de première connexion # ============================================================ yubikeyFirstLoginSupervisor = @@ -212,7 +216,10 @@ let current_user="$(${pkgs.coreutils}/bin/id -un)" + # -------------------------------------------------------- # Pour le moment, uniquement Alice. + # -------------------------------------------------------- + if [ "$current_user" != "alice" ]; then exit 0 fi @@ -220,52 +227,96 @@ let state_dir="$HOME/.local/state/nixos-workstations" marker="$state_dir/yubikey-pin-initialized" - # Initialisation déjà effectuée. + 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" + + # -------------------------------------------------------- + # 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 exit 0 fi - # Laisse KDE terminer son démarrage. - ${pkgs.coreutils}/bin/sleep 3 + # Laisse Plasma terminer son démarrage. + ${pkgs.coreutils}/bin/sleep 4 # -------------------------------------------------------- - # Assistant plein écran + # Boucle de supervision # -------------------------------------------------------- - ${pkgs.kdePackages.konsole}/bin/konsole \ - --separate \ - --fullscreen \ - --hide-menubar \ - --hide-tabbar \ - -e ${yubikeyPinChange} + while [ ! -e "$marker" ]; do + + assistant_running=0 + + # ------------------------------------------------------ + # Vérifie si l'assistant précédemment lancé tourne + # réellement toujours. + # ------------------------------------------------------ + + if [ -s "$active_file" ]; then + + assistant_pid="$(${pkgs.coreutils}/bin/cat "$active_file" 2>/dev/null || true)" + + if [ -n "$assistant_pid" ] \ + && ${pkgs.coreutils}/bin/kill -0 "$assistant_pid" 2>/dev/null; then + + assistant_running=1 + + else + + # Fichier devenu obsolète. + rm -f "$active_file" + + fi + fi + + # ------------------------------------------------------ + # Aucun assistant actif : + # on en ouvre un. + # ------------------------------------------------------ + + if [ "$assistant_running" -eq 0 ]; then + + ${pkgs.kdePackages.konsole}/bin/konsole \ + --separate \ + --fullscreen \ + --hide-menubar \ + --hide-tabbar \ + -e ${yubikeyPinChange} \ + >/dev/null 2>&1 & + + # Laisse le temps à Konsole et au script de démarrer. + ${pkgs.coreutils}/bin/sleep 2 + + else + + ${pkgs.coreutils}/bin/sleep 2 + + fi + + done # -------------------------------------------------------- - # L'assistant vient de se terminer. - # -------------------------------------------------------- - - if [ -e "$marker" ]; then - # PIN correctement changé. - exit 0 - fi - - # Pas de marqueur : + # Le marqueur existe : + # l'initialisation est terminée. # - # - utilisateur ayant fermé la fenêtre ; - # - Ctrl+C ; - # - erreur ykman ; - # - changement du PIN abandonné. - # - # Dans tous ces cas, on ferme la session d'Alice. + # On ne touche PAS à la session KDE. + # -------------------------------------------------------- - session_id="''${XDG_SESSION_ID:-}" - - if [ -n "$session_id" ]; then - ${pkgs.systemd}/bin/loginctl terminate-session "$session_id" - else - ${pkgs.systemd}/bin/loginctl terminate-user "$current_user" - fi - - exit 1 + exit 0 ''; in