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.goifaceLineRE (used in getWifiInterface and getEthInterface)
  • macspoof/macspoof.goifaceLineRE + ifaceNameRE (used in GetInterfaces and EnableRandomMAC)
  • screen/screen.goresDimensionRE (used in GetWidth and GetResolution)

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:

  1. config/rofi/apps.txt now launches Firefox Private with --class firefox-private, giving it a distinct WM_CLASS.
  2. config/window/icons.toml maps firefox-private to `` — the nf-fa-user_secret glyph (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.”

← Back to README