Marty Oehme
6ac552d3d5
Added a simple wayland configuration. Currently set up simple wayland configuration based on river window manager and waybar. Rivercarro is the layout manager, being the same in principle as rivertile, the default layout manager for river, only it comes with smart gaps (gaps turn off if there is only one window open) and monocle mode (give one window all space). Runs `keyd` in the background to replace the old `xcape` capslock switching (capslock is escape and if held control). Uses `swaybg` to set a wallpaper. Added powermenu and lockscreen scripts. Improved lockscreen script to detect and work for wayland. Moved old rofi mode 'powermenu' to more general powermenu script, which works with any rofi-like selector (dmenu, bemenu, wofi, etc.) Loses some of its design quality but since it was wonky anyway, and I rarely see the menu, we could repurpose its functionality for a more general powermenu concept. Currently hardcoded for `bemenu` but can be easily swapped and possibly even extended back to rofi. Fixed file upload link sharing to clipboard. Updated rofi-pass to pass-pick. Made rofi-pass universal and less integrated to rofi - that's also the reason for the name change. `pass-pick` works with rofi (default), bemenu or dmenu. In theory it should also work with any other picker that contains a stdin listing function similar to dmenu. It has been definitely tested both on rofi and bemenu. The best user experience still reigns on rofi, where available keys are displayed on the picker and the keys themselves make the most sense. But all functions can be reached from bemenu as well, though the key mappings are more arbitrary and can not be changed as in rofi. The autofilling tool works with both xdotool and ydotool, so should work both on X11 and on Wayland. Ydotool ideally requires its daemon to be running, otherwise some of the typing may get gut off. Otherwise no change should be necessary. Updated qutebrowser open_download for bemenu. Updated download opening script to work with both rofi and bemenu. Prefers original rofi implementation but works with both, and can be set to use a custom dmenu-like file picker as well. Add brightnessctl and removed custom audio / brightness scripts since they became unnecessary. Updated bootstrap script to include system files: With `keyd` taking its configuration from the `/etc` directory and not home, a second stow stage was necessary. These stow files are in a module called `system-packages` inside the top-level `bootstrap` stow package. They will not be installed by the default dotfile stow invocation but have been integrated as an extra step into the install script. Installing this module requires sudo privileges! Switched vifm überzug to sixel graphics rendering. überzug relies on X11 functionality to work, while sixel does not. Unfortunately, alacritty does not work with sixel graphics yet, only foot does (somewhat). Waybar currently runs the gruvbox dark soft color scheme. Added the old polybar archupdates script to waybar and extended it to output json format with additional metadata that waybar can read. Can still output the old plaintext format that polybar expects. Added a wireguard connection to waybar,shows if currently connected to either a wireguard or tun VPN service. If so, shows an icon in the waybar - that can be hovered over to show the full assigned IP address. Added an upcoming event display to waybar, a simple event indicator to show upcoming events on the calendar, on hovering over it the tooltip lists all upcoming events. Added `screenshot` script to take simple screenshots and rectangle region shots of the current output. Can be invoked through the river shortcut PrintScr: `PrintScr` - Fullscreen screenshot `Mod+PrintScr` - Region screenshot `Shift+PrintScr` - Fullscreen screenshot and file upload `Mod+Shift+PrintScr` - Region screenshot and file upload Extended `sharefile` to take paths through stdin and make use of `fd` if it is found on the system.
361 lines
11 KiB
Bash
Executable file
361 lines
11 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
#
|
|
# Pass picker
|
|
#
|
|
# Use a dmenu-like list selector to display and autofill your pass passwords.
|
|
# Can work with rofi, bemenu and dmenu, or a custom picker given as an option.
|
|
# Invoke it with `pass-pick`. You can set options through environment variables
|
|
# or through a configuration file.
|
|
#
|
|
# Keys:
|
|
# By default shows the available keys on rofi, but not on bemenu/dmenu.
|
|
# ROFI mapped keys (main password list):
|
|
# return autofill username/password combination
|
|
# alt+return enter entry submenu
|
|
# alt+u autofill username
|
|
# alt+p autofill password
|
|
# alt+ctrl+u send username to clipboard
|
|
# alt+ctrl+p send password to clipboard
|
|
# ROFI mapped keys (individual entry):
|
|
# return autofill selected field
|
|
# alt+return send selected field to clipboard
|
|
# alt+s reveal hidden password field
|
|
# alt+backspace back to main password menu
|
|
# Those options also work on bemenu, but have different (and fixed) mappings.
|
|
# BEMENU mapped keys (main password list):
|
|
# return autofill username/password combination
|
|
# alt+2 send username to clipboard
|
|
# alt+3 send password to clipboard
|
|
# alt+4 autofill username
|
|
# alt+5 autofill password
|
|
# alt+6 enter entry submenu
|
|
# BEMENU mapped keys (individual entry):
|
|
# return autofill selected field
|
|
# alt+2 send selected field to clipboard
|
|
# alt+3 back to main password menu
|
|
# alt+4 reveal hidden password field
|
|
|
|
# Selector wrapper
|
|
# Prefers rofi if found, otherwise bemenu or dmenu if found, complains if no selector available.
|
|
# Passes along any options given to main script.
|
|
rofi_opts=("$@")
|
|
_picker() {
|
|
if [ -n "$PICKER" ]; then
|
|
"${PICKER[@]}"
|
|
elif command -v rofi 1>/dev/null 2>/dev/null; then
|
|
rofi -dmenu -no-auto-select -i "${rofi_opts[@]}" "$@" -p "entry"
|
|
elif command -v bemenu 1>/dev/null 2>/dev/null; then
|
|
bemenu -l 20 -i -p "entry >"
|
|
elif command -v dmenu 1>/dev/null 2>/dev/null; then
|
|
dmenu -i -p "entry >"
|
|
else
|
|
printf "%s: 📦 %s must be installed for %s function.\n" "critical" "rofi/dmenu" "this" >&2
|
|
notify-send "📦 rofi/dmenu" --urgency="critical" "must be installed for this function."
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# parse, see https://unix.stackexchange.com/a/331965/8541
|
|
_parse_config() {
|
|
(grep -e "^$2=" -m 1 "$1" 2>/dev/null || printf "var=__UNDEFINED__\n") | head -n1 | cut -d '=' -f 2-
|
|
}
|
|
|
|
# read config file
|
|
get_config() {
|
|
local locations=(
|
|
"$PP_CONFIGURATION_FILE"
|
|
"${xdg_config_home:-$HOME/.config}/pass-picker/pass-picker.conf"
|
|
"$HOME/.pass-picker.conf"
|
|
"/etc/pass-picker.conf"
|
|
)
|
|
|
|
# return the first config file with a valid path
|
|
for config in "${locations[@]}"; do
|
|
if [[ -n "$config" && -f "$config" ]]; then
|
|
# see if the config has been given a value
|
|
local val
|
|
val="$(_parse_config "$config" "$1")"
|
|
break
|
|
fi
|
|
done
|
|
|
|
# if there was a config file but no value
|
|
# or there was no config file at all
|
|
if [ "$val" = "__UNDEFINED__" ] || [ -z "$val" ]; then
|
|
val="$2"
|
|
fi
|
|
printf -- "%s" "$val"
|
|
}
|
|
|
|
set_defaults() {
|
|
# The location of the pass-picker config file
|
|
# PP_CONFIGURATION_FILE="~/.config/pass-picker/pass-picker.conf"
|
|
# set options, leaving already set environment variables intact
|
|
# try to read any settings from config files
|
|
PICKER="${PP_PICKER:-$(get_config PICKER)}"
|
|
|
|
KEY_AUTOFILL="${PP_KEY_AUTOFILL:-$(get_config KEY_AUTOFILL Return)}"
|
|
KEY_ENTRY_OPEN="${PP_KEY_ENTRY_OPEN:-$(get_config KEY_ENTRY_OPEN Alt+Return)}"
|
|
KEY_FILL_USER="${PP_KEY_FILL_USER:-$(get_config KEY_FILL_USER Alt+u)}"
|
|
KEY_CLIP_USER="${PP_KEY_CLIP_USER:-$(get_config KEY_CLIP_USER Ctrl+Alt+u)}"
|
|
KEY_FILL_PASS="${PP_KEY_FILL_PASS:-$(get_config KEY_FILL_PASS Alt+p)}"
|
|
KEY_CLIP_PASS="${PP_KEY_CLIP_PASS:-$(get_config KEY_CLIP_PASS Ctrl+Alt+p)}"
|
|
KEY_ENTRYMENU_FILL="${PP_KEY_ENTRYMENU_FILL:-$(get_config KEY_ENTRYMENU_FILL Return)}"
|
|
KEY_ENTRYMENU_CLIP="${PP_KEY_ENTRYMENU_CLIP:-$(get_config KEY_ENTRYMENU_CLIP Alt+Return)}"
|
|
KEY_ENTRYMENU_SHOWFIELD="${KEY_ENTRYMENU_SHOWFIELD:-$(get_config KEY_ENTRYMENU_SHOWFIELD Alt+s)}"
|
|
KEY_ENTRYMENU_QUIT="${PP_KEY_ENTRYMENU_QUIT:-$(get_config KEY_ENTRYMENU_QUIT Alt+BackSpace)}"
|
|
|
|
AUTOFILL_BACKEND="${PP_AUTOFILL_BACKEND:-$(get_config AUTOFILL_BACKEND ydotool)}"
|
|
AUTOFILL_CHAIN="${PP_AUTOENTRY_CHAIN:-$(get_config AUTOFILL_CHAIN 'username :tab password')}"
|
|
AUTOFILL_DELAY="${PP_AUTOENTRY_DELAY:-$(get_config AUTOFILL_DELAY 30)}"
|
|
PASS_USERNAME_FIELD="${PP_PASS_USERNAME_FIELD:-$(get_config PASS_USERNAME_FIELD 'username user login')}"
|
|
}
|
|
|
|
# exit on escape pressed
|
|
exit_check() {
|
|
[ "$1" -eq 1 ] && exit
|
|
}
|
|
|
|
# simply return a list of all passwords in pass store
|
|
# TODO only show website names (+ folder names), and account names for multiple accounts on one site
|
|
list_passwords() {
|
|
shopt -s nullglob globstar
|
|
prefix=${PASSWORD_STORE_DIR:-~/.password-store}
|
|
password_files=("$prefix"/**/*.gpg)
|
|
password_files=("${password_files[@]#"$prefix"/}")
|
|
password_files=("${password_files[@]%.gpg}")
|
|
|
|
printf '%s\n' "${password_files[@]}"
|
|
}
|
|
|
|
# return password for argument passed
|
|
show_password() {
|
|
pass show "$1" | head -n1
|
|
}
|
|
|
|
# send password to clipboard
|
|
clip_password() {
|
|
pass show -c "$1"
|
|
}
|
|
|
|
# attempt to return the field specified
|
|
# attempts all (space separated) fields until the
|
|
# first one successfully returned
|
|
_p_get_field() {
|
|
local gp_entry="$1"
|
|
local gp_field="$2"
|
|
local clip="$3"
|
|
|
|
# return on first successfully returned key
|
|
for key in $gp_field; do
|
|
local value
|
|
value=$(_p_get_key_value "$gp_entry" "$key")
|
|
|
|
# found entry
|
|
if [ -n "$value" ]; then
|
|
|
|
if [ -n "$clip" ]; then
|
|
# copies to clipboard, removes any trailing newlines,
|
|
# and only keeps it in for 1 paste (1 loop to read in script, 1 to output)
|
|
if command -v wl-copy; then
|
|
echo "$value" | wl-copy -o && break
|
|
elif command -v xclip; then
|
|
echo "$value" | xclip -i -selection 'clipboard' -loops 2 -rmlastnl && break
|
|
elif command -v xsel; then
|
|
echo "$value" | xsel -b && break
|
|
else
|
|
notify-send "No clipboard utility" "Install wl-copy, xclip or xsel."
|
|
fi
|
|
else
|
|
echo "$value" && break
|
|
fi
|
|
|
|
fi
|
|
done
|
|
}
|
|
|
|
# returns the corresponding value for the key passed in
|
|
# arguments:
|
|
# $1: pass (file) entry to search through
|
|
# $2: string name of the containting key
|
|
_p_get_key_value() {
|
|
local value
|
|
value=$(list_fields "$1" | grep "$2")
|
|
|
|
# get everything after first colon, remove whitespace
|
|
echo "$value" | cut -d':' -f2- | tr -d '[:blank:]'
|
|
}
|
|
|
|
# return username for argument passed
|
|
show_username() {
|
|
_p_get_field "$1" "${PASS_USERNAME_FIELD}"
|
|
}
|
|
|
|
clip_username() {
|
|
_p_get_field "$1" "${PASS_USERNAME_FIELD}" "-c"
|
|
}
|
|
|
|
show_field() {
|
|
_p_get_field "$1" "$2"
|
|
}
|
|
|
|
clip_field() {
|
|
_p_get_field "$1" "$2" "-c"
|
|
}
|
|
|
|
list_fields() {
|
|
pass show "$1" | tail -n+2
|
|
}
|
|
|
|
# invoke the dotool to type inputs
|
|
_type() {
|
|
local tool="${AUTOFILL_BACKEND}"
|
|
local toolmode="$1"
|
|
local key="$2"
|
|
|
|
if [ "$tool" = "xdotool" ]; then
|
|
"$tool" "$toolmode" --delay "${AUTOFILL_DELAY}" "$key"
|
|
elif [ "$tool" = "ydotool" ]; then
|
|
"$tool" "$toolmode" --key-delay "${AUTOFILL_DELAY}" "$key"
|
|
else
|
|
"$tool" "$toolmode" "$key"
|
|
fi
|
|
}
|
|
|
|
# automatically fill out fields
|
|
# transform special chain entries into valid dotool commands
|
|
autofill() {
|
|
local selected="${1}"
|
|
local autoentry_chain="${2}"
|
|
|
|
for part in $autoentry_chain; do
|
|
case "$part" in
|
|
":tab") _type key Tab ;;
|
|
":return") _type key Return ;;
|
|
":space") _type key space ;;
|
|
"username") _type type "$(show_username "$selected")" ;;
|
|
"password") _type type "$(show_password "$selected")" ;;
|
|
":direct") _type type "$selected" ;;
|
|
*) printf '%s' "$selected" ;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
# opens a menu for the specified pass entry, containing its individual fields
|
|
entrymenu() {
|
|
local entry="$1"
|
|
local deobfuscate="$2"
|
|
local k_entrymenu_fill="${KEY_ENTRYMENU_FILL}"
|
|
local k_entrymenu_clip="${KEY_ENTRYMENU_CLIP}"
|
|
local k_entrymenu_showfield="${KEY_ENTRYMENU_SHOWFIELD}"
|
|
local k_entrymenu_quit="${KEY_ENTRYMENU_QUIT}"
|
|
|
|
local pass
|
|
if [ "$deobfuscate" = "true" ]; then
|
|
pass="$(show_password "$entry")"
|
|
else
|
|
pass="(hidden)"
|
|
fi
|
|
|
|
local field
|
|
field=$(
|
|
printf "password: %s\n%s" "$pass" "$(list_fields "$entry")" |
|
|
_picker \
|
|
-kb-accept-entry "" \
|
|
-kb-custom-1 "$k_entrymenu_fill" \
|
|
-kb-custom-2 "$k_entrymenu_clip" \
|
|
-kb-custom-3 "$k_entrymenu_quit" \
|
|
-kb-custom-4 "$k_entrymenu_showfield" \
|
|
-mesg " ᐊ $k_entrymenu_quit ᐊ | $k_entrymenu_fill: fill selection | $k_entrymenu_clip: clip selection | $k_entrymenu_showfield: reveal password"
|
|
)
|
|
exit_value=$?
|
|
exit_check "$exit_value"
|
|
|
|
# get field name
|
|
field=${field%%:*}
|
|
case "$exit_value" in
|
|
"0" | "10")
|
|
if [ "$field" = "password" ]; then
|
|
autofill "$entry" "password"
|
|
else
|
|
autofill "$(show_field "$entry" "$field")" ":direct"
|
|
fi
|
|
exit 0
|
|
;;
|
|
"11")
|
|
if [ "$field" = "password" ]; then
|
|
clip_password "$entry"
|
|
else
|
|
clip_field "$entry" "$field"
|
|
fi
|
|
exit 0
|
|
;;
|
|
"12")
|
|
main
|
|
;;
|
|
"13")
|
|
local toggle
|
|
if [ "$deobfuscate" = "true" ]; then
|
|
toggle=false
|
|
else
|
|
toggle=true
|
|
fi
|
|
entrymenu "$entry" "$toggle"
|
|
;;
|
|
esac
|
|
}
|
|
|
|
main() {
|
|
local autoentry_chain="${AUTOFILL_CHAIN}"
|
|
local k_autofill="${KEY_AUTOFILL}"
|
|
local k_fill_user="${KEY_FILL_USER}"
|
|
local k_clip_user="${KEY_CLIP_USER}"
|
|
local k_fill_pass="${KEY_FILL_PASS}"
|
|
local k_clip_pass="${KEY_CLIP_PASS}"
|
|
local k_submenu="${KEY_ENTRY_OPEN}"
|
|
|
|
entry="$(
|
|
list_passwords |
|
|
_picker -kb-accept-entry "" \
|
|
-kb-custom-1 "$k_autofill" \
|
|
-kb-custom-2 "$k_clip_user" \
|
|
-kb-custom-3 "$k_clip_pass" \
|
|
-kb-custom-4 "$k_fill_user" \
|
|
-kb-custom-5 "$k_fill_pass" \
|
|
-kb-custom-6 "$k_submenu" \
|
|
-mesg "| $k_autofill: fill credentials | $k_submenu: open entry | $k_fill_user: fill username | $k_fill_pass: fill password | $k_clip_user: clip username | $k_clip_pass: clip password |"
|
|
)"
|
|
exit_value=$?
|
|
|
|
echo "$entry"
|
|
exit_check "$exit_value"
|
|
case "$exit_value" in
|
|
"0" | "10")
|
|
autofill "$entry" "$autoentry_chain"
|
|
exit 0
|
|
;;
|
|
"11")
|
|
clip_username "$entry"
|
|
exit 0
|
|
;;
|
|
"12")
|
|
clip_password "$entry"
|
|
exit
|
|
;;
|
|
"13")
|
|
autofill "$entry" "username"
|
|
exit
|
|
;;
|
|
"14")
|
|
autofill "$entry" "password"
|
|
exit
|
|
;;
|
|
"15")
|
|
entrymenu "$entry"
|
|
exit
|
|
;;
|
|
esac
|
|
}
|
|
|
|
set_defaults
|
|
main
|