Copy a password without leaving a trace of it

The launcher's Copy Password command, built alone and last as the plan
required, because every line of it is the security design: the secret
travels rbw to wl-copy through a pipe -- never argv, never a file --
and the copy carries wl-clipboard's --sensitive hint, which vicinae's
clipboard history documents it ignores. That claim was not taken on
faith: a plain probe landed in the live history database and a
sensitive one did not, before any of this was written. A transient
timer clears the clipboard after thirty seconds. An unconfigured rbw
gets a setup message; a vault that locks between list and get gets an
honest failure instead of an empty copy claiming success. rbw joins
desktop-packages, and the contract pins the whole journey with a stub
vault, including that the secret never appears on a command line.
This commit is contained in:
Gabriel Brown
2026-08-21 19:38:38 -04:00
parent 4e978bf3b7
commit c02329ac3c
5 changed files with 125 additions and 13 deletions
+40 -1
View File
@@ -7,6 +7,7 @@
# panama-pick process pick a process by CPU; SIGTERM it
# panama-pick ssh pick a Host from ~/.ssh/config; open a session
# panama-pick recent pick a recently used file; open it
# panama-pick password pick a Bitwarden entry; copy it, concealed
#
# One helper rather than five scripts because every subcommand is the same
# sentence: build a list, let dmenu pick a line, act on the index. dmenu is
@@ -96,8 +97,46 @@ PY
[[ -n "$idx" ]] || exit 0
exec xdg-open "$(line_at "$idx" <<<"$entries")"
;;
password)
# The security shape, in one place:
# * the secret travels rbw -> pipe -> wl-copy; it is never an argument
# and never a file (argv is world-readable, files outlive intentions)
# * --sensitive offers the x-kde-passwordManagerHint MIME, which
# vicinae's clipboard history documents it ignores -- verified against
# the live history before this was written
# * the clipboard clears itself after 30 seconds, from a transient timer
# so it happens even if this shell is long gone
if ! command -v rbw >/dev/null 2>&1; then
notify-send "Passwords" "rbw is not installed" 2>/dev/null || true
exit 1
fi
if ! entries="$(rbw list --fields name,user 2>/dev/null)" || [[ -z "$entries" ]]; then
notify-send "Passwords" \
"rbw is not set up. Run: rbw config set email <you>; rbw register; rbw login" \
2>/dev/null || true
exit 0
fi
idx="$(awk -F'\t' '{ if ($2 != "") printf "%s (%s)\n", $1, $2; else print $1 }' <<<"$entries" \
| menu "Copy password" 'Bitwarden ({count})')" || exit 0
[[ -n "$idx" ]] || exit 0
picked="$(line_at "$idx" <<<"$entries")"
name="$(cut -f1 <<<"$picked")"
user="$(cut -f2 <<<"$picked")"
# `--` keeps an entry named like a flag from parsing as one; the pipeline
# status catches a vault that locked between list and get, so a failed
# read is reported instead of an empty copy claiming success.
if ! rbw get -- "$name" ${user:+"$user"} | wl-copy --trim-newline --sensitive; then
notify-send "Passwords" "Could not read \"$name\" — is the vault locked?" 2>/dev/null || true
exit 1
fi
systemd-run --user --collect --on-active=30s \
--unit="panama-clip-clear-$(date +%s)-$RANDOM" \
wl-copy --clear >/dev/null 2>&1 || true
notify-send --icon=dialog-password-symbolic \
"Password copied" "\"$name\" — the clipboard clears in 30 seconds" 2>/dev/null || true
;;
*)
echo 'usage: panama-pick window|quit-window|process|ssh|recent' >&2
echo 'usage: panama-pick window|quit-window|process|ssh|recent|password' >&2
exit 2
;;
esac
+9
View File
@@ -0,0 +1,9 @@
#!/usr/bin/env bash
# @vicinae.schemaVersion 1
# @vicinae.title Copy Password
# @vicinae.mode silent
# @vicinae.icon ../../icons/hicolor/scalable/apps/panama-settings.svg
# @vicinae.description Pick a Bitwarden entry; the password lands on the clipboard, concealed from history, and clears in 30 seconds.
# @vicinae.keywords ["password", "bitwarden", "vault", "credentials", "login", "secret"]
exec "$HOME/.config/quickshell/scripts/panama-pick" password