From 7868ffe909a369758ee7f997f201c11c39528d19 Mon Sep 17 00:00:00 2001 From: SusieeTheFemboy <96988330+SusieeTheLinuxUser@users.noreply.github.com> Date: Thu, 29 Oct 2026 04:38:06 +0100 Subject: [PATCH 1/3] Address review: no /tmp fallback, create the private dir private_dir() creates $XDG_RUNTIME_DIR or ~/.cache if missing and no longer falls back to a shared temp dir; without either, the status file and window raising are skipped. Co-Authored-By: Claude Opus 5.5 --- src/main.rs | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/main.rs b/src/main.rs index 22cb31c..f0f53e8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -232,15 +232,18 @@ fn status_rows(st: &State) -> Vec<(String, String)> { rows } -/// Somewhere only this user can write: never a shared /tmp, where another user could plant files. -fn private_dir() -> PathBuf { - dirs::runtime_dir().or_else(dirs::cache_dir).unwrap_or_else(std::env::temp_dir) +/// Somewhere only this user can write, never a shared /tmp where another user could plant files +/// or symlinks. None if there's no such place: the status file and window raising are skipped. +fn private_dir() -> Option { + let dir = dirs::runtime_dir().or_else(dirs::cache_dir)?; + std::fs::create_dir_all(&dir).ok()?; + Some(dir) } /// For the KDE widget (`plasmoid/`), which polls this file while Rig Hub runs. The widget looks in /// the same place: `${XDG_RUNTIME_DIR:-${XDG_CACHE_HOME:-$HOME/.cache}}`. -fn status_path() -> PathBuf { - private_dir().join("rig-hub-status.json") +fn status_path() -> Option { + Some(private_dir()?.join("rig-hub-status.json")) } fn write_status(st: &State, rows: &[(String, String)]) -> bool { @@ -248,7 +251,9 @@ fn write_status(st: &State, rows: &[(String, String)]) -> bool { Some(audio::Battery::Level(p) | audio::Battery::Charging(Some(p))) => format!("{p}%"), _ => String::new(), }; - write_atomic(&status_path(), &serde_json::json!({ "panel": panel, "rows": rows }).to_string()) + // nowhere to write: nothing to retry either + let Some(path) = status_path() else { return true }; + write_atomic(&path, &serde_json::json!({ "panel": panel, "rows": rows }).to_string()) } /// Write then rename, so readers (the widget, Plasma) never see half a file. @@ -518,7 +523,7 @@ fn kwin_raise() { fn raise() { use std::io::Write; use std::os::unix::fs::OpenOptionsExt; - let script = private_dir().join("rig-hub-raise.js"); + let Some(script) = private_dir().map(|d| d.join("rig-hub-raise.js")) else { return }; let js = r#"for (const w of workspace.windowList()) if (w.resourceClass === "rig-hub") { w.minimized = false; workspace.activeWindow = w; }"#; // KWin runs whatever is in this file, so nobody else may be able to write it let _ = std::fs::remove_file(&script); @@ -1353,8 +1358,8 @@ fn main() -> eframe::Result { }, }; // numbers from a previous run would look live until our first refresh - if screenshot.is_none() { - let _ = std::fs::remove_file(status_path()); + if let (None, Some(path)) = (&screenshot, status_path()) { + let _ = std::fs::remove_file(path); } #[cfg(target_os = "linux")] install_widget(); From 7d067c7825072be5d5a3d47bfa90c939b1cb128b Mon Sep 17 00:00:00 2001 From: SusieeTheFemboy <96988330+SusieeTheLinuxUser@users.noreply.github.com> Date: Thu, 29 Oct 2026 04:41:25 +0100 Subject: [PATCH 2/3] Rig Hub 0.1.0-alpha.2 Co-Authored-By: Claude Opus 5.5 --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8caedc7..539a480 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2886,7 +2886,7 @@ dependencies = [ [[package]] name = "rig-hub" -version = "0.1.0-alpha.1" +version = "0.1.0-alpha.2" dependencies = [ "anyhow", "dirs", diff --git a/Cargo.toml b/Cargo.toml index 5eabf49..089e621 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rig-hub" -version = "0.1.0-alpha.1" +version = "0.1.0-alpha.2" edition = "2024" license = "GPL-3.0-or-later" description = "One app for your mouse, cooler LCD, headset and mic on Linux" From b2c3906471a4fc4b3012349b843ca7ecbea66d11 Mon Sep 17 00:00:00 2001 From: SusieeTheFemboy <96988330+SusieeTheLinuxUser@users.noreply.github.com> Date: Thu, 29 Oct 2026 04:48:13 +0100 Subject: [PATCH 3/3] Address review: owner-only cache fallback, retry with no dir Without $XDG_RUNTIME_DIR, use ~/.cache/rig-hub set to 0700 (the widget reads the same place), and retry the status write later when there's no directory yet. Co-Authored-By: Claude Opus 5.5 --- plasmoid/contents/ui/main.qml | 2 +- src/main.rs | 17 +++++++++++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/plasmoid/contents/ui/main.qml b/plasmoid/contents/ui/main.qml index 1c8aa59..6f69593 100644 --- a/plasmoid/contents/ui/main.qml +++ b/plasmoid/contents/ui/main.qml @@ -10,7 +10,7 @@ PlasmoidItem { // { panel: "85%", rows: [[label, value], …] } written by Rig Hub; null while it isn't running property var status: null // pgrep first: the file outlives Rig Hub, and stale numbers would look live - readonly property string poll: `pgrep -x rig-hub >/dev/null && cat "\${XDG_RUNTIME_DIR:-\${XDG_CACHE_HOME:-$HOME/.cache}}/rig-hub-status.json"` + readonly property string poll: `pgrep -x rig-hub >/dev/null && cat "\${XDG_RUNTIME_DIR:-\${XDG_CACHE_HOME:-$HOME/.cache}/rig-hub}/rig-hub-status.json"` // a second launch just brings the running one to the front readonly property string open: `PATH="$HOME/.local/bin:$HOME/.cargo/bin:$PATH" setsid -f rig-hub` diff --git a/src/main.rs b/src/main.rs index f0f53e8..e535a64 100644 --- a/src/main.rs +++ b/src/main.rs @@ -235,13 +235,22 @@ fn status_rows(st: &State) -> Vec<(String, String)> { /// Somewhere only this user can write, never a shared /tmp where another user could plant files /// or symlinks. None if there's no such place: the status file and window raising are skipped. fn private_dir() -> Option { - let dir = dirs::runtime_dir().or_else(dirs::cache_dir)?; + if let Some(dir) = dirs::runtime_dir() { + return Some(dir); // the system makes it owner-only + } + // ~/.cache can be group-writable under a loose umask, so use our own owner-only folder in it + let dir = dirs::cache_dir()?.join("rig-hub"); std::fs::create_dir_all(&dir).ok()?; + #[cfg(unix)] + { + use std::os::unix::fs::PermissionsExt; + std::fs::set_permissions(&dir, std::fs::Permissions::from_mode(0o700)).ok()?; + } Some(dir) } /// For the KDE widget (`plasmoid/`), which polls this file while Rig Hub runs. The widget looks in -/// the same place: `${XDG_RUNTIME_DIR:-${XDG_CACHE_HOME:-$HOME/.cache}}`. +/// the same place: `${XDG_RUNTIME_DIR:-${XDG_CACHE_HOME:-$HOME/.cache}/rig-hub}`. fn status_path() -> Option { Some(private_dir()?.join("rig-hub-status.json")) } @@ -251,8 +260,8 @@ fn write_status(st: &State, rows: &[(String, String)]) -> bool { Some(audio::Battery::Level(p) | audio::Battery::Charging(Some(p))) => format!("{p}%"), _ => String::new(), }; - // nowhere to write: nothing to retry either - let Some(path) = status_path() else { return true }; + // nowhere to write yet: false, so the next refresh tries again + let Some(path) = status_path() else { return false }; write_atomic(&path, &serde_json::json!({ "panel": panel, "rows": rows }).to_string()) }