diff --git a/src/backend/src/main.rs b/src/backend/src/main.rs index 3eea459e..46062e40 100644 --- a/src/backend/src/main.rs +++ b/src/backend/src/main.rs @@ -1,18 +1,15 @@ #![warn(clippy::pedantic)] #![warn(clippy::cognitive_complexity)] +use crate::shared::CONFIG; use sha2::{Digest, Sha512}; use simple_logger::SimpleLogger; use warp::Filter; mod config; +mod shared; mod sockets; mod systemdata; mod terminal; -mod types; - -lazy_static::lazy_static! { - static ref CONFIG: config::Config = config::config(); -} #[allow(clippy::too_many_lines)] fn main() { @@ -60,11 +57,13 @@ fn main() { .and(warp::body::bytes()) .map(|pass| { if CONFIG.pass { + dbg!(&pass); let mut hasher = Sha512::new(); hasher.update(pass); let shasum = format!("{:x?}", hasher.finalize()) .split(&['[', ']', ',', ' '][..]) .collect::(); + dbg!(&shasum, &CONFIG.hash); if shasum == CONFIG.hash { let mut claims = jwts::Claims::new(); claims.exp = Some( diff --git a/src/backend/src/types.rs b/src/backend/src/shared.rs similarity index 71% rename from src/backend/src/types.rs rename to src/backend/src/shared.rs index 14c12540..b664f7f3 100644 --- a/src/backend/src/types.rs +++ b/src/backend/src/shared.rs @@ -1,5 +1,33 @@ use nanoserde::{DeJson, SerJson}; +lazy_static::lazy_static! { + pub static ref CONFIG: crate::config::Config = crate::config::config(); +} + +pub fn validate_token(token: &str) -> bool { + let key = jwts::jws::Key::new(&crate::CONFIG.secret, jwts::jws::Algorithm::HS256); + let verified: jwts::jws::Token; + if let Ok(token) = jwts::jws::Token::verify_with_key(token, &key) { + verified = token; + } else { + log::error!("Couldn't verify token"); + return false; + }; + let config = jwts::ValidationConfig { + iat_validation: false, + nbf_validation: false, + exp_validation: true, + expected_iss: Some("DietPi Dashboard".to_string()), + expected_sub: None, + expected_aud: None, + expected_jti: None, + }; + if verified.validate_claims(&config).is_err() { + return false; + } + true +} + #[derive(SerJson)] pub struct SysData { pub cpu: f32, diff --git a/src/backend/src/sockets.rs b/src/backend/src/sockets.rs index b99b913b..bb59e44b 100644 --- a/src/backend/src/sockets.rs +++ b/src/backend/src/sockets.rs @@ -11,17 +11,17 @@ use tokio::sync::{ use tokio::time::sleep; use warp::ws::Message; -use crate::{systemdata, types, CONFIG}; +use crate::{shared, systemdata, CONFIG}; async fn main_handler( socket_ptr: Arc>>, - data_recv: &mut Receiver>, + data_recv: &mut Receiver>, ) { let handle = tokio::spawn(async move { let mut socket_send = socket_ptr.lock().await; loop { let _send = (*socket_send) - .send(Message::text(SerJson::serialize_json(&types::SysData { + .send(Message::text(SerJson::serialize_json(&shared::SysData { cpu: systemdata::cpu().await, ram: systemdata::ram().await, swap: systemdata::swap().await, @@ -41,14 +41,14 @@ async fn main_handler( async fn process_handler( socket_ptr: Arc>>, - data_recv: &mut Receiver>, + data_recv: &mut Receiver>, ) { let handle = tokio::spawn(async move { loop { let mut socket_send = socket_ptr.lock().await; let _send = (*socket_send) .send(Message::text(SerJson::serialize_json( - &types::ProcessList { + &shared::ProcessList { processes: systemdata::processes().await, }, ))) @@ -85,12 +85,12 @@ async fn process_handler( async fn software_handler( socket_ptr: Arc>>, - data_recv: &mut Receiver>, + data_recv: &mut Receiver>, ) { let mut socket_send = socket_ptr.lock().await; let _send = (*socket_send) .send(Message::text(SerJson::serialize_json( - &types::DPSoftwareList { + &shared::DPSoftwareList { software: systemdata::dpsoftware(), response: String::new(), }, @@ -118,7 +118,7 @@ async fn software_handler( .replace("", ""); let _send = socket_send .send(Message::text(SerJson::serialize_json( - &types::DPSoftwareList { + &shared::DPSoftwareList { software: systemdata::dpsoftware(), response: out, }, @@ -131,7 +131,7 @@ async fn software_handler( async fn management_handler( socket_ptr: Arc>>, - data_recv: &mut Receiver>, + data_recv: &mut Receiver>, ) { let mut socket_send = socket_ptr.lock().await; let _send = (*socket_send) @@ -153,12 +153,12 @@ async fn management_handler( async fn service_handler( socket_ptr: Arc>>, - data_recv: &mut Receiver>, + data_recv: &mut Receiver>, ) { let mut socket_send = socket_ptr.lock().await; let _send = (*socket_send) .send(Message::text(SerJson::serialize_json( - &types::ServiceList { + &shared::ServiceList { services: systemdata::services(), }, ))) @@ -175,7 +175,7 @@ async fn service_handler( .unwrap(); let _send = (*socket_send) .send(Message::text(SerJson::serialize_json( - &types::ServiceList { + &shared::ServiceList { services: systemdata::services(), }, ))) @@ -192,7 +192,7 @@ async fn browser_refresh( let dir_path = path.rsplit_once('/').unwrap().0; let _send = socket_send .send(Message::text(SerJson::serialize_json( - &types::BrowserList { + &shared::BrowserList { contents: systemdata::browser_dir(std::path::Path::new(dir_path)), }, ))) @@ -201,13 +201,13 @@ async fn browser_refresh( async fn browser_handler( socket_ptr: Arc>>, - data_recv: &mut Receiver>, + data_recv: &mut Receiver>, ) { let mut socket_send = socket_ptr.lock().await; // Get initial listing of $HOME let _send = (*socket_send) .send(Message::text(SerJson::serialize_json( - &types::BrowserList { + &shared::BrowserList { contents: systemdata::browser_dir(std::path::Path::new( &std::env::var_os("HOME").unwrap_or_else(|| "/root".into()), )), @@ -223,7 +223,7 @@ async fn browser_handler( "cd" => { let _send = (*socket_send) .send(Message::text(SerJson::serialize_json( - &types::BrowserList { + &shared::BrowserList { contents: systemdata::browser_dir(std::path::Path::new( &data.args[0], )), @@ -234,7 +234,7 @@ async fn browser_handler( "open" => { let _send = (*socket_send) .send(Message::text(SerJson::serialize_json( - &types::BrowserFileData { + &shared::BrowserFileData { textdata: std::fs::read_to_string(std::path::Path::new( &data.args[0], )) @@ -287,57 +287,26 @@ pub async fn socket_handler(socket: warp::ws::WebSocket) { let (data_send, mut data_recv) = mpsc::channel(1); tokio::task::spawn(async move { let mut first_message = true; - let mut req: types::Request; + let mut req: shared::Request; while let Some(Ok(data)) = socket_recv.next().await { if data.is_close() { break; } req = DeJson::deserialize_json(data.to_str().unwrap()).unwrap(); - if CONFIG.pass { - let key = jwts::jws::Key::new(&CONFIG.secret, jwts::jws::Algorithm::HS256); - let verified: jwts::jws::Token; - if let Ok(token) = jwts::jws::Token::verify_with_key(&req.token, &key) { - verified = token; - } else { - log::error!("Couldn't verify token"); - if !first_message { - data_send.send(None).await.unwrap(); - } - data_send - .send(Some(types::Request { - page: "/login".to_string(), - token: String::new(), - cmd: String::new(), - args: Vec::new(), - })) - .await - .unwrap(); - continue; - }; - let config = jwts::ValidationConfig { - iat_validation: false, - nbf_validation: false, - exp_validation: true, - expected_iss: Some("DietPi Dashboard".to_string()), - expected_sub: None, - expected_aud: None, - expected_jti: None, - }; - if verified.validate_claims(&config).is_err() { - if !first_message { - data_send.send(None).await.unwrap(); - } - data_send - .send(Some(types::Request { - page: "/login".to_string(), - token: String::new(), - cmd: String::new(), - args: Vec::new(), - })) - .await - .unwrap(); - continue; + if CONFIG.pass && !shared::validate_token(&req.token) { + if !first_message { + data_send.send(None).await.unwrap(); } + data_send + .send(Some(shared::Request { + page: "/login".to_string(), + token: String::new(), + cmd: String::new(), + args: Vec::new(), + })) + .await + .unwrap(); + continue; } if req.cmd.is_empty() { if first_message { @@ -383,9 +352,9 @@ pub async fn socket_handler(socket: warp::ws::WebSocket) { "/login" => { // Internal poll, see other thread let _send = (*socket_ptr.lock().await) - .send(Message::text(SerJson::serialize_json(&types::TokenError { - error: true, - }))) + .send(Message::text(SerJson::serialize_json( + &shared::TokenError { error: true }, + ))) .await; } _ => {} diff --git a/src/backend/src/systemdata.rs b/src/backend/src/systemdata.rs index d5e00833..604e9f98 100644 --- a/src/backend/src/systemdata.rs +++ b/src/backend/src/systemdata.rs @@ -16,7 +16,7 @@ use std::sync::atomic::{AtomicU64, Ordering::Relaxed}; use std::time::Duration; use tokio::time::sleep; -use crate::types; +use crate::shared; // Use u64::MAX to originally set traffic lazy_static! { @@ -42,12 +42,12 @@ pub async fn cpu() -> f32 { } #[allow(clippy::cast_precision_loss)] -pub async fn ram() -> types::UsageData { +pub async fn ram() -> shared::UsageData { let ram = memory::memory().await.unwrap(); let ram_used = (ram.total() - ram.available()).get::(); let ram_total = ram.total().get::(); - types::UsageData { + shared::UsageData { used: ram_used, total: ram_total, percent: round_percent((ram_used as f64 / ram_total as f64) * 100.0), @@ -55,12 +55,12 @@ pub async fn ram() -> types::UsageData { } #[allow(clippy::cast_precision_loss)] -pub async fn swap() -> types::UsageData { +pub async fn swap() -> shared::UsageData { let swap = memory::swap().await.unwrap(); let swap_used = swap.used().get::(); let swap_total = swap.total().get::(); - types::UsageData { + shared::UsageData { used: swap_used, total: swap_total, percent: if swap_total == 0 { @@ -71,17 +71,17 @@ pub async fn swap() -> types::UsageData { } } -pub async fn disk() -> types::UsageData { +pub async fn disk() -> shared::UsageData { let disk = disk::usage("/").await.unwrap(); - types::UsageData { + shared::UsageData { used: disk.used().get::(), total: disk.total().get::(), percent: round_percent(disk.ratio().get::().into()), } } -pub async fn network() -> types::NetData { +pub async fn network() -> shared::NetData { // Get data from all interfaces let (sent, recv) = net::io_counters() .await @@ -95,7 +95,7 @@ pub async fn network() -> types::NetData { }) .await; - let data = types::NetData { + let data = shared::NetData { recieved: recv.saturating_sub(BYTES_RECV.load(Relaxed)), sent: sent.saturating_sub(BYTES_SENT.load(Relaxed)), }; @@ -106,7 +106,7 @@ pub async fn network() -> types::NetData { data } -pub async fn processes() -> Vec { +pub async fn processes() -> Vec { let processes = process::processes() .await .unwrap() @@ -187,7 +187,7 @@ pub async fn processes() -> Vec { } Err(_) => continue, } - process_list.push(types::ProcessData { + process_list.push(shared::ProcessData { pid, name, cpu, @@ -199,7 +199,7 @@ pub async fn processes() -> Vec { } #[allow(clippy::too_many_lines)] -pub fn dpsoftware() -> Vec { +pub fn dpsoftware() -> Vec { let free_out = Command::new("/boot/dietpi/dietpi-software") .arg("free") .output() @@ -234,7 +234,7 @@ pub fn dpsoftware() -> Vec { }); 'software: for element in out_list.iter().skip(4).take(out_list.len() - 4) { if free_list.contains(&(index as i16)) { - software_list.push(types::DPSoftwareData { + software_list.push(shared::DPSoftwareData { id: -1, installed: false, name: String::new(), @@ -273,7 +273,7 @@ pub fn dpsoftware() -> Vec { } 3 => { if el1.contains("DISABLED") { - software_list.push(types::DPSoftwareData { + software_list.push(shared::DPSoftwareData { id: -1, installed: false, name: String::new(), @@ -296,7 +296,7 @@ pub fn dpsoftware() -> Vec { _ => {} } } - software_list.push(types::DPSoftwareData { + software_list.push(shared::DPSoftwareData { id, dependencies: depends, docs, @@ -310,7 +310,7 @@ pub fn dpsoftware() -> Vec { } #[allow(clippy::cast_sign_loss, clippy::cast_possible_truncation)] -pub async fn host() -> types::HostData { +pub async fn host() -> shared::HostData { let info = host::platform().await.unwrap(); let uptime = host::uptime().await.unwrap().get::().round() as u64; let dp_file = fs::read_to_string(&std::path::Path::new("/boot/dietpi/.version")).unwrap(); @@ -352,7 +352,7 @@ pub async fn host() -> types::HostData { net::Address::Inet6(addr6) => ip = addr6.ip().to_string(), _ => (), } - types::HostData { + shared::HostData { hostname: info.hostname().to_string(), uptime, arch: arch.to_string(), @@ -365,7 +365,7 @@ pub async fn host() -> types::HostData { } } -pub fn services() -> Vec { +pub fn services() -> Vec { let services = &Command::new("/boot/dietpi/dietpi-services") .arg("status") .output() @@ -409,7 +409,7 @@ pub fn services() -> Vec { None => status = "dead".to_string(), } } - services_list.push(types::ServiceData { + services_list.push(shared::ServiceData { name, log, status, @@ -419,16 +419,16 @@ pub fn services() -> Vec { services_list } -pub fn global() -> types::GlobalData { +pub fn global() -> shared::GlobalData { let update = fs::read_to_string("/run/dietpi/.update_available").unwrap_or_else(|_| String::new()); - types::GlobalData { + shared::GlobalData { update, login: crate::CONFIG.pass, } } -pub fn browser_dir(path: &std::path::Path) -> Vec { +pub fn browser_dir(path: &std::path::Path) -> Vec { let dir = fs::read_dir(path).unwrap(); let mut file_list = Vec::new(); for file in dir { @@ -449,7 +449,7 @@ pub fn browser_dir(path: &std::path::Path) -> Vec { buf = val; } else { log::error!("Could not read directory"); - return vec![types::BrowserDirData { + return vec![shared::BrowserDirData { path: "/".to_string(), name: "ERROR".to_string(), maintype: "dir".to_string(), @@ -492,7 +492,7 @@ pub fn browser_dir(path: &std::path::Path) -> Vec { prettytype = "Plain Text File".to_string(); } } - file_list.push(types::BrowserDirData { + file_list.push(shared::BrowserDirData { path: file.path().into_os_string().into_string().unwrap(), name: file.file_name().into_string().unwrap(), maintype, diff --git a/src/backend/src/terminal.rs b/src/backend/src/terminal.rs index c8276b6e..f3180ca5 100644 --- a/src/backend/src/terminal.rs +++ b/src/backend/src/terminal.rs @@ -22,24 +22,7 @@ pub async fn term_handler(socket: warp::ws::WebSocket) { let token = socket_recv.next().await.unwrap().unwrap(); let token = token.to_str().unwrap(); if token.get(..5) == Some("token") { - let key = jwts::jws::Key::new(&crate::CONFIG.secret, jwts::jws::Algorithm::HS256); - let verified: jwts::jws::Token; - if let Ok(token) = jwts::jws::Token::verify_with_key(&token[5..], &key) { - verified = token; - } else { - log::error!("Couldn't verify token"); - return; - }; - let config = jwts::ValidationConfig { - iat_validation: false, - nbf_validation: false, - exp_validation: true, - expected_iss: Some("DietPi Dashboard".to_string()), - expected_sub: None, - expected_aud: None, - expected_jti: None, - }; - if verified.validate_claims(&config).is_err() { + if !crate::shared::validate_token(&token[5..]) { return; } } else {