diff options
Diffstat (limited to 'bin/rofipass')
| -rwxr-xr-x | bin/rofipass | 351 |
1 files changed, 351 insertions, 0 deletions
diff --git a/bin/rofipass b/bin/rofipass new file mode 100755 index 0000000..b9620f8 --- /dev/null +++ b/bin/rofipass @@ -0,0 +1,351 @@ +#!/usr/bin/env sh +# rofipass - rofi front end for pass +# +# Derived from rofipass by Augusto Coronel (https://github.com/aocoronel/rofipass), +# released under the MIT License, whose notice is kept below as it requires. +# Modifications Copyright (C) 2026 Danilo M. <danix@danix.xyz>, released under +# the GNU General Public License version 2 (see LICENSE). +# +# MIT License +# +# Copyright (c) 2025 Augusto Coronel +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +### Colors + +help_color="#7c5cff" +div_color="#334433" +label="#f067fc" + +### + +### Bindings + +kb_copy_email="Ctrl+2" # EMAIL +kb_copy_otp="Ctrl-1" # COPY TOTP +kb_add_pass="Ctrl+r" # PASSWORD +kb_add_otp="Ctrl+t" # ADD TOTP +kb_delete="Ctrl-x" # DELETE +kb_edit="Ctrl+y" # EDIT +kb_close_tomb="Ctrl-z" # CLOSE TOMB +kb_open_tomb="Ctrl-o" # OPEN TOMB + +### + +clipmethod="$XDG_SESSION_TYPE" +passdir=${PASSWORD_STORE_DIR:-$HOME/.password-store} + +COLOR_YELLOW="$(tput setaf 226)" +COLOR_RED="$(tput setaf 196)" +COLOR_GREEN="$(tput setaf 82)" +COLOR_BLUE="$(tput setaf 87)" +COLOR_RESET=$(tput sgr0) + +printfc() { + mode=$1 + case $mode in + "ERROR" | "FATAL") + color="$COLOR_RED" + ;; + "WARN") + mode="WARNING" + color="$COLOR_YELLOW" + ;; + "DEBUG") + color="$COLOR_BLUE" + ;; + "INFO") + color="$COLOR_GREEN" + ;; + esac + text=$2 + printf "%s[%s]:%s %s\n" "${color}" "${mode}" "${COLOR_RESET}" "${text}" +} + +check_command() { + for cmd in "$@"; do + if ! command -v "$cmd" >/dev/null 2>&1; then + printfc FATAL "$cmd is not installed." + return 1 + fi + done +} + +_notify() { + message="$1" + header="rofipass" + urgency="$2" + time=${3:-$time} + echo "$message" + if [ "$time" -eq 0 ]; then + notify-send -u "$urgency" "$header" "$message" + else + notify-send -u "$urgency" "$header" "$message" --expire-time="$time"000 --wait + fi +} + +die() { + mode=$1 + message=$2 + urgency=$3 + + printfc "$mode" "$message" + _notify "$message" "$urgency" + exit 1 +} + +version() { + echo "v1.1.0" +} + +usage() { + cat <<EOF +rofipass | A rofi extension for pass + +Usage: rofipass [OPTIONS] <COMMAND> + +Options: + -e <EDITOR> Set editor + -f Lift swap restrictions (for tomb) + -h Display this help message and exit + -l <LENGTH> Default password length on generation + -t <TERM> Default terminal emulator (for tomb) + -v Display the current version number + -T <SECONDS> Clearing time + +Example: + rofipass -f -l 72 -t kitty -e nvim -T 10 +EOF +} + +_rofi() { + rofi -dmenu -theme ~/.config/rofi/udt/list.rasi -i -no-levenshtein-sort "$@" +} + +copy_email() { + email=$(pass "$menu" | sed -n 's/^email=//p') + case "$clipmethod" in + "x11") + xclip "$email" || die FATAL "failed to copy the email." "critical" + _notify "Copied to clipboard. Clearing in $time seconds" "normal" + ;; + "wayland") + wl-copy "$email" || die FATAL "failed to copy the email." "critical" + _notify "Copied to clipboard. Clearing in $time seconds" "normal" + ;; + esac + # clearboard +} + +append_otp() { + check_command zbarimg || die FATAL "zbarimg is not installed." "critical" + case "$clipmethod" in + "x11") + xclip -o | zbarimg -q --raw - | pass otp append "$menu" || die FATAL "failed to append OTP to $menu" "critical" + _notify "Inserted OTP successfully to $menu" "normal" + ;; + "wayland") + wl-paste --type image/png | zbarimg -q --raw - | pass otp append "$menu" || die FATAL "failed to append OTP to $menu" "critical" + _notify "Inserted OTP successfully to $menu" "normal" + ;; + esac +} + +clearboard() { + [ -x "$(command -v notifyctl)" ] && notifyctl close-all + + case "$clipmethod" in + "x11") + echo "" | xclip -sel clip + ;; + "wayland") + [ -x "$(command -v cliphist)" ] && cliphist wipe + echo "" | wl-copy + ;; + esac +} + +tomb_open() { + if [ -n "$FORCE" ]; then + $term -e sh -c "pass open -f" + else + $term -e sh -c "pass open" + fi +} + +tomb_close() { + $term -e sh -c "pass close" + pass_val=$? + if [ "$pass_val" -ne 0 ]; then + die FATAL "failed to close tomb." -u "critical" + else + _notify "Your password tomb has been closed!" "normal" 0 + fi +} + +deleteMenu() { + delask=$(printf "1. Yes\n2. No" | _rofi -p ' Delete:' -mesg "<span color='${label}'>Really delete</span> <span color='${help_color}'>$menu?</span>") + val=$? + [ $val -eq 1 ] && { + _notify "Cancelled!" "low" 0 + main + } + [ "$delask" = "1. Yes" ] && pass rm -f "$menu" && _notify "Deleted $menu" "normal" 0 + main +} + +add_password() { + length=${length:-72} + addmenu=$( + echo | _rofi -p ' New password:' -lines 0 \ + -theme-str 'window { width: 25em; } listview { lines: 0; } entry { placeholder: "Enter password name"; }' + ) + val=$? + if [ $val -eq 1 ]; then + _notify "Cancelled!" "low" 0 + main + elif [ $val -eq 0 ]; then + if command -v "passgen.py" >/dev/null 2>&1; then + passgen.py 3 | pass insert -e "$addmenu" + else + pass generate "$addmenu" "$length" + fi + if [ $val -eq 1 ]; then + _notify ERROR "failed to add password" 0 + main + else + _notify "Added $addmenu" "normal" 0 + fi + fi + main +} + +edit_password() { + $term -e sh -c "export EDITOR=\"$editor\"; pass edit \"$menu\"" +} + +main() { + enable_tomb=0 + enable_otp=0 + enable_zbar=0 + + if ! command -v "tomb" >/dev/null 2>&1; then + enable_tomb=1 + fi + if ! command -v "zbarimg" >/dev/null 2>&1; then + enable_zbar=1 + fi + + pass otp -h >/dev/null 2>&1 || enable_otp=1 + + HELP="" + + HELP="$HELP<span color='${label}'>Actions: </span><span color='${help_color}'>${kb_add_pass}</span>: Add <span color='${div_color}'>|</span> <span color='${help_color}'>${kb_delete}</span>: Delete <span color='${div_color}'>|</span> <span color='${help_color}'>${kb_edit}</span>: Edit" + + if [ "$enable_zbar" -eq 0 ]; then + ZBAR_HELP=" <span color='${div_color}'>|</span> <span color='${help_color}'>${kb_add_otp}</span>: Add OTP" + HELP="$HELP$ZBAR_HELP" + fi + + HELP="$HELP +<span color='${label}'>Copy: </span><span color='${help_color}'>Enter</span>: Copy Password <span color='${div_color}'>|</span> <span color='${help_color}'>${kb_copy_email}</span>: Copy Email" + + if [ "$enable_otp" -eq 0 ]; then + OTP_HELP=" <span color='${div_color}'>|</span> <span color='${help_color}'>${kb_copy_otp}</span>: Copy OTP" + HELP="$HELP$OTP_HELP" + fi + + if [ "$enable_tomb" -eq 0 ]; then + TOMB_HELP="<span color='${label}'>Tomb: </span><span color='${help_color}'>${kb_close_tomb}</span>: Close Tomb <span color='${div_color}'>|</span> <span color='${help_color}'>${kb_open_tomb}</span>: Open Tomb" + HELP="$HELP +$TOMB_HELP" + fi + + pass=$(find -L "$passdir" -type f -name '*.gpg' -printf '%P\n' | sed 's/\.gpg//') + menu=$(echo "${pass}" | _rofi -p ' Pass:' -mesg "${HELP}" -kb-custom-1 "${kb_add_pass}" -kb-custom-2 "${kb_copy_otp}" -kb-custom-3 "${kb_delete}" -kb-custom-4 "${kb_edit}" -kb-custom-5 "${kb_close_tomb}" -kb-custom-6 "${kb_open_tomb}" -kb-custom-7 "${kb_copy_email}" -kb-custom-8 "${kb_add_otp}") + + val=$? + case "$val" in + 1) exit ;; + 12) deleteMenu ;; + 11) # OTP Copy + [ "$enable_otp" -eq 0 ] && { + timeout 3 pass otp -c "$menu" || die ERROR "failed to copy OTP!" "normal" + _notify "Copied to clipboard. Clearing in $time seconds" "normal" + # clearboard + } + ;; + 10) add_password ;; + 13) edit_password ;; + 14) [ "$enable_tomb" -eq 0 ] && tomb_close ;; + 15) [ "$enable_tomb" -eq 0 ] && tomb_open ;; + 16) copy_email ;; + 17) [ "$enable_zbar" -eq 0 ] && append_otp ;; + 0) + pass -c "$menu" || die ERROR "failed to copy the password!" "normal" + _notify "Copied to clipboard. Clearing in $time seconds" "normal" + # clearboard + ;; + esac +} + +while getopts ":hvfl:t:T:e:" opt; do + case "$opt" in + h) + usage + exit 0 + ;; + e) + editor="$OPTARG" + ;; + v) + version + exit 0 + ;; + f) + FORCE=true + ;; + l) + length="$OPTARG" + ;; + t) + term="$OPTARG" + ;; + T) + time="$OPTARG" + ;; + ?) + printfc FATAL "invalid option '-$OPTARG'" >&2 + exit 1 + ;; + esac +done + +shift $((OPTIND - 1)) + +check_command rofi pass || exit 1 + +[ ! -d "$passdir" ] && die FATAL "no password directory found!" "low" + +[ -z "$editor" ] && editor=${EDITOR:-nano} +term=${term:-kitty} +time=${time:-5} + +main |
