v1.2.0
Five security review passes over the whole plugin since 1.1.1, each starting
cold with no memory of the last. Thirteen findings, all fixed, all with
regression tests. Nothing here changes how the plugin is used.
The vault stays shut
A suspended machine now counts against the auto-lock. Qt schedules its
timers on the monotonic clock, which Linux stops while the machine is
suspended, so a fifteen-minute countdown armed just before the lid closed still
had fifteen minutes left when the lid opened -- a vault left overnight came
back exactly as open as it was left. The deadline is now kept in wall-clock
terms as well and polled, and between the two it is whichever notices first
that locks.
A vault read that lands after the lock is discarded. Nothing cancels a bw
that is already running, and bw list items takes seconds on a large vault. A
lock or a logout could be followed a moment later by the whole item list
arriving and settling back into a panel that had just thrown it away -- every
login's password rides along in its raw object. After logging in to a second
account, the first account's items were what the list drew, and what Enter
copied, until the new account's items landed. Every reader now records the
vault generation it started under, and an answer from a generation that has
passed is dropped.
Logging out takes the keyring with it. Two of the three entries the plugin
writes are the master password -- as it is for fingerprint unlock, encrypted
under your PIN for PIN unlock -- and both live in the login keyring, which is a
file on disk. The PIN copy was never cleared on logout, and the fingerprint
copy only when the panel happened to believe a reader was present. Both are
cleared unconditionally now, as is the session token when the vault locks.
Locking clears what the panel is holding. A generated password nobody
copied, an item or Send left mid-compose, the payload on its way to bw, and
the master password typed into either setup form all used to outlive a lock in
a process that runs for the whole desktop session.
Nothing outside is trusted
A hostile server cannot exhaust or mislead the shell. A forty-byte reply
claiming an item had two hundred million attachments was enough to take the
whole Quickshell process down, bar included; list lengths are bounded now. An
attachment size reported in exponential notation silently disabled both the
download size limit and the free-space check, because the shell reads 1e+30
as an error rather than a number -- sizes are clamped before they reach the
script. And an id the server chooses can no longer arrive at bw as an option:
-- ends the options first.
A web page cannot freeze the bar. The scanner that reads a window title
looking for a site name backtracked quadratically, so a long enough title --
and a page writes its own title -- cost seconds of the GUI thread every time
the panel opened over that tab. It reads the same titles the same way in one
linear pass now. Learned suggestions are also bounded: the store only ever
grew, and the first read past its cap wiped everything you had taught it.
The generator's server is trusted only while it is ours. bw serve has no
authentication and a loopback port is reachable by every account on the
machine, so an HTTP 200 was never evidence the answer came from us. The port is
probed before we start, anything already answering means bw generate carries
that visit instead, and a value already delivered is dropped if our own server
turns out not to have bound. The server also now lives only as long as the
generator screen rather than the whole session.
Settings cannot fail open
Nothing validates shell.json, and a bad value there failed quietly in the
dangerous direction: a non-numeric minute count reached QML as NaN, landed in
an integer property as 0, and 0 is how "never lock" is spelled, while a
count past the documented ceiling overflowed the timer's interval into a
negative number that never fired. Each numeric setting is now held to its
documented range on the way in, and anything unreadable falls back to its
default rather than to zero.