OpenRiot v4.1 Release Notes

Games — Release Notes

New: Optional Games Installation

Games are no longer forced. On first run of openriot –install , an interactive prompt asks:

Do you want to install Games (~1.75G)? [Y/n]

• Answering Y (or pressing Enter) installs all nine games and remembers the choice. • Answering n skips games, removes the Games submenu from rofi, and remembers the choice. • To change later, delete ~/.config/openriot/games.cfg and re-run openriot –install .

Disk size shown upfront

The prompt displays the total installed size (~1.75 GB) so users know the cost before committing.

Files added

• source/installer/games.go — GamesPreference() and StripGamesFromRofi()

Files modified

• source/main.go — checks preference before deploying desktop configs • source/installer/cmd.go — checks preference before installing packages • source/installer/games.go — prompt includes size hint

Release Notes — settings.go Pure-Go Refactor

What Was Done

File: source/settings/settings.go + source/polybar/polybar.go

Replaced shell subprocess self-reinvocations in the Settings menu with direct Go function calls, eliminating 4 sh -c shell-outs.

Setting │ Before │ After │ Status ───────────────┼──────────────────────────────────────────┼──────────────────────────┼──────────── WireGuard VPN │ exec.Command(“sh”, “-c”, │ wireguard.Toggle() │ ✅ Working │ “$HOME/.local/share/openriot/install/ope │ │ │ nriot –wireguard”).Start() │ │ Night Light │ exec.Command(“sh”, “-c”, │ nightlight.Toggle() │ ✅ Working │ “$HOME/.local/share/openriot/install/ope │ │ │ nriot –night-light”).Start() │ │ Stealth Mode │ exec.Command(“sh”, “-c”, │ macspoof.StealthToggle()│ ✅ Working │ “$HOME/.local/share/openriot/install/ope │ + notifications │ │ nriot –stealth”).Start() │ │ Proton Sync │ exec.Command(“sh”, “-c”, │ polybar.TriggerSync() │ ✅ Working │ “$HOME/.local/share/openriot/install/ope │ │ │ nriot –proton-drive-sync”).Start() │ │

UX Fixes

• Stealth Mode notifications: Added proper notifications (restarting → enabled/disabled) to match –stealth CLI behavior. • Proton Sync label: Changed label from “Turn on/Turn off” to “(Sync)” since it’s an action, not a toggle. Implemented via new label field on entry struct. • Proton Sync not-configured: Added “Not configured” notification when Proton Drive is not set up.

New Function

source/polybar/polybar.go — TriggerSync()

Exported function that encapsulates the full sync flow:

  1. Check if configured → send “Not configured” notification if not
  2. Check sync state → send “Synchronized” notification if already synced
  3. Send “Syncing…” notification and launch alacritty with sync menu

Security Fixes

CVE-level: MAC Spoofing Shell Injection & TOCTOU Race ( source/macspoof/macspoof.go:104 )

The EnableRandomMAC function previously constructed a root-privileged shell command via fmt.Sprintf with unvalidated user input:

  // BEFORE (v4.0) — vulnerable
  cmd := exec.Command("doas", "sh", "-c",
      fmt.Sprintf(`... > /tmp/hostname.tmp && mv /tmp/hostname.tmp %s`, ...))

Two critical vulnerabilities existed:

• Shell injection: Interface names were concatenated into hostnameFile ( “/etc/hostname.” + iface ) without validation. Any shell metacharacter in iface would execute arbitrary commands as root via doas . • TOCTOU race: Writing to predictable /tmp/hostname.tmp allowed symlink attacks. An attacker could create /tmp/hostname.tmp → /etc/passwd and the doas mv would overwrite arbitrary system files as root.

Fix: Complete rewrite using doas ed with no shell subprocess, no temp files, and strict regex validation ( ^[a-z]+[0-9]+$ ):

  // AFTER (v4.1) — safe
  cmd := exec.Command("doas", "ed", "-s", hostnameFile)
  cmd.Stdin = strings.NewReader("0a\nlladdr random\n.\nw\nq\n")

DisableRandomMAC already used safe doas sed (no shell, no temp file) and remains unchanged.


Core Dumps Persisting for GUI Applications ( config/xsession/openriot-xsession , config/fish/config.fish )

Despite login.conf coredump=0 being set during install, Firefox and other X11 applications continued generating firefox.core files in ~/ because:

• login.conf only affects processes that go through login(1) • GUI apps launched via xenodm → ~/.xsession → i3 do not inherit login.conf resource limits

Fix: Added ulimit -c 0 to:

• config/xsession/openriot-xsession:6 — the parent of all X11 processes. This propagates to Firefox, GTK apps, and everything launched from the desktop. • config/fish/config.fish:9 — backup for shell-launched processes.

This is a breaking behavioral change for users who rely on core dumps. The .xsession file always overwrites on install ( docs/architecture.md states “ALWAYS overwrite”), so this will take effect on next openriot –install .


Lock Screen System Complete Rewrite

Directory-Based Organization Replaces Flat Prefix Files

v4.0 used a flat directory with filename prefixes:

~/.local/share/openriot/Locked/ ├── locked_01.jpg ├── locked_02.jpg ├── … ├── stealth_01.jpg └── stealth_02.jpg

v4.1 uses semantic subdirectories:

~/.local/share/openriot/Locked/ ├── default/ # shown in default mode, AND in stealth mode ├── stealth/ # shown only in stealth mode ├── holiday/ # shown in BOTH modes (seasonal, optional) └── retro/ # shown in BOTH modes (classic wallpapers, optional)

Files changed: source/lock/lock.go

Behavior matrix:

Mode │ Pools included ────────────────────────────┼───────────────────────────────────────────────────────────────────── Default (stealth OFF) │ default/.jpg + holiday/.jpg + retro/.jpg Stealth (stealth ON) │ default/.jpg + stealth/.jpg + holiday/.jpg + retro/*.jpg

Bug fixed: In v4.0, stealth mode exclusively showed stealth_.jpg and completely hid locked_.jpg . Users in stealth mode lost access to their entire default wallpaper collection. v4.1 pools both directories.

Migration required: Existing locked_.jpg files must be moved to default/.jpg and stealth_.jpg to stealth/.jpg . The holiday/ and retro/ directories are optional — create them to add images, delete them to revert.


Bug Fixes

Workspace Notifications Restored ( source/workspace/workspace.go:52 )

v3.x showed “On workspace 2” when pressing SUPER+2 while already on workspace 2. v4.0 broke this by silently returning with no notification:

  // v4.0 (broken)
  current := GetCurrent()
  if current == target {
      return // Already on this workspace — NO notification
  }

Fix: Notify even when already on the target workspace:

  // v4.1
  if current == target {
      notify.SendNotify(iconName, "Workspace", fmt.Sprintf("On workspace %d", target), "normal",
1500, 0)
      return
  }

Transmission-GTK Ignored Daemon Config ( install/packages.yaml:215 )

transmission-gtk stores settings in ~/.config/transmission/settings.json , while the standalone daemon uses ~/.config/transmission-daemon/settings.json . v4.0 only deployed to the daemon directory, so transmission-gtk (launched via polybar/rofi) ignored all defaults including blocklist, speed limits, and RPC settings.

Fix: Added second config deployment entry:

  • pattern: “transmission-daemon/settings.json” target: “~/.config/transmission” preserve_if_exists: [settings.json]

Cleanup

Removed Duplicate –notify-dunst Command ( source/main.go:742 , docs/architecture.md:145 )

–notify-dunst and –notify-status were byte-identical handlers calling notify.Status() .

Removed –notify-dunst entirely. –notify-status is the canonical command for polybar integration.


Installer Changes

Stealth Mode No Longer Enabled by Default ( install/packages.yaml:298 )

Removed the mac-spoof source build step from the install pipeline. MAC randomization is no longer automatically enabled during openriot –install . Users must explicitly toggle it via the settings menu or openriot –stealth .


Files Changed

File │ Change ─────────────────────────────────────┼──────────────────────────────────────────────────────────── source/macspoof/macspoof.go │ Security rewrite of EnableRandomMAC source/lock/lock.go │ Directory-based lock screen pooling + holiday/retro │ support source/workspace/workspace.go │ Restored “On workspace N” notification source/main.go │ Removed –notify-dunst duplicate config/xsession/openriot-xsession │ Added ulimit -c 0 config/fish/config.fish │ Added ulimit -c 0 install/packages.yaml │ Removed auto-enable stealth; added transmission-gtk config │ path docs/architecture.md │ Removed –notify-dunst documentation