Compare commits

...

10 commits

6 changed files with 95 additions and 73 deletions

View file

@ -1,65 +1,83 @@
# bwzy - bitwarden ... fuzzy
bwzy is a fuzzy finder for Bitwarden using the official bitwarden cli.
bwzy is a fuzzy finder and auto-filler for Bitwarden (read-only at present).
It runs in the terminal and uses the official bitwarden CLI.
The `bw` cli is great, but not very user-friendly.
`bwzy` tries to make this quicker by caching the information and presenting it via the magnificient [fzf](https://junegunn.github.io/fzf/).
![bwzy screenshot](./bwzy.jpg)
# current features
- READ-ONLY ui
- terminal UI
- more user-friendly than the `bw` command line client
- search based on name and folder
- hide based on name (i.e. "hide archives")
- copy user/pass/totp
- cache the items in shared memory (`/dev/shm/`) to make it fast
- cache does not persist through reboots (by default)
- local cache for speed
- refresh/flush cache
- preview items in `YAML` form
- auto-fill for hyprland
- auto-fill (currently working in hyprland)
- one-shot mode for use in scripts
# requirements
The following software is needed by `bwzy`:
- [fzf](https://junegunn.github.io/fzf/) for fuzzy finding
- [bitwarden cli client](https://contributing.bitwarden.com/getting-started/clients/cli) to access bitwarden
- [fzf](https://junegunn.github.io/fzf/) for fuzzy finding
- [jq](https://jqlang.github.io/jq/) to work with the JSON
- [OATH Toolkit](https://www.nongnu.org/oath-toolkit/) allows generating TOTP tokens
- [charmbracelet - gum](https://github.com/charmbracelet/gum) for the loading spinner and color
it also expects `grep`, `sed` and `awk` to be available
It also expects `grep`, `sed` and `awk` to be available
Additinally, you will need clipboard and keyboard automation such as `wtype` and `wl-copy` under wayland.
Additionally, you will need clipboard and keyboard automation such as `wtype` and `wl-copy` under wayland.
## configuration
All configuration is done via environment variables, with defaults shown
```bash
BWZY_CACHE=`/dev/shm/bwzy-cache` # where the passwords are cached
BWZY_KEEP_CACHE='true' # set to false and cache will be purged
BWZY_COPY_CMD='wl-copy' # the command to copy something to the clipboard
BWZY_TYPE_CMD='wtype' # the command used to type / send keyboard events
BWZY_HIDE_CMD='' # the command to hide bwzy
BWZY_REFOCUS_CMD='' # the command to refocuse the previous window
BWZY_COPY_AND_HIDE='true' # set to 'false' to not hide bwzy on copy
BWZY_NOTIFY_CMD='notify-send -i bitwarden' # send a notification
# functional settings
BWZY_CACHE=`/dev/shm/bwzy-cache` # where the passwords are cached
BWZY_KEEP_CACHE='true' # set to false and cache will be purged on exit
BWZY_COPY_CMD='wl-copy' # the command to copy something to the clipboard
BWZY_TYPE_CMD='wtype' # the command used to type / send keyboard events
BWZY_HIDE_CMD='' # the command to hide bwzy.desktop or a terminal named `bwzy`
BWZY_REFOCUS_CMD='' # the command to refocus the previous window
BWZY_COPY_AND_HIDE='true' # set to 'false' to not hide bwzy on copy - does not affect auto-fill
BWZY_NOTIFY_CMD='notify-send -i bitwarden' # send a notification (optional, but nice to know if a TOTP has been copied)
BWZY_FILTER="-zz~ " # exclude items with this string in name of folder
# cosmetic overrides which adjust the looks
BWZY_USER_SYMBOL='u+'
BWZY_PASS_SYMBOL='p+'
BWZY_TOTP_SYMBOL='t+'
BWZY_LINK_SYMBOL='l+'
BWZY_AUTO_SYMBOL='a+'
BWZY_FOLDER_SYMBOL='/'
BWZY_POINTER_SYMBOL='> '
BWZY_PROMPT_SYMBOL='? '
BWZY_USER_SYMBOL='u+' # new prompt on user copy
BWZY_PASS_SYMBOL='p+' # new prompt on password copy
BWZY_TOTP_SYMBOL='t+' # new prompt on TOTP copy
BWZY_LINK_SYMBOL='l+' # new prompt on link copy
BWZY_AUTO_SYMBOL='a+' # new prompt on auto-fill
BWZY_FOLDER_SYMBOL='/' # new symbol used for a folder
BWZY_POINTER_SYMBOL='> ' # the line marker used by FZF
BWZY_PROMPT_SYMBOL='? ' # the prompt symbol used by FZF
```
`bwzy` is being tested as my daily driver under [Hyprland](https://hypr.land/) and [Wayland](https://wayland.freedesktop.org/) only, but may be adaptable by the intrepid adventurer. The configuration items to look at are:
- `BWZY_COPY_CMD`
- `BWZY_TYPE_CMD`
- `BWZY_HIDE_CMD`
- `BWZY_REFOCUS_CMD`
- `BWZY_COPY_AND_HIDE`
- `BWZY_NOTIFY_CMD`
Note: under [hyprland](https://hypr.land/) the following works:
```bash
BWZY_HIDE_CMD=hyprctl dispatch movetoworkspacesilent special:tools,title:bwzy
BWZY_REFOCUS_CMD=hyprctl dispatch focuscurrentorlast
```
which places the bwzy window launched vi the [bwzy.desktop](./bwzy.desktop) file into a special workspace when not needed.
This hides the bwzy window, a terminal window with the title set to `bwzy`, to a special workplace. A shortcut defined in my window manager brings that window to the foreground.
The [bwzy.desktop](./bwzy.desktop) file shows the way I launch it.
If you have a font and terminal with support for unicode, you can use fancy symbols. Here are mine:
```bash
BWZY_USER_SYMBOL=' '
@ -72,23 +90,13 @@ BWZY_POINTER_SYMBOL=' '
BWZY_PROMPT_SYMBOL=' '
```
## arch install
```bash
pacman -S fzf bitwarden-cli jq haskell-yaml oath-toolkit gum
```
## install dependency
# tips and tricks
Arch Linux:
```bash
sudo pacman -S --needed wtype ydotool xdotool xvkbd wl-clipboard xclip xsel bat jq sed awk fzf
```
## tips and tricks
By default the cache is removed on reboot since it lives in `/dev/shm/`. if you have a secure encrypted file system you can override the cache location so that it persists during reboots. Be safe and know your risks.
By default the cache is removed on reboot since it lives in `/dev/shm/`. If you have a secure encrypted file system you can override the cache location so that it persists during reboots. I use this often as I'm often completely offline, but still need access to my passwords for offline work. Be safe and know your risks.
# feature ideas
- ~~auto-fill~~ (done)
- ~~"archive" feature to filter thingsi~~ (done)
- ability to edit an entry
- ability to add a new entry
- ~~"archive" feature to filter things~~ (done)
- edit an entry
- add a new entry
- folder based navigation (as in select from list of folders)

53
bwzy
View file

@ -10,12 +10,10 @@ cleanup() {
# defaults
BWZY_CACHE="${BWZY_CACHE:-/dev/shm/bwzy-cache}"
BWZY_FILTER="${BWZY_FILTER:-zz~ }"
# options passed to fzf for default and oneshot modes
BWZY_DEFAULT_OPTS=(--layout reverse --height 100%)
BWZY_ONESHOT_OPTS=(--layout default --height 10 --no-header)
bwzy_autofill=${BWZY_AUTOFILL_HELPER:-"$(dirname "$0")/bwzy-autofill"}
# visual settings
BWZY_POINTER_SYMBOL=${BWZY_POINTER_SYMBOL:-> }
BWZY_PROMPT_SYMBOL=${BWZY_PROMPT_SYMBOL:-? }
BWZY_USER_SYMBOL=${BWZY_USER_SYMBOL:-u+}
@ -24,12 +22,18 @@ BWZY_TOTP_SYMBOL=${BWZY_TOTP_SYMBOL:-t+}
BWZY_LINK_SYMBOL=${BWZY_LINK_SYMBOL:-l+}
BWZY_AUTO_SYMBOL=${BWZY_AUTO_SYMBOL:-a+}
BWZY_FOLDER_SYMBOL=${BWZY_FOLDER_SYMBOL:-/}
export GLAMOUR_STYLE=tokyo-night
# these are needed by the auto-completer
export BWZY_COPY_CMD=${BWZY_COPY_CMD:-wl-copy}
export BWZY_TYPE_CMD=${BWZY_TYPE_CMD:-wtype}
# and the auto-completer itself
export BWZY_AUTOFILL_HELPER=${BWZY_AUTOFILL_HELPER:-$(dirname "$(realpath "$0")")/bwzy-autofill}
export BWZY_TOTP_COPY=${BWZY_TOTP_COPY:-$(dirname "$(realpath "$0")")/bwzy-copy-totp}
# set | rg BWZY
# exit 0
read -r -d '' HELP_TEXT<<'EOH'
bwzy is a fuzzy wrapper to the bitwarden cli
@ -45,13 +49,13 @@ Usage:
EOH
# set some defaults to override based on options
CLEAR_CACHE='false'
SYNC_CACHE='false'
FORCE_SYNC='false'
DEBUG='false'
BWZY_OPTS=("${BWZY_DEFAULT_OPTS[@]}")
FILTER_ARG='-v' # argument to grep
CLEAR_CACHE='false'
DEBUG='false'
FORCE_SYNC='false'
ONESHOT='false'
SYNC_CACHE='false'
FILTER_ARG='-v' # argument to grep
# read in the options
while getopts "acdfhis1" o; do
@ -76,7 +80,12 @@ while getopts "acdfhis1" o; do
;;
h)
# show help and exit
echo "$HELP_TEXT" | gum format
( echo "$HELP_TEXT"
echo -e "\n# active settings:"
echo '```bash'
set | grep '^BWZY_' | sort
echo '```'
) | bat -l markdown --plain
exit 0
;;
s)
@ -151,7 +160,7 @@ pre_action="execute-silent($BWZY_REFOCUS_CMD && $BWZY_HIDE_CMD)"
# set up queries for the fields
select_user="$jq_select_id | .login.username' <$items"
select_pass="$jq_select_id | .login.password' <$items"
select_totp="$jq_select_id | .login.totp' <$items | sed 's/.*secret=//; s/&.*//' | oathtool -b --totp -"
select_totp="$jq_select_id | .login.totp' <$items"
select_link="$jq_select_id | .login.uris[1].uri' <$items"
select_user_pass_totp="$select_user; $select_pass; $select_totp"
@ -164,9 +173,9 @@ if [[ $ONESHOT == 'true' ]]; then
else
copy_user="execute-silent($select_user | $BWZY_COPY_CMD)"
copy_pass="execute-silent($select_pass | $BWZY_COPY_CMD)"
copy_totp="execute-silent($select_totp | $BWZY_COPY_CMD)"
copy_totp="execute-silent($select_totp | $BWZY_TOTP_COPY)"
copy_link="execute-silent($select_link | $BWZY_COPY_CMD)"
auto_paste="execute-silent(($select_user_pass_totp) | $bwzy_autofill)"
auto_paste="execute-silent(($select_user_pass_totp) | $BWZY_AUTOFILL_HELPER)"
copy_user="${pre_action}+${copy_user}+change-prompt($BWZY_USER_SYMBOL)"
copy_pass="${pre_action}+${copy_pass}+change-prompt($BWZY_PASS_SYMBOL)"
@ -178,9 +187,9 @@ fi
preview_item="$jq_select_id' < $items | json2yaml | bat --color=always -p -l yaml"
read -r -d '' fzf_header <<FZF_HEADER
[a-/] preview on/off [a-w] preview wrap [a-h] this help
[a-.] preview on/off [a-/] preview wrap [a-?] this help
[a-u] copy username [a-p] copy password [a-t] copy totp
[a-l] copy link [enter] auto-fill [esc] quit
[a-l] copy link [enter] auto-fill [esc] clear/quit
FZF_HEADER
# | awk -F "$TAB" '{ printf "%s\t%-35s\t%27s\n", $1, $2, $3 }' \
@ -191,22 +200,22 @@ FZF_HEADER
jq -r '.[] | [ .id, .name, "`'"$BWZY_FOLDER_SYMBOL"'" + .folderId + "`" ] | join("'"$TAB"'")' <"$items" \
| sed -e "$folder_sed" \
| grep ${FILTER_ARG} "${BWZY_FILTER}" \
| gum format \
| bat -l markdown --color=always --style=plain \
| fzf --ansi -i --delimiter="$TAB" --with-nth 2,3 \
--header-first \
--marker='' --pointer="$BWZY_POINTER_SYMBOL" \
--prompt="$BWZY_PROMPT_SYMBOL" \
--info 'inline-right:' \
--info 'inline' \
--info-command 'echo "($FZF_MATCH_COUNT/$FZF_TOTAL_COUNT)"' \
--bind "alt-u:$copy_user" \
--bind "alt-p:$copy_pass" \
--bind "alt-t:$copy_totp" \
--bind "alt-l:$copy_link" \
--bind "enter:$auto_paste" \
--bind 'alt-/:toggle-preview' \
--bind 'alt-w:toggle-preview-wrap' \
--bind 'alt-h:toggle-header' \
--bind 'esc:abort' \
--bind 'alt-,:toggle-preview' \
--bind 'alt-/:toggle-preview-wrap' \
--bind 'alt-?:toggle-header' \
--bind 'esc:cancel' \
--bind 'focus:transform-preview-label:echo {2} / {3}' \
--bind "focus:change-prompt($BWZY_PROMPT_SYMBOL)" \
--preview-window 'down:75%:hidden' \

View file

@ -18,9 +18,4 @@ $BWZY_TYPE_CMD \
-s $next_sleep \
-k return
# Copy the TOTP to clipboard
if [[ -n "$TOTP" ]]; then
echo -n "$TOTP" | cli-copy
[[ -n "$BWZY_NOTIFY_CMD" ]] && $BWZY_NOTIFY_CMD "TOTP copied to clipboard"
fi
$BWZY_TOTP_COPY <<<"$TOTP"

10
bwzy-copy-totp Executable file
View file

@ -0,0 +1,10 @@
#/bin/bash
read -r TOTP_STRING || TOTP_STRING="null"
# Copy the TOTP to clipboard
if [[ "$TOTP_STRING" != "null" ]]; then
TOTP=$(echo $TOTP_STRING | sed 's/.*secret=//; s/&.*//' | oathtool -b --totp -)
echo -n "$TOTP" | cli-copy
[[ -n "$BWZY_NOTIFY_CMD" ]] && $BWZY_NOTIFY_CMD "TOTP copied to clipboard"
fi

View file

@ -2,7 +2,7 @@
Name=bwzy
Categories=ConsoleOnly;
GenericName=Bitwarden Fuzzy
Comment=Terminal MUA using notmuch mail
Comment=FZF bitwarden UI
Exec=kitty -T 'bwzy' --detach bwzy
Terminal=false
Icon=bitwarden

BIN
bwzy.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 774 KiB