feat: added most beacon DS and listener CRUD
This commit is contained in:
parent
0d6b2b4c16
commit
b381261cea
33
Cargo.lock
generated
33
Cargo.lock
generated
@ -2191,6 +2191,16 @@ dependencies = [
|
||||
"tokio-stream",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pem"
|
||||
version = "3.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e459365e590736a54c3fa561947c84837534b8e9af6fc5bf781307e82658fae"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pem-rfc7468"
|
||||
version = "0.7.0"
|
||||
@ -2430,6 +2440,19 @@ dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rcgen"
|
||||
version = "0.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75e669e5202259b5314d1ea5397316ad400819437857b90861765f24c4cf80a2"
|
||||
dependencies = [
|
||||
"pem",
|
||||
"ring",
|
||||
"rustls-pki-types",
|
||||
"time",
|
||||
"yasna",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "reactive_graph"
|
||||
version = "0.1.4"
|
||||
@ -2971,6 +2994,7 @@ dependencies = [
|
||||
"leptos_meta",
|
||||
"leptos_router",
|
||||
"pbkdf2",
|
||||
"rcgen",
|
||||
"rpassword",
|
||||
"serde",
|
||||
"sha2",
|
||||
@ -4291,6 +4315,15 @@ version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"
|
||||
|
||||
[[package]]
|
||||
name = "yasna"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd"
|
||||
dependencies = [
|
||||
"time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yoke"
|
||||
version = "0.7.5"
|
||||
|
||||
@ -39,6 +39,7 @@ sha2 = { version = "0.10", optional = true }
|
||||
hex = { version = "0.4", optional = true }
|
||||
serde = "1.0"
|
||||
cfg-if = "1.0.0"
|
||||
rcgen = { version = "0.13.2", optional = true }
|
||||
|
||||
[features]
|
||||
hydrate = ["leptos/hydrate", "chrono/wasmbind"]
|
||||
@ -60,6 +61,7 @@ ssr = [
|
||||
"dep:pbkdf2",
|
||||
"dep:sha2",
|
||||
"dep:hex",
|
||||
"dep:rcgen",
|
||||
"leptos/ssr",
|
||||
"leptos_meta/ssr",
|
||||
"leptos_router/ssr",
|
||||
|
||||
121
sparse-server/migrations/20250130040842_add_beacons.sql
Normal file
121
sparse-server/migrations/20250130040842_add_beacons.sql
Normal file
@ -0,0 +1,121 @@
|
||||
CREATE TABLE beacon_listener (
|
||||
listener_id integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||
|
||||
port int NOT NULL,
|
||||
public_ip varchar NOT NULL,
|
||||
domain_name varchar NOT NULL,
|
||||
certificate varchar NOT NULL,
|
||||
privkey varchar NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE beacon_config (
|
||||
config_id integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||
|
||||
mode text check (mode in ('single', 'regular', 'random', 'cron')),
|
||||
|
||||
regular_interval int,
|
||||
|
||||
random_min_time int,
|
||||
random_max_time int,
|
||||
|
||||
cron_schedule varchar
|
||||
);
|
||||
|
||||
CREATE TABLE beacon_category (
|
||||
category_id integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||
category_name varchar NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE beacon_template (
|
||||
template_id integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||
template_name varchar NOT NULL,
|
||||
operating_system varchar NOT NULL,
|
||||
config_id int NOT NULL,
|
||||
listener_id int NOT NULL,
|
||||
|
||||
source_ip varchar NOT NULL,
|
||||
source_mac varchar,
|
||||
source_mode text check (source_mode in ('host', 'custom')),
|
||||
source_netmask int,
|
||||
source_gateway varchar,
|
||||
|
||||
FOREIGN KEY (config_id) REFERENCES beacon_config
|
||||
FOREIGN KEY (listener_id) REFERENCES beacon_listener
|
||||
);
|
||||
|
||||
CREATE TABLE beacon_instance (
|
||||
beacon_id varchar PRIMARY KEY NOT NULL,
|
||||
template_id int NOT NULL,
|
||||
peer_ip varchar NOT NULL,
|
||||
nickname varchar NOT NULL,
|
||||
|
||||
cwd varchar NOT NULL,
|
||||
operating_system varchar NOT NULL,
|
||||
beacon_userent varchar NOT NULL,
|
||||
hostname varchar NOT NULL,
|
||||
|
||||
FOREIGN KEY (template_id) REFERENCES beacon_template
|
||||
);
|
||||
|
||||
CREATE TABLE beacon_category_assignment (
|
||||
category_id int,
|
||||
beacon_id varchar,
|
||||
|
||||
PRIMARY KEY (category_id, beacon_id),
|
||||
|
||||
FOREIGN KEY (category_id) REFERENCES beacon_category,
|
||||
FOREIGN KEY (beacon_id) REFERENCES beacon_instance
|
||||
);
|
||||
|
||||
CREATE TABLE beacon_config_assignment (
|
||||
config_id int,
|
||||
beacon_id varchar,
|
||||
|
||||
PRIMARY KEY (config_id, beacon_id),
|
||||
|
||||
FOREIGN KEY (config_id) REFERENCES beacon_config,
|
||||
FOREIGN KEY (beacon_id) REFERENCES beacon_instance
|
||||
);
|
||||
|
||||
CREATE TABLE beacon_command (
|
||||
command_id integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||
|
||||
cmd_type text check (cmd_type in ('update', 'exec', 'install', 'upload', 'download', 'reload_config', 'chdir', 'ls')),
|
||||
|
||||
exec_command varchar,
|
||||
|
||||
install_target varchar,
|
||||
|
||||
upload_src varchar,
|
||||
upload_dest varchar,
|
||||
|
||||
download_path varchar,
|
||||
|
||||
config_id int,
|
||||
|
||||
FOREIGN KEY (config_id) REFERENCES beacon_config
|
||||
);
|
||||
|
||||
CREATE TABLE beacon_command_invocation (
|
||||
beacon_id varchar NOT NULL,
|
||||
command_id int NOT NULL,
|
||||
|
||||
invoker_id int NOT NULL,
|
||||
|
||||
invocation_date int,
|
||||
invocation_result varchar,
|
||||
|
||||
PRIMARY KEY (beacon_id, command_id),
|
||||
|
||||
FOREIGN KEY (command_id) REFERENCES beacon_command,
|
||||
FOREIGN KEY (beacon_id) REFERENCES beacon_instance,
|
||||
FOREIGN KEY (invoker_id) REFERENCES users
|
||||
);
|
||||
|
||||
CREATE TABLE beacon_checkin (
|
||||
beacon_id varchar NOT NULL,
|
||||
|
||||
checkin_date int,
|
||||
|
||||
FOREIGN KEY (beacon_id) REFERENCES beacon_instance
|
||||
);
|
||||
@ -1,7 +1,7 @@
|
||||
use leptos::prelude::*;
|
||||
use leptos_meta::{provide_meta_context, MetaTags, Stylesheet, Title};
|
||||
use leptos_router::{
|
||||
components::{A, Route, Router, Routes},
|
||||
components::{A, ParentRoute, Route, Router, Routes},
|
||||
hooks::use_query_map,
|
||||
path
|
||||
};
|
||||
@ -30,12 +30,8 @@ pub struct User {
|
||||
|
||||
#[server]
|
||||
pub async fn me() -> Result<Option<User>, ServerFnError> {
|
||||
tracing::info!("I'm being checked!");
|
||||
|
||||
let user = crate::db::user::get_auth_session().await?;
|
||||
|
||||
tracing::debug!("User returned: {:?}", user);
|
||||
|
||||
Ok(user.map(|user| User {
|
||||
user_id: user.user_id,
|
||||
user_name: user.user_name
|
||||
@ -149,12 +145,22 @@ pub fn App() -> impl IntoView {
|
||||
</Suspense>
|
||||
</nav>
|
||||
|
||||
<aside class="beacons">
|
||||
</aside>
|
||||
<crate::beacons::BeaconSidebar />
|
||||
|
||||
<Routes fallback=|| "Page not found.".into_view()>
|
||||
<Route path=path!("users") view=crate::users::UserView />
|
||||
<Route path=path!("login") view=move || view! { <LoginPage login/> }/>
|
||||
<ParentRoute path=path!("beacons") view=crate::beacons::BeaconView>
|
||||
<Route path=path!("categories") view=crate::beacons::CategoriesView/>
|
||||
<Route path=path!("commands") view=crate::beacons::CommandsView/>
|
||||
<Route path=path!("configs") view=crate::beacons::ConfigsView/>
|
||||
<Route path=path!("templates") view=crate::beacons::TemplatesView/>
|
||||
<Route path=path!("instances") view=crate::beacons::InstancesView/>
|
||||
<Route path=path!("listeners") view=crate::beacons::ListenersView/>
|
||||
<Route path=path!("") view=|| view! {
|
||||
<p>"Select a menu item on the left to get started"</p>
|
||||
}/>
|
||||
</ParentRoute>
|
||||
<Route path=path!("") view=HomePage/>
|
||||
</Routes>
|
||||
</Router>
|
||||
|
||||
10
sparse-server/src/beacon_handler.rs
Normal file
10
sparse-server/src/beacon_handler.rs
Normal file
@ -0,0 +1,10 @@
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
sync::{Arc, RwLock},
|
||||
};
|
||||
|
||||
use tokio::task::JoinHandle;
|
||||
|
||||
pub type BeaconListenerHandle = JoinHandle<()>;
|
||||
|
||||
pub type BeaconListenerMap = Arc<RwLock<HashMap<i64, BeaconListenerHandle>>>;
|
||||
54
sparse-server/src/beacons.rs
Normal file
54
sparse-server/src/beacons.rs
Normal file
@ -0,0 +1,54 @@
|
||||
use leptos::prelude::*;
|
||||
use leptos_router::{components::A, nested_router::Outlet};
|
||||
|
||||
mod categories;
|
||||
mod commands;
|
||||
mod configs;
|
||||
mod instances;
|
||||
mod listeners;
|
||||
mod templates;
|
||||
|
||||
pub use categories::CategoriesView;
|
||||
pub use commands::CommandsView;
|
||||
pub use configs::ConfigsView;
|
||||
pub use instances::InstancesView;
|
||||
pub use listeners::ListenersView;
|
||||
pub use templates::TemplatesView;
|
||||
|
||||
#[component]
|
||||
pub fn BeaconView() -> impl IntoView {
|
||||
#[cfg(feature = "hydrate")]
|
||||
Effect::new(move || {
|
||||
let user = expect_context::<ReadSignal<Option<crate::app::User>>>();
|
||||
if user.get().is_none() {
|
||||
let navigate = leptos_router::hooks::use_navigate();
|
||||
navigate("/login?next=beacons", Default::default());
|
||||
}
|
||||
});
|
||||
|
||||
view! {
|
||||
<main class="beacons">
|
||||
<aside class="beacon-menu">
|
||||
<ul>
|
||||
<li><A href="/beacons/listeners">"Listeners"</A></li>
|
||||
<li><A href="/beacons/configs">"Configs"</A></li>
|
||||
<li><A href="/beacons/categories">"Categories"</A></li>
|
||||
<li><A href="/beacons/templates">"Templates"</A></li>
|
||||
<li><A href="/beacons/instances">"Instances"</A></li>
|
||||
<li><A href="/beacons/commands">"Commands"</A></li>
|
||||
</ul>
|
||||
</aside>
|
||||
|
||||
<Outlet />
|
||||
</main>
|
||||
}
|
||||
}
|
||||
|
||||
#[component]
|
||||
pub fn BeaconSidebar() -> impl IntoView {
|
||||
view! {
|
||||
<aside class="beacons">
|
||||
|
||||
</aside>
|
||||
}
|
||||
}
|
||||
13
sparse-server/src/beacons/categories.rs
Normal file
13
sparse-server/src/beacons/categories.rs
Normal file
@ -0,0 +1,13 @@
|
||||
use leptos::prelude::*;
|
||||
|
||||
#[component]
|
||||
pub fn CategoriesView() -> impl IntoView {
|
||||
view! {
|
||||
<div>
|
||||
<p>"Categories"</p>
|
||||
<ul>
|
||||
<li>"Windows"</li>
|
||||
</ul>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
10
sparse-server/src/beacons/commands.rs
Normal file
10
sparse-server/src/beacons/commands.rs
Normal file
@ -0,0 +1,10 @@
|
||||
use leptos::prelude::*;
|
||||
|
||||
#[component]
|
||||
pub fn CommandsView() -> impl IntoView {
|
||||
view! {
|
||||
<div>
|
||||
|
||||
</div>
|
||||
}
|
||||
}
|
||||
10
sparse-server/src/beacons/configs.rs
Normal file
10
sparse-server/src/beacons/configs.rs
Normal file
@ -0,0 +1,10 @@
|
||||
use leptos::prelude::*;
|
||||
|
||||
#[component]
|
||||
pub fn ConfigsView() -> impl IntoView {
|
||||
view! {
|
||||
<div>
|
||||
|
||||
</div>
|
||||
}
|
||||
}
|
||||
10
sparse-server/src/beacons/instances.rs
Normal file
10
sparse-server/src/beacons/instances.rs
Normal file
@ -0,0 +1,10 @@
|
||||
use leptos::prelude::*;
|
||||
|
||||
#[component]
|
||||
pub fn InstancesView() -> impl IntoView {
|
||||
view! {
|
||||
<div>
|
||||
|
||||
</div>
|
||||
}
|
||||
}
|
||||
226
sparse-server/src/beacons/listeners.rs
Normal file
226
sparse-server/src/beacons/listeners.rs
Normal file
@ -0,0 +1,226 @@
|
||||
use std::net::Ipv4Addr;
|
||||
|
||||
use leptos::{either::Either, prelude::*};
|
||||
use serde::{Serialize, Deserialize};
|
||||
#[cfg(feature = "ssr")]
|
||||
use {
|
||||
sqlx::SqlitePool,
|
||||
leptos::server_fn::error::NoCustomError,
|
||||
crate::{db::user, beacon_handler::BeaconListenerMap},
|
||||
rcgen::{generate_simple_self_signed, CertifiedKey},
|
||||
};
|
||||
|
||||
#[cfg(feature = "ssr")]
|
||||
struct DbListener {
|
||||
listener_id: i64,
|
||||
port: i64,
|
||||
public_ip: String,
|
||||
domain_name: String
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
pub struct PubListener {
|
||||
listener_id: i64,
|
||||
port: i64,
|
||||
public_ip: String,
|
||||
domain_name: String,
|
||||
active: bool
|
||||
}
|
||||
|
||||
#[server]
|
||||
pub async fn get_listeners() -> Result<Vec<PubListener>, ServerFnError> {
|
||||
let user = user::get_auth_session().await?;
|
||||
|
||||
if user.is_none() {
|
||||
return Err(ServerFnError::<NoCustomError>::ServerError("You are not signed in!".to_owned()));
|
||||
}
|
||||
|
||||
let db = expect_context::<SqlitePool>();
|
||||
let beacon_handles = expect_context::<BeaconListenerMap>();
|
||||
|
||||
let listeners = sqlx::query_as!(
|
||||
DbListener,
|
||||
"SELECT listener_id, port, public_ip, domain_name FROM beacon_listener"
|
||||
)
|
||||
.fetch_all(&db)
|
||||
.await?;
|
||||
|
||||
let Ok(beacon_handles_handle) = beacon_handles.read() else {
|
||||
return Err(ServerFnError::<NoCustomError>::ServerError("".to_string()));
|
||||
};
|
||||
|
||||
Ok(listeners
|
||||
.into_iter()
|
||||
.map(|b| PubListener {
|
||||
listener_id: b.listener_id,
|
||||
port: b.port,
|
||||
public_ip: b.public_ip,
|
||||
domain_name: b.domain_name,
|
||||
active: beacon_handles_handle
|
||||
.get(&b.listener_id)
|
||||
.map(|h| !h.is_finished())
|
||||
.unwrap_or(false)
|
||||
})
|
||||
.collect())
|
||||
}
|
||||
|
||||
#[server]
|
||||
pub async fn add_listener(public_ip: String, port: i16, domain_name: String) -> Result<(), ServerFnError> {
|
||||
let user = user::get_auth_session().await?;
|
||||
|
||||
if user.is_none() {
|
||||
return Err(ServerFnError::<NoCustomError>::ServerError("You are not signed in!".to_owned()));
|
||||
}
|
||||
|
||||
if public_ip.parse::<Ipv4Addr>().is_err() {
|
||||
return Err(ServerFnError::<NoCustomError>::ServerError("Unable to parse public IP address".to_owned()));
|
||||
}
|
||||
|
||||
let subject_alt_names = vec![public_ip.to_string(), domain_name.clone()];
|
||||
let CertifiedKey { cert, key_pair } = tokio::task::spawn_blocking(|| {
|
||||
generate_simple_self_signed(subject_alt_names)
|
||||
}).await??;
|
||||
|
||||
let db = expect_context::<SqlitePool>();
|
||||
|
||||
let public_ip = public_ip.to_string();
|
||||
let cert = cert.pem().to_string();
|
||||
let key_pair = key_pair.serialize_pem().to_string();
|
||||
|
||||
sqlx::query!(
|
||||
"INSERT INTO beacon_listener (port, public_ip, domain_name, certificate, privkey) VALUES (?, ?, ?, ?, ?)",
|
||||
port,
|
||||
public_ip,
|
||||
domain_name,
|
||||
cert,
|
||||
key_pair
|
||||
)
|
||||
.execute(&db)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[server]
|
||||
pub async fn start_listener(listener_id: i64) -> Result<(), ServerFnError> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[component]
|
||||
pub fn ListenersView() -> impl IntoView {
|
||||
let add_listener = ServerAction::<AddListener>::new();
|
||||
|
||||
let listeners = Resource::new(
|
||||
move || add_listener.version().get(),
|
||||
|_| async { get_listeners().await }
|
||||
);
|
||||
|
||||
view! {
|
||||
<div class="listeners">
|
||||
<ActionForm action=add_listener>
|
||||
<fieldset>
|
||||
{move || match add_listener.value().get() {
|
||||
Some(Ok(_)) => Either::Right(()),
|
||||
None => Either::Right(()),
|
||||
Some(Err(e)) => Either::Left(view! {
|
||||
<p>"Error creating listener:"</p>
|
||||
<p>{format!("{e:?}")}</p>
|
||||
})
|
||||
}}
|
||||
<legend>"Add a new listener"</legend>
|
||||
<label>"Public IP address"</label>
|
||||
<input name="public_ip"/>
|
||||
<label>"Port"</label>
|
||||
<input name="port" type="number"/>
|
||||
<label>"Domain name (for HTTPS)"</label>
|
||||
<input name="domain_name"/>
|
||||
<div></div>
|
||||
<input type="submit" value="Submit"/>
|
||||
</fieldset>
|
||||
</ActionForm>
|
||||
|
||||
<Suspense fallback=|| view! { <p>"Loading..."</p> }>
|
||||
{ move || match listeners.get() {
|
||||
Some(inner) => Either::Right(match inner {
|
||||
Err(e) => Either::Left(view! {
|
||||
<p>"There was an error loading listeners:"</p>
|
||||
<p>{format!("error: {}", e)}</p>
|
||||
}),
|
||||
Ok(ls) => Either::Right(view! {
|
||||
<DisplayListeners
|
||||
listener_resource=listeners
|
||||
listeners=ls
|
||||
/>
|
||||
})
|
||||
}),
|
||||
None => Either::Left(view! {
|
||||
<p>"Loading..."</p>
|
||||
})
|
||||
}}
|
||||
</Suspense>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
#[component]
|
||||
fn DisplayListeners(listener_resource: Resource<Result<Vec<PubListener>, ServerFnError>>, listeners: Vec<PubListener>) -> impl IntoView {
|
||||
let (error_msg, set_error_msg) = signal(None);
|
||||
let start_listener_action = Action::new(move |&id: &i64| async move {
|
||||
match start_listener(id).await {
|
||||
Ok(()) => {
|
||||
listener_resource.refetch();
|
||||
}
|
||||
Err(e) => {
|
||||
set_error_msg(Some(e.to_string()));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let listeners_view = listeners
|
||||
.iter()
|
||||
.map(|listener| view! {
|
||||
<li>
|
||||
{listener.listener_id}
|
||||
": "
|
||||
{listener.domain_name.clone()}
|
||||
" ("
|
||||
{listener.public_ip.clone()}
|
||||
":"
|
||||
{listener.port}
|
||||
")"
|
||||
{match listener.active {
|
||||
true => Either::Left(view! {
|
||||
<span>"active!"</span>
|
||||
}),
|
||||
false => Either::Right(view! {
|
||||
<button
|
||||
on:click={
|
||||
let id = listener.listener_id;
|
||||
move |e| {
|
||||
let _ = e.prevent_default();
|
||||
start_listener_action.dispatch(id);
|
||||
}
|
||||
}
|
||||
>
|
||||
"activate"
|
||||
</button>
|
||||
})
|
||||
}}
|
||||
</li>
|
||||
})
|
||||
.collect_view();
|
||||
|
||||
view! {
|
||||
{move || error_msg
|
||||
.get()
|
||||
.map(|err| view! {
|
||||
<p>
|
||||
"Error starting listener: "
|
||||
{err}
|
||||
</p>
|
||||
})}
|
||||
<ul>
|
||||
{listeners_view}
|
||||
</ul>
|
||||
}
|
||||
}
|
||||
10
sparse-server/src/beacons/templates.rs
Normal file
10
sparse-server/src/beacons/templates.rs
Normal file
@ -0,0 +1,10 @@
|
||||
use leptos::prelude::*;
|
||||
|
||||
#[component]
|
||||
pub fn TemplatesView() -> impl IntoView {
|
||||
view! {
|
||||
<div>
|
||||
|
||||
</div>
|
||||
}
|
||||
}
|
||||
@ -1,10 +1,10 @@
|
||||
pub mod app;
|
||||
|
||||
pub mod users;
|
||||
|
||||
pub mod error;
|
||||
|
||||
#[cfg(feature = "ssr")]
|
||||
pub mod beacon_handler;
|
||||
pub mod beacons;
|
||||
pub mod db;
|
||||
pub mod error;
|
||||
pub mod users;
|
||||
|
||||
#[cfg(feature = "hydrate")]
|
||||
#[wasm_bindgen::prelude::wasm_bindgen]
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
#[cfg(feature = "ssr")]
|
||||
pub(crate) mod beacons {
|
||||
pub(crate) mod beacon_binaries {
|
||||
#[allow(dead_code)]
|
||||
pub const LINUX_BEACON: &'static [u8] = include_bytes!(std::env!("SPARSE_BEACON_LINUX"));
|
||||
#[allow(dead_code)]
|
||||
@ -15,16 +15,15 @@ pub(crate) mod beacons {
|
||||
|
||||
#[cfg(feature = "ssr")]
|
||||
mod cli;
|
||||
|
||||
#[cfg(feature = "ssr")]
|
||||
mod webserver;
|
||||
|
||||
#[cfg(feature = "ssr")]
|
||||
mod beacons;
|
||||
#[cfg(feature = "ssr")]
|
||||
pub mod users;
|
||||
|
||||
pub mod error;
|
||||
|
||||
pub mod db;
|
||||
pub mod beacon_handler;
|
||||
|
||||
#[cfg(feature = "ssr")]
|
||||
#[tokio::main]
|
||||
@ -56,7 +55,7 @@ async fn main() -> anyhow::Result<std::process::ExitCode> {
|
||||
|
||||
let db_exists = std::fs::metadata(&db_location);
|
||||
|
||||
let run_init = if let Err(e) = db_exists {
|
||||
if let Err(e) = db_exists {
|
||||
if !options.init_ok {
|
||||
tracing::error!("Database doesn't exist, and initialization not allowed!");
|
||||
tracing::error!("{:?}", e);
|
||||
@ -64,10 +63,7 @@ async fn main() -> anyhow::Result<std::process::ExitCode> {
|
||||
}
|
||||
|
||||
tracing::info!("Database doesn't exist, readying initialization");
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
}
|
||||
|
||||
let pool = SqlitePool::connect_with(
|
||||
SqliteConnectOptions::from_str(&format!("sqlite://{}", db_location.to_string_lossy()))?
|
||||
|
||||
@ -255,7 +255,7 @@ pub fn UserView() -> impl IntoView {
|
||||
let user = expect_context::<ReadSignal<Option<crate::app::User>>>();
|
||||
if user.get().is_none() {
|
||||
let navigate = leptos_router::hooks::use_navigate();
|
||||
navigate("/login?next=/users", Default::default());
|
||||
navigate("/login?next=users", Default::default());
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@ -12,6 +12,7 @@ pub async fn serve_web(management_address: SocketAddrV4, _bind_address: SocketAd
|
||||
let conf = get_configuration(None).unwrap();
|
||||
let leptos_options = conf.leptos_options;
|
||||
let routes = generate_route_list(App);
|
||||
let beacon_listeners = crate::beacon_handler::BeaconListenerMap::default();
|
||||
|
||||
let compression_layer = tower_http::compression::CompressionLayer::new()
|
||||
.gzip(true)
|
||||
@ -23,7 +24,10 @@ pub async fn serve_web(management_address: SocketAddrV4, _bind_address: SocketAd
|
||||
.leptos_routes_with_context(
|
||||
&leptos_options,
|
||||
routes,
|
||||
move || provide_context(db.clone()),
|
||||
move || {
|
||||
provide_context(std::sync::Arc::clone(&beacon_listeners));
|
||||
provide_context(db.clone())
|
||||
},
|
||||
{
|
||||
let leptos_options = leptos_options.clone();
|
||||
move || shell(leptos_options.clone())
|
||||
|
||||
38
sparse-server/style/_beacons.scss
Normal file
38
sparse-server/style/_beacons.scss
Normal file
@ -0,0 +1,38 @@
|
||||
@use 'beacons/listeners';
|
||||
@use 'beacons/configs';
|
||||
@use 'beacons/categories';
|
||||
@use 'beacons/templates';
|
||||
@use 'beacons/instances';
|
||||
@use 'beacons/commands';
|
||||
|
||||
main.beacons {
|
||||
display: grid;
|
||||
grid-template-columns: 120px 1fr;
|
||||
padding: 0;
|
||||
|
||||
aside.beacon-menu {
|
||||
border-right: 1px solid #2e2e59;
|
||||
|
||||
ul {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
li a, li a:visited {
|
||||
display: inline-block;
|
||||
padding: 10px;
|
||||
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
aside.beacons {
|
||||
|
||||
}
|
||||
@ -1,3 +1,14 @@
|
||||
main.main {
|
||||
|
||||
}
|
||||
|
||||
main.login {
|
||||
form {
|
||||
display: grid;
|
||||
grid-template-columns: 125px 200px;
|
||||
|
||||
input, label {
|
||||
margin: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
0
sparse-server/style/beacons/_categories.scss
Normal file
0
sparse-server/style/beacons/_categories.scss
Normal file
0
sparse-server/style/beacons/_commands.scss
Normal file
0
sparse-server/style/beacons/_commands.scss
Normal file
0
sparse-server/style/beacons/_configs.scss
Normal file
0
sparse-server/style/beacons/_configs.scss
Normal file
0
sparse-server/style/beacons/_instances.scss
Normal file
0
sparse-server/style/beacons/_instances.scss
Normal file
14
sparse-server/style/beacons/_listeners.scss
Normal file
14
sparse-server/style/beacons/_listeners.scss
Normal file
@ -0,0 +1,14 @@
|
||||
main.beacons div.listeners {
|
||||
form {
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
fieldset {
|
||||
display: grid;
|
||||
grid-template-columns: 300px 200px;
|
||||
|
||||
input, label {
|
||||
margin: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
0
sparse-server/style/beacons/_templates.scss
Normal file
0
sparse-server/style/beacons/_templates.scss
Normal file
@ -1,5 +1,10 @@
|
||||
@use '_users';
|
||||
@use '_main';
|
||||
@use '_beacons';
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html, body {
|
||||
font-family: sans-serif;
|
||||
|
||||
@ -10,10 +10,12 @@ typedef struct {
|
||||
typedef union SourceIp {
|
||||
struct {
|
||||
char mode; // set to 0
|
||||
char source_mac[6];
|
||||
ipaddr_t source_ip;
|
||||
} use_host_networking;
|
||||
struct {
|
||||
char mode; // set to 1
|
||||
char source_mac[6];
|
||||
unsigned short netmask;
|
||||
ipaddr_t source_ip;
|
||||
ipaddr_t gateway;
|
||||
@ -25,8 +27,6 @@ typedef struct Parameters {
|
||||
SourceIp_t source_ip;
|
||||
unsigned short destination_port;
|
||||
unsigned short pubkey_cert_size;
|
||||
unsigned short privkey_size;
|
||||
unsigned short privkey_cert_size;
|
||||
unsigned short beacon_name_length;
|
||||
unsigned short domain_name_length;
|
||||
char pubkey_cert[1024];
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user