125 lines
3.8 KiB
Nix
125 lines
3.8 KiB
Nix
with import ./lib;
|
|
{ pkgs, ... }@args:
|
|
|
|
let
|
|
# config cannot be declared in the input attribute set because that would
|
|
# cause callPackage to inject the wrong config. Instead, get it from ...
|
|
# via args.
|
|
config = args.config or {};
|
|
|
|
cfg = eval.config;
|
|
|
|
eval = lib.evalModules {
|
|
modules = lib.singleton {
|
|
_file = toString ./default.nix;
|
|
imports = lib.singleton config;
|
|
options = {
|
|
appName = lib.mkOption {
|
|
default = "pinentry-urxvt";
|
|
type = lib.types.str;
|
|
};
|
|
display = lib.mkOption {
|
|
default = null;
|
|
type = lib.types.nullOr lib.types.str;
|
|
};
|
|
xwud.className = lib.mkOption {
|
|
default = "PinentryUrxvtXwudFloat";
|
|
type = lib.types.str;
|
|
};
|
|
};
|
|
};
|
|
};
|
|
|
|
|
|
in
|
|
|
|
# pinentry-urxvt - A mechanism for PIN entry utilizing rxvt-unicode
|
|
#
|
|
# This spawns a PIN entry terminal on top of a tinted screenshot of the
|
|
# current display's root window. The display for spawning the terminal can
|
|
# be predefined, in which case both the current and the predefined display
|
|
# will show the screenshot.
|
|
#
|
|
# The purpose of the screenshot, aside from looking nice, is to prevent entry
|
|
# of the PIN into the wrong window, e.g. by accidentally moving the cursor
|
|
# while typing. If necessary, the screenshot can be closed by sending 'q',
|
|
# 'Q', or ctrl-c while its focused.
|
|
#
|
|
pkgs.write "pinentry-urxvt" {
|
|
"/bin/pinentry".link = pkgs.writeDash "pinentry-urxvt-wrapper" ''
|
|
set -efu
|
|
|
|
trap cleanup EXIT
|
|
|
|
cleanup() {
|
|
${pkgs.utillinux}/bin/kill -- $(${pkgs.coreutils}/bin/cat "$displayers")
|
|
rm "$displayers"
|
|
rm "$screenshot"
|
|
}
|
|
|
|
displayers=$(${pkgs.coreutils}/bin/mktemp -t pinentry-urxvt.$$.displayers.XXXXXXXX)
|
|
screenshot=$(${pkgs.coreutils}/bin/mktemp -t pinentry-urxvt.$$.screenshot.XXXXXXXX)
|
|
|
|
${pkgs.xorg.xwd}/bin/xwd -root |
|
|
${pkgs.imagemagick}/bin/convert xwd:- -fill \#424242 -colorize 80% xwd:"$screenshot"
|
|
|
|
display_screenshot() {
|
|
${pkgs.exec "pinentry-urxvt.display_screenshot" {
|
|
filename = "${pkgs.xorg.xwud}/bin/xwud";
|
|
argv = [
|
|
cfg.xwud.className
|
|
"-noclick"
|
|
];
|
|
}} < "$screenshot" &
|
|
wait_for_screenshot $! && echo $! >>"$displayers"
|
|
}
|
|
|
|
# Wait for the xwud window by trying to intercept the call to munmap().
|
|
# If it cannot be intercepted within 0.1s, assume that attaching strace
|
|
# wasn't fast enough or xwud doesn't call munmap() anymore. In either
|
|
# case fall back to search the window by class name, assuming there can
|
|
# be only one per display.
|
|
wait_for_screenshot() {
|
|
if ! \
|
|
${pkgs.coreutils}/bin/timeout 0.1 \
|
|
${pkgs.strace}/bin/strace -p "$1" -e munmap 2>&1 |
|
|
read -r _
|
|
then
|
|
until ${pkgs.xdotool}/bin/xdotool search \
|
|
--classname ${lib.shell.escape cfg.xwud.className}
|
|
do
|
|
${pkgs.coreutils}/bin/sleep 0.1
|
|
done
|
|
fi
|
|
}
|
|
|
|
display_screenshot
|
|
|
|
${lib.optionalString (cfg.display != null) /* sh */ ''
|
|
if test "$DISPLAY" != ${lib.shell.escape cfg.display}; then
|
|
export DISPLAY=${lib.shell.escape cfg.display}
|
|
display_screenshot
|
|
fi
|
|
''}
|
|
|
|
exec 3<&0 4>&1 5>&2
|
|
${pkgs.rxvt_unicode}/bin/urxvt \
|
|
-name ${lib.shell.escape cfg.appName} \
|
|
-e ${pkgs.writeDash "pinentry-urxvt-tty" ''
|
|
set -efu
|
|
exec 2>&5
|
|
TTY=$(${pkgs.coreutils}/bin/tty)
|
|
while read -r line <&3; do
|
|
case $line in
|
|
'OPTION ttyname='*)
|
|
echo "OPTION ttyname=$TTY"
|
|
;;
|
|
*)
|
|
echo "$line"
|
|
esac
|
|
done | ${pkgs.pinentry.tty}/bin/pinentry-tty "$@" >&4
|
|
''} \
|
|
"$@"
|
|
'';
|
|
}
|