aboutsummaryrefslogtreecommitdiffstats
path: root/bin/rofipass
diff options
context:
space:
mode:
Diffstat (limited to 'bin/rofipass')
-rwxr-xr-xbin/rofipass351
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