Add USB storage device control feature
- Add USB policy fields to machines schema (policy, status, error) - Create usbPolicyEvents table for audit logging - Implement Convex mutations/queries for USB policy management - Add REST API endpoints for desktop agent communication - Create Rust usb_control module for Windows registry manipulation - Integrate USB policy check in agent heartbeat loop - Add USB policy control component in admin device overview - Add localhost:3001 to auth trustedOrigins for dev 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
0e9310d6e4
commit
49aa143a80
11 changed files with 1116 additions and 1 deletions
|
|
@ -1129,6 +1129,109 @@ async fn post_heartbeat(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct UsbPolicyResponse {
|
||||
pending: bool,
|
||||
policy: Option<String>,
|
||||
applied_at: Option<i64>,
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct UsbPolicyStatusReport {
|
||||
machine_token: String,
|
||||
status: String,
|
||||
error: Option<String>,
|
||||
current_policy: Option<String>,
|
||||
}
|
||||
|
||||
async fn check_and_apply_usb_policy(base_url: &str, token: &str) {
|
||||
let url = format!("{}/api/machines/usb-policy?machineToken={}", base_url, token);
|
||||
|
||||
let response = match HTTP_CLIENT.get(&url).send().await {
|
||||
Ok(resp) => resp,
|
||||
Err(e) => {
|
||||
eprintln!("[agent] Falha ao verificar politica USB: {e}");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let policy_response: UsbPolicyResponse = match response.json().await {
|
||||
Ok(data) => data,
|
||||
Err(e) => {
|
||||
eprintln!("[agent] Falha ao parsear resposta de politica USB: {e}");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
if !policy_response.pending {
|
||||
return;
|
||||
}
|
||||
|
||||
let policy_str = match policy_response.policy {
|
||||
Some(p) => p,
|
||||
None => {
|
||||
eprintln!("[agent] Politica USB pendente mas sem valor de policy");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
eprintln!("[agent] Aplicando politica USB: {}", policy_str);
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
use crate::usb_control::{apply_usb_policy, UsbPolicy};
|
||||
|
||||
let policy = match UsbPolicy::from_str(&policy_str) {
|
||||
Some(p) => p,
|
||||
None => {
|
||||
eprintln!("[agent] Politica USB invalida: {}", policy_str);
|
||||
report_usb_policy_status(base_url, token, "FAILED", Some(format!("Politica invalida: {}", policy_str)), None).await;
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
match apply_usb_policy(policy) {
|
||||
Ok(result) => {
|
||||
eprintln!("[agent] Politica USB aplicada com sucesso: {:?}", result);
|
||||
report_usb_policy_status(base_url, token, "APPLIED", None, Some(policy_str)).await;
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("[agent] Falha ao aplicar politica USB: {e}");
|
||||
report_usb_policy_status(base_url, token, "FAILED", Some(e.to_string()), None).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
{
|
||||
eprintln!("[agent] Controle de USB nao suportado neste sistema operacional");
|
||||
report_usb_policy_status(base_url, token, "FAILED", Some("Sistema operacional nao suportado".to_string()), None).await;
|
||||
}
|
||||
}
|
||||
|
||||
async fn report_usb_policy_status(
|
||||
base_url: &str,
|
||||
token: &str,
|
||||
status: &str,
|
||||
error: Option<String>,
|
||||
current_policy: Option<String>,
|
||||
) {
|
||||
let url = format!("{}/api/machines/usb-policy", base_url);
|
||||
|
||||
let report = UsbPolicyStatusReport {
|
||||
machine_token: token.to_string(),
|
||||
status: status.to_string(),
|
||||
error,
|
||||
current_policy,
|
||||
};
|
||||
|
||||
if let Err(e) = HTTP_CLIENT.post(&url).json(&report).send().await {
|
||||
eprintln!("[agent] Falha ao reportar status de politica USB: {e}");
|
||||
}
|
||||
}
|
||||
|
||||
struct HeartbeatHandle {
|
||||
token: String,
|
||||
base_url: String,
|
||||
|
|
@ -1198,6 +1301,9 @@ impl AgentRuntime {
|
|||
eprintln!("[agent] Falha inicial ao enviar heartbeat: {error}");
|
||||
}
|
||||
|
||||
// Verifica politica USB apos heartbeat inicial
|
||||
check_and_apply_usb_policy(&base_clone, &token_clone).await;
|
||||
|
||||
let mut ticker = tokio::time::interval(Duration::from_secs(interval));
|
||||
ticker.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Delay);
|
||||
|
||||
|
|
@ -1215,6 +1321,9 @@ impl AgentRuntime {
|
|||
{
|
||||
eprintln!("[agent] Falha ao enviar heartbeat: {error}");
|
||||
}
|
||||
|
||||
// Verifica politica USB apos cada heartbeat
|
||||
check_and_apply_usb_policy(&base_clone, &token_clone).await;
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue