feat: record results of beacon callbacks
This commit is contained in:
@@ -11,9 +11,9 @@ uuid = { version = "1.14.0", features = ["serde"] }
|
||||
enum_delegate = "0.2.0"
|
||||
async-trait = "0.1.86"
|
||||
serde_json = "1.0.139"
|
||||
thiserror = "2.0.11"
|
||||
|
||||
leptos = { version = "0.7.7", optional = true }
|
||||
thiserror = { version = "2.0.11", optional = true }
|
||||
pcap-sys = { path = "../pcap-sys", optional = true }
|
||||
tokio = { version = "1.43.0", features = ["fs", "io-std", "io-util", "net", "process", "rt", "sync", "time", "tokio-macros"], optional = true }
|
||||
smoltcp = { version = "0.12.0", default-features = false, features = ["proto-ipv4", "socket", "socket-tcp", "medium-ethernet", "std"], optional = true }
|
||||
@@ -23,11 +23,25 @@ hyper-util = { version = "0.1.10", features = ["client", "client-legacy", "http1
|
||||
hyper = { version = "1.6.0", features = ["client", "http1", "http2"], optional = true }
|
||||
rustls = { version = "0.23.23", default-features = false, features = ["std"], optional = true }
|
||||
sqlx = { version = "0.8", default-features = false, features = ["chrono", "macros", "migrate", "runtime-tokio", "sqlite", "sqlx-sqlite", "uuid"], optional = true }
|
||||
bytes = { version = "1.10.0", optional = true }
|
||||
http-body-util = { version = "0.1.2", optional = true }
|
||||
|
||||
[build-dependencies]
|
||||
bindgen = "0.69"
|
||||
|
||||
[features]
|
||||
beacon = ["dep:thiserror", "dep:pcap-sys", "dep:tokio", "dep:smoltcp", "dep:http", "dep:hyper-util", "dep:rustls", "dep:hyper", "dep:rmp-serde", "uuid/v4"]
|
||||
beacon = [
|
||||
"dep:pcap-sys",
|
||||
"dep:tokio",
|
||||
"dep:smoltcp",
|
||||
"dep:http",
|
||||
"dep:hyper-util",
|
||||
"dep:rustls",
|
||||
"dep:hyper",
|
||||
"dep:rmp-serde",
|
||||
"dep:bytes",
|
||||
"dep:http-body-util",
|
||||
"uuid/v4"
|
||||
]
|
||||
server-ssr = ["uuid/v4", "dep:sqlx"]
|
||||
server = ["dep:leptos"]
|
||||
|
||||
@@ -1,47 +1,106 @@
|
||||
/// # Rules for actions:
|
||||
/// Cannot have fields that have the following names:
|
||||
/// `target_beacon_id`, `target_category_id`, or `cmd_type`
|
||||
#[cfg(feature = "server")]
|
||||
use leptos::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[cfg(feature = "beacon")]
|
||||
use crate::{payload_types::Parameters, adapter::BeaconAdapter, error::BeaconError};
|
||||
use crate::version::Version;
|
||||
|
||||
mod ls;
|
||||
mod update;
|
||||
mod exec;
|
||||
mod upload;
|
||||
mod install;
|
||||
mod download;
|
||||
// mod ls;
|
||||
// mod update;
|
||||
// mod upload;
|
||||
// mod install;
|
||||
// mod download;
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
pub struct FileId(pub uuid::Uuid);
|
||||
|
||||
/// Macro used to enforce the invariant that struct names are used to identify
|
||||
/// the enum branch as well
|
||||
macro_rules! define_actions_enum {
|
||||
($(($mod:ident, $act:ident)),+) => {
|
||||
#[derive(::serde::Serialize, ::serde::Deserialize)]
|
||||
($(($mod:ident, $act:ident)),+$(,)?) => {
|
||||
#[derive(::serde::Serialize, ::serde::Deserialize, Clone, Debug)]
|
||||
#[serde(tag = "cmd_type")]
|
||||
pub enum Actions {
|
||||
$($act($mod::$act)),+,
|
||||
}
|
||||
|
||||
$(
|
||||
impl From<$mod::$act> for Actions {
|
||||
fn from(act: $mod::$act) -> Self {
|
||||
Self::$act(act)
|
||||
}
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
define_actions_enum! {
|
||||
(ls, Ls),
|
||||
(update, Update),
|
||||
(exec, Exec),
|
||||
(upload, Upload),
|
||||
(install, Install),
|
||||
(download, Download)
|
||||
#[cfg(feature = "server-ssr")]
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum BuildActionError {
|
||||
#[error("sqlx error")]
|
||||
Sqlx(#[from] sqlx::Error),
|
||||
#[error("io error")]
|
||||
Io(#[from] std::io::Error),
|
||||
#[error("json error")]
|
||||
Json(#[from] serde_json::Error)
|
||||
}
|
||||
|
||||
define_actions_enum! {
|
||||
(exec, Exec),
|
||||
// (ls, Ls),
|
||||
// (update, Update),
|
||||
// (upload, Upload),
|
||||
// (install, Install),
|
||||
// (download, Download),
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
#[cfg(feature = "beacon")]
|
||||
impl Action for Actions {
|
||||
const REQ_VERSION: Version = Version::new(2, 0);
|
||||
const REQ_OS: Option< &'static str> = None;
|
||||
const REQ_FIELDS: &'static[(&'static str, &'static str,Option< &'static str>)] = &[];
|
||||
|
||||
type ActionData = String;
|
||||
|
||||
async fn execute<'a, T, S>(
|
||||
&self,
|
||||
parameters: &Parameters,
|
||||
adapter: &'a T,
|
||||
client: &'a hyper_util::client::legacy::Client<S, http_body_util::Full<bytes::Bytes>>
|
||||
) -> Result<Self::ActionData, BeaconError<T::Error>>
|
||||
where
|
||||
T: 'a + BeaconAdapter,
|
||||
S: hyper_util::client::legacy::connect::Connect + Clone + Send + Sync + 'static
|
||||
{
|
||||
macro_rules! match_arm {
|
||||
($cmd:expr) => {
|
||||
$cmd
|
||||
.execute(parameters, adapter, client)
|
||||
.await
|
||||
.and_then(|v| serde_json::to_string(&v)
|
||||
.map_err(Into::into))
|
||||
}
|
||||
}
|
||||
match self {
|
||||
Actions::Exec(e) => match_arm!(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "server")]
|
||||
pub const ACTION_BUILDERS: &'static [&'static (dyn ActionBuilder + Send + Sync)] = &[
|
||||
&ActionBuilderImpl::<ls::Ls>::new(),
|
||||
&ActionBuilderImpl::<update::Update>::new(),
|
||||
&ActionBuilderImpl::<exec::Exec>::new(),
|
||||
&ActionBuilderImpl::<upload::Upload>::new(),
|
||||
&ActionBuilderImpl::<install::Install>::new(),
|
||||
&ActionBuilderImpl::<download::Download>::new(),
|
||||
//&ActionBuilderImpl::<ls::Ls>::new(),
|
||||
//&ActionBuilderImpl::<update::Update>::new(),
|
||||
//&ActionBuilderImpl::<upload::Upload>::new(),
|
||||
//&ActionBuilderImpl::<install::Install>::new(),
|
||||
//&ActionBuilderImpl::<download::Download>::new(),
|
||||
];
|
||||
|
||||
#[async_trait::async_trait]
|
||||
@@ -51,33 +110,53 @@ pub trait Action: Serialize + for<'a> Deserialize<'a> {
|
||||
const REQ_FIELDS: &'static [(&'static str, &'static str, Option<&'static str>)];
|
||||
|
||||
type ActionData: Serialize + for<'a> Deserialize<'a>;
|
||||
#[cfg(feature = "server-ssr")]
|
||||
type BuilderData: for<'a> Deserialize<'a>;
|
||||
|
||||
#[cfg(feature = "beacon")]
|
||||
async fn execute(&self) -> Self::ActionData;
|
||||
#[cfg(feature = "server-ssr")]
|
||||
async fn build_action(data: Self::BuilderData, db: &sqlx::SqlitePool) -> Result<Self, BuildActionError>;
|
||||
|
||||
#[cfg(feature = "server")]
|
||||
fn render_data(&self, data: Self::ActionData) -> impl IntoView;
|
||||
|
||||
#[cfg(feature = "beacon")]
|
||||
async fn execute<'a, T, S>(
|
||||
&self,
|
||||
parameters: &Parameters,
|
||||
adapter: &'a T,
|
||||
client: &'a hyper_util::client::legacy::Client<S, http_body_util::Full<bytes::Bytes>>
|
||||
) -> Result<Self::ActionData, BeaconError<T::Error>>
|
||||
where
|
||||
T: 'a + BeaconAdapter,
|
||||
S: hyper_util::client::legacy::connect::Connect + Clone + Send + Sync + 'static;
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
#[cfg(feature = "server")]
|
||||
pub trait ActionBuilder {
|
||||
fn name(&self) -> &'static str;
|
||||
fn required_version(&self) -> Version;
|
||||
fn required_os(&self) -> Option<&'static str>;
|
||||
fn form_elements(&self) -> &'static [(&'static str, &'static str, Option<&'static str>)];
|
||||
fn verify_json_body(&self, body: serde_json::Value) -> Result<(), serde_json::Error>;
|
||||
#[cfg(feature = "server-ssr")]
|
||||
async fn build_action(&self, body: serde_json::Value, db: &sqlx::SqlitePool) -> Result<Actions, BuildActionError>;
|
||||
}
|
||||
|
||||
#[cfg(feature = "server")]
|
||||
pub struct ActionBuilderImpl<T>(std::marker::PhantomData<T>);
|
||||
|
||||
#[cfg(feature = "server")]
|
||||
impl<T> ActionBuilderImpl<T> {
|
||||
pub const fn new() -> Self {
|
||||
Self(std::marker::PhantomData)
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
#[cfg(feature = "server")]
|
||||
impl<T> ActionBuilder for ActionBuilderImpl<T>
|
||||
where
|
||||
T: Action
|
||||
T: Action, Actions: From<T>
|
||||
{
|
||||
fn name(&self) -> &'static str {
|
||||
let tname = std::any::type_name::<T>();
|
||||
@@ -92,7 +171,15 @@ where
|
||||
fn form_elements(&self) -> &'static [(&'static str, &'static str, Option<&'static str>)] {
|
||||
T::REQ_FIELDS
|
||||
}
|
||||
fn verify_json_body(&self, body: serde_json::Value) -> Result<(), serde_json::Error> {
|
||||
serde_json::from_value::<T>(body).map(|_| ())
|
||||
#[cfg(feature = "server-ssr")]
|
||||
async fn build_action(&self, body: serde_json::Value, db: &sqlx::SqlitePool) -> Result<Actions, BuildActionError> {
|
||||
let builder_data: T::BuilderData = serde_json::from_value(body)?;
|
||||
let built_action = T::build_action(builder_data, db).await?;
|
||||
Ok(built_action.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "server")]
|
||||
unsafe impl<T> Send for ActionBuilderImpl<T> {}
|
||||
#[cfg(feature = "server")]
|
||||
unsafe impl<T> Sync for ActionBuilderImpl<T> {}
|
||||
|
||||
@@ -2,9 +2,11 @@
|
||||
use leptos::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[cfg(feature = "beacon")]
|
||||
use crate::payload_types::Parameters;
|
||||
use crate::version::Version;
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
pub struct Download {
|
||||
download_src: super::FileId,
|
||||
download_path: String,
|
||||
@@ -22,7 +24,7 @@ impl super::Action for Download {
|
||||
type ActionData = ();
|
||||
|
||||
#[cfg(feature = "beacon")]
|
||||
async fn execute(&self) -> Self::ActionData {
|
||||
async fn execute(&self, _: &Parameters) -> Self::ActionData {
|
||||
"Hi".to_string();
|
||||
}
|
||||
|
||||
|
||||
@@ -2,9 +2,11 @@
|
||||
use leptos::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[cfg(feature = "beacon")]
|
||||
use crate::{adapter::BeaconAdapter, error::BeaconError, payload_types::Parameters};
|
||||
use crate::version::Version;
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct Exec {
|
||||
exec_cmd: String
|
||||
}
|
||||
@@ -18,10 +20,28 @@ impl super::Action for Exec {
|
||||
];
|
||||
|
||||
type ActionData = String;
|
||||
#[cfg(feature = "server-ssr")]
|
||||
type BuilderData = Self;
|
||||
|
||||
#[cfg(feature = "server-ssr")]
|
||||
async fn build_action(data: Self::BuilderData, _db: &sqlx::SqlitePool) -> Result<Self, super::BuildActionError> {
|
||||
Ok(data)
|
||||
}
|
||||
|
||||
#[cfg(feature = "beacon")]
|
||||
async fn execute(&self) -> Self::ActionData {
|
||||
"Execute".to_string()
|
||||
async fn execute<'a, T, S>(
|
||||
&self,
|
||||
_parameters: &Parameters,
|
||||
_adapter: &'a T,
|
||||
_client: &'a hyper_util::client::legacy::Client<S, http_body_util::Full<bytes::Bytes>>
|
||||
) -> Result<Self::ActionData, BeaconError<T::Error>>
|
||||
where
|
||||
T: 'a + BeaconAdapter,
|
||||
S: hyper_util::client::legacy::connect::Connect + Clone + Send + Sync + 'static
|
||||
{
|
||||
println!("Execute command {}", self.exec_cmd);
|
||||
|
||||
Ok("Execute".to_string())
|
||||
}
|
||||
|
||||
#[cfg(feature = "server")]
|
||||
|
||||
@@ -2,9 +2,11 @@
|
||||
use leptos::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[cfg(feature = "beacon")]
|
||||
use crate::payload_types::Parameters;
|
||||
use crate::version::Version;
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
pub struct Install {
|
||||
install_target: std::path::PathBuf
|
||||
}
|
||||
@@ -20,7 +22,7 @@ impl super::Action for Install {
|
||||
type ActionData = ();
|
||||
|
||||
#[cfg(feature = "beacon")]
|
||||
async fn execute(&self) -> Self::ActionData {
|
||||
async fn execute(&self, _: &Parameters) -> Self::ActionData {
|
||||
"Hi".to_string();
|
||||
}
|
||||
|
||||
|
||||
@@ -2,9 +2,11 @@
|
||||
use leptos::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[cfg(feature = "beacon")]
|
||||
use crate::payload_types::Parameters;
|
||||
use crate::version::Version;
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
pub struct Ls;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
@@ -16,7 +18,7 @@ impl super::Action for Ls {
|
||||
type ActionData = ();
|
||||
|
||||
#[cfg(feature = "beacon")]
|
||||
async fn execute(&self) -> Self::ActionData {
|
||||
async fn execute(&self, _: &Parameters) -> Self::ActionData {
|
||||
"Hi".to_string();
|
||||
}
|
||||
|
||||
|
||||
@@ -2,9 +2,11 @@
|
||||
use leptos::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[cfg(feature = "beacon")]
|
||||
use crate::payload_types::Parameters;
|
||||
use crate::version::Version;
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
pub struct Update;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
@@ -16,7 +18,7 @@ impl super::Action for Update {
|
||||
type ActionData = ();
|
||||
|
||||
#[cfg(feature = "beacon")]
|
||||
async fn execute(&self) -> Self::ActionData {
|
||||
async fn execute(&self, _: &Parameters) -> Self::ActionData {
|
||||
"Hello".to_string();
|
||||
}
|
||||
|
||||
|
||||
@@ -2,9 +2,11 @@
|
||||
use leptos::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[cfg(feature = "beacon")]
|
||||
use crate::payload_types::Parameters;
|
||||
use crate::version::Version;
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
pub struct Upload {
|
||||
upload_src: String
|
||||
}
|
||||
@@ -20,7 +22,7 @@ impl super::Action for Upload {
|
||||
type ActionData = ();
|
||||
|
||||
#[cfg(feature = "beacon")]
|
||||
async fn execute(&self) -> Self::ActionData {
|
||||
async fn execute(&self, _: &Parameters) -> Self::ActionData {
|
||||
"Hi".to_string();
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ pub struct BeaconInterface {
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
pub trait BeaconAdapter {
|
||||
pub trait BeaconAdapter: Send + Sync {
|
||||
type Error: error::AdapterError + Send + Sync;
|
||||
|
||||
const OPERATING_SYSTEM: &'static str;
|
||||
|
||||
@@ -37,4 +37,6 @@ where
|
||||
RmpSerdeDecode(#[from] rmp_serde::decode::Error),
|
||||
#[error("http error")]
|
||||
Hyper(#[from] hyper::Error),
|
||||
#[error("serde json error")]
|
||||
Json(#[from] serde_json::Error),
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ pub struct RegisterBeacon {
|
||||
pub operating_system: String,
|
||||
pub userent: String,
|
||||
pub hostname: String,
|
||||
pub version: crate::version::Version,
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
@@ -37,4 +38,10 @@ pub enum RuntimeConfig {
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
pub struct BeaconConfig {
|
||||
pub runtime_config: RuntimeConfig,
|
||||
pub unfinished_actions: Vec<(i64, crate::actions::Actions)>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
pub struct CommandInvocationResult {
|
||||
pub result_body: String,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user