diff --git a/bin/src/config.rs b/bin/src/config.rs
index a8705c1..045ea00 100644
--- a/bin/src/config.rs
+++ b/bin/src/config.rs
@@ -1,10 +1,10 @@
-use serde::Deserialize;
+use serde::{Deserialize, Serialize};
use rayhunter::analysis::analyzer::AnalyzerConfig;
use crate::error::RayhunterError;
-#[derive(Debug, Deserialize)]
+#[derive(Debug, Deserialize, Serialize)]
#[serde(default)]
pub struct Config {
pub qmdl_store_path: String,
@@ -32,11 +32,11 @@ impl Default for Config {
}
}
-pub fn parse_config
(path: P) -> Result
+pub async fn parse_config(path: P) -> Result
where
P: AsRef,
{
- if let Ok(config_file) = std::fs::read_to_string(&path) {
+ if let Ok(config_file) = tokio::fs::read_to_string(&path).await {
Ok(toml::from_str(&config_file).map_err(RayhunterError::ConfigFileParsingError)?)
} else {
Ok(Config::default())
diff --git a/bin/src/daemon.rs b/bin/src/daemon.rs
index f0754ac..6749f21 100644
--- a/bin/src/daemon.rs
+++ b/bin/src/daemon.rs
@@ -20,7 +20,7 @@ use crate::diag::run_diag_read_thread;
use crate::error::RayhunterError;
use crate::pcap::get_pcap;
use crate::qmdl_store::RecordingStore;
-use crate::server::{get_qmdl, restart_daemon, serve_static, ServerState};
+use crate::server::{get_config, get_qmdl, restart_daemon, serve_static, set_config, ServerState};
use crate::stats::{get_qmdl_manifest, get_system_stats};
use analysis::{
@@ -60,6 +60,8 @@ fn get_router() -> AppRouter {
.route("/api/analysis", get(get_analysis_status))
.route("/api/analysis/{name}", post(start_analysis))
.route("/api/restart-daemon", post(restart_daemon))
+ .route("/api/config", get(get_config))
+ .route("/api/config", post(set_config))
.route("/", get(|| async { Redirect::permanent("/index.html") }))
.route("/{*path}", get(serve_static))
}
@@ -187,8 +189,8 @@ async fn main() -> Result<(), RayhunterError> {
let args = parse_args();
loop {
- let config = parse_config(&args.config_path)?;
- if !run_with_config(&config).await? {
+ let config = parse_config(&args.config_path).await?;
+ if !run_with_config(&args, &config).await? {
return Ok(());
}
@@ -199,7 +201,10 @@ async fn main() -> Result<(), RayhunterError> {
}
}
-async fn run_with_config(config: &config::Config) -> Result {
+async fn run_with_config(
+ args: &config::Args,
+ config: &config::Config,
+) -> Result {
// TaskTrackers give us an interface to spawn tokio threads, and then
// eventually await all of them ending
let task_tracker = TaskTracker::new();
@@ -264,6 +269,7 @@ async fn run_with_config(config: &config::Config) -> Result>,
pub diag_device_ctrl_sender: Sender,
pub ui_update_sender: Sender,
@@ -35,12 +40,15 @@ pub async fn get_qmdl(
StatusCode::NOT_FOUND,
format!("couldn't find qmdl file with name {}", qmdl_idx),
))?;
- let qmdl_file = qmdl_store.open_entry_qmdl(entry_index).await.map_err(|e| {
- (
- StatusCode::INTERNAL_SERVER_ERROR,
- format!("error opening QMDL file: {}", e),
- )
- })?;
+ let qmdl_file = qmdl_store
+ .open_entry_qmdl(entry_index)
+ .await
+ .map_err(|err| {
+ (
+ StatusCode::INTERNAL_SERVER_ERROR,
+ format!("error opening QMDL file: {}", err),
+ )
+ })?;
let limited_qmdl_file = qmdl_file.take(entry.qmdl_size_bytes as u64);
let qmdl_stream = ReaderStream::new(limited_qmdl_file);
@@ -84,13 +92,12 @@ pub async fn restart_daemon(
let mut restart_tx = state.daemon_restart_tx.write().await;
if let Some(sender) = restart_tx.take() {
- sender.send(()).map_err(|()| {
+ sender.send(()).map_err(|_| {
(
StatusCode::INTERNAL_SERVER_ERROR,
"couldn't send restart signal".to_string(),
)
})?;
-
Ok((StatusCode::ACCEPTED, "restart signal sent".to_string()))
} else {
Ok((
@@ -99,3 +106,37 @@ pub async fn restart_daemon(
))
}
}
+
+pub async fn get_config(
+ State(state): State>,
+) -> Result, (StatusCode, String)> {
+ let config = parse_config(&state.config_path).await.map_err(|err| {
+ (
+ StatusCode::INTERNAL_SERVER_ERROR,
+ format!("failed to read config file: {}", err),
+ )
+ })?;
+
+ Ok(Json(config))
+}
+
+pub async fn set_config(
+ State(state): State>,
+ Json(config): Json,
+) -> Result<(StatusCode, String), (StatusCode, String)> {
+ let config_str = toml::to_string_pretty(&config).map_err(|err| {
+ (
+ StatusCode::INTERNAL_SERVER_ERROR,
+ format!("failed to serialize config as TOML: {}", err),
+ )
+ })?;
+
+ write(&state.config_path, config_str).await.map_err(|err| {
+ (
+ StatusCode::INTERNAL_SERVER_ERROR,
+ format!("failed to write config file: {}", err),
+ )
+ })?;
+
+ Ok((StatusCode::ACCEPTED, "wrote config".to_string()))
+}
diff --git a/lib/src/analysis/analyzer.rs b/lib/src/analysis/analyzer.rs
index 54caecb..6a31bc0 100644
--- a/lib/src/analysis/analyzer.rs
+++ b/lib/src/analysis/analyzer.rs
@@ -11,7 +11,7 @@ use super::{
null_cipher::NullCipherAnalyzer, priority_2g_downgrade::LteSib6And7DowngradeAnalyzer,
};
-#[derive(Debug, Clone, Deserialize)]
+#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(default)]
pub struct AnalyzerConfig {
pub imsi_requested: bool,