aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/auth.rs41
-rw-r--r--src/config.rs11
-rw-r--r--src/main.rs3
-rw-r--r--src/routes/start.rs57
-rw-r--r--src/wol.rs29
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 @@
1pub fn auth(secret: &str) -> bool { 1use std::error::Error;
2 secret == "aaa" 2use axum::headers::HeaderValue;
3use axum::http::StatusCode;
4use tracing::error;
5use crate::auth::AuthError::{MissingSecret, ServerError, WrongSecret};
6use crate::config::SETTINGS;
7
8pub 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
23pub enum AuthError {
24 WrongSecret,
25 MissingSecret,
26 ServerError(Box<dyn Error>),
27}
28
29impl 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 @@
1use config::Config;
2use once_cell::sync::Lazy;
3
4pub static SETTINGS: Lazy<Config> = Lazy::new(setup);
5
6fn 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::*};
5use crate::routes::start::start; 5use crate::routes::start::start;
6 6
7mod auth; 7mod auth;
8mod config;
8mod routes; 9mod routes;
10mod wol;
9 11
10#[tokio::main] 12#[tokio::main]
11async fn main() { 13async 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 @@
1use axum::headers::HeaderMap; 1use axum::headers::HeaderMap;
2use axum::http::StatusCode;
2use axum::Json; 3use axum::Json;
4use axum::response::{IntoResponse, Response};
3use serde::{Deserialize, Serialize}; 5use serde::{Deserialize, Serialize};
6use std::error::Error;
4use serde_json::{json, Value}; 7use serde_json::{json, Value};
5use crate::auth::auth; 8use tracing::error;
9use crate::auth::{auth, AuthError};
10use crate::config::SETTINGS;
11use crate::wol::{create_buffer, send_packet};
6 12
7pub async fn start(headers: HeaderMap, Json(payload): Json<StartPayload>) -> Json<Value> { 13pub 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
46pub enum StartError {
47 Auth(AuthError),
48 Generic,
49 Server(Box<dyn Error>),
50}
51
52impl 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 @@
1use std::net::{SocketAddr, UdpSocket};
2use 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
9pub 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
25pub 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