refactor(rust): move device_id to bin-shared (#9040)

Both `device_id` and `device_info` are used by the headless-client and
the GUI client / IPC service. They should therefore be defined in the
`bin-shared` crate.
This commit is contained in:
Thomas Eizinger
2025-05-06 14:52:37 +10:00
committed by GitHub
parent 5ac5fc45e4
commit f2b1fbe718
10 changed files with 56 additions and 48 deletions

4
rust/Cargo.lock generated
View File

@@ -2118,6 +2118,9 @@ dependencies = [
"resolv-conf",
"ring",
"rtnetlink",
"serde",
"serde_json",
"smbios-lib",
"socket-factory",
"tempfile",
"thiserror 1.0.69",
@@ -2275,7 +2278,6 @@ dependencies = [
"serde",
"serde_json",
"serde_variant",
"smbios-lib",
"strum",
"tempfile",
"thiserror 1.0.69",

View File

@@ -8,6 +8,7 @@ license = { workspace = true }
[dependencies]
anyhow = { workspace = true }
atomicwrites = { workspace = true }
axum = { workspace = true, features = ["http1", "tokio"] }
clap = { workspace = true, features = ["derive", "env"] }
dns-types = { workspace = true }
@@ -17,11 +18,15 @@ gat-lending-iterator = { workspace = true }
hex-literal = { workspace = true }
ip-packet = { workspace = true }
ip_network = { workspace = true, features = ["serde"] }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
smbios-lib = { workspace = true }
socket-factory = { workspace = true }
thiserror = { workspace = true }
tokio = { workspace = true, features = ["io-util", "net", "rt", "sync", "process"] }
tracing = { workspace = true }
tun = { workspace = true }
uuid = { workspace = true }
[dev-dependencies]
bufferpool = { workspace = true }

View File

@@ -1,3 +1,5 @@
//! Generate a persistent device ID, stores it to disk, and reads it back.
use anyhow::{Context as _, Result};
use atomicwrites::{AtomicFile, OverwriteBehavior};
use std::{
@@ -15,43 +17,12 @@ pub struct DeviceId {
/// e.g. `C:\ProgramData\dev.firezone.client/firezone-id.json` or
/// `/var/lib/dev.firezone.client/config/firezone-id.json`.
pub(crate) fn path() -> Result<PathBuf> {
let path = firezone_bin_shared::known_dirs::ipc_service_config()
let path = crate::known_dirs::ipc_service_config()
.context("Failed to compute path for firezone-id file")?
.join("firezone-id.json");
Ok(path)
}
fn device_serial() -> Option<String> {
const DEFAULT_SERIAL: &str = "123456789";
let data = smbioslib::table_load_from_device().ok()?;
let serial = data.find_map(|sys_info: smbioslib::SMBiosSystemInformation| {
sys_info.serial_number().to_utf8_lossy()
})?;
if serial == DEFAULT_SERIAL {
return None;
}
Some(serial)
}
fn device_uuid() -> Option<String> {
let data = smbioslib::table_load_from_device().ok()?;
let uuid = data.find_map(|sys_info: smbioslib::SMBiosSystemInformation| sys_info.uuid());
uuid?.to_string().into()
}
pub fn device_info() -> phoenix_channel::DeviceInfo {
phoenix_channel::DeviceInfo {
device_serial: device_serial(),
device_uuid: device_uuid(),
..Default::default()
}
}
/// Returns the device ID without generating it
pub fn get() -> Result<DeviceId> {
let path = path()?;

View File

@@ -0,0 +1,22 @@
pub fn serial() -> Option<String> {
const DEFAULT_SERIAL: &str = "123456789";
let data = smbioslib::table_load_from_device().ok()?;
let serial = data.find_map(|sys_info: smbioslib::SMBiosSystemInformation| {
sys_info.serial_number().to_utf8_lossy()
})?;
if serial == DEFAULT_SERIAL {
return None;
}
Some(serial)
}
pub fn uuid() -> Option<String> {
let data = smbioslib::table_load_from_device().ok()?;
let uuid = data.find_map(|sys_info: smbioslib::SMBiosSystemInformation| sys_info.uuid());
uuid?.to_string().into()
}

View File

@@ -6,8 +6,6 @@ mod dns_control;
mod network_changes;
mod tun_device_manager;
pub mod signals;
#[cfg(target_os = "linux")]
pub mod linux;
@@ -26,7 +24,10 @@ pub mod macos;
#[cfg(target_os = "macos")]
pub use macos as platform;
pub mod device_id;
pub mod device_info;
pub mod known_dirs;
pub mod signals;
pub mod uptime;
pub const TOKEN_ENV_KEY: &str = "FIREZONE_TOKEN";

View File

@@ -114,7 +114,7 @@ fn run_gui(cli: Cli) -> Result<()> {
);
// Get the device ID before starting Tokio, so that all the worker threads will inherit the correct scope.
// Technically this means we can fail to get the device ID on a newly-installed system, since the IPC service may not have fully started up when the GUI process reaches this point, but in practice it's unlikely.
if let Ok(id) = firezone_headless_client::device_id::get() {
if let Ok(id) = firezone_bin_shared::device_id::get() {
Telemetry::set_firezone_id(id.id);
}
fix_log_filter(&mut settings)?;

View File

@@ -9,7 +9,7 @@ license = { workspace = true }
[dependencies]
anyhow = { workspace = true }
atomicwrites = { workspace = true } # Needed to safely backup `/etc/resolv.conf` and write the device ID on behalf of `gui-client`
atomicwrites = { workspace = true } # Needed to safely backup `/etc/resolv.conf`
backoff = { workspace = true }
clap = { workspace = true, features = ["derive", "env", "string"] }
connlib-client-shared = { workspace = true }
@@ -31,7 +31,6 @@ secrecy = { workspace = true }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
serde_variant = { workspace = true }
smbios-lib = { workspace = true }
strum = { workspace = true }
thiserror = { workspace = true }
# This actually relies on many other features in Tokio, so this will probably

View File

@@ -1,10 +1,11 @@
use crate::{CallbackHandler, CliCommon, ConnlibMsg, device_id};
use crate::{CallbackHandler, CliCommon, ConnlibMsg};
use anyhow::{Context as _, Result, bail};
use atomicwrites::{AtomicFile, OverwriteBehavior};
use clap::Parser;
use connlib_model::ResourceView;
use firezone_bin_shared::{
DnsControlMethod, DnsController, TOKEN_ENV_KEY, TunDeviceManager, known_dirs,
DnsControlMethod, DnsController, TOKEN_ENV_KEY, TunDeviceManager, device_id, device_info,
known_dirs,
platform::{tcp_socket_factory, udp_socket_factory},
signals,
};
@@ -15,7 +16,7 @@ use futures::{
future::poll_fn,
task::{Context, Poll},
};
use phoenix_channel::LoginUrl;
use phoenix_channel::{DeviceInfo, LoginUrl};
use secrecy::SecretString;
use serde::{Deserialize, Serialize};
use std::{
@@ -566,7 +567,11 @@ impl<'a> Handler<'a> {
&token,
device_id.id,
None,
device_id::device_info(),
DeviceInfo {
device_serial: device_info::serial(),
device_uuid: device_info::uuid(),
..Default::default()
},
)
.context("Failed to create `LoginUrl`")?;

View File

@@ -24,8 +24,6 @@ use tokio::sync::mpsc;
use tracing_subscriber::{EnvFilter, Layer as _, Registry, fmt, layer::SubscriberExt as _};
mod clear_logs;
/// Generate a persistent device ID, stores it to disk, and reads it back.
pub mod device_id;
mod ipc_service;
pub use clear_logs::clear_logs;

View File

@@ -7,19 +7,20 @@ use backoff::ExponentialBackoffBuilder;
use clap::Parser;
use connlib_client_shared::Session;
use firezone_bin_shared::{
DnsController, TOKEN_ENV_KEY, TunDeviceManager, new_dns_notifier, new_network_notifier,
DnsController, TOKEN_ENV_KEY, TunDeviceManager, device_id, device_info, new_dns_notifier,
new_network_notifier,
platform::{tcp_socket_factory, udp_socket_factory},
signals,
};
use firezone_headless_client::{CallbackHandler, CliCommon, ConnlibMsg, device_id};
use firezone_headless_client::{CallbackHandler, CliCommon, ConnlibMsg};
use firezone_logging::telemetry_span;
use firezone_telemetry::Telemetry;
use firezone_telemetry::otel;
use futures::StreamExt as _;
use opentelemetry_sdk::metrics::{PeriodicReader, SdkMeterProvider};
use phoenix_channel::LoginUrl;
use phoenix_channel::PhoenixChannel;
use phoenix_channel::get_user_agent;
use phoenix_channel::{DeviceInfo, LoginUrl};
use secrecy::{Secret, SecretString};
use std::{
path::{Path, PathBuf},
@@ -194,7 +195,11 @@ fn main() -> Result<()> {
&token,
firezone_id.clone(),
cli.firezone_name,
device_id::device_info(),
DeviceInfo {
device_serial: device_info::serial(),
device_uuid: device_info::uuid(),
..Default::default()
},
)?;
if cli.check {