diff --git a/modules/home-manager/application/gnupg/default.nix b/modules/home-manager/application/gnupg/default.nix index c746a8a..77f341d 100644 --- a/modules/home-manager/application/gnupg/default.nix +++ b/modules/home-manager/application/gnupg/default.nix @@ -51,5 +51,7 @@ in programs.password-store = { enable = cfg.pass; }; + + home.file.".local/bin/gpg-attach-key".source = ./files/gpg-attach-key.sh; }; } diff --git a/modules/home-manager/application/gnupg/files/gpg-attach-key.sh b/modules/home-manager/application/gnupg/files/gpg-attach-key.sh new file mode 100755 index 0000000..2851e85 --- /dev/null +++ b/modules/home-manager/application/gnupg/files/gpg-attach-key.sh @@ -0,0 +1,137 @@ +#!/usr/bin/env bash + +UUID="1429a4c6-78f5-4f46-98bc-894106b52399" +mountpoint="" + +usage() { + cat <&2 +Attach GPG master key +--- + +$0 [action] [--debug] [--help] + +mount or unmount encrypted device based on UUID and attach GnuPG private keys +to private key directory. Actions can be + + - 'mount' to mount USB device and attach keys + - 'unmount' to remove private keys attached and unmount USB device +EOF +} + +error() { + local message + printf -v message "\e[31mERROR:\e[0m %s\n" "$1" + >&2 printf "%b" "${message}" + show_stack_trace +} + +show_stack_trace() { + if [[ $DEBUG -eq 1 ]]; then + local message + message="└─ \e[1mStack trace\e[0m:\n" + for ((i = 2; i < ${#FUNCNAME[@]} - 1; i++)); do + if [[ $i = $((${#FUNCNAME[@]} - 2)) ]]; then + message="${message} └" + else + message="${message} ├" + fi + message="${message}─ source:\e[3;34m${BASH_SOURCE[$i]}\e[0m" + message="${message} function:\e[3;34m${FUNCNAME[$i]}\e[0m" + message="${message} line:\e[3;34m${BASH_LINENO[$i - 1]}\e[0m\n" + done + >&2 printf "%b" "${message}" + fi +} + +debug() { + local message + if [[ $DEBUG -eq 1 ]]; then + printf -v message "\e[3;34mDEBUG:\e[0m %s\n" "$*" + >&2 printf "%b" "$message" + show_stack_trace + fi +} + +# shellcheck disable=SC2317 +process_args() { + while :; do + case $1 in + -h | --help) + usage + exit 0 + ;; + m | mount) + action="mount" + ;; + u | umount | unmount) + action="unmount" + ;; + -d | --debug) + DEBUG=1 + ;; + *) + break + ;; + esac + shift + done +} + +main() { + if [ ! -L "/dev/disk/by-uuid/${UUID}" ]; then + error "disk with UUID ${UUID} not found" + exit 10 + fi + if [ -z "${GNUPGHOME}" ]; then + error "GNUPGHOME env variable not set, can't determine gnuph home directory" + exit 11 + fi + key_destination="${GNUPGHOME}/private-keys-v1.d" + + case "$action" in + "mount") + debug "Mount encryted key" + if ! udisksctl unlock -b /dev/disk/by-uuid/${UUID}; then + error "Unlock disk ${UUID} failed" + exit 10 + fi + mountpoint=$(udisksctl mount -b /dev/mapper/luks-${UUID} | awk '{print $4}') + + while read -r key_file; do + + debug "Create symlink for ${key_file}" + base=$(basename "$key_file") + + #create symlink to key file if not exist + if [ ! -e "${key_destination}/${base}" ]; then + ln -s "$key_file" "${key_destination}/${base}" + fi + done < <(find "${mountpoint%.}/.gpg_master/" -type f -name "*.key") + ;; + + "unmount") + debug "unmount encrypted key" + while read -r key_file; do + debug "Remove key \`${key_file}\`" + rm "$key_file" + done < <(find "${key_destination}" -type l -name "*.key") + + if ! udisksctl unmount -b /dev/mapper/luks-${UUID} 2 &>/dev/null; then + error "Can't unmount volume \`luks-${UUID}\`" + fi + + if ! udisksctl lock -b /dev/disk/by-uuid/${UUID} 2 &>/dev/null; then + error "Can't lock device \`${UUID}\`" + fi + ;; + *) + error "What do you want, mount or unmount:" + usage + exit 1 + ;; + esac +} + +process_args "$@" +main +exit 0