This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

tools.pinentry-rofi-age: add rofi-based PIN prompt for age-plugin-tpm

- use session keyring (@s) instead of user keyring (@u) for caching
- use keyctl padd instead of keyctl add to avoid PIN in /proc/*/cmdline
- make keyctl timeout failures non-fatal
- reject empty PIN input
- "Clear cache" falls through to re-prompt instead of aborting
- integrate with pass wrapper via maybe_set_tpm_pin
- apply same keyring and security fixes to tools.pinentry-rofi

+154 -7
+25
tools/pass/flake-module.nix
··· 16 16 pkgs.age-plugin-tpm 17 17 self.packages.${system}.pass-otp 18 18 self.packages.${system}.age-detect 19 + self.packages.${system}.pinentry-rofi-age 19 20 ] 20 21 ++ (pkgs.lib.optionals pkgs.stdenv.isDarwin [ 21 22 pkgs.age-plugin-se ··· 65 66 fi 66 67 fi 67 68 69 + maybe_set_tpm_pin() { 70 + local target="''${1:-<stdin>}" 71 + if [[ "''${KEY_TYPE:-}" != "tpm" ]]; then 72 + return 0 73 + fi 74 + if [[ -n "''${AGE_TPM_PIN:-}" ]]; then 75 + return 0 76 + fi 77 + AGE_TPM_PIN="$(${self.packages.${system}.pinentry-rofi-age}/bin/pinentry-rofi-age "$target")" 78 + export AGE_TPM_PIN 79 + } 80 + 81 + decrypt_target="" 82 + if [[ "''${1:-}" == "show" ]]; then 83 + decrypt_target="''${2:-}" 84 + elif [[ -n "''${1:-}" ]] && [[ "''${1:-}" != -* ]] && [[ "''${1:-}" != "otp" ]]; then 85 + decrypt_target="''${1:-}" 86 + fi 87 + 88 + if [[ -n "$decrypt_target" ]]; then 89 + maybe_set_tpm_pin "$decrypt_target" 90 + fi 91 + 68 92 # Handle OTP commands by delegating to pass-otp 69 93 if [[ "''${1:-}" == "otp" ]]; then 70 94 shift ··· 88 112 fi 89 113 90 114 # Show pass and pipe to OTP (identities already set up by age-detect) 115 + maybe_set_tpm_pin "$pass_name" 91 116 ${exePath} show "$pass_name" | pass-otp $clip_arg 92 117 else 93 118 # Pass all other commands directly to passage (identities already set up)
+16
tools/pinentry-rofi-age/flake-module.nix
··· 1 + { 2 + perSystem = 3 + { pkgs, ... }: 4 + { 5 + packages.pinentry-rofi-age = pkgs.writeShellApplication { 6 + name = "pinentry-rofi-age"; 7 + runtimeInputs = with pkgs; [ 8 + rofi 9 + coreutils 10 + gnused 11 + keyutils 12 + ]; 13 + text = builtins.readFile ./pinentry-rofi-age.sh; 14 + }; 15 + }; 16 + }
+102
tools/pinentry-rofi-age/pinentry-rofi-age.sh
··· 1 + #!/usr/bin/env bash 2 + # pinentry-rofi-age: A rofi-based pinentry for age-plugin-tpm 3 + # Shows the file being decrypted and caches PIN in kernel keyring 4 + set -efu 5 + 6 + CACHE_KEY="pinentry-rofi-age-pin" 7 + CACHE_TIMEOUT=300 # 5 minutes 8 + 9 + # Get cached PIN from kernel keyring 10 + get_cached_pin() { 11 + local key_id 12 + key_id=$(keyctl search @s user "$CACHE_KEY" 2>/dev/null) || return 1 13 + keyctl pipe "$key_id" 2>/dev/null 14 + } 15 + 16 + # Store PIN in kernel keyring with timeout 17 + cache_pin() { 18 + local pin="$1" 19 + keyctl purge user "$CACHE_KEY" >/dev/null 2>&1 || true 20 + local key_id 21 + key_id=$(printf '%s' "$pin" | keyctl padd user "$CACHE_KEY" @s) || return 0 22 + keyctl timeout "$key_id" "$CACHE_TIMEOUT" || true 23 + } 24 + 25 + # Extend cache timeout (sliding window) 26 + extend_cache() { 27 + local key_id 28 + key_id=$(keyctl search @s user "$CACHE_KEY" 2>/dev/null) || return 0 29 + keyctl timeout "$key_id" "$CACHE_TIMEOUT" || true 30 + } 31 + 32 + # Clear cached PIN 33 + clear_cache() { 34 + keyctl purge user "$CACHE_KEY" >/dev/null 2>&1 || true 35 + } 36 + 37 + # Escape string for pango markup 38 + escape_pango() { 39 + sed 's/&/\&amp;/g; s/</\&lt;/g; s/>/\&gt;/g' 40 + } 41 + 42 + # Determine target for display 43 + raw_target="${1:-<stdin>}" 44 + target=$(printf "%s" "$raw_target" | escape_pango) 45 + 46 + # Build the rofi message 47 + mesg="<b>Decrypt:</b> 48 + $target" 49 + mesg_args=(-mesg "$mesg") 50 + 51 + # Determine theme 52 + theme_file="/var/theme/config/rofi-theme" 53 + theme_args=() 54 + if [[ -r "$theme_file" ]]; then 55 + theme=$(cat "$theme_file") 56 + theme_args=(-theme "$theme") 57 + fi 58 + 59 + # Check for cached PIN 60 + cached_pin="" 61 + if cached_pin=$(get_cached_pin 2>/dev/null) && [[ -n "$cached_pin" ]]; then 62 + choice=$(printf "OK\nCancel\nClear cache" | rofi -dmenu \ 63 + -i \ 64 + -no-custom \ 65 + -no-fixed-num-lines \ 66 + "${mesg_args[@]}" \ 67 + "${theme_args[@]}" \ 68 + 2>/dev/null) || exit 1 69 + 70 + case "$choice" in 71 + "OK") 72 + extend_cache 73 + echo "$cached_pin" 74 + exit 0 75 + ;; 76 + "Cancel") 77 + exit 1 78 + ;; 79 + "Clear cache") 80 + clear_cache 81 + # Fall through to password prompt below 82 + ;; 83 + esac 84 + fi 85 + 86 + # Use rofi in password mode 87 + result=$(rofi -dmenu \ 88 + -password \ 89 + -p "TPM PIN" \ 90 + -lines 0 \ 91 + -no-fixed-num-lines \ 92 + "${mesg_args[@]}" \ 93 + "${theme_args[@]}" \ 94 + < /dev/null 2>/dev/null) || exit 1 95 + 96 + if [[ -z "$result" ]]; then 97 + exit 1 98 + fi 99 + 100 + cache_pin "$result" 101 + 102 + echo "$result"
+11 -7
tools/pinentry-rofi/pinentry-rofi.sh
··· 10 10 # Get cached PIN from kernel keyring 11 11 get_cached_pin() { 12 12 local key_id 13 - key_id=$(keyctl search @u user "$CACHE_KEY" 2>/dev/null) || return 1 13 + key_id=$(keyctl search @s user "$CACHE_KEY" 2>/dev/null) || return 1 14 14 keyctl pipe "$key_id" 2>/dev/null 15 15 } 16 16 ··· 19 19 local pin="$1" 20 20 # Remove old key if exists 21 21 keyctl purge user "$CACHE_KEY" >/dev/null 2>&1 || true 22 - # Add new key with timeout 22 + # Add new key with timeout (using padd to avoid PIN in /proc/*/cmdline) 23 23 local key_id 24 - key_id=$(keyctl add user "$CACHE_KEY" "$pin" @u) 25 - keyctl timeout "$key_id" "$CACHE_TIMEOUT" 24 + key_id=$(printf '%s' "$pin" | keyctl padd user "$CACHE_KEY" @s) || return 0 25 + keyctl timeout "$key_id" "$CACHE_TIMEOUT" || true 26 26 } 27 27 28 28 # Extend cache timeout (sliding window) 29 29 extend_cache() { 30 30 local key_id 31 - key_id=$(keyctl search @u user "$CACHE_KEY" 2>/dev/null) || return 1 32 - keyctl timeout "$key_id" "$CACHE_TIMEOUT" 31 + key_id=$(keyctl search @s user "$CACHE_KEY" 2>/dev/null) || return 0 32 + keyctl timeout "$key_id" "$CACHE_TIMEOUT" || true 33 33 } 34 34 35 35 # Clear cached PIN ··· 126 126 ;; 127 127 "Clear cache") 128 128 clear_cache 129 - exit 1 129 + # Fall through to password prompt below 130 130 ;; 131 131 esac 132 132 fi ··· 140 140 "${mesg_args[@]}" \ 141 141 "${theme_args[@]}" \ 142 142 < /dev/null 2>/dev/null) || exit 1 143 + 144 + if [[ -z "$result" ]]; then 145 + exit 1 146 + fi 143 147 144 148 # Cache the PIN 145 149 cache_pin "$result"