diff options
author | fx <[email protected]> | 2023-10-09 13:07:54 +0200 |
---|---|---|
committer | fx <[email protected]> | 2023-10-09 13:07:54 +0200 |
commit | bc5f721de8996b48550b5069f5592caf2968e822 (patch) | |
tree | fe7bf485cda800d6fff595c0573b9bca4a4c1dd0 /src | |
parent | 159cb1b3c940440ebe03e5042c361be563324978 (diff) | |
download | webol-bc5f721de8996b48550b5069f5592caf2968e822.tar webol-bc5f721de8996b48550b5069f5592caf2968e822.tar.gz webol-bc5f721de8996b48550b5069f5592caf2968e822.zip |
added wol func and bad auth
Diffstat (limited to 'src')
-rw-r--r-- | src/auth.rs | 41 | ||||
-rw-r--r-- | src/config.rs | 11 | ||||
-rw-r--r-- | src/main.rs | 3 | ||||
-rw-r--r-- | src/routes/start.rs | 57 | ||||
-rw-r--r-- | src/wol.rs | 29 |
5 files changed, 129 insertions, 12 deletions
diff --git a/src/auth.rs b/src/auth.rs index b1ad76d..b7693a0 100644 --- a/src/auth.rs +++ b/src/auth.rs | |||
@@ -1,3 +1,40 @@ | |||
1 | pub fn auth(secret: &str) -> bool { | 1 | use std::error::Error; |
2 | secret == "aaa" | 2 | use axum::headers::HeaderValue; |
3 | use axum::http::StatusCode; | ||
4 | use tracing::error; | ||
5 | use crate::auth::AuthError::{MissingSecret, ServerError, WrongSecret}; | ||
6 | use crate::config::SETTINGS; | ||
7 | |||
8 | pub fn auth(secret: Option<&HeaderValue>) -> Result<bool, AuthError> { | ||
9 | if let Some(value) = secret { | ||
10 | let key = SETTINGS | ||
11 | .get_string("apikey") | ||
12 | .map_err(|err| ServerError(Box::new(err)))?; | ||
13 | if value.to_str().map_err(|err| ServerError(Box::new(err)))? == key.as_str() { | ||
14 | Ok(true) | ||
15 | } else { | ||
16 | Err(WrongSecret) | ||
17 | } | ||
18 | } else { | ||
19 | Err(MissingSecret) | ||
20 | } | ||
3 | } | 21 | } |
22 | |||
23 | pub enum AuthError { | ||
24 | WrongSecret, | ||
25 | MissingSecret, | ||
26 | ServerError(Box<dyn Error>), | ||
27 | } | ||
28 | |||
29 | impl AuthError { | ||
30 | pub fn get(self) -> (StatusCode, &'static str) { | ||
31 | match self { | ||
32 | AuthError::WrongSecret => (StatusCode::UNAUTHORIZED, "Wrong credentials"), | ||
33 | AuthError::MissingSecret => (StatusCode::BAD_REQUEST, "Missing credentials"), | ||
34 | AuthError::ServerError(err) => { | ||
35 | error!("server error: {}", err.to_string()); | ||
36 | (StatusCode::INTERNAL_SERVER_ERROR, "Server Error") | ||
37 | }, | ||
38 | } | ||
39 | } | ||
40 | } \ No newline at end of file | ||
diff --git a/src/config.rs b/src/config.rs index e69de29..4c79810 100644 --- a/src/config.rs +++ b/src/config.rs | |||
@@ -0,0 +1,11 @@ | |||
1 | use config::Config; | ||
2 | use once_cell::sync::Lazy; | ||
3 | |||
4 | pub static SETTINGS: Lazy<Config> = Lazy::new(setup); | ||
5 | |||
6 | fn setup() -> Config { | ||
7 | Config::builder() | ||
8 | .add_source(config::Environment::with_prefix("WEBOL").separator("_")) | ||
9 | .build() | ||
10 | .unwrap() | ||
11 | } \ No newline at end of file | ||
diff --git a/src/main.rs b/src/main.rs index 60f2214..0fe170d 100644 --- a/src/main.rs +++ b/src/main.rs | |||
@@ -5,11 +5,12 @@ use tracing_subscriber::{EnvFilter, fmt::{self, time::LocalTime}, prelude::*}; | |||
5 | use crate::routes::start::start; | 5 | use crate::routes::start::start; |
6 | 6 | ||
7 | mod auth; | 7 | mod auth; |
8 | mod config; | ||
8 | mod routes; | 9 | mod routes; |
10 | mod wol; | ||
9 | 11 | ||
10 | #[tokio::main] | 12 | #[tokio::main] |
11 | async fn main() { | 13 | async fn main() { |
12 | |||
13 | unsafe { local_offset::set_soundness(local_offset::Soundness::Unsound); } | 14 | unsafe { local_offset::set_soundness(local_offset::Soundness::Unsound); } |
14 | let time_format = | 15 | let time_format = |
15 | time::macros::format_description!("[year]-[month]-[day] [hour]:[minute]:[second]"); | 16 | time::macros::format_description!("[year]-[month]-[day] [hour]:[minute]:[second]"); |
diff --git a/src/routes/start.rs b/src/routes/start.rs index cda6352..e7d7e0e 100644 --- a/src/routes/start.rs +++ b/src/routes/start.rs | |||
@@ -1,18 +1,33 @@ | |||
1 | use axum::headers::HeaderMap; | 1 | use axum::headers::HeaderMap; |
2 | use axum::http::StatusCode; | ||
2 | use axum::Json; | 3 | use axum::Json; |
4 | use axum::response::{IntoResponse, Response}; | ||
3 | use serde::{Deserialize, Serialize}; | 5 | use serde::{Deserialize, Serialize}; |
6 | use std::error::Error; | ||
4 | use serde_json::{json, Value}; | 7 | use serde_json::{json, Value}; |
5 | use crate::auth::auth; | 8 | use tracing::error; |
9 | use crate::auth::{auth, AuthError}; | ||
10 | use crate::config::SETTINGS; | ||
11 | use crate::wol::{create_buffer, send_packet}; | ||
6 | 12 | ||
7 | pub async fn start(headers: HeaderMap, Json(payload): Json<StartPayload>) -> Json<Value> { | 13 | pub async fn start(headers: HeaderMap, Json(payload): Json<StartPayload>) -> Result<Json<Value>, StartError> { |
8 | let mut res = StartResponse { id: payload.id, boot: false }; | 14 | let secret = headers.get("authorization"); |
9 | if let Some(secret) = headers.get("authorization") { | 15 | if auth(secret).map_err(StartError::Auth)? { |
10 | if !auth(secret.to_str().unwrap()) { Json(json!(res)) } else { | 16 | let bind_addr = SETTINGS |
11 | res.boot = true; | 17 | .get_string("bindaddr") |
12 | Json(json!(res)) | 18 | .map_err(|err| StartError::Server(Box::new(err)))?; |
13 | } | 19 | let broadcast_addr = SETTINGS |
20 | .get_string("broadcastaddr") | ||
21 | .map_err(|err| StartError::Server(Box::new(err)))?; | ||
22 | let _ = send_packet( | ||
23 | &bind_addr.parse().map_err(|err| StartError::Server(Box::new(err)))?, | ||
24 | &broadcast_addr.parse().map_err(|err| StartError::Server(Box::new(err)))?, | ||
25 | // TODO: MAC saved in DB | ||
26 | create_buffer(std::env::var("MAC").unwrap().as_str()).map_err(|err| StartError::Server(Box::new(err)))? | ||
27 | ).map_err(|err| StartError::Server(Box::new(err))); | ||
28 | Ok(Json(json!(StartResponse { id: payload.id, boot: true }))) | ||
14 | } else { | 29 | } else { |
15 | Json(json!(res)) | 30 | Err(StartError::Generic) |
16 | } | 31 | } |
17 | } | 32 | } |
18 | 33 | ||
@@ -27,3 +42,27 @@ struct StartResponse { | |||
27 | id: String, | 42 | id: String, |
28 | boot: bool, | 43 | boot: bool, |
29 | } | 44 | } |
45 | |||
46 | pub enum StartError { | ||
47 | Auth(AuthError), | ||
48 | Generic, | ||
49 | Server(Box<dyn Error>), | ||
50 | } | ||
51 | |||
52 | impl IntoResponse for StartError { | ||
53 | fn into_response(self) -> Response { | ||
54 | let (status, error_message) = match self { | ||
55 | StartError::Auth(err) => err.get(), | ||
56 | StartError::Generic => (StatusCode::INTERNAL_SERVER_ERROR, ""), | ||
57 | StartError::Server(err) => { | ||
58 | error!("server error: {}", err.to_string()); | ||
59 | (StatusCode::INTERNAL_SERVER_ERROR, "Server Error") | ||
60 | }, | ||
61 | |||
62 | }; | ||
63 | let body = Json(json!({ | ||
64 | "error": error_message, | ||
65 | })); | ||
66 | (status, body).into_response() | ||
67 | } | ||
68 | } \ No newline at end of file | ||
diff --git a/src/wol.rs b/src/wol.rs new file mode 100644 index 0000000..80b66cd --- /dev/null +++ b/src/wol.rs | |||
@@ -0,0 +1,29 @@ | |||
1 | use std::net::{SocketAddr, UdpSocket}; | ||
2 | use std::num::ParseIntError; | ||
3 | |||
4 | /// Creates the magic packet from a mac address | ||
5 | /// | ||
6 | /// # Panics | ||
7 | /// | ||
8 | /// Panics if `mac_addr` is an invalid mac | ||
9 | pub fn create_buffer(mac_addr: &str) -> Result<Vec<u8>, ParseIntError> { | ||
10 | let mut mac = Vec::new(); | ||
11 | let sp = mac_addr.split(':'); | ||
12 | for f in sp { | ||
13 | mac.push(u8::from_str_radix(f, 16)?); | ||
14 | }; | ||
15 | let mut buf = vec![255; 6]; | ||
16 | for _ in 0..16 { | ||
17 | for i in &mac { | ||
18 | buf.push(*i); | ||
19 | } | ||
20 | } | ||
21 | Ok(buf) | ||
22 | } | ||
23 | |||
24 | /// Sends a buffer on UDP broadcast | ||
25 | pub fn send_packet(bind_addr: &SocketAddr, broadcast_addr: &SocketAddr, buffer: Vec<u8>) -> Result<usize, std::io::Error> { | ||
26 | let socket = UdpSocket::bind(bind_addr)?; | ||
27 | socket.set_broadcast(true)?; | ||
28 | socket.send_to(&buffer, broadcast_addr) | ||
29 | } \ No newline at end of file | ||