diff options
| -rw-r--r-- | Cargo.lock | 9 | ||||
| -rw-r--r-- | Cargo.toml | 1 | ||||
| -rw-r--r-- | mullvad-platform-metadata/Cargo.toml | 12 | ||||
| -rw-r--r-- | mullvad-platform-metadata/src/lib.rs | 151 | ||||
| -rw-r--r-- | mullvad-problem-report/Cargo.toml | 5 | ||||
| -rw-r--r-- | mullvad-problem-report/src/metadata.rs | 155 |
6 files changed, 176 insertions, 157 deletions
diff --git a/Cargo.lock b/Cargo.lock index b7c07e91e2..36841748bc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1322,6 +1322,13 @@ dependencies = [ ] [[package]] +name = "mullvad-platform-metadata" +version = "0.1.0" +dependencies = [ + "rs-release", +] + +[[package]] name = "mullvad-problem-report" version = "2020.8.0-beta2" dependencies = [ @@ -1332,9 +1339,9 @@ dependencies = [ "err-derive", "lazy_static", "mullvad-paths", + "mullvad-platform-metadata", "mullvad-rpc", "regex", - "rs-release", "talpid-types", "tokio", "uuid", diff --git a/Cargo.toml b/Cargo.toml index f87705cf22..4d155d203a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ members = [ "mullvad-problem-report", "mullvad-jni", "mullvad-paths", + "mullvad-platform-metadata", "mullvad-types", "mullvad-rpc", # "mullvad-tests", diff --git a/mullvad-platform-metadata/Cargo.toml b/mullvad-platform-metadata/Cargo.toml new file mode 100644 index 0000000000..d1ba2f6a14 --- /dev/null +++ b/mullvad-platform-metadata/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "mullvad-platform-metadata" +version = "0.1.0" +authors = ["Mullvad VPN"] +description = "Platform metadata detection functions" +license = "GPL-3.0" +edition = "2018" +publish = false + + +[target.'cfg(target_os = "linux")'.dependencies] +rs-release = "0.1.7" diff --git a/mullvad-platform-metadata/src/lib.rs b/mullvad-platform-metadata/src/lib.rs new file mode 100644 index 0000000000..bcdc640ee6 --- /dev/null +++ b/mullvad-platform-metadata/src/lib.rs @@ -0,0 +1,151 @@ +use std::process::Command; + +#[cfg(target_os = "linux")] +mod imp { + pub fn version() -> String { + // The OS version information is obtained first from the os-release file. If that + // information is incomplete or unavailable, an attempt is made to obtain the + // version information from the lsb_release command. If that fails, any partial + // information from os-release is used if available, or a fallback message if + // reading from the os-release file produced + // no version information. + let version = read_os_release_file().unwrap_or_else(|incomplete_info| { + parse_lsb_release().unwrap_or_else(|| { + incomplete_info.unwrap_or_else(|| String::from("[Failed to detect version]")) + }) + }); + + format!("Linux {}", version) + } + + fn read_os_release_file() -> Result<String, Option<String>> { + let mut os_release_info = rs_release::get_os_release().map_err(|_| None)?; + let os_name = os_release_info.remove("NAME"); + let os_version = os_release_info.remove("VERSION"); + + if os_name.is_some() || os_version.is_some() { + let full_info_available = os_name.is_some() && os_version.is_some(); + + let gathered_info = format!( + "{} {}", + os_name.unwrap_or_else(|| "[unknown distribution]".to_owned()), + os_version.unwrap_or_else(|| "[unknown version]".to_owned()) + ); + + if full_info_available { + Ok(gathered_info) + } else { + // Partial version information + Err(Some(gathered_info)) + } + } else { + // No information was obtained + Err(None) + } + } + + fn parse_lsb_release() -> Option<String> { + super::command_stdout_lossy("lsb_release", &["-ds"]).and_then(|output| { + if output.is_empty() { + None + } else { + Some(output) + } + }) + } + + pub fn extra_metadata() -> impl Iterator<Item = (String, String)> { + std::iter::empty() + } +} + +#[cfg(target_os = "macos")] +mod imp { + pub fn version() -> String { + format!( + "macOS {}", + super::command_stdout_lossy("sw_vers", &["-productVersion"]) + .unwrap_or(String::from("[Failed to detect version]")) + ) + } + + pub fn extra_metadata() -> impl Iterator<Item = (String, String)> { + std::iter::empty() + } +} + +#[cfg(windows)] +mod imp { + pub fn version() -> String { + let system_info = + super::command_stdout_lossy("systeminfo", &["/FO", "LIST"]).unwrap_or_else(String::new); + + let mut version = None; + let mut full_version = None; + + for info_line in system_info.lines() { + let mut info_parts = info_line.split(":"); + + match info_parts.next() { + Some("OS Name") => { + version = info_parts + .next() + .map(|s| s.trim().trim_start_matches("Microsoft Windows ")) + } + Some("OS Version") => full_version = info_parts.next().map(str::trim), + _ => {} + } + } + + let version = version.unwrap_or("N/A"); + let full_version = full_version.unwrap_or("N/A"); + format!("Windows {} ({})", version, full_version) + } + + pub fn extra_metadata() -> impl Iterator<Item = (String, String)> { + std::iter::empty() + } +} + +#[cfg(target_os = "android")] +mod imp { + use std::collections::HashMap; + + pub fn version() -> String { + let version = get_prop("ro.build.version.release").unwrap_or_else(|| "N/A".to_owned()); + let api_level = get_prop("ro.build.version.sdk").unwrap_or_else(|| "N/A".to_owned()); + + let manufacturer = + get_prop("ro.product.manufacturer").unwrap_or_else(|| "Unknown brand".to_owned()); + let product = get_prop("ro.product.model").unwrap_or_else(|| "Unknown model".to_owned()); + + format!( + "Android {} (API: {}) - {} {}", + version, api_level, manufacturer, product + ) + } + + pub fn extra_metadata() -> HashMap<String, String> { + let mut metadata = HashMap::new(); + metadata.insert( + "abi".to_owned(), + get_prop("ro.product.cpu.abilist").unwrap_or_else(|| "N/A".to_owned()), + ); + metadata + } + + fn get_prop(property: &str) -> Option<String> { + super::command_stdout_lossy("getprop", &[property]) + } +} + +/// Helper for getting stdout of some command as a String. Ignores the exit code of the command. +fn command_stdout_lossy(cmd: &str, args: &[&str]) -> Option<String> { + Command::new(cmd) + .args(args) + .output() + .map(|output| String::from_utf8_lossy(&output.stdout).trim().to_string()) + .ok() +} + +pub use imp::{extra_metadata, version}; diff --git a/mullvad-problem-report/Cargo.toml b/mullvad-problem-report/Cargo.toml index 79ae9b757d..18a749650f 100644 --- a/mullvad-problem-report/Cargo.toml +++ b/mullvad-problem-report/Cargo.toml @@ -18,6 +18,7 @@ uuid = { version = "0.8", features = ["v4"] } tokio = { version = "0.2", features = [ "rt-core" ] } mullvad-paths = { path = "../mullvad-paths" } +mullvad-platform-metadata = { path = "../mullvad-platform-metadata" } mullvad-rpc = { path = "../mullvad-rpc" } talpid-types = { path = "../talpid-types" } @@ -26,10 +27,6 @@ talpid-types = { path = "../talpid-types" } duct = "0.13" -[target.'cfg(target_os = "linux")'.dependencies] -rs-release = "0.1.7" - - [target.'cfg(windows)'.build-dependencies] winres = "0.1" winapi = "0.3" diff --git a/mullvad-problem-report/src/metadata.rs b/mullvad-problem-report/src/metadata.rs index 1e4d6c864d..0d7eecfb47 100644 --- a/mullvad-problem-report/src/metadata.rs +++ b/mullvad-problem-report/src/metadata.rs @@ -1,5 +1,4 @@ -use std::{collections::BTreeMap, process::Command}; - +use std::collections::BTreeMap; pub const PRODUCT_VERSION: &str = include_str!(concat!(env!("OUT_DIR"), "/product-version.txt")); @@ -10,155 +9,7 @@ pub fn collect() -> BTreeMap<String, String> { "mullvad-product-version".to_owned(), PRODUCT_VERSION.to_owned(), ); - metadata.insert("os".to_owned(), os::version()); - metadata.extend(os::extra_metadata()); + metadata.insert("os".to_owned(), mullvad_platform_metadata::version()); + metadata.extend(mullvad_platform_metadata::extra_metadata()); metadata } - -#[cfg(target_os = "linux")] -mod os { - pub fn version() -> String { - // The OS version information is obtained first from the os-release file. If that - // information is incomplete or unavailable, an attempt is made to obtain the - // version information from the lsb_release command. If that fails, any partial - // information from os-release is used if available, or a fallback message if - // reading from the os-release file produced - // no version information. - let version = read_os_release_file().unwrap_or_else(|incomplete_info| { - parse_lsb_release().unwrap_or_else(|| { - incomplete_info.unwrap_or_else(|| String::from("[Failed to detect version]")) - }) - }); - - format!("Linux {}", version) - } - - fn read_os_release_file() -> Result<String, Option<String>> { - let mut os_release_info = rs_release::get_os_release().map_err(|_| None)?; - let os_name = os_release_info.remove("NAME"); - let os_version = os_release_info.remove("VERSION"); - - if os_name.is_some() || os_version.is_some() { - let full_info_available = os_name.is_some() && os_version.is_some(); - - let gathered_info = format!( - "{} {}", - os_name.unwrap_or_else(|| "[unknown distribution]".to_owned()), - os_version.unwrap_or_else(|| "[unknown version]".to_owned()) - ); - - if full_info_available { - Ok(gathered_info) - } else { - // Partial version information - Err(Some(gathered_info)) - } - } else { - // No information was obtained - Err(None) - } - } - - fn parse_lsb_release() -> Option<String> { - super::command_stdout_lossy("lsb_release", &["-ds"]).and_then(|output| { - if output.is_empty() { - None - } else { - Some(output) - } - }) - } - - pub fn extra_metadata() -> impl Iterator<Item = (String, String)> { - std::iter::empty() - } -} - -#[cfg(target_os = "macos")] -mod os { - pub fn version() -> String { - format!( - "macOS {}", - super::command_stdout_lossy("sw_vers", &["-productVersion"]) - .unwrap_or(String::from("[Failed to detect version]")) - ) - } - - pub fn extra_metadata() -> impl Iterator<Item = (String, String)> { - std::iter::empty() - } -} - -#[cfg(windows)] -mod os { - pub fn version() -> String { - let system_info = - super::command_stdout_lossy("systeminfo", &["/FO", "LIST"]).unwrap_or_else(String::new); - - let mut version = None; - let mut full_version = None; - - for info_line in system_info.lines() { - let mut info_parts = info_line.split(":"); - - match info_parts.next() { - Some("OS Name") => { - version = info_parts - .next() - .map(|s| s.trim().trim_start_matches("Microsoft Windows ")) - } - Some("OS Version") => full_version = info_parts.next().map(str::trim), - _ => {} - } - } - - let version = version.unwrap_or("N/A"); - let full_version = full_version.unwrap_or("N/A"); - format!("Windows {} ({})", version, full_version) - } - - pub fn extra_metadata() -> impl Iterator<Item = (String, String)> { - std::iter::empty() - } -} - -#[cfg(target_os = "android")] -mod os { - use std::collections::HashMap; - - pub fn version() -> String { - let version = get_prop("ro.build.version.release").unwrap_or_else(|| "N/A".to_owned()); - let api_level = get_prop("ro.build.version.sdk").unwrap_or_else(|| "N/A".to_owned()); - - let manufacturer = - get_prop("ro.product.manufacturer").unwrap_or_else(|| "Unknown brand".to_owned()); - let product = get_prop("ro.product.model").unwrap_or_else(|| "Unknown model".to_owned()); - - format!( - "Android {} (API: {}) - {} {}", - version, api_level, manufacturer, product - ) - } - - pub fn extra_metadata() -> HashMap<String, String> { - let mut metadata = HashMap::new(); - metadata.insert( - "abi".to_owned(), - get_prop("ro.product.cpu.abilist").unwrap_or_else(|| "N/A".to_owned()), - ); - metadata - } - - fn get_prop(property: &str) -> Option<String> { - super::command_stdout_lossy("getprop", &[property]) - } -} - -/// Helper for getting stdout of some command as a String. Ignores the exit code of the command. -fn command_stdout_lossy(cmd: &str, args: &[&str]) -> Option<String> { - Command::new(cmd) - .args(args) - .output() - .map(|output| String::from_utf8_lossy(&output.stdout).trim().to_string()) - .ok() -} |
