From 734ec7901d4635e7f55fc96bd1304ac9d9c5c7b2 Mon Sep 17 00:00:00 2001 From: landrigun Date: Thu, 16 Feb 2023 11:29:21 +0000 Subject: [PATCH] add a message module holding struct to manager json response body + fix tests --- src/jwt/jwt.rs | 30 +--------------------- src/jwt/mod.rs | 5 ++-- src/main.rs | 1 + src/message/message.rs | 48 +++++++++++++++++++++++++++++++++++ src/message/mod.rs | 4 +++ src/router/router.rs | 23 +++++------------ tests/python/test_requests.py | 6 ++--- 7 files changed, 66 insertions(+), 51 deletions(-) create mode 100644 src/message/message.rs create mode 100644 src/message/mod.rs diff --git a/src/jwt/jwt.rs b/src/jwt/jwt.rs index 3ab3428..f642376 100644 --- a/src/jwt/jwt.rs +++ b/src/jwt/jwt.rs @@ -5,37 +5,9 @@ use serde::{Deserialize, Serialize}; use std::collections::HashSet; use tokio::fs; +use crate::message::JWTMessage; use crate::stores::Credentials; -#[derive(Serialize)] -/// JWTMessage aims to have a generic struct to build HTTP response message with JWT -pub struct JWTMessage { - #[serde(skip_serializing_if = "String::is_empty")] - access_token: String, - #[serde(skip_serializing_if = "String::is_empty")] - refresh_token: String, - #[serde(skip_serializing_if = "String::is_empty")] - pubkey: String, -} - -impl JWTMessage { - pub fn with_access(access_token: String) -> Self { - JWTMessage { - access_token: access_token, - refresh_token: "".to_string(), - pubkey: "".to_string(), - } - } - - pub fn with_pubkey(pubkey: String) -> Self { - JWTMessage { - access_token: "".to_string(), - refresh_token: "".to_string(), - pubkey: base64::encode(pubkey), - } - } -} - #[derive(Serialize, Deserialize)] struct JWTCustomClaims { email: String, diff --git a/src/jwt/mod.rs b/src/jwt/mod.rs index b447102..ae4d8f4 100644 --- a/src/jwt/mod.rs +++ b/src/jwt/mod.rs @@ -1,5 +1,4 @@ -//! jwt module aims to read `.pem` files, sign/validate the token and have useful functions to -//! manage HTTP response message +//! jwt module aims to read `.pem` files, sign/validate the token mod jwt; -pub use jwt::{JWTMessage, JWTSigner}; +pub use jwt::JWTSigner; diff --git a/src/main.rs b/src/main.rs index 9b9384d..d103358 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,6 @@ mod config; mod jwt; +mod message; mod router; mod stores; diff --git a/src/message/message.rs b/src/message/message.rs new file mode 100644 index 0000000..3dc0cb7 --- /dev/null +++ b/src/message/message.rs @@ -0,0 +1,48 @@ +use serde::Serialize; + +#[derive(Serialize)] +/// JWTMessage aims to have a generic struct to build HTTP response message with JWT +pub struct JWTMessage { + #[serde(skip_serializing_if = "String::is_empty")] + access_token: String, + #[serde(skip_serializing_if = "String::is_empty")] + refresh_token: String, + #[serde(skip_serializing_if = "String::is_empty")] + pubkey: String, +} + +impl JWTMessage { + pub fn with_access(access_token: String) -> Self { + JWTMessage { + access_token: access_token, + refresh_token: "".to_string(), + pubkey: "".to_string(), + } + } + + pub fn with_pubkey(pubkey: String) -> Self { + JWTMessage { + access_token: "".to_string(), + refresh_token: "".to_string(), + pubkey: base64::encode(pubkey), + } + } +} + +#[derive(Serialize, Default)] +/// ValidationMessage aims to build a JSON HTTP response body for JWT validation +pub struct ValidationMessage { + valid: bool, + #[serde(skip_serializing_if = "String::is_empty")] + reason: String, +} + +impl ValidationMessage { + pub fn set_valid(&mut self, valid: bool) { + self.valid = valid; + } + + pub fn set_reason(&mut self, reason: &str) { + self.reason = reason.to_string(); + } +} diff --git a/src/message/mod.rs b/src/message/mod.rs new file mode 100644 index 0000000..5da0789 --- /dev/null +++ b/src/message/mod.rs @@ -0,0 +1,4 @@ +//! message lib holds all structs to manager auth JSON response body +mod message; + +pub use message::{JWTMessage, ValidationMessage}; diff --git a/src/router/router.rs b/src/router/router.rs index 2182fed..d284234 100644 --- a/src/router/router.rs +++ b/src/router/router.rs @@ -3,10 +3,10 @@ use http::{HTTPRequest, HTTPResponse, JSONMessage}; use json::JsonValue; -use serde::Serialize; use crate::config::Config; -use crate::jwt::{JWTMessage, JWTSigner}; +use crate::jwt::JWTSigner; +use crate::message::{JWTMessage, ValidationMessage}; use crate::stores::{Credentials, FileStore, Store}; // TODO: must be mapped with corresponding handler @@ -14,14 +14,6 @@ const GET_ROUTE: &'static str = "/get/"; const VALIDATE_ROUTE: &'static str = "/validate/"; const PUBKEY_ROUTE: &'static str = "/pubkey/"; -#[derive(Serialize, Default)] -/// ValidationMessage aims to build a JSON HTTP response body for JWT validation -struct ValidationMessage { - is_valid: bool, - #[serde(skip_serializing_if = "String::is_empty")] - reason: String, -} - async fn handle_get(request: HTTPRequest<'_>, config: Config, method: &str) -> HTTPResponse { if method.trim().to_lowercase() != "post" { return HTTPResponse::as_400(); @@ -75,11 +67,10 @@ async fn handle_validate(request: HTTPRequest<'_>, config: Config, method: &str) match request.get_body_value("token") { Some(t) => t, None => { - let mut message = JSONMessage::default(); - message.put("valid", "false"); - message.put("reason", "no token provided in the request body"); - let json = message.try_into().unwrap(); + let mut message = ValidationMessage::default(); + message.set_reason("no token provided in the request body"); + let json = json::parse(&serde_json::to_string(&message).unwrap()).unwrap(); return HTTPResponse::as_200(Some(json)); } } @@ -99,10 +90,10 @@ async fn handle_validate(request: HTTPRequest<'_>, config: Config, method: &str) let mut message = ValidationMessage::default(); match jwt_signer.validate(&token) { Ok(()) => { - message.is_valid = true; + message.set_valid(true); } Err(e) => { - message.reason = e; + message.set_reason(&e); } } diff --git a/tests/python/test_requests.py b/tests/python/test_requests.py index 11e6a39..e1c7b19 100644 --- a/tests/python/test_requests.py +++ b/tests/python/test_requests.py @@ -48,14 +48,14 @@ class TestResponse(TestCase): ) self.assertEqual(resp.status_code, 200, "bad status code returned") self.assertIsNotNone(resp.json(), "response data can't be empty") - self.assertEqual(resp.json()["valid"], "false", "bad status returned") + self.assertEqual(resp.json()["valid"], False, "bad status returned") self.assertEqual(resp.json()["reason"], "no token provided in the request body") def test_validate_target_empty_token(self): resp = requests.post(URL + "/validate/", json={"tutu": "tutu", "token": ""}) self.assertEqual(resp.status_code, 200, "bad status code returned") self.assertIsNotNone(resp.json(), "response data can't be empty") - self.assertEqual(resp.json()["valid"], "false", "bad status returned") + self.assertEqual(resp.json()["valid"], False, "bad status returned") self.assertEqual( resp.json()["reason"], "token validation failed details=JWT compact encoding error", @@ -67,7 +67,7 @@ class TestResponse(TestCase): resp = requests.post(URL + "/validate/", json={"token": token}) self.assertEqual(resp.status_code, 200, "bad status code returned") self.assertIsNotNone(resp.json(), "response data can't be empty") - self.assertEqual(resp.json()["valid"], "true", "bad status returned") + self.assertEqual(resp.json()["valid"], True, "bad status returned") # TODO: must be updated after implementing `/refresh/` url handler def test_refresh_target(self):