#!/bin/sh
# alloy-secret-copy — put something on the clipboard WITHOUT recording it.
#
# The write half of the private clipboard. Alloy ships a password manager
# (gopass) and a clipboard history (cliphist, two `wl-paste --watch` watchers
# in the sway config), and until 2026-08-17 the second recorded the output of
# the first: `gopass show -c` put a password on the clipboard, the watcher
# stored it in cliphist's database on disk, and $mod+Shift+v read it back
# later. gopass clearing the clipboard after its timeout does not help, because
# the copy has already been archived by then. GO alloy problem e7a9e38c.
#
# WHY A SENTINEL RATHER THAN A MIME TYPE. The ecosystem convention is an extra
# offer type, `x-kde-passwordManagerHint: secret`, which KeePassXC emits and
# KDE's Klipper honours. Two things stop it working here: the cliphist in this
# image carries no such string, so there is nothing to honour it, and wl-copy
# offers one type at a time, so a password offered under the hint alone could
# not be pasted into anything that asks for text/plain. Honouring the hint is
# still the right long-term fix and belongs in a clipboard daemon Alloy owns;
# this is the version that works with the tools already installed.
#
# WHY NOT STOP THE WATCHER. Killing `wl-paste --watch` for the duration and
# restarting it afterwards was the other candidate. It fails open: if the
# process that killed it dies before it restarts, clipboard history is dead
# until the next login and nothing says so. The sentinel fails the other way.
#
# THE FAILURE DIRECTION IS THE POINT. A stale sentinel pauses clipboard
# history, which is a feature quietly not working. A missing sentinel writes a
# password to disk. Those are not the same size of mistake, so the mechanism is
# built to fail toward the first: the sentinel is created BEFORE the clipboard
# is written, and a backstop removes it even if nothing ever calls
# alloy-secret-clear.
#
# Reads the secret on stdin so it never appears in argv, which is world
# readable through /proc.

set -eu

sentinel="${XDG_RUNTIME_DIR:-/tmp}/alloy-secret-clipboard"

# The backstop, in seconds. Longer than gopass's own clipboard timeout (45s by
# default) so a normal copy-then-clear cycle is covered by the clear command,
# and short enough that a crash costs a minute of history rather than a
# session. A second copy while one is live re-arms it rather than stacking.
BACKSTOP=90

# Before the write, not after: the watcher fires on the clipboard changing, so
# a sentinel created afterwards would race the thing it exists to prevent.
: > "$sentinel"

# Detached, and it survives this script exiting, which is the whole job: gopass
# calls this and returns immediately.
( sleep "$BACKSTOP"; rm -f "$sentinel" ) >/dev/null 2>&1 &

exec wl-copy
