diff --git a/.gitmodules b/.gitmodules index 4f856be..b458b74 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "polybar/.local/share/pomo-app"] path = polybar/.local/share/pomo-app url = https://github.com/jsspencer/pomo.git +[submodule "pass/.local/share/pass-pick"] + path = pass/.local/share/pass-pick + url = https://git.martyoeh.me/Marty/pass-pick.git diff --git a/README.md b/README.md index 61e6e61..e827554 100644 --- a/README.md +++ b/README.md @@ -7,14 +7,14 @@ The current dotfiles are geared toward wayland for which the setup looks similar * [x] vim configuration for simple programming tasks (especially go/typescript/python/bash) and prose * [x] academic workflow tools, to allow quick citation, pdf compilation, and preview -* [x] simple, efficient polybar with package update notification, and spotify (mpris) integration +* [x] simple, efficient waybar with package update notification, and spotify (mpris) integration * [x] tmux session management through `tm` and `tl` tools * [x] tmux fuzzy-searching of terminal sessions to switch to with hot-key (``) in addition to normal session switching * [x] system-wide color management (terminals, vim, qutebrowser, polybar, xresources) through `styler` command using [base16](http://chriskempson.com/projects/base16/) themes -* [x] quick theme switching by activating `styler` and fuzzy-searching themes with hot-key (`+F8`) +* [x] quick theme switching by activating `styler` and fuzzy-searching themes with hot-key (default `=+S`) * [x] many vim color-schemes with quick light/dark switching (`F8`) and individual theme switch (`+F8`) -* [x] quick directory jumping using z, with fzf integration -* [x] fzf integrations for bibtex citation, vim buffer management, most recently used switching, shell command history, and more +* [x] quick directory jumping using `z`, with `fzf` integration +* [x] `fzf`-like integrations for bibtex citation, vim buffer management, most recently used switching, shell command history, and more [![Styler recoloring demo](https://gitlab.com/marty-oehme/dotfiles/-/wikis/uploads/bde87deda694590a2e08e21552e11309/styler.webp)](https://gitlab.com/marty-oehme/dotfiles/-/wikis/uploads/90894e53eff378db4d7f9f49e7a69fab/styler.mp4) diff --git a/pass/.local/bin/pass-pick b/pass/.local/bin/pass-pick deleted file mode 100755 index b6ca935..0000000 --- a/pass/.local/bin/pass-pick +++ /dev/null @@ -1,388 +0,0 @@ -#!/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 wtype)}" - 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')}" - - PASS_COFFIN_OPEN_TIME="${PP_PASS_COFFIN_OPEN_TIME:-$(get_config PASS_COFFIN_OPEN_TIME 0)}" - PASS_COFFIN_LOCATION="${PP_PASS_COFFIN_LOCATION:-$(get_config PASS_COFFIN_LOCATION)}" -} - -# 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" = "wtype" ]; then - if [ "$toolmode" = "type" ]; then - "$tool" -s "${AUTOFILL_DELAY}" -- "$key" - elif [ "$toolmode" = "key" ]; then - "$tool" -s "${AUTOFILL_DELAY}" -k "$key" - fi - elif [ "$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 -} - -open_coffin() { - ## there's a closed coffin in our directory - if [ -f "${PASS_COFFIN_LOCATION:-${PASSWORD_STORE_DIR:-~/.password-store}/.coffin/coffin.tar.gpg}" ]; then - if [ "$PASS_COFFIN_OPEN_TIME" -eq 0 ]; then - coffin_should_close_instantly=true - pass open -t 1h # we still set a maximum time limit just to hedge against failures - else - pass open -t "${PASS_COFFIN_OPEN_TIME:-3h}" - fi - fi -} - -# make sure we remember to close the coffin if the program terminates -close_coffin() { - if [ "$coffin_should_close_instantly" = true ]; then - pass close - fi -} -trap close_coffin SIGINT SIGTERM ERR EXIT - -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}" - - open_coffin - - 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" - ;; - "11") - clip_username "$entry" - ;; - "12") - clip_password "$entry" - ;; - "13") - autofill "$entry" "username" - ;; - "14") - autofill "$entry" "password" - ;; - "15") - entrymenu "$entry" - ;; - esac - - exit 0 -} - -set_defaults -main diff --git a/pass/.local/bin/pass-pick b/pass/.local/bin/pass-pick new file mode 120000 index 0000000..342e886 --- /dev/null +++ b/pass/.local/bin/pass-pick @@ -0,0 +1 @@ +../share/pass-pick/pass-pick \ No newline at end of file diff --git a/pass/.local/share/pass-pick b/pass/.local/share/pass-pick new file mode 160000 index 0000000..846c679 --- /dev/null +++ b/pass/.local/share/pass-pick @@ -0,0 +1 @@ +Subproject commit 846c6793538514a2ea8bbbddad5ff82fddf21a33