diff --git a/rust/windows-client/src-tauri/src/client.rs b/rust/windows-client/src-tauri/src/client.rs index b37e6bc4b..466665dc7 100644 --- a/rust/windows-client/src-tauri/src/client.rs +++ b/rust/windows-client/src-tauri/src/client.rs @@ -50,10 +50,6 @@ pub(crate) struct GuiParams { inject_faults: bool, } -/// Newtype for our per-user directory in AppData, e.g. -/// `C:/Users/$USER/AppData/Local/dev.firezone.client` -pub(crate) struct AppLocalDataDir(std::path::PathBuf); - // Hides Powershell's console on Windows // const CREATE_NO_WINDOW: u32 = 0x08000000; diff --git a/rust/windows-client/src-tauri/src/client/crash_handling.rs b/rust/windows-client/src-tauri/src/client/crash_handling.rs index 8c1231368..d21affd43 100755 --- a/rust/windows-client/src-tauri/src/client/crash_handling.rs +++ b/rust/windows-client/src-tauri/src/client/crash_handling.rs @@ -4,9 +4,8 @@ //! //! TODO: Capture crash dumps on panic. -use crate::client::BUNDLE_ID; +use crate::client::settings::app_local_data_dir; use anyhow::{anyhow, bail, Context}; -use known_folders::{get_known_folder_path, KnownFolder}; use std::{fs::File, io::Write, path::PathBuf}; const SOCKET_NAME: &str = "dev.firezone.client.crash_handler"; @@ -104,10 +103,10 @@ impl minidumper::ServerHandler for Handler { /// Called when a crash has been received and a backing file needs to be /// created to store it. fn create_minidump_file(&self) -> Result<(File, PathBuf), std::io::Error> { - let dump_path = get_known_folder_path(KnownFolder::ProgramData) - .expect("should be able to find C:/ProgramData") - .join(BUNDLE_ID) - .join("dumps") + let dump_path = app_local_data_dir() + .expect("app_local_data_dir() failed") + .join("data") + .join("logs") .join("last_crash.dmp"); if let Some(dir) = dump_path.parent() { diff --git a/rust/windows-client/src-tauri/src/client/gui.rs b/rust/windows-client/src-tauri/src/client/gui.rs index c286eb29b..bb6d05afa 100644 --- a/rust/windows-client/src-tauri/src/client/gui.rs +++ b/rust/windows-client/src-tauri/src/client/gui.rs @@ -3,12 +3,12 @@ // TODO: `git grep` for unwraps before 1.0, especially this gui module -use crate::client::{self, deep_link, network_changes, AppLocalDataDir, BUNDLE_ID}; +use crate::client::{self, deep_link, network_changes, BUNDLE_ID}; use anyhow::{anyhow, bail, Context, Result}; use arc_swap::ArcSwap; use client::{ about, logging, - settings::{self, AdvancedSettings}, + settings::{self, app_local_data_dir, AdvancedSettings}, }; use connlib_client_shared::{file_logger, ResourceDescription}; use connlib_shared::messages::ResourceId; @@ -29,14 +29,6 @@ const MAX_PARTITION_TIME: Duration = Duration::from_secs(60 * 60 * 24 * 30); pub(crate) type CtlrTx = mpsc::Sender; -// TODO: Move out of GUI module, shouldn't be here -pub(crate) fn app_local_data_dir() -> Result { - let path = known_folders::get_known_folder_path(known_folders::KnownFolder::LocalAppData) - .context("should be able to ask Windows where AppData/Local is")? - .join(BUNDLE_ID); - Ok(AppLocalDataDir(path)) -} - /// All managed state that we might need to access from odd places like Tauri commands. /// /// Note that this never gets Dropped because of @@ -63,7 +55,9 @@ impl Managed { /// Runs the Tauri GUI and returns on exit or unrecoverable error pub(crate) fn run(params: client::GuiParams) -> Result<()> { // Change to data dir so the file logger will write there and not in System32 if we're launching from an app link - let cwd = app_local_data_dir()?.0.join("data"); + let cwd = app_local_data_dir() + .ok_or_else(|| anyhow!("app_local_data_dir() failed"))? + .join("data"); std::fs::create_dir_all(&cwd)?; std::env::set_current_dir(&cwd)?; diff --git a/rust/windows-client/src-tauri/src/client/settings.rs b/rust/windows-client/src-tauri/src/client/settings.rs index a9ba4c9d4..aa14bcefb 100644 --- a/rust/windows-client/src-tauri/src/client/settings.rs +++ b/rust/windows-client/src-tauri/src/client/settings.rs @@ -1,13 +1,24 @@ //! Everything related to the Settings window, including //! advanced settings and code for manipulating diagnostic logs. -use crate::client::gui::{self, ControllerRequest, Managed}; -use anyhow::Result; +use crate::client::gui::{ControllerRequest, Managed}; +use anyhow::{anyhow, Result}; use serde::{Deserialize, Serialize}; -use std::{path::PathBuf, result::Result as StdResult, time::Duration}; +use std::{path::PathBuf, time::Duration}; use tokio::sync::oneshot; use url::Url; +/// Returns e.g. `C:/Users/User/AppData/Local/dev.firezone.client +/// +/// This is where we can save config, logs, crash dumps, etc. +/// It's per-user and doesn't roam across different PCs in the same domain. +/// It's read-write for non-elevated processes. +pub(crate) fn app_local_data_dir() -> Option { + let path = known_folders::get_known_folder_path(known_folders::KnownFolder::LocalAppData)? + .join(crate::client::BUNDLE_ID); + Some(path) +} + #[derive(Clone, Deserialize, Serialize)] pub(crate) struct AdvancedSettings { pub auth_base_url: Url, @@ -43,7 +54,9 @@ struct DirAndPath { } fn advanced_settings_path() -> Result { - let dir = gui::app_local_data_dir()?.0.join("config"); + let dir = app_local_data_dir() + .ok_or_else(|| anyhow!("app_local_data_dir() failed"))? + .join("config"); let path = dir.join("advanced_settings.json"); Ok(DirAndPath { dir, path }) } @@ -52,7 +65,7 @@ fn advanced_settings_path() -> Result { pub(crate) async fn apply_advanced_settings( managed: tauri::State<'_, Managed>, settings: AdvancedSettings, -) -> StdResult<(), String> { +) -> Result<(), String> { apply_advanced_settings_inner(managed.inner(), &settings) .await .map_err(|e| e.to_string()) @@ -61,7 +74,7 @@ pub(crate) async fn apply_advanced_settings( #[tauri::command] pub(crate) async fn reset_advanced_settings( managed: tauri::State<'_, Managed>, -) -> StdResult { +) -> Result { let settings = AdvancedSettings::default(); apply_advanced_settings_inner(managed.inner(), &settings) @@ -74,7 +87,7 @@ pub(crate) async fn reset_advanced_settings( #[tauri::command] pub(crate) async fn get_advanced_settings( managed: tauri::State<'_, Managed>, -) -> StdResult { +) -> Result { let (tx, rx) = oneshot::channel(); if let Err(e) = managed .ctlr_tx