feat(windows): use ProgramData to store device ID instead of per-user… (#3172)

Fulfills #3159.

This means the device ID is only tied to the Windows install instead of
the user account. I also fixed up the logs and errors for that module
real quick since I was already there.
This commit is contained in:
Reactor Scram
2024-01-11 15:57:55 -06:00
committed by GitHub
parent f22bd6e889
commit 9b7c5d4ebd
4 changed files with 43 additions and 10 deletions

10
rust/Cargo.lock generated
View File

@@ -2053,6 +2053,7 @@ dependencies = [
"hostname",
"ipconfig",
"keyring",
"known-folders",
"rand 0.8.5",
"ring 0.17.7",
"secrecy",
@@ -3232,6 +3233,15 @@ dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "known-folders"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4397c789f2709d23cfcb703b316e0766a8d4b17db2d47b0ab096ef6047cae1d8"
dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "kuchikiki"
version = "0.8.2"

View File

@@ -41,6 +41,7 @@ tracing-panic = "0.1.1"
zip = { version = "0.6.6", features = ["deflate", "time"], default-features = false }
rand = "0.8.5"
windows-implement = "0.52.0"
known-folders = "1.1.0"
# These dependencies are locked behind `cfg(windows)` because they either can't compile at all on Linux, or they need native dependencies like glib that are difficult to get. Try not to add more here.

View File

@@ -1,15 +1,31 @@
use known_folders::{get_known_folder_path, KnownFolder};
use tokio::fs;
/// Get the device ID, generating it if it's not already on disk.
#[derive(thiserror::Error, Debug)]
pub(crate) enum Error {
#[error(transparent)]
Io(#[from] std::io::Error),
#[error("Can't find well-known folder")]
KnownFolder,
}
/// Returns the device ID, generating it and saving it to disk if needed.
///
/// Per <https://github.com/firezone/firezone/issues/2697> and <https://github.com/firezone/firezone/issues/2711>,
/// clients must generate their own random IDs and persist them to disk, to handle situations like VMs where a hardware ID is not unique or not available.
///
/// # Arguments
///
/// * `identifier` - Our Tauri bundle identifier, e.g. "dev.firezone.client"
///
/// Returns: The UUID as a String, suitable for sending verbatim to `connlib_client_shared::Session::connect`.
///
/// Errors: If the disk is unwritable when initially generating the ID, or unwritable when re-generating an invalid ID.
pub(crate) async fn device_id(
app_local_data_dir: &crate::client::AppLocalDataDir,
) -> anyhow::Result<String> {
let dir = app_local_data_dir.0.join("config");
pub(crate) async fn device_id(identifier: &str) -> Result<String, Error> {
let dir = get_known_folder_path(KnownFolder::ProgramData)
.ok_or(Error::KnownFolder)?
.join(identifier)
.join("config");
let path = dir.join("device_id.json");
// Try to read it back from disk
@@ -18,8 +34,9 @@ pub(crate) async fn device_id(
.ok()
.and_then(|s| serde_json::from_str::<DeviceIdJson>(&s).ok())
{
tracing::debug!("device ID loaded from disk is {}", j.id.to_string());
return Ok(j.device_id());
let device_id = j.device_id();
tracing::debug!(?device_id, "Loaded device ID from disk");
return Ok(device_id);
}
// Couldn't read, it's missing or invalid, generate a new one and save it.
@@ -28,9 +45,14 @@ pub(crate) async fn device_id(
// TODO: This file write has the same possible problems with power loss as described here https://github.com/firezone/firezone/pull/2757#discussion_r1416374516
// Since the device ID is random, typically only written once in the device's lifetime, and the read will error out if it's corrupted, it's low-risk.
fs::create_dir_all(&dir).await?;
fs::write(&path, serde_json::to_string(&j)?).await?;
fs::write(
&path,
serde_json::to_string(&j).expect("Device ID should always be serializable"),
)
.await?;
tracing::debug!("device ID saved to disk is {}", j.id.to_string());
let device_id = j.device_id();
tracing::debug!(?device_id, "Saved device ID to disk");
Ok(j.device_id())
}

View File

@@ -309,7 +309,7 @@ impl Controller {
advanced_settings: AdvancedSettings,
notify_controller: Arc<Notify>,
) -> Result<Self> {
let device_id = client::device_id::device_id(&app_local_data_dir(&app)?).await?;
let device_id = client::device_id::device_id(&app.config().tauri.bundle.identifier).await?;
let mut this = Self {
advanced_settings,