This repository has no description
2.3 kB
102 lines
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
4set -efu
5
6CACHE_KEY="pinentry-rofi-age-pin"
7CACHE_TIMEOUT=300 # 5 minutes
8
9# Get cached PIN from kernel keyring
10get_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
17cache_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)
26extend_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
33clear_cache() {
34 keyctl purge user "$CACHE_KEY" >/dev/null 2>&1 || true
35}
36
37# Escape string for pango markup
38escape_pango() {
39 sed 's/&/\&/g; s/</\</g; s/>/\>/g'
40}
41
42# Determine target for display
43raw_target="${1:-<stdin>}"
44target=$(printf "%s" "$raw_target" | escape_pango)
45
46# Build the rofi message
47mesg="<b>Decrypt:</b>
48$target"
49mesg_args=(-mesg "$mesg")
50
51# Determine theme
52theme_file="/var/theme/config/rofi-theme"
53theme_args=()
54if [[ -r "$theme_file" ]]; then
55 theme=$(cat "$theme_file")
56 theme_args=(-theme "$theme")
57fi
58
59# Check for cached PIN
60cached_pin=""
61if 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
84fi
85
86# Use rofi in password mode
87result=$(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
96if [[ -z "$result" ]]; then
97 exit 1
98fi
99
100cache_pin "$result"
101
102echo "$result"