{ config, lib, pkgs, ... }: let cfg = config.security.pam.yubico; in { options.security.pam.yubico = { logoutOnRemove = lib.mkEnableOption "Logout on Yubikey remove"; asClient = lib.mkEnableOption "Use Yubikey as client"; clients = lib.mkOption { type = with lib.types; attrsOf (listOf str); example = { myUser = [ "myYubikeyTokenID" ]; }; default = {}; description = "The users that are allowed to use the Yubikey"; }; product_id = lib.mkOption { type = lib.types.str; default = "1050/407/543"; description = "The product id of the Yubikey"; }; }; config = lib.mkIf cfg.enable { systemd.tmpfiles.rules = let keysFiles = builtins.mapAttrs (n: v: pkgs.writeText "authorized_yubikeys_${n}" '' ${lib.concatStringsSep ":" ([ n ] ++ v)} '') cfg.clients; in if cfg.asClient then (builtins.concatMap (n: [ "d /home/${n}/.yubico 0655 ${n} users -" "L+ /home/${n}/.yubico/authorized_yubikeys 0644 ${n} users - ${keysFiles.${n}}" "Z /home/${n}/.yubico - root root" ]) (builtins.attrNames cfg.clients)) else [ "d /var/yubico 0700 root root -" ]; services.udev.extraRules = lib.mkIf (cfg.logoutOnRemove && !cfg.asClient) '' SUBSYSTEM=="usb", ACTION=="remove", ENV{PRODUCT}=="${cfg.product_id}", RUN+="${pkgs.systemd}/bin/loginctl lock-sessions" ''; security.pam = { services.hyprlock.yubicoAuth = lib.mkIf config.programs.hyprlock.enable false; yubico = { id = "106508"; mode = if cfg.asClient then "client" else "challenge-response"; control = "required"; challengeResponsePath = lib.mkIf (!cfg.asClient) "/var/yubico"; }; }; }; }