remove duplicate hardware
This commit is contained in:
parent
2c90276e3e
commit
56f957a346
@ -1,144 +0,0 @@
|
||||
use anyhow::{Context, Result};
|
||||
use std::fs;
|
||||
|
||||
/// Extracts a unique hardware identifier from the system
|
||||
/// This function reads /proc/cpuinfo to find a stable CPU serial number
|
||||
pub fn get_hardware_id() -> Result<String> {
|
||||
// Try to read /proc/cpuinfo first (common on Raspberry Pi and other ARM systems)
|
||||
if let Ok(hardware_id) = read_cpu_serial() {
|
||||
return Ok(hardware_id);
|
||||
}
|
||||
|
||||
// Fallback: try to read machine-id
|
||||
if let Ok(machine_id) = read_machine_id() {
|
||||
return Ok(machine_id);
|
||||
}
|
||||
|
||||
// Last resort: generate a warning and use hostname + MAC address hash
|
||||
eprintln!("Warning: Could not read CPU serial or machine-id, using fallback method");
|
||||
get_fallback_id()
|
||||
}
|
||||
|
||||
/// Reads CPU serial number from /proc/cpuinfo
|
||||
/// This is the most reliable method on Raspberry Pi systems
|
||||
fn read_cpu_serial() -> Result<String> {
|
||||
let cpuinfo = fs::read_to_string("/proc/cpuinfo")
|
||||
.context("Failed to read /proc/cpuinfo")?;
|
||||
|
||||
for line in cpuinfo.lines() {
|
||||
if line.starts_with("Serial") {
|
||||
if let Some(serial) = line.split(':').nth(1) {
|
||||
let serial = serial.trim();
|
||||
if !serial.is_empty() && serial != "0000000000000000" {
|
||||
return Ok(format!("CPU_{}", serial));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
anyhow::bail!("No valid CPU serial found in /proc/cpuinfo")
|
||||
}
|
||||
|
||||
/// Reads machine ID from /etc/machine-id (systemd systems)
|
||||
fn read_machine_id() -> Result<String> {
|
||||
let machine_id = fs::read_to_string("/etc/machine-id")
|
||||
.context("Failed to read /etc/machine-id")?;
|
||||
|
||||
let machine_id = machine_id.trim();
|
||||
if machine_id.len() >= 8 {
|
||||
Ok(format!("MACHINE_{}", &machine_id[..16]))
|
||||
} else {
|
||||
anyhow::bail!("Invalid machine-id format")
|
||||
}
|
||||
}
|
||||
|
||||
/// Fallback method to generate a hardware ID
|
||||
/// Uses hostname + network interface information
|
||||
fn get_fallback_id() -> Result<String> {
|
||||
use std::process::Command;
|
||||
|
||||
// Get hostname
|
||||
let hostname_output = Command::new("hostname")
|
||||
.output()
|
||||
.context("Failed to execute hostname command")?;
|
||||
|
||||
let hostname = String::from_utf8_lossy(&hostname_output.stdout)
|
||||
.trim()
|
||||
.to_string();
|
||||
|
||||
// Try to get MAC address from network interfaces
|
||||
if let Ok(mac) = get_primary_mac_address() {
|
||||
return Ok(format!("FALLBACK_{}_{}", hostname, mac));
|
||||
}
|
||||
|
||||
// Very last resort: just use hostname with timestamp
|
||||
let timestamp = std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.unwrap_or_default()
|
||||
.as_secs();
|
||||
|
||||
Ok(format!("FALLBACK_{}_{}", hostname, timestamp))
|
||||
}
|
||||
|
||||
/// Attempts to get the MAC address of the primary network interface
|
||||
fn get_primary_mac_address() -> Result<String> {
|
||||
let interfaces_dir = "/sys/class/net";
|
||||
let entries = fs::read_dir(interfaces_dir)
|
||||
.context("Failed to read network interfaces directory")?;
|
||||
|
||||
for entry in entries {
|
||||
let entry = entry?;
|
||||
let interface_name = entry.file_name();
|
||||
let interface_name = interface_name.to_string_lossy();
|
||||
|
||||
// Skip loopback and common virtual interfaces
|
||||
if interface_name == "lo" || interface_name.starts_with("docker")
|
||||
|| interface_name.starts_with("veth") {
|
||||
continue;
|
||||
}
|
||||
|
||||
let mac_path = format!("{}/{}/address", interfaces_dir, interface_name);
|
||||
if let Ok(mac) = fs::read_to_string(&mac_path) {
|
||||
let mac = mac.trim().replace(':', "");
|
||||
if mac.len() == 12 && mac != "000000000000" {
|
||||
return Ok(mac.to_uppercase());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
anyhow::bail!("No valid MAC address found")
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_hardware_id_format() {
|
||||
// Test that we can get some kind of hardware ID
|
||||
// The exact format will depend on the system, but it should not be empty
|
||||
let result = get_hardware_id();
|
||||
match result {
|
||||
Ok(id) => {
|
||||
assert!(!id.is_empty(), "Hardware ID should not be empty");
|
||||
assert!(id.len() >= 8, "Hardware ID should be at least 8 characters");
|
||||
println!("Hardware ID: {}", id);
|
||||
}
|
||||
Err(e) => {
|
||||
println!("Could not get hardware ID: {}", e);
|
||||
// On systems without the expected files, this might fail
|
||||
// That's okay for testing purposes
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fallback_id() {
|
||||
let result = get_fallback_id();
|
||||
assert!(result.is_ok(), "Fallback ID generation should always work");
|
||||
|
||||
let id = result.unwrap();
|
||||
assert!(id.starts_with("FALLBACK_"), "Fallback ID should have correct prefix");
|
||||
assert!(id.len() > 10, "Fallback ID should be reasonably long");
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,6 @@
|
||||
use clap::{Parser, Subcommand};
|
||||
use anyhow::Result;
|
||||
|
||||
mod hardware;
|
||||
mod config;
|
||||
mod api;
|
||||
mod frame_data;
|
||||
@ -17,10 +16,10 @@ mod hardware_fingerprint;
|
||||
mod device_registration;
|
||||
mod websocket_client;
|
||||
|
||||
use hardware::get_hardware_id;
|
||||
use config::{Config, ConfigManager};
|
||||
use api::ApiClient;
|
||||
use app::Application;
|
||||
use hardware_fingerprint::HardwareFingerprintService;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(name = "meteor-edge-client")]
|
||||
@ -145,7 +144,9 @@ async fn register_device(jwt_token: String, api_url: String) -> Result<()> {
|
||||
|
||||
// Get hardware ID
|
||||
println!("🔍 Reading hardware identifier...");
|
||||
let hardware_id = get_hardware_id()?;
|
||||
let mut fingerprint_service = HardwareFingerprintService::new();
|
||||
let fingerprint = fingerprint_service.generate_fingerprint().await?;
|
||||
let hardware_id = fingerprint.computed_hash[..16].to_string();
|
||||
println!(" Hardware ID: {}", hardware_id);
|
||||
|
||||
// Create API client
|
||||
@ -184,13 +185,17 @@ async fn show_status() -> Result<()> {
|
||||
println!("📊 Meteor Edge Client Status");
|
||||
println!("============================");
|
||||
|
||||
// Show hardware information
|
||||
match get_hardware_id() {
|
||||
Ok(hardware_id) => {
|
||||
println!("🔧 Hardware ID: {}", hardware_id);
|
||||
// Show hardware information using the new fingerprint service
|
||||
let mut fingerprint_service = HardwareFingerprintService::new();
|
||||
match fingerprint_service.generate_fingerprint().await {
|
||||
Ok(fingerprint) => {
|
||||
println!("🔧 Hardware ID: {}", fingerprint.computed_hash[..16].to_string());
|
||||
println!(" CPU ID: {}", fingerprint.cpu_id);
|
||||
println!(" Board Serial: {}", fingerprint.board_serial);
|
||||
println!(" MAC Addresses: {}", fingerprint.mac_addresses.join(", "));
|
||||
}
|
||||
Err(e) => {
|
||||
println!("❌ Could not read hardware ID: {}", e);
|
||||
println!("❌ Could not read hardware fingerprint: {}", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -12,7 +12,7 @@ export interface HardwareFingerprint {
|
||||
board_serial: string;
|
||||
mac_addresses: string[];
|
||||
disk_uuid: string;
|
||||
tmp_attestation?: string;
|
||||
tpm_attestation?: string;
|
||||
}
|
||||
|
||||
export interface SecurityChallenge {
|
||||
@ -131,8 +131,8 @@ export class DeviceSecurityService {
|
||||
}
|
||||
|
||||
// TPM attestation validation if available
|
||||
if (fingerprint.tmp_attestation) {
|
||||
const tpmValid = await this.validateTpmAttestation(fingerprint.tmp_attestation);
|
||||
if (fingerprint.tpm_attestation) {
|
||||
const tpmValid = await this.validateTpmAttestation(fingerprint.tpm_attestation);
|
||||
if (!tpmValid) {
|
||||
riskFactors.push('TPM attestation validation failed');
|
||||
confidence *= 0.7;
|
||||
@ -324,7 +324,7 @@ export class DeviceSecurityService {
|
||||
fingerprint.board_serial,
|
||||
...fingerprint.mac_addresses.sort(),
|
||||
fingerprint.disk_uuid,
|
||||
fingerprint.tmp_attestation || '',
|
||||
fingerprint.tpm_attestation || '',
|
||||
].join('|');
|
||||
|
||||
return crypto.createHash('sha256').update(data).digest('hex');
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user