use anyhow::Result; use gethostname::gethostname; use local_ip_address::local_ip; use dns_lookup::lookup_addr; use std::io; use std::io::Write; use std::env; use std::process; use uzers::{get_current_uid, get_current_gid, get_current_username, get_current_groupname}; use rusqlite::Connection; use crate::common::is_binary::is_binary; use crate::meta_plugin::MetaPlugin; #[derive(Debug, Clone, Default)] pub struct CwdMetaPlugin { meta_name: String, is_saved: bool, } #[derive(Debug, Clone, Default)] pub struct BinaryMetaPlugin { meta_name: String, buffer: Vec, max_buffer_size: usize, is_saved: bool, item_id: Option, conn: Option<*mut Connection>, } impl BinaryMetaPlugin { pub fn new() -> BinaryMetaPlugin { BinaryMetaPlugin { meta_name: "binary".to_string(), buffer: Vec::new(), max_buffer_size: 4096, // 4KB is_saved: false, item_id: None, conn: None, } } } impl MetaPlugin for BinaryMetaPlugin { fn is_internal(&self) -> bool { true } fn create(&self) -> Result> { Ok(Box::new(io::sink())) } fn finalize(&mut self) -> io::Result { // Since we save during initialize() or update(), return empty to avoid duplicate saves Ok("".to_string()) } fn update(&mut self, data: &[u8]) { // Only collect up to max_buffer_size let remaining_capacity = self.max_buffer_size.saturating_sub(self.buffer.len()); if remaining_capacity > 0 { let bytes_to_copy = std::cmp::min(data.len(), remaining_capacity); self.buffer.extend_from_slice(&data[..bytes_to_copy]); // Check if we've reached our buffer limit and save if so if self.buffer.len() >= self.max_buffer_size && !self.is_saved { if let (Some(conn), Some(item_id)) = (self.conn, self.item_id) { // Convert raw pointer back to reference (unsafe) let conn_ref = unsafe { &*conn }; let is_binary = is_binary(&self.buffer); let value = if is_binary { "true".to_string() } else { "false".to_string() }; // Save to database immediately let meta = crate::db::Meta { id: item_id, name: self.meta_name.clone(), value, }; let _ = crate::db::store_meta(conn_ref, meta); self.is_saved = true; } } } } fn meta_name(&mut self) -> String { self.meta_name.clone() } fn initialize(&mut self, conn: &Connection, item_id: i64) -> Result<()> { self.item_id = Some(item_id); // Store raw pointer to connection - unsafe but necessary for this design self.conn = Some(conn as *const _ as *mut Connection); Ok(()) } } impl CwdMetaPlugin { pub fn new() -> CwdMetaPlugin { CwdMetaPlugin { meta_name: "cwd".to_string(), is_saved: false, } } } impl MetaPlugin for CwdMetaPlugin { fn is_internal(&self) -> bool { true } fn create(&self) -> Result> { Ok(Box::new(io::sink())) } fn finalize(&mut self) -> io::Result { // Since we save during initialize(), return empty to avoid duplicate saves Ok("".to_string()) } fn update(&mut self, _data: &[u8]) { // No update needed } fn meta_name(&mut self) -> String { self.meta_name.clone() } fn initialize(&mut self, conn: &Connection, item_id: i64) -> Result<()> { let cwd = match env::current_dir() { Ok(path) => path.to_string_lossy().to_string(), Err(_) => "unknown".to_string(), }; self.save_meta(conn, item_id, cwd)?; self.is_saved = true; Ok(()) } } #[derive(Debug, Clone, Default)] pub struct UidMetaPlugin { meta_name: String, is_saved: bool, } impl UidMetaPlugin { pub fn new() -> UidMetaPlugin { UidMetaPlugin { meta_name: "uid".to_string(), is_saved: false, } } } impl MetaPlugin for UidMetaPlugin { fn is_internal(&self) -> bool { true } fn create(&self) -> Result> { Ok(Box::new(io::sink())) } fn finalize(&mut self) -> io::Result { // Since we save during initialize(), return empty to avoid duplicate saves Ok("".to_string()) } fn update(&mut self, _data: &[u8]) { // No update needed } fn meta_name(&mut self) -> String { self.meta_name.clone() } fn initialize(&mut self, conn: &Connection, item_id: i64) -> Result<()> { let uid = get_current_uid().to_string(); self.save_meta(conn, item_id, uid)?; self.is_saved = true; Ok(()) } } #[derive(Debug, Clone, Default)] pub struct UserMetaPlugin { meta_name: String, is_saved: bool, } impl UserMetaPlugin { pub fn new() -> UserMetaPlugin { UserMetaPlugin { meta_name: "user".to_string(), is_saved: false, } } } impl MetaPlugin for UserMetaPlugin { fn is_internal(&self) -> bool { true } fn create(&self) -> Result> { Ok(Box::new(io::sink())) } fn finalize(&mut self) -> io::Result { // Since we save during initialize(), return empty to avoid duplicate saves Ok("".to_string()) } fn update(&mut self, _data: &[u8]) { // No update needed } fn meta_name(&mut self) -> String { self.meta_name.clone() } fn initialize(&mut self, conn: &Connection, item_id: i64) -> Result<()> { let user = match get_current_username() { Some(username) => username.to_string_lossy().to_string(), None => "unknown".to_string(), }; self.save_meta(conn, item_id, user)?; self.is_saved = true; Ok(()) } } #[derive(Debug, Clone, Default)] pub struct GidMetaPlugin { meta_name: String, is_saved: bool, } impl GidMetaPlugin { pub fn new() -> GidMetaPlugin { GidMetaPlugin { meta_name: "gid".to_string(), is_saved: false, } } } impl MetaPlugin for GidMetaPlugin { fn is_internal(&self) -> bool { true } fn create(&self) -> Result> { Ok(Box::new(io::sink())) } fn finalize(&mut self) -> io::Result { // Since we save during initialize(), return empty to avoid duplicate saves Ok("".to_string()) } fn update(&mut self, _data: &[u8]) { // No update needed } fn meta_name(&mut self) -> String { self.meta_name.clone() } fn initialize(&mut self, conn: &Connection, item_id: i64) -> Result<()> { let gid = get_current_gid().to_string(); self.save_meta(conn, item_id, gid)?; self.is_saved = true; Ok(()) } } #[derive(Debug, Clone, Default)] pub struct GroupMetaPlugin { meta_name: String, is_saved: bool, } impl GroupMetaPlugin { pub fn new() -> GroupMetaPlugin { GroupMetaPlugin { meta_name: "group".to_string(), is_saved: false, } } } impl MetaPlugin for GroupMetaPlugin { fn is_internal(&self) -> bool { true } fn create(&self) -> Result> { Ok(Box::new(io::sink())) } fn finalize(&mut self) -> io::Result { // Since we save during initialize(), return empty to avoid duplicate saves Ok("".to_string()) } fn update(&mut self, _data: &[u8]) { // No update needed } fn meta_name(&mut self) -> String { self.meta_name.clone() } fn initialize(&mut self, conn: &Connection, item_id: i64) -> Result<()> { let group = match get_current_groupname() { Some(groupname) => groupname.to_string_lossy().to_string(), None => "unknown".to_string(), }; self.save_meta(conn, item_id, group)?; self.is_saved = true; Ok(()) } } #[derive(Debug, Clone, Default)] pub struct ShellMetaPlugin { meta_name: String, is_saved: bool, } impl ShellMetaPlugin { pub fn new() -> ShellMetaPlugin { ShellMetaPlugin { meta_name: "shell".to_string(), is_saved: false, } } } impl MetaPlugin for ShellMetaPlugin { fn is_internal(&self) -> bool { true } fn create(&self) -> Result> { Ok(Box::new(io::sink())) } fn finalize(&mut self) -> io::Result { // Since we save during initialize(), return empty to avoid duplicate saves Ok("".to_string()) } fn update(&mut self, _data: &[u8]) { // No update needed } fn meta_name(&mut self) -> String { self.meta_name.clone() } fn initialize(&mut self, conn: &Connection, item_id: i64) -> Result<()> { let shell = match env::var("SHELL") { Ok(shell) => shell, Err(_) => "unknown".to_string(), }; self.save_meta(conn, item_id, shell)?; self.is_saved = true; Ok(()) } } #[derive(Debug, Clone, Default)] pub struct ShellPidMetaPlugin { meta_name: String, is_saved: bool, } impl ShellPidMetaPlugin { pub fn new() -> ShellPidMetaPlugin { ShellPidMetaPlugin { meta_name: "shell_pid".to_string(), is_saved: false, } } } impl MetaPlugin for ShellPidMetaPlugin { fn is_internal(&self) -> bool { true } fn create(&self) -> Result> { Ok(Box::new(io::sink())) } fn finalize(&mut self) -> io::Result { // Since we save during initialize(), return empty to avoid duplicate saves Ok("".to_string()) } fn update(&mut self, _data: &[u8]) { // No update needed } fn meta_name(&mut self) -> String { self.meta_name.clone() } fn initialize(&mut self, conn: &Connection, item_id: i64) -> Result<()> { let pid = match env::var("PPID") { Ok(ppid) => ppid, Err(_) => process::id().to_string(), }; self.save_meta(conn, item_id, pid)?; self.is_saved = true; Ok(()) } } #[derive(Debug, Clone, Default)] pub struct KeepPidMetaPlugin { meta_name: String, is_saved: bool, } impl KeepPidMetaPlugin { pub fn new() -> KeepPidMetaPlugin { KeepPidMetaPlugin { meta_name: "keep_pid".to_string(), is_saved: false, } } } impl MetaPlugin for KeepPidMetaPlugin { fn is_internal(&self) -> bool { true } fn create(&self) -> Result> { Ok(Box::new(io::sink())) } fn finalize(&mut self) -> io::Result { // Since we save during initialize(), return empty to avoid duplicate saves Ok("".to_string()) } fn update(&mut self, _data: &[u8]) { // No update needed } fn meta_name(&mut self) -> String { self.meta_name.clone() } fn initialize(&mut self, conn: &Connection, item_id: i64) -> Result<()> { let pid = process::id().to_string(); self.save_meta(conn, item_id, pid)?; self.is_saved = true; Ok(()) } } #[derive(Debug, Clone, Default)] pub struct HostnameMetaPlugin { meta_name: String, is_saved: bool, } impl HostnameMetaPlugin { pub fn new() -> HostnameMetaPlugin { HostnameMetaPlugin { meta_name: "hostname".to_string(), is_saved: false, } } } impl MetaPlugin for HostnameMetaPlugin { fn is_internal(&self) -> bool { true } fn create(&self) -> Result> { Ok(Box::new(io::sink())) } fn finalize(&mut self) -> io::Result { // Since we save during initialize(), return empty to avoid duplicate saves Ok("".to_string()) } fn update(&mut self, _data: &[u8]) { // No update needed for hostname } fn meta_name(&mut self) -> String { self.meta_name.clone() } fn initialize(&mut self, conn: &Connection, item_id: i64) -> Result<()> { let hostname = match gethostname().into_string() { Ok(hostname) => hostname, Err(_) => "unknown".to_string(), }; self.save_meta(conn, item_id, hostname)?; self.is_saved = true; Ok(()) } } #[derive(Debug, Clone, Default)] pub struct FullHostnameMetaPlugin { meta_name: String, is_saved: bool, } impl FullHostnameMetaPlugin { pub fn new() -> FullHostnameMetaPlugin { FullHostnameMetaPlugin { meta_name: "full_hostname".to_string(), is_saved: false, } } } impl MetaPlugin for FullHostnameMetaPlugin { fn is_internal(&self) -> bool { true } fn create(&self) -> Result> { Ok(Box::new(io::sink())) } fn finalize(&mut self) -> io::Result { // Since we save during initialize(), return empty to avoid duplicate saves Ok("".to_string()) } fn update(&mut self, _data: &[u8]) { // No update needed for full hostname } fn meta_name(&mut self) -> String { self.meta_name.clone() } fn initialize(&mut self, conn: &Connection, item_id: i64) -> Result<()> { // Try to get the FQDN through reverse DNS lookup let hostname = match local_ip() { Ok(my_local_ip) => { match lookup_addr(&my_local_ip) { Ok(hostname) => hostname, Err(_) => { // Fall back to regular hostname if reverse DNS fails match gethostname().into_string() { Ok(hostname) => hostname, Err(_) => "unknown".to_string(), } } } } Err(_) => { // Fall back to regular hostname if we can't get local IP match gethostname().into_string() { Ok(hostname) => hostname, Err(_) => "unknown".to_string(), } } }; self.save_meta(conn, item_id, hostname)?; self.is_saved = true; Ok(()) } }