summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/auth.rs49
-rw-r--r--src/error.rs19
-rw-r--r--src/routes/device.rs63
-rw-r--r--src/routes/start.rs2
4 files changed, 72 insertions, 61 deletions
diff --git a/src/auth.rs b/src/auth.rs
index eb4d1bf..22f87e7 100644
--- a/src/auth.rs
+++ b/src/auth.rs
@@ -1,49 +1,30 @@
1use axum::http::{StatusCode, HeaderValue}; 1use axum::http::HeaderValue;
2use axum::http::header::ToStrError; 2use tracing::{debug, trace};
3use tracing::{debug, error, trace};
4use crate::auth::Error::{MissingSecret, WrongSecret};
5use crate::config::Config; 3use crate::config::Config;
4use crate::error::Error;
6 5
7pub fn auth(config: &Config, secret: Option<&HeaderValue>) -> Result<bool, Error> { 6pub fn auth(config: &Config, secret: Option<&HeaderValue>) -> Result<Response, Error> {
8 debug!("auth request with secret {:?}", secret); 7 debug!("auth request with secret {:?}", secret);
9 if let Some(value) = secret { 8 let res = if let Some(value) = secret {
10 trace!("value exists"); 9 trace!("auth value exists");
11 let key = &config.apikey; 10 let key = &config.apikey;
12 if value.to_str()? == key.as_str() { 11 if value.to_str()? == key.as_str() {
13 debug!("successful auth"); 12 debug!("successful auth");
14 Ok(true) 13 Response::Success
15 } else { 14 } else {
16 debug!("unsuccessful auth (wrong secret)"); 15 debug!("unsuccessful auth (wrong secret)");
17 Err(WrongSecret) 16 Response::WrongSecret
18 } 17 }
19 } else { 18 } else {
20 debug!("unsuccessful auth (no secret)"); 19 debug!("unsuccessful auth (no secret)");
21 Err(MissingSecret) 20 Response::MissingSecret
22 } 21 };
22 Ok(res)
23} 23}
24 24
25#[derive(Debug, thiserror::Error)] 25#[derive(Debug)]
26pub enum Error { 26pub enum Response {
27 #[error("wrong secret")] 27 Success,
28 WrongSecret, 28 WrongSecret,
29 #[error("missing secret")] 29 MissingSecret
30 MissingSecret,
31 #[error("parse error: {source}")]
32 HeaderToStr {
33 #[from]
34 source: ToStrError
35 }
36}
37
38impl Error {
39 pub fn get(self) -> (StatusCode, &'static str) {
40 match self {
41 Self::WrongSecret => (StatusCode::UNAUTHORIZED, "Wrong credentials"),
42 Self::MissingSecret => (StatusCode::BAD_REQUEST, "Missing credentials"),
43 Self::HeaderToStr { source } => {
44 error!("auth: {}", source);
45 (StatusCode::INTERNAL_SERVER_ERROR, "Server Error")
46 },
47 }
48 }
49} 30}
diff --git a/src/error.rs b/src/error.rs
index 4f1bedd..63b214e 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -1,4 +1,4 @@
1use crate::auth::Error as AuthError; 1use axum::http::header::ToStrError;
2use axum::http::StatusCode; 2use axum::http::StatusCode;
3use axum::response::{IntoResponse, Response}; 3use axum::response::{IntoResponse, Response};
4use axum::Json; 4use axum::Json;
@@ -11,12 +11,6 @@ pub enum Error {
11 #[error("generic error")] 11 #[error("generic error")]
12 Generic, 12 Generic,
13 13
14 #[error("auth: {source}")]
15 Auth {
16 #[from]
17 source: AuthError,
18 },
19
20 #[error("db: {source}")] 14 #[error("db: {source}")]
21 Db { 15 Db {
22 #[from] 16 #[from]
@@ -29,6 +23,12 @@ pub enum Error {
29 source: std::num::ParseIntError, 23 source: std::num::ParseIntError,
30 }, 24 },
31 25
26 #[error("header parse: {source}")]
27 ParseHeader {
28 #[from]
29 source: ToStrError,
30 },
31
32 #[error("io: {source}")] 32 #[error("io: {source}")]
33 Io { 33 Io {
34 #[from] 34 #[from]
@@ -40,7 +40,6 @@ impl IntoResponse for Error {
40 fn into_response(self) -> Response { 40 fn into_response(self) -> Response {
41 error!("{}", self.to_string()); 41 error!("{}", self.to_string());
42 let (status, error_message) = match self { 42 let (status, error_message) = match self {
43 Self::Auth { source } => source.get(),
44 Self::Generic => (StatusCode::INTERNAL_SERVER_ERROR, ""), 43 Self::Generic => (StatusCode::INTERNAL_SERVER_ERROR, ""),
45 Self::Db { source } => { 44 Self::Db { source } => {
46 error!("{source}"); 45 error!("{source}");
@@ -50,6 +49,10 @@ impl IntoResponse for Error {
50 error!("{source}"); 49 error!("{source}");
51 (StatusCode::INTERNAL_SERVER_ERROR, "Server Error") 50 (StatusCode::INTERNAL_SERVER_ERROR, "Server Error")
52 } 51 }
52 Self::ParseHeader { source } => {
53 error!("{source}");
54 (StatusCode::INTERNAL_SERVER_ERROR, "Server Error")
55 }
53 Self::ParseInt { source } => { 56 Self::ParseInt { source } => {
54 error!("{source}"); 57 error!("{source}");
55 (StatusCode::INTERNAL_SERVER_ERROR, "Server Error") 58 (StatusCode::INTERNAL_SERVER_ERROR, "Server Error")
diff --git a/src/routes/device.rs b/src/routes/device.rs
index aa52cf7..5ca574a 100644
--- a/src/routes/device.rs
+++ b/src/routes/device.rs
@@ -1,18 +1,23 @@
1use std::sync::Arc; 1use crate::auth::auth;
2use crate::db::Device;
3use crate::error::Error;
2use axum::extract::State; 4use axum::extract::State;
3use axum::Json;
4use axum::http::HeaderMap; 5use axum::http::HeaderMap;
6use axum::Json;
5use serde::{Deserialize, Serialize}; 7use serde::{Deserialize, Serialize};
6use serde_json::{json, Value}; 8use serde_json::{json, Value};
9use std::sync::Arc;
7use tracing::{debug, info}; 10use tracing::{debug, info};
8use crate::auth::auth;
9use crate::db::Device;
10use crate::error::Error;
11 11
12pub async fn get(State(state): State<Arc<crate::AppState>>, headers: HeaderMap, Json(payload): Json<GetDevicePayload>) -> Result<Json<Value>, Error> { 12pub async fn get(
13 State(state): State<Arc<crate::AppState>>,
14 headers: HeaderMap,
15 Json(payload): Json<GetDevicePayload>,
16) -> Result<Json<Value>, Error> {
13 info!("add device {}", payload.id); 17 info!("add device {}", payload.id);
14 let secret = headers.get("authorization"); 18 let secret = headers.get("authorization");
15 if auth(&state.config, secret)? { 19 let authorized = matches!(auth(&state.config, secret)?, crate::auth::Response::Success);
20 if authorized {
16 let device = sqlx::query_as!( 21 let device = sqlx::query_as!(
17 Device, 22 Device,
18 r#" 23 r#"
@@ -21,7 +26,9 @@ pub async fn get(State(state): State<Arc<crate::AppState>>, headers: HeaderMap,
21 WHERE id = $1; 26 WHERE id = $1;
22 "#, 27 "#,
23 payload.id 28 payload.id
24 ).fetch_one(&state.db).await?; 29 )
30 .fetch_one(&state.db)
31 .await?;
25 32
26 debug!("got device {:?}", device); 33 debug!("got device {:?}", device);
27 34
@@ -36,10 +43,18 @@ pub struct GetDevicePayload {
36 id: String, 43 id: String,
37} 44}
38 45
39pub async fn put(State(state): State<Arc<crate::AppState>>, headers: HeaderMap, Json(payload): Json<PutDevicePayload>) -> Result<Json<Value>, Error> { 46pub async fn put(
40 info!("add device {} ({}, {}, {})", payload.id, payload.mac, payload.broadcast_addr, payload.ip); 47 State(state): State<Arc<crate::AppState>>,
48 headers: HeaderMap,
49 Json(payload): Json<PutDevicePayload>,
50) -> Result<Json<Value>, Error> {
51 info!(
52 "add device {} ({}, {}, {})",
53 payload.id, payload.mac, payload.broadcast_addr, payload.ip
54 );
41 let secret = headers.get("authorization"); 55 let secret = headers.get("authorization");
42 if auth(&state.config, secret)? { 56 let authorized = matches!(auth(&state.config, secret)?, crate::auth::Response::Success);
57 if authorized {
43 sqlx::query!( 58 sqlx::query!(
44 r#" 59 r#"
45 INSERT INTO devices (id, mac, broadcast_addr, ip) 60 INSERT INTO devices (id, mac, broadcast_addr, ip)
@@ -49,7 +64,9 @@ pub async fn put(State(state): State<Arc<crate::AppState>>, headers: HeaderMap,
49 payload.mac, 64 payload.mac,
50 payload.broadcast_addr, 65 payload.broadcast_addr,
51 payload.ip 66 payload.ip
52 ).execute(&state.db).await?; 67 )
68 .execute(&state.db)
69 .await?;
53 70
54 Ok(Json(json!(PutDeviceResponse { success: true }))) 71 Ok(Json(json!(PutDeviceResponse { success: true })))
55 } else { 72 } else {
@@ -62,18 +79,26 @@ pub struct PutDevicePayload {
62 id: String, 79 id: String,
63 mac: String, 80 mac: String,
64 broadcast_addr: String, 81 broadcast_addr: String,
65 ip: String 82 ip: String,
66} 83}
67 84
68#[derive(Serialize)] 85#[derive(Serialize)]
69pub struct PutDeviceResponse { 86pub struct PutDeviceResponse {
70 success: bool 87 success: bool,
71} 88}
72 89
73pub async fn post(State(state): State<Arc<crate::AppState>>, headers: HeaderMap, Json(payload): Json<PostDevicePayload>) -> Result<Json<Value>, Error> { 90pub async fn post(
74 info!("edit device {} ({}, {}, {})", payload.id, payload.mac, payload.broadcast_addr, payload.ip); 91 State(state): State<Arc<crate::AppState>>,
92 headers: HeaderMap,
93 Json(payload): Json<PostDevicePayload>,
94) -> Result<Json<Value>, Error> {
95 info!(
96 "edit device {} ({}, {}, {})",
97 payload.id, payload.mac, payload.broadcast_addr, payload.ip
98 );
75 let secret = headers.get("authorization"); 99 let secret = headers.get("authorization");
76 if auth(&state.config, secret)? { 100 let authorized = matches!(auth(&state.config, secret)?, crate::auth::Response::Success);
101 if authorized {
77 let device = sqlx::query_as!( 102 let device = sqlx::query_as!(
78 Device, 103 Device,
79 r#" 104 r#"
@@ -85,7 +110,9 @@ pub async fn post(State(state): State<Arc<crate::AppState>>, headers: HeaderMap,
85 payload.broadcast_addr, 110 payload.broadcast_addr,
86 payload.ip, 111 payload.ip,
87 payload.id 112 payload.id
88 ).fetch_one(&state.db).await?; 113 )
114 .fetch_one(&state.db)
115 .await?;
89 116
90 Ok(Json(json!(device))) 117 Ok(Json(json!(device)))
91 } else { 118 } else {
diff --git a/src/routes/start.rs b/src/routes/start.rs
index 66b7cb4..ec4f98f 100644
--- a/src/routes/start.rs
+++ b/src/routes/start.rs
@@ -20,7 +20,7 @@ pub async fn start(
20) -> Result<Json<Value>, Error> { 20) -> Result<Json<Value>, Error> {
21 info!("POST request"); 21 info!("POST request");
22 let secret = headers.get("authorization"); 22 let secret = headers.get("authorization");
23 let authorized = auth(&state.config, secret)?; 23 let authorized = matches!(auth(&state.config, secret)?, crate::auth::Response::Success);
24 if authorized { 24 if authorized {
25 let device = sqlx::query_as!( 25 let device = sqlx::query_as!(
26 Device, 26 Device,