linux-rust: show device info in UI

This commit is contained in:
Kavish Devar
2025-11-10 13:32:47 +05:30
parent fa8bc11060
commit 64470c4d34
5 changed files with 513 additions and 83 deletions
+12 -8
View File
@@ -9,18 +9,13 @@ use std::collections::HashMap;
use serde::{Deserialize, Serialize};
use serde_json;
use std::path::PathBuf;
use crate::utils::get_devices_path;
const PSM: u16 = 0x1001;
const CONNECT_TIMEOUT: Duration = Duration::from_secs(10);
const POLL_INTERVAL: Duration = Duration::from_millis(200);
const HEADER_BYTES: [u8; 4] = [0x04, 0x00, 0x04, 0x00];
fn get_devices_path() -> PathBuf {
let data_dir = std::env::var("XDG_DATA_HOME")
.unwrap_or_else(|_| format!("{}/.local/share", std::env::var("HOME").unwrap_or_default()));
PathBuf::from(data_dir).join("librepods").join("devices.json")
}
pub mod opcodes {
pub const SET_FEATURE_FLAGS: u8 = 0x4D;
pub const REQUEST_NOTIFICATIONS: u8 = 0x0F;
@@ -268,11 +263,18 @@ pub struct AirPodsInformation {
pub version3: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "kind", content = "data")]
pub enum DeviceInformation {
AirPods(AirPodsInformation),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DeviceData {
pub name: String,
pub type_: DeviceType,
pub le: LEData,
pub information: Option<AirPodsInformation>,
pub information: Option<DeviceInformation>,
}
pub struct AACPManagerState {
@@ -620,7 +622,8 @@ impl AACPManager {
let mut state = self.state.lock().await;
if let Some(mac) = state.airpods_mac {
if let Some(device_data) = state.devices.get_mut(&mac.to_string()) {
device_data.information = Some(info.clone());
device_data.name = info.name.clone();
device_data.information = Some(DeviceInformation::AirPods(info.clone()));
}
}
let json = serde_json::to_string(&state.devices).unwrap();
@@ -668,6 +671,7 @@ impl AACPManager {
if let Some(mac) = state.airpods_mac {
let mac_str = mac.to_string();
let device_data = state.devices.entry(mac_str.clone()).or_insert(DeviceData {
name: mac_str.clone(),
type_: DeviceType::AirPods,
le: LEData { irk: "".to_string(), enc_key: "".to_string() },
information: None,
+3 -38
View File
@@ -2,46 +2,20 @@ use std::cmp::PartialEq;
use bluer::monitor::{Monitor, MonitorEvent, Pattern};
use bluer::{Address, Session};
use aes::Aes128;
use aes::cipher::{BlockEncrypt, KeyInit, BlockDecrypt};
use aes::cipher::{KeyInit, BlockDecrypt};
use aes::cipher::generic_array::GenericArray;
use std::collections::{HashMap, HashSet};
use log::{info, debug};
use serde_json;
use crate::bluetooth::aacp::ProximityKeyType;
use futures::StreamExt;
use hex;
use std::path::PathBuf;
use std::str::FromStr;
use std::sync::Arc;
use tokio::sync::Mutex;
use crate::bluetooth::aacp::BatteryStatus;
use crate::ui::tray::MyTray;
use crate::bluetooth::aacp::{DeviceData, LEData, DeviceType};
fn get_devices_path() -> PathBuf {
let data_dir = std::env::var("XDG_DATA_HOME")
.unwrap_or_else(|_| format!("{}/.local/share", std::env::var("HOME").unwrap_or_default()));
PathBuf::from(data_dir).join("librepods").join("devices.json")
}
fn get_preferences_path() -> PathBuf {
let config_dir = std::env::var("XDG_CONFIG_HOME")
.unwrap_or_else(|_| format!("{}/.config", std::env::var("HOME").unwrap_or_default()));
PathBuf::from(config_dir).join("librepods").join("preferences.json")
}
fn e(key: &[u8; 16], data: &[u8; 16]) -> [u8; 16] {
let mut swapped_key = *key;
swapped_key.reverse();
let mut swapped_data = *data;
swapped_data.reverse();
let cipher = Aes128::new(&GenericArray::from(swapped_key));
let mut block = GenericArray::from(swapped_data);
cipher.encrypt_block(&mut block);
let mut result: [u8; 16] = block.into();
result.reverse();
result
}
use crate::bluetooth::aacp::{DeviceData, DeviceType};
use crate::utils::{get_devices_path, get_preferences_path, ah};
fn decrypt(key: &[u8; 16], data: &[u8; 16]) -> [u8; 16] {
let cipher = Aes128::new(&GenericArray::from(*key));
@@ -50,15 +24,6 @@ fn decrypt(key: &[u8; 16], data: &[u8; 16]) -> [u8; 16] {
block.into()
}
fn ah(k: &[u8; 16], r: &[u8; 3]) -> [u8; 3] {
let mut r_padded = [0u8; 16];
r_padded[..3].copy_from_slice(r);
let encrypted = e(k, &r_padded);
let mut hash = [0u8; 3];
hash.copy_from_slice(&encrypted[..3]);
hash
}
fn verify_rpa(addr: &str, irk: &[u8; 16]) -> bool {
let rpa: Vec<u8> = addr.split(':')
.map(|s| u8::from_str_radix(s, 16).unwrap())