OpenRiot v6.8 — Hello, Friend
“I’m in.” — every hacker movie, one second before the disaster that would have been prevented by input validation
Release Overview
v6.8 is the release where we sat down with a printout of the entire
codebase, a red pen, and the disposition of someone who just found out
their home directory is /. No new features. No new modules. Just a
full security and code quality audit of every .go file in the tree,
executed one surgical change at a time.
Twenty-two functions were silently discarding the error from
os.UserHomeDir(). Three packages were compiling the same regex on
every polybar tick. A real OpenWeatherMap API key was sitting in
plain source code. A hardcoded Proton Mail URL had your account index
baked into a public binary. A Firefox Private window launched with the
same WM_CLASS as regular Firefox and could never get its own icon.
v6.7 was proof. v6.8 is clean.
Total changes: 35 audit fixes, 1 security fix, 2 UX improvements.
🔐 Security: Stop Leaking Secrets in Source
There is a rule in operational security older than the internet: you do not commit credentials to a repository. We violated it.
Hardcoded OpenWeatherMap API Key Removed
source/weather/weather.go contained a live API key as a package
constant:
// WRONG — and embarrassing
apiKey = "85a4e3c55b73909f42c6a23ec35b7147"
Every clone of this repo, every fork, every reader of the git history
had this key. It is gone. The weather module now requires api= in
~/.config/weather.cfg. No key configured → module hidden. Per the
architecture docs, this was always the intended behavior. The constant
was a shortcut that became a liability.
Hardcoded Personal Proton Mail URL Removed
--proton opened https://mail.proton.me/u/11/inbox — with /u/11/
being a user-specific account index belonging to exactly one person on
the planet. Everyone else got redirected. It now opens
https://mail.proton.me/inbox like a normal link.
🏠 The $HOME Problem
Here is a thing that happens: you call os.UserHomeDir(), ignore the
error, and build a path from an empty string. The path becomes
/.cache/openriot/crypto.json. You try to read it. You fail silently.
Or worse — you os.MkdirAll it. At filesystem root.
Twenty-two instances of this pattern existed across the codebase. Every single one has been fixed. The pattern appeared in:
- Package-level
var home, _ = os.UserHomeDir()(init-time, silent) os.Getenv("HOME")with no fallback (unset in non-login contexts)- Inline
home, _ := os.UserHomeDir()with discarded error
Every fix follows the same rule: check the error, return it or return
a safe default. No silent failures. No writes to /.
Affected packages: backgrounds, crypto, installer (cmd, crush,
utils), lock (lock, cache), network, nightlight, notify
(notify, cooldown), paths, polybar, rofi, screenrec, screenshot,
settings, weather, windowicon, wireguard, workspaceicons.
🗑️ Dead Code Burial
Ghost code. It compiles. It ships. It does nothing. Or worse — it does something wrong and you just never noticed because nothing calls it.
--version Registry Entry
commands.go registered --version as a dispatchable command. It
was never reachable — main.go intercepts --version before the
registry is consulted. The handler used os.Getenv("OPENRIOT_VERSION")
which is empty at runtime (version is injected at build time via
ldflags). It would have printed openriot (blank). Removed.
GetWithTimeout in update/update.go
GetWithTimeout(timeout time.Duration) accepted a timeout parameter
and then ignored it entirely, calling getRemoteVersion() which had
its own hardcoded 10-second timeout. The parameter was decorative.
While removing it, the duplicate private functions getLocalVersion()
and getRemoteVersion() — which were inferior copies of the exported
versions in versions.go — were also eliminated.
getCurrentUsername() in polybar/polybar.go
Defined. Never called. Sole reason "os/user" was imported. Gone.
Duplicate formatNumber in crypto/crypto.go
Three separate functions formatted numbers with commas. formatNumber
was identical to formatNumberWithWidth(v, 10). formatNumberSimple
was identical to formatNumberWithWidth(v, 0). Both are now one-line
delegations. The loop body exists exactly once.
Duplicate runStealthNotify Body
runStealthNotify() in helpers.go duplicated the entire body of
runStealthToggle() in its else-branch. The duplicate bloc vanished;
the else-branch now calls runStealthToggle().
Duplicate Next() / Prev() in backgrounds/backgrounds.go
80 lines of identical wallpaper-cycling logic duplicated between
Next() and Prev(). Extracted to cycle(home string, delta int) int.
Next() calls cycle(home, 1). Prev() calls cycle(home, -1).
Duplicate Release Notes Path Resolution
ShowReleaseNotes() and AskShowReleaseNotes() both independently
resolved homeDir → VERSION file → version string → notes path.
Extracted to getReleaseNotesPath() (string, error).
⚡ Optimization: Regex Compiled Once
Three packages were calling regexp.MatchString(pattern, line) inside
a tight loop over ifconfig output on every polybar tick. This
recompiles the pattern on every iteration — every line, every call.
A compiled *regexp.Regexp is now a package-level variable in each:
network/network.go—ifaceLineRE(used ingetWifiInterfaceandgetEthInterface)macspoof/macspoof.go—ifaceLineRE+ifaceNameRE(used inGetInterfacesandEnableRandomMAC)screen/screen.go—resDimensionRE(used inGetWidthandGetResolution)
One compile per process lifetime instead of one per line per call.
🦊 Firefox Private Window Icon
Firefox Private browsing windows shared WM_CLASS=firefox with
regular Firefox. There was no way to distinguish them in workspace
icons — both showed .
The fix is two parts:
config/rofi/apps.txtnow launches Firefox Private with--class firefox-private, giving it a distinct WM_CLASS.config/window/icons.tomlmapsfirefox-privateto `` — thenf-fa-user_secretglyph (U+F21B) — matching the stealth intent of private browsing.
Open a private window from Rofi, watch the workspace bar show ``
instead of . The distinction is real now.
🌡️ Weather: Icon After Temperature
The weather module was outputting 103°F — icon before temp.
Every other polybar module puts the label after the data. The weather
module now outputs 103°F . Small. Correct.
🔒 HTTP Timeout: Weather
weather/weather.go was calling bare http.Get(url) with no timeout.
Per the architecture docs (and the lesson learned in earlier releases):
http.Get() has no timeout by default and hangs indefinitely on slow
or dead networks. The weather module runs on every polybar tick. A
hung HTTP call means a hung module means a frozen polybar slot.
Fixed with http.Client{Timeout: 10 * time.Second}.
🧾 Files Changed
| File | Nature of Change |
|---|---|
source/weather/weather.go |
API key removed, $HOME fixed, http timeout, icon order |
source/commands/commands.go |
Dead --version removed, $HOME fixed (3 handlers) |
source/commands/helpers.go |
Duplicate stealth logic collapsed, $HOME fixed |
source/update/update.go |
Dead GetWithTimeout, duplicate funcs, home var removed |
source/polybar/polybar.go |
Dead getCurrentUsername removed, $HOME fixed (5 fns) |
source/crypto/crypto.go |
Package-level homeDir fixed, 3 formatters collapsed |
source/network/network.go |
$HOME fixed, regex compiled at package level |
source/backgrounds/backgrounds.go |
$HOME fixed, cycle() extracted from Next/Prev |
source/lock/lock.go |
$HOME in Lock() fixed |
source/lock/cache.go |
$HOME in BuildCache() fixed |
source/notify/notify.go |
statePath() error handled, $HOME fixed in Setup() |
source/notify/cooldown.go |
$HOME fixed in ShouldSend() and RecordSend() |
source/paths/paths.go |
$HOME fixed in GetIconPath() |
source/wireguard/wireguard.go |
Package-level homeDir fixed |
source/macspoof/macspoof.go |
Regex compiled at package level (2 patterns) |
source/nightlight/nightlight.go |
Package-level homeDir fixed |
source/rofi/rofi.go |
Package-level homeDir fixed |
source/screenrec/screenrec.go |
Package-level homeDir/cacheDir fixed |
source/screenshot/screenshot.go |
$HOME fixed |
source/settings/settings.go |
Package-level homeDir fixed |
source/screen/screen.go |
Regex compiled at package level |
source/windowicon/windowicon.go |
$HOME in loadMappings() fixed |
source/installer/cmd.go |
$HOME in findPackagesYaml() fixed |
source/installer/crush.go |
$HOME in install() fixed |
source/installer/utils.go |
$HOME in ShareLog() and MakeIcon() fixed |
source/installer/release_notes.go |
getReleaseNotesPath() extracted |
config/window/icons.toml |
Added firefox-private → `` |
config/rofi/apps.txt |
--class firefox-private added to Firefox Private |
AGENTS.md |
Fixed docs/ paths (wrong case on all three filenames) |
🗣️ Final Words
“v6.0 was beauty. v6.1 was correctness. v6.2 was readability. v6.3 was choice. v6.4 was independence. v6.5 was honesty. v6.6 was precision. v6.7 was proof. v6.8 is clean.”
In Mr. Robot, Elliot doesn’t hack systems by finding zero-days. He finds the thing nobody bothered to fix because it hadn’t caused a problem yet. The unlocked door. The default password. The API key in the repo no one reads anymore.
v6.8 is the episode where we read the repo. All of it. The weather
module had your API key. The Proton link had your account index.
Twenty-two functions were one empty $HOME away from writing state
files to the filesystem root. None of it had caused a visible problem.
That’s the point — it wouldn’t, until it did.
The codebase is now the thing it was supposed to be: a system that knows where it lives, says what it knows, and does not silently fail in the dark.
— The OpenRiot Crew
“The quietest bugs are the ones that never crash. They just slowly do the wrong thing, in the wrong place, forever.”