Jelajahi Sumber

[i3][rofi] Update rofi to be more useful

Enter should call up hosts, not a blank terminal. And rofi can use pass
for input!
Colin Powell 4 tahun lalu
induk
melakukan
2a3a30dc72

+ 8 - 5
i3/.config/i3/config

@@ -64,7 +64,8 @@ bar {
 #bindsym $mod+shift+m exec --no-startup-id surf https://15five-dev.atlassian.net/secure/Dashboard.jspa
 
 # SCRATCHPAD
-bindsym $mod+Return exec $term
+bindsym $mod+Return exec rofi -show ssh
+bindsym $mod+Shift+Return exec $term
 bindsym $mod+BackSpace exec $term --working-directory ~/src/ff/fifteen5/
 #bindsym $mod+Shift+BackSpace floating enable, move position 48 px 48 px, move scratchpad
 #bindsym $mod+Ctrl+BackSpace exec $term -e tmux new-session -A -s scratch
@@ -266,6 +267,12 @@ bindsym XF86Search exec ~/.config/i3/bright.sh 1 # decrease screen brightness
 
 # ROFI
 bindsym $mod+space   exec rofi -show combi -display-window "W"
+bindsym $mod+P exec --no-startup-id ~/.config/rofi/rofi-pass.sh
+bindsym $mod+Shift+p exec --no-startup-id ~/.config/rofi/rofi-otp.sh
+bindsym $mod+o exec --no-startup-id ~/.config/rofi/www.sh
+bindsym $mod+Shift+o       exec ~/.config/rofi/web-search.sh
+bindsym $mod+Shift+b exec ~/.config/rofi/books-search.sh
+bindsym $mod+Shift+s exec ~/.config/rofi/slack.sh
 
 # Lock with 
 bindsym $mod+Shift+F12 exec --no-startup-id i3lock -i ~/var/media/backgrounds/astrobin/`ls -Ar ~/var/media/backgrounds/astrobin/ | tail -n 1` -t
@@ -276,10 +283,6 @@ exec hsetroot -cover ~/var/media/backgrounds/bing/`ls -A ~/var/media/backgrounds
 ##### APP BINDS ###################################
 
 bindsym $mod+n       exec $browser
-bindsym $mod+o exec --no-startup-id ~/.config/rofi/www.sh
-bindsym $mod+Shift+o       exec ~/.config/rofi/web-search.sh
-bindsym $mod+Shift+b exec ~/.config/rofi/books-search.sh
-bindsym $mod+Shift+s exec ~/.config/rofi/slack.sh
 bindsym $mod+Shift+c exec org-capture
 
 bindsym $mod+Shift+y exec xfreerdp /u:powellc /p:mainroot /v:telesto.local /w:1200 /h:700

+ 1 - 1
rofi/.config/rofi/config.rasi

@@ -5,6 +5,6 @@ configuration {
 	terminal: "alacritty";
 	font: "Inconsolata 10";
 	show-icons: true;
-	combi-modi: "ssh,window,drun";
+	combi-modi: "window,drun,ssh";
 }
 @import "/usr/share/rofi/themes/gruvbox-dark-hard.rasi"

+ 880 - 0
rofi/.config/rofi/rofi-pass.sh

@@ -0,0 +1,880 @@
+#!/usr/bin/env bash
+
+# rofi-pass
+# (c) 2015 Rasmus Steinke <rasi@xssn.at>
+basecommand="$0"
+
+# set default settings
+_rofi () {
+	rofi -no-auto-select -i "$@"
+}
+
+_pwgen () {
+	pwgen -y "$@"
+}
+
+_image_viewer () {
+	feh -
+}
+
+config_dir=${XDG_CONFIG_HOME:-$HOME/.config}
+cache_dir=${XDG_CACHE_HOME:-$HOME/.cache}
+
+# We expect to find these fields in pass(1)'s output
+URL_field='url'
+USERNAME_field='user'
+AUTOTYPE_field='autotype'
+OTPmethod_field='otp_method'
+
+default_autotype="user :tab pass"
+delay=2
+wait=0.2
+xdotool_delay=12
+default_do='menu' # menu, copyPass, typeUser, typePass, copyUser, copyUrl, viewEntry, typeMenu, actionMenu, copyMenu, openUrl
+auto_enter='false'
+notify='false'
+help_color=""
+clip=primary
+clip_clear=45
+default_user="${ROFI_PASS_DEFAULT_USER-$(whoami)}"
+default_user2=john_doe
+password_length=12
+fix_layout=false
+
+# default shortcuts
+autotype="Alt+1"
+type_user="Alt+2"
+type_pass="Alt+3"
+open_url="Alt+4"
+copy_name="Alt+u"
+copy_url="Alt+l"
+copy_pass="Alt+p"
+show="Alt+o"
+copy_menu="Alt+c"
+action_menu="Alt+a"
+type_menu="Alt+t"
+help="Alt+h"
+switch="Alt+x"
+insert_pass="Alt+n"
+qrcode="Alt+q"
+previous_root="Shift+Left"
+next_root="Shift+Right"
+
+# Safe permissions
+umask 077
+
+has_qrencode() {
+	command -v qrencode >/dev/null 2>&1
+}
+
+listgpg () {
+	mapfile -d '' pw_list < <(find -L . -name '*.gpg' -print0)
+	pw_list=("${pw_list[@]#./}")
+	printf '%s\n' "${pw_list[@]}" | sort -n
+}
+
+# get all password files and output as newline-delimited text
+list_passwords() {
+	cd "${root}" || exit
+	mapfile -t pw_list < <(listgpg)
+	printf '%s\n' "${pw_list[@]%.gpg}" | sort -n
+}
+
+doClip () {
+	case "$clip" in
+		"primary") xclip ;;
+		"clipboard") xclip -selection clipboard;;
+		"both") xclip; xclip -o | xclip -selection clipboard;;
+	esac
+}
+
+checkIfPass () {
+	printf '%s\n' "${root}: $selected_password" >| "$cache_dir/rofi-pass/last_used"
+}
+
+
+autopass () {
+	x_repeat_enabled=$(xset q | awk '/auto repeat:/ {print $3}')
+	xset r off
+
+	rm -f "$cache_dir/rofi-pass/last_used"
+	printf '%s\n' "${root}: $selected_password" > "$cache_dir/rofi-pass/last_used"
+	for word in ${stuff["$AUTOTYPE_field"]}; do
+		case "$word" in
+			":tab") xdotool key Tab;;
+			":space") xdotool key space;;
+			":delay") sleep "${delay}";;
+			":enter") xdotool key Return;;
+			":otp") printf '%s' "$(generateOTP)" | xdotool type --delay ${xdotool_delay} --clearmodifiers --file -;;
+			"pass") printf '%s' "${password}" | xdotool type --delay ${xdotool_delay} --clearmodifiers --file -;;
+			"path") printf '%s' "${selected_password}" | rev | cut -d'/' -f1 | rev | xdotool type --clearmodifiers --file -;;
+			*) printf '%s' "${stuff[${word}]}" | xdotool type --delay ${xdotool_delay} --clearmodifiers --file -;;
+		esac
+	done
+
+	if [[ ${auto_enter} == "true" ]]; then
+		xdotool key Return
+	fi
+
+	xset r "$x_repeat_enabled"
+	unset x_repeat_enabled
+	clearUp
+}
+
+generateQrCode() {
+	has_qrencode
+
+	if [[ $? -eq "1" ]]; then
+		printf '%s\n' "qrencode not found" | _rofi -dmenu
+		exit_code=$?
+		if [[ $exit_code -eq "1" ]]; then
+			exit
+		else
+			"${basecommand}"
+		fi
+	fi
+
+	checkIfPass
+	pass "$selected_password" | head -n 1 | qrencode -d 300 -v 8 -l H -o - | _image_viewer
+	if [[ $? -eq "1" ]]; then
+		printf '%s\n' "" | _rofi -dmenu -mesg "Image viewer not defined or cannot read from pipe"
+		exit_value=$?
+		if [[ $exit_value -eq "1" ]]; then
+			exit
+		else
+			"${basecommand}"
+		fi
+	fi
+	clearUp
+}
+
+openURL () {
+	checkIfPass
+	$BROWSER "$(PASSWORD_STORE_DIR="${root}" pass "$selected_password" | grep "${URL_field}: " | gawk '{sub(/:/,"")}{print $2}1' | head -1)"; exit;
+	clearUp
+}
+
+typeUser () {
+	checkIfPass
+
+	x_repeat_enabled=$(xset q | awk '/auto repeat:/ {print $3}')
+	xset r off
+
+	printf '%s' "${stuff[${USERNAME_field}]}" | xdotool type --delay ${xdotool_delay} --clearmodifiers --file -
+
+	xset r "$x_repeat_enabled"
+	unset x_repeat_enabled
+
+	clearUp
+}
+
+typePass () {
+	checkIfPass
+
+	x_repeat_enabled=$(xset q | awk '/auto repeat:/ {print $3}')
+	xset r off
+
+	printf '%s' "${password}" | xdotool type --delay ${xdotool_delay} --clearmodifiers --file -
+
+	if [[ $notify == "true" ]]; then
+		if [[ "${stuff[notify]}" == "false" ]]; then
+			:
+		else
+			notify-send "rofi-pass" "finished typing password";
+		fi
+	elif [[ $notify == "false" ]]; then
+		if [[ "${stuff[notify]}" == "true" ]]; then
+			notify-send "rofi-pass" "finished typing password";
+		else
+			:
+		fi
+	fi
+
+	xset r "$x_repeat_enabled"
+	unset x_repeat_enabled
+	clearUp
+}
+
+typeField () {
+	checkIfPass
+	local to_type
+
+	x_repeat_enabled=$(xset q | awk '/auto repeat:/ {print $3}')
+	xset r off
+
+	case $typefield in
+		"OTP") to_type="$(generateOTP)" ;;
+		*) to_type="${stuff[${typefield}]}" ;;
+	esac
+
+	printf '%s' "$to_type" | xdotool type --delay ${xdotool_delay} --clearmodifiers --file -
+
+	xset r "$x_repeat_enabled"
+	unset x_repeat_enabled
+	unset to_type
+
+	clearUp
+}
+
+generateOTP () {
+	checkIfPass
+
+	# First, we check if there is a non-conventional OTP command in the pass file
+	if PASSWORD_STORE_DIR="${root}" pass "$selected_password" | grep -q "${OTPmethod_field}: "; then
+		# We execute the commands after otp_method: AS-IS
+		bash -c "$(PASSWORD_STORE_DIR="${root}" pass "$selected_password" | grep "${OTPmethod_field}: " | cut -d' ' -f2-)"
+	else
+		# If there is no method defined, fallback to pass-otp
+		PASSWORD_STORE_DIR="${root}" pass otp "$selected_password"
+	fi
+
+	clearUp
+}
+
+copyUser () {
+	checkIfPass
+	printf '%s' "${stuff[${USERNAME_field}]}" | doClip
+	clearUp
+}
+
+copyField () {
+	checkIfPass
+	printf '%s' "${stuff[${copyfield}]}" | doClip
+	clearUp
+}
+
+copyURL () {
+	checkIfPass
+	printf '%s' "${stuff[${URL_field}]}" | doClip
+	clearUp
+}
+
+copyPass () {
+	checkIfPass
+	printf '%s' "$password" | doClip
+	if [[ $notify == "true" ]]; then
+		notify-send "rofi-pass" "Copied Password\\nClearing in $clip_clear seconds"
+	fi
+
+	if [[ $notify == "true" ]]; then
+		(sleep $clip_clear; printf '%s' "" | xclip; printf '%s' "" | xclip -selection clipboard | notify-send "rofi-pass" "Clipboard cleared") &
+	elif [[ $notify == "false" ]]; then
+		(sleep $clip_clear; printf '%s' "" | xclip; printf '%s' "" | xclip -selection clipboard) &
+	fi
+}
+
+viewEntry () {
+	checkIfPass
+	showEntry "${selected_password}"
+}
+
+generatePass () {
+	askmenu_content=(
+		"Yes"
+		"No"
+	)
+
+	askGenMenu=$(printf '%s\n' "${askmenu_content[@]}" | _rofi -dmenu -p "Generate new Password for ${selected_password}? > ")
+	askgen_exit=$?
+
+	if [[ $askgen_exit -eq 1 ]]; then
+		exit
+	fi
+	if [[ $askGenMenu == "Yes" ]]; then
+		true
+	elif [[ $askGenMenu == "No" ]]; then
+		actionMenu
+	fi
+
+	checkIfPass
+
+	symbols_content=(
+		"0  Cancel"
+		"1  Yes"
+		"2  No"
+	)
+
+	symbols=$(printf '%s\n' "${symbols_content[@]}" | _rofi -dmenu -p "Use Symbols? > ")
+	symbols_val=$?
+
+	if [[ $symbols_val -eq 1 ]]; then
+		exit
+	fi
+	if [[ $symbols == "0  Cancel" ]]; then
+		mainMenu;
+	elif [[ $symbols == "1  Yes" ]]; then
+		symbols="";
+	elif [[ $symbols == "2  No" ]]; then
+		symbols="-n";
+	fi
+
+	HELP="<span color='$help_color'>Enter Number or hit Enter to use default length</span>"
+	length=$(printf '%s' "" | _rofi -dmenu -mesg "${HELP}" -p "Password length? (Default: ${password_length}) > ")
+	length_exit=$?
+
+	if [[ $length_exit -eq 1 ]]; then
+		exit
+	fi
+	if [[ $length == "" ]]; then
+		PASSWORD_STORE_DIR="${root}" pass generate ${symbols} -i "$selected_password" "${password_length}" > /dev/null;
+	else
+		PASSWORD_STORE_DIR="${root}" pass generate ${symbols} -i "$selected_password" "${length}" > /dev/null;
+	fi
+}
+
+# main Menu
+mainMenu () {
+	if [[ $1 == "--bmarks" ]]; then
+		selected_password="$(list_passwords 2>/dev/null \
+			| _rofi -mesg "Bookmarks Mode. ${switch} to switch" \
+			-dmenu \
+			-kb-custom-10 "${switch}" \
+			-select "$entry" \
+			-p "rofi-pass > ")"
+
+		rofi_exit=$?
+
+		if [[ $rofi_exit -eq 1 ]]; then
+			exit
+		elif [[ $rofi_exit -eq 19 ]]; then
+			${basecommand}
+		elif [[ $rofi_exit -eq 0 ]]; then
+			openURL
+		fi
+	else
+		unset selected_password
+
+		args=( -dmenu
+			-kb-custom-1 "${autotype}"
+			-kb-custom-2 "${type_user}"
+			-kb-custom-3 "${type_pass}"
+			-kb-custom-4 "${open_url}"
+			-kb-custom-5 "${copy_name}"
+			-kb-custom-6 "${copy_pass}"
+			-kb-custom-7 "${show}"
+			-kb-custom-8 "${copy_url}"
+			-kb-custom-9 "${type_menu}"
+			-kb-custom-10 "${previous_root}"
+			-kb-custom-11 "${next_root}"
+			-kb-custom-14 "${action_menu}"
+			-kb-custom-15 "${copy_menu}"
+			-kb-custom-16 "${help}"
+			-kb-custom-17 "${switch}"
+			-kb-custom-18 "${insert_pass}"
+			-kb-custom-19 "${qrcode}"
+		)
+		args+=( -kb-mode-previous ""    # These keyboard shortcut options are needed, because
+		-kb-mode-next ""            # Shift+<Left|Right> are otherwise taken by rofi.
+		-select "$entry"
+		-p "> "	)
+
+		if [[ ${#roots[@]} -gt "1" || $custom_root == "true" ]]; then
+			args+=(-mesg "PW Store: ${root}")
+		fi
+
+		selected_password="$(list_passwords 2>/dev/null | _rofi "${args[@]}")"
+
+		rofi_exit=$?
+		if [[ $rofi_exit -eq 1 ]]; then
+			exit
+		fi
+
+		# Actions based on exit code, which do not need the entry.
+		# The exit code for -kb-custom-X is X+9.
+		case "${rofi_exit}" in
+			19) roots_index=$(( (roots_index-1+roots_length) % roots_length)); root=${roots[$roots_index]}; mainMenu; return;;
+			20) roots_index=$(( (roots_index+1) % roots_length)); root=${roots[$roots_index]}; mainMenu; return;;
+			25) helpMenu; return;;
+			26) ${basecommand} --bmarks; return;;
+		esac
+
+		mapfile -t password_temp < <(PASSWORD_STORE_DIR="${root}" pass show "$selected_password")
+		password=${password_temp[0]}
+
+		if [[ ${password} == "#FILE="* ]]; then
+			pass_file="${password#*=}"
+			mapfile -t password_temp2 < <(PASSWORD_STORE_DIR="${root}" pass show "${pass_file}")
+			password=${password_temp2[0]}
+		fi
+
+		fields=$(printf '%s\n' "${password_temp[@]:1}" | awk '$1 ~ /:$/ || /otpauth:\/\// {$1=$1;print}')
+		declare -A stuff
+		stuff["pass"]=${password}
+
+		if [[ -n $fields ]]; then
+			while read -r LINE; do
+				unset _id _val
+				case "$LINE" in
+					"otpauth://"*|"${OTPmethod_field}"*)
+						_id="OTP"
+						_val=""
+						;;
+					*)
+						_id="${LINE%%: *}"
+						_val="${LINE#* }"
+						;;
+				esac
+
+				if [[ -n "$_id" ]]; then
+					stuff["${_id}"]=${_val}
+				fi
+			done < <(printf '%s\n' "${fields}")
+
+			if test "${stuff['autotype']+autotype}"; then
+				:
+			else
+				stuff["autotype"]="${USERNAME_field} :tab pass"
+			fi
+		fi
+	fi
+
+	if [[ -z "${stuff["${AUTOTYPE_field}"]}" ]]; then
+		if [[ -n $default_autotype ]]; then
+			stuff["${AUTOTYPE_field}"]="${default_autotype}"
+		fi
+	fi
+	if [[ -z "${stuff["${USERNAME_field}"]}" ]]; then
+		if [[ -n $default_user ]]; then
+			if [[ "$default_user" == ":filename" ]]; then
+				stuff["${USERNAME_field}"]="$(basename "$selected_password")"
+			else
+				stuff["${USERNAME_field}"]="${default_user}"
+			fi
+		fi
+	fi
+	pass_content="$(for key in "${!stuff[@]}"; do printf '%s\n' "${key}: ${stuff[$key]}"; done)"
+
+	# actions based on keypresses
+	# The exit code for -kb-custom-X is X+9.
+	case "${rofi_exit}" in
+		0) typeMenu;;
+		10) sleep $wait; autopass;;
+		11) sleep $wait; typeUser;;
+		12) sleep $wait; typePass;;
+		13) openURL;;
+		14) copyUser;;
+		15) copyPass;;
+		16) viewEntry;;
+		17) copyURL;;
+		18) default_do="menu" typeMenu;;
+		23) actionMenu;;
+		24) copyMenu;;
+		27) insertPass;;
+		28) generateQrCode;;
+	esac
+	clearUp
+}
+
+
+clearUp () {
+	password=''
+	selected_password=''
+	unset stuff
+	unset password
+	unset selected_password
+	unset password_temp
+	unset stuff
+}
+
+helpMenu () {
+	_rofi -dmenu -mesg "Hint: All hotkeys are configurable in config file" -p "Help > " <<- EOM
+	${autotype}: Autotype
+	${type_user}: Type Username
+	${type_pass}: Type Password
+	${qrcode}: Generate and display qrcode
+	---
+	${copy_name}: Copy Username
+	${copy_pass}: Copy Password
+	${copy_url}: Copy URL
+	${open_url}: Open URL
+	${copy_menu}: Copy Custom Field
+	---
+	${action_menu}: Edit, Move, Delete, Re-generate Submenu
+	${show}: Show Password File
+	${insert_pass}: Insert new Pass Entry
+	${switch}: Switch Pass/Bookmark Mode
+	---
+	${previous_root}: Switch to previous password store (--root)
+	${next_root}: Switch to next password store (--root)
+EOM
+help_val=$?
+
+if [[ $help_val -eq 1 ]]; then
+	exit;
+else
+	unset helptext; mainMenu;
+fi
+}
+
+
+typeMenu () {
+	if [[ -n $default_do ]]; then
+		if [[ $default_do == "menu" ]]; then
+			checkIfPass
+			local -a keys=("${!stuff[@]}")
+			keys=("${keys[@]/$AUTOTYPE_field}")
+			typefield=$({ printf '%s' "${AUTOTYPE_field}" ; printf '%s\n' "${keys[@]}" | sort; } | _rofi -dmenu  -p "Choose Field to type > ")
+			typefield_exit=$?
+			if [[ $typefield_exit -eq 1 ]]; then
+				exit
+			fi
+			case "$typefield" in
+				'') exit;;
+				'pass') sleep $wait; typePass;;
+				"${AUTOTYPE_field}") sleep $wait; autopass;;
+				*) sleep $wait; typeField
+			esac
+			clearUp
+		elif [[ $default_do == "${AUTOTYPE_field}" ]]; then
+			sleep $wait; autopass
+		else
+			${default_do}
+		fi
+	fi
+}
+
+copyMenu () {
+	checkIfPass
+	copyfield=$(printf '%s\n' "${!stuff[@]}" | sort | _rofi -dmenu  -p "Choose Field to copy > ")
+	val=$?
+	if [[ $val -eq 1 ]]; then
+		exit;
+	fi
+	if [[ $copyfield == "pass" ]]; then
+		copyPass;
+	else
+		copyField
+	fi
+	clearUp
+}
+
+actionMenu () {
+	checkIfPass
+	action_content=("< Return"
+		"---"
+		"1 Move Password File"
+		"2 Copy Password File"
+		"3 Delete Password File"
+		"4 Edit Password File"
+		"5 Generate New Password"
+	)
+
+	action=$(printf '%s\n' "${action_content[@]}" | _rofi -dmenu -p "Choose Action > ")
+	if [[ ${action} == "1 Move Password File" ]]; then
+		manageEntry move;
+	elif [[ ${action} == "3 Delete Password File" ]]; then
+		manageEntry delete;
+	elif [[ ${action} == "2 Copy Password File" ]]; then
+		manageEntry copy;
+	elif [[ ${action} == "4 Edit Password File" ]]; then
+		manageEntry edit;
+	elif [[ ${action} == "5 Generate New Password" ]]; then
+		generatePass;
+	elif [[ ${action} == "< Return" ]]; then
+		mainMenu;
+	elif [[ ${action} == "" ]]; then
+		exit
+	fi
+}
+
+showEntry () {
+	if [[ -z $pass_content ]]; then
+		pass_temp=$(PASSWORD_STORE_DIR="${root}" pass show "$selected_password")
+		password="${pass_temp%%$'\n'*}"
+		pass_key_value=$(printf '%s\n' "${pass_temp}" | tail -n+2 | grep ': ')
+		declare -A stuff
+
+		while read -r LINE; do
+			_id="${LINE%%: *}"
+			_val="${LINE#* }"
+			stuff["${_id}"]=${_val}
+		done < <(printf '%s\n' "${pass_key_value}")
+
+		stuff["pass"]=${password}
+
+		if test "${stuff['autotype']+autotype}"; then
+			:
+		else
+			stuff["autotype"]="${USERNAME_field} :tab pass"
+		fi
+
+		pass_content="$(for key in "${!stuff[@]}"; do printf '%s\n' "${key}: ${stuff[$key]}"; done)"
+	fi
+
+	bla_content=("< Return"
+		"${pass_content}"
+	)
+
+	bla=$(printf '%s\n' "${bla_content[@]}" | _rofi -dmenu -mesg "Enter: Copy entry to clipboard" -p "> ")
+	rofi_exit=$?
+
+	word=$(printf '%s' "$bla" | gawk -F': ' '{print $1}')
+
+	if [[ ${rofi_exit} -eq 1 ]]; then
+		exit
+	elif [[ ${rofi_exit} -eq 0 ]]; then
+		if [[ ${bla} == "< Return" ]]; then
+			mainMenu
+		else
+			if [[ -z $(printf '%s' "${stuff[${word}]}") ]]; then
+				printf '%s' "$word" | doClip
+			else
+				printf '%s' "${stuff[${word}]}" | doClip
+			fi
+			if [[ $notify == "true" ]]; then
+				notify-send "rofi-pass" "Copied Password\\nClearing in $clip_clear seconds"
+			fi
+			if [[ $notify == "true" ]]; then
+				(sleep $clip_clear; printf '%s' "" | xclip; printf '%s' "" | xclip -selection clipboard | notify-send "rofi-pass" "Clipboard cleared") &
+			elif [[ $notify == "false" ]]; 	then
+				(sleep $clip_clear; printf '%s' "" | xclip; printf '%s' "" | xclip -selection clipboard) &
+			fi
+			exit
+		fi
+	fi
+	exit
+	unset stuff
+	unset password
+	unset selected_password
+	unset password_temp
+	unset stuff
+	exit
+}
+
+manageEntry () {
+	if [[ "$1" == "edit" ]]; then
+		EDITOR=$EDITOR PASSWORD_STORE_DIR="${root}" pass edit "${selected_password}"
+		mainMenu
+	elif [[ $1 == "move" ]]; then
+		cd "${root}" || exit
+		group_array=(*/)
+		group=$(printf '%s\n' "${group_array[@]%/}" | _rofi -dmenu -p "Choose Group > ")
+		if [[ $group == "" ]]; then
+			exit
+		fi
+		PASSWORD_STORE_DIR="${root}" pass mv "$selected_password" "${group}"
+		mainMenu
+	elif [[ $1 == "copy" ]]; then
+		cd "${root}" || exit
+		group_array=(*/)
+		group=$(printf '%s\n' "${group_array[@]%/}" | _rofi -dmenu -p "Choose Group > ")
+		if [[ $group == "" ]]; then
+			exit
+		else
+			new_name="$(listgpg | _rofi -dmenu -format 'f' -mesg "Copying to same Group. Please enter a name for the new entry" -p "> ")"
+		fi
+		PASSWORD_STORE_DIR="${root}" pass cp "$selected_password" "${group}/${new_name}"
+		mainMenu
+	elif [[ "$1" == "delete" ]]; then
+		HELP="<span color='$help_color'>Selected entry: ${selected_password}</span>"
+		ask_content=("Yes"
+			"No"
+		)
+		ask=$(printf '%s\n' "${ask_content[@]}" | _rofi -mesg "${HELP}" -dmenu -p "Are You Sure? > ")
+		if [[ "$ask" == "Yes" ]]; then
+			PASSWORD_STORE_DIR="${root}" pass rm --force "${selected_password}"
+		elif [[ "$ask" == "No" ]]; then
+			mainMenu
+		elif [[ -z "$ask" ]]; then
+			exit
+		fi
+	else
+		mainMenu
+	fi
+}
+
+insertPass () {
+	url=$(xclip --selection clipboard -o)
+
+	if [[ "${url:0:4}" == "http" ]]; then
+		domain_name="$(printf '%s\n' "${url}" | awk -F / '{l=split($3,a,"."); print (a[l-1]=="com"?a[l-2] OFS:X) a[l-1] OFS a[l]}' OFS=".")"
+		help_content="Domain: ${domain_name}
+		Type name, make sure it is unique"
+	else
+		help_content="Hint: Copy URL to clipboard before calling this menu.
+		Type name, make sure it is unique"
+	fi
+
+	cd "${root}" || exit
+	group_array=(*/)
+	grouplist=$(printf '%s\n' "${group_array[@]%/}")
+	name="$(listgpg | _rofi -dmenu -format 'f' -filter "${domain_name}" -mesg "${help_content}" -p "> ")"
+	val=$?
+
+	if [[ $val -eq 1 ]]; then
+		exit
+	fi
+
+	user_content=("${default_user2}"
+		"${USER}"
+		"${default_user}"
+	)
+
+	user=$(printf '%s\n' "${user_content[@]}" | _rofi -dmenu -mesg "Chose Username or type" -p "> ")
+	val=$?
+
+	if [[ $val -eq 1 ]]; then
+		exit
+	fi
+
+	group_content=("No Group"
+		"---"
+		"${grouplist}"
+	)
+
+	group=$(printf '%s\n' "${group_content[@]}" | _rofi -dmenu -p "Choose Group > ")
+	val=$?
+
+	if [[ $val -eq 1 ]]; then
+		exit
+	fi
+
+	pw=$(printf '%s' "Generate" | _rofi -dmenu -password -p "Password > " -mesg "Type Password or hit Enter to generate one")
+
+	if [[ $pw == "Generate" ]]; then
+		pw=$(_pwgen "${password_length}")
+	fi
+
+	clear
+
+	if [[ "$group" == "No Group" ]]; then
+		if [[ $url == http* ]]; then
+			pass_content=("${pw}"
+				"---"
+				"${USERNAME_field}: ${user}"
+				"${URL_field}: ${url}"
+			)
+			printf '%s\n' "${pass_content[@]}" | PASSWORD_STORE_DIR="${root}" pass insert -m "${name}" > /dev/null && PASSWORD_STORE_DIR="${root}" pass edit "${name}"
+		else
+			pass_content=("${pw}"
+				"---"
+				"${USERNAME_field}: ${user}"
+			)
+			printf '%s\n' "${pass_content[@]}" | PASSWORD_STORE_DIR="${root}" pass insert -m "${name}" > /dev/null && PASSWORD_STORE_DIR="${root}" pass edit "${name}"
+		fi
+	else
+		if [[ $url == http* ]]; then
+			pass_content=("${pw}"
+				"---"
+				"${USERNAME_field}: ${user}"
+				"${URL_field}: ${url}"
+			)
+			printf '%s\n' "${pass_content[@]}" | PASSWORD_STORE_DIR="${root}" pass insert -m "${group}/${name}" > /dev/null && PASSWORD_STORE_DIR="${root}" pass edit "${group}/${name}"
+		else
+			pass_content=("${pw}"
+				"---"
+				"${USERNAME_field}: ${user}"
+			)
+			printf '%s\n' "${pass_content[@]}" | PASSWORD_STORE_DIR="${root}" pass insert -m "${group}/${name}" > /dev/null
+			if [[ $edit_new_pass == "true" ]]; then
+				PASSWORD_STORE_DIR="${root}" pass edit "${group}/${name}"
+			fi
+		fi
+	fi
+}
+
+help_msg () {
+	cat <<'EOF'
+	Usage:
+	rofi-pass [command]
+
+	Commands:
+	--insert         insert new entry to password store
+	--root           set custom root directories (colon separated)
+	--last-used      highlight last used item
+	--show-last      show details of last used Entry
+	--bmarks         start in bookmarks mode
+
+	rofi-pass version 1.5.3
+EOF
+}
+
+get_config_file () {
+	configs=("$ROFI_PASS_CONFIG"
+		"$config_dir/rofi-pass/config"
+		"/etc/rofi-pass.conf")
+
+	# return the first config file with a valid path
+	for config in "${configs[@]}"; do
+		# '-n' is needed in case ROFI_PASS_CONFIG is not set
+		if [[ -n "${config}" && -f "${config}" ]]; then
+			printf "%s" "$config"
+			return
+		fi
+	done
+}
+
+main () {
+	# load config file
+	config_file="$(get_config_file)"
+	[[ -n "$config_file" ]] && source "$config_file"
+
+	# create tmp dir
+	if [[ ! -d "$cache_dir/rofi-pass" ]]; then
+		mkdir -p "$cache_dir/rofi-pass"
+	fi
+
+	# fix keyboard layout if enabled in config
+	if [[ $fix_layout == "true" ]]; then
+		layout_cmd
+	fi
+
+	# set help color
+	if [[ $help_color == "" ]]; then
+		help_color=$(rofi -dump-xresources | grep 'rofi.color.normal' | gawk -F ',' '/,/{gsub(/ /, "", $2); print $2}')
+	fi
+
+	# check for BROWSER variable, use xdg-open as fallback
+	if [[ -z $BROWSER ]]; then
+		export BROWSER=xdg-open
+	fi
+
+	# check if alternative root directory was given on commandline
+	if [[ -r "$cache_dir/rofi-pass/last_used" ]] && [[ $1 == "--last-used" || $1 == "--show-last" ]]; then
+		roots=("$(awk -F ': ' '{ print $1 }' "$cache_dir/rofi-pass/last_used")")
+	elif [[ -n "$2" && "$1" == "--root" ]]; then
+		custom_root=true; IFS=: read -r -a roots <<< "$2"
+	elif [[ -n $root ]]; then
+		custom_root=true; IFS=: read -r -a roots <<< "${root}"
+	elif [[ -n ${PASSWORD_STORE_DIR} ]]; then
+		roots=("${PASSWORD_STORE_DIR}")
+	else
+		roots=("$HOME/.password-store")
+	fi
+	roots_index=0
+	roots_length=${#roots[@]}
+	export root=${roots[$roots_index]}
+	export PASSWORD_STORE_DIR="${root}"
+	case $1 in
+		--insert)
+			insertPass
+			;;
+		--root)
+			mainMenu
+			;;
+		--help)
+			help_msg
+			;;
+		--last-used)
+			if [[ -r "$cache_dir/rofi-pass/last_used" ]]; then
+				entry="$(awk -F ': ' '{ print $2 }' "$cache_dir/rofi-pass/last_used")"
+			fi
+			mainMenu
+			;;
+		--show-last)
+			if [[ -r "$cache_dir/rofi-pass/last_used" ]]; then
+				selected_password="$(awk -F ': ' '{ print $2 }' "$cache_dir/rofi-pass/last_used")" viewEntry
+			else
+				mainMenu
+			fi
+			;;
+		--bmarks)
+			mainMenu --bmarks;
+			;;
+		*)
+			mainMenu
+			;;
+	esac
+}
+
+main "$@"

+ 1 - 0
rofi/.config/rofi/web-search.sh

@@ -32,6 +32,7 @@ URLS=(
 	["maps"]="https://www.openstreetmap.com/search?query="
 	["pirate"]="https://thepiratebay.zone/search/"
 	["search"]="https://search.unbl.ink/?q="
+	["ebay"]="https://www.ebay.com/sch/"
 )
 
 # List for rofi