Browse Source

WIP retrieve users

master
astria 3 months ago
parent
commit
f2c6caa248
  1. 8
      requests/auth.http
  2. 6
      requests/user.http
  3. 2
      src/controllers/auth.rs
  4. 3
      src/controllers/mod.rs
  5. 63
      src/controllers/user_controller.rs
  6. 1
      src/models/http_header.rs
  7. 4
      src/models/mod.rs
  8. 7
      src/models/token.rs
  9. 8
      src/models/user_info.rs
  10. 4
      src/parsers.rs
  11. 11
      src/routes/auth.rs
  12. 3
      src/routes/mod.rs
  13. 40
      src/routes/proxy.rs
  14. 22
      src/routes/user_routes.rs
  15. 24
      src/services/users.rs
  16. 28
      src/utils/jwt.rs
  17. 3
      src/utils/mod.rs

8
requests/auth.http

@ -21,4 +21,10 @@ Content-Type: application/json
"username": "astria",
"email": "astria@example.com",
"password": "securepassword"
}
}
###
GET /api/auth HTTP/1.1
Host: localhost:7878
User-Agent: curl/7.68.0
Accept: */*

6
requests/user.http

@ -0,0 +1,6 @@
###
GET /api/user HTTP/1.1
Host: localhost:7878
User-Agent: curl/7.68.0
Accept: */*
Authorization: Bearer 3e1d1902151506191008255c46523e1f1b0d150217001f0937525b503406020d1f0c092c19102b4b5e5568160212010f00331d1b3e544758375912091e

2
src/controllers/auth.rs

@ -84,7 +84,7 @@ pub async fn login(http_request: HttpRequest, stream: &mut TokioTcpStream) {
return;
}
let token = crypt::encrypt(&format!("jklhsdfhjkdfsjkhlfzerhjsdf_{}:{}", user.username, user.email));
let token = crypt::encrypt(&format!("{}_{}:{}", std::env::var("JWT_KEY").unwrap_or_default(), user.username, user.email));
let response = format!("HTTP/1.1 200 OK\r\n\r\nLogin Successful\r\nAuthorization: Bearer {}", token);
if let Err(e) = stream.write_all(response.as_bytes()).await {

3
src/controllers/mod.rs

@ -1 +1,2 @@
pub mod auth;
pub mod auth;
pub mod user_controller;

63
src/controllers/user_controller.rs

@ -0,0 +1,63 @@
use tokio::net::TcpStream;
use tokio::io::AsyncWriteExt;
use crate::models::token::Token;
use crate::models::user_info::UserInfo;
use crate::models::HttpRequest::HttpRequest;
use crate::utils::{crypt, jwt};
pub async fn get_user_info(http_request: HttpRequest, stream: &mut TcpStream) {
// Placeholder for actual user info retrieval logic
let authorization = http_request.headers.authorization.clone().unwrap_or_default();
let token_str = authorization.strip_prefix("Bearer ").unwrap_or("");
println!("Extracted token: {}", token_str);
let token = crate::utils::crypt::decrypt(token_str);
println!("Decrypted token: {:?}", token);
if !jwt::verify_token(&token) {
let response = "HTTP/1.1 401 Unauthorized\r\n\r\nInvalid or missing token";
if let Err(e) = stream.write_all(response.as_bytes()).await {
eprintln!("Error writing response: {}", e);
}
return;
}
let token = match jwt::extract(&token) {
Some(token) => token,
None => {
let response = "HTTP/1.1 400 Bad Request\r\n\r\nMalformed token";
if let Err(e) = stream.write_all(response.as_bytes()).await {
eprintln!("Error writing response: {}", e);
}
return;
}
};
let user_info = match crate::services::users::get_user_profile(token).await {
Ok(Some(info)) => info,
Ok(None) => {
let response = "HTTP/1.1 404 Not Found\r\n\r\nUser not found";
if let Err(e) = stream.write_all(response.as_bytes()).await {
eprintln!("Error writing response: {}", e);
}
return;
}
Err(e) => {
let response = format!("HTTP/1.1 500 Internal Server Error\r\n\r\nError: {}", e);
if let Err(e) = stream.write_all(response.as_bytes()).await {
eprintln!("Error writing response: {}", e);
}
return;
}
};
let response = format!(
"HTTP/1.1 200 OK\r\nContent-Type: application/json\r\n\r\n{{\"id\": {}, \"username\": \"{}\", \"email\": \"{}\"}}",
user_info.id, user_info.username, user_info.email
);
if let Err(e) = stream.write_all(response.as_bytes()).await {
eprintln!("Error writing response: {}", e);
}
}

1
src/models/http_header.rs

@ -6,4 +6,5 @@ pub struct HttpHeader {
pub version: Option<String>,
pub content_length: Option<usize>,
pub content_type: Option<String>,
pub authorization: Option<String>,
}

4
src/models/mod.rs

@ -1,4 +1,6 @@
pub mod HttpRequest;
pub mod http_header;
pub mod credentials;
pub mod user;
pub mod user;
pub mod user_info;
pub mod token;

7
src/models/token.rs

@ -0,0 +1,7 @@
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize)]
pub struct Token {
pub email: String,
pub username: String
}

8
src/models/user_info.rs

@ -0,0 +1,8 @@
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize)]
pub struct UserInfo {
pub id: i32,
pub username: String,
pub email: String,
}

4
src/parsers.rs

@ -8,6 +8,7 @@ pub fn parse_headers(header_lines: Vec<String>) -> HttpHeader {
content_type: None,
path: None,
version: None,
authorization: None,
};
let mut iter = 0;
@ -44,6 +45,9 @@ pub fn parse_headers(header_lines: Vec<String>) -> HttpHeader {
"content-type" => {
headers.content_type = Some(splitted[1].trim().to_string());
}
"authorization" => {
headers.authorization = Some(splitted[1].trim().to_string());
}
_ => {
println!("Unknown header: {}", splitted[0]);
}

11
src/routes/auth.rs

@ -4,19 +4,12 @@ use tokio::net::TcpStream as TokioTcpStream;
use tokio::io::AsyncWriteExt;
pub async fn handle_auth_request(http_request: HttpRequest, stream: &mut TokioTcpStream) {
println!("Received auth request: {} {}", http_request.headers.method.as_ref().expect(""), http_request.headers.path.as_ref().expect("").join("/"));
match http_request.headers.method.as_ref().expect("").as_str() {
"POST" => {
// Handle login or registration
post(http_request, stream).await;
}
"GET" => {
// Handle fetching user info or logout
println!("Handling auth GET request for path: {}", http_request.headers.path.as_ref().expect("").join("/"));
let response = "HTTP/1.1 200 OK\r\n\r\nAuth GET Response";
if let Err(e) = stream.write_all(response.as_bytes()).await {
eprintln!("Error writing response: {}", e);
}
}
_ => {
// Method not allowed
let response = "HTTP/1.1 405 METHOD NOT ALLOWED\r\n\r\nMethod Not Allowed";
@ -44,4 +37,4 @@ pub async fn post(http_request: HttpRequest, stream: &mut TokioTcpStream) {
}
}
}
}
}

3
src/routes/mod.rs

@ -1,3 +1,4 @@
pub mod proxy;
pub mod statics;
pub mod auth;
pub mod auth;
pub mod user_routes;

40
src/routes/proxy.rs

@ -1,7 +1,7 @@
use crate::models::HttpRequest::HttpRequest;
use crate::routes::statics;
use tokio::net::TcpStream as TokioTcpStream;
use crate::routes::auth;
use crate::routes::{auth, user_routes};
use tokio::{io::AsyncWriteExt, net::TcpStream as TokioTcpStream};
fn is_file(file: &str) -> bool {
file.contains('.')
@ -10,7 +10,15 @@ fn is_file(file: &str) -> bool {
pub async fn proxy(http_request: HttpRequest, stream: &mut TokioTcpStream) {
println!("Proxying request...");
if is_file(http_request.clone().headers.path.expect("").join("/").as_str()) {
if is_file(
http_request
.clone()
.headers
.path
.expect("")
.join("/")
.as_str(),
) {
statics::serve_static_file(http_request.clone(), stream).await;
} else {
handle_api_request(http_request.clone(), stream).await;
@ -18,16 +26,24 @@ pub async fn proxy(http_request: HttpRequest, stream: &mut TokioTcpStream) {
}
pub async fn handle_api_request(http_request: HttpRequest, stream: &mut TokioTcpStream) {
println!("{:?}", http_request.headers.path.clone().expect("")[0].as_str());
println!(
"{:?}",
http_request.headers.path.clone().expect("")[0].as_str()
);
match http_request.headers.path.clone().expect("")[1].as_str() {
"api" => {
match http_request.headers.path.clone().expect("")[2].as_str() {
"auth" => auth::handle_auth_request(http_request, stream).await,
_ => futures::future::ready(()).await,
"api" => match http_request.headers.path.clone().expect("")[2].as_str() {
"auth" => auth::handle_auth_request(http_request, stream).await,
"user" => user_routes::handle_user_request(http_request, stream).await,
_ => {
if let Err(e) = stream.write_all("HTTP/1.1 404 Not Found\r\n\r\n".as_bytes()).await {
eprintln!("Error writing response: {}", e);
}
}
},
_ => futures::future::ready(()).await,
_ => {
if let Err(e) = stream.write_all("HTTP/1.1 404 Not Found\r\n\r\n".as_bytes()).await {
eprintln!("Error writing response: {}", e);
}
}
};
}
}

22
src/routes/user_routes.rs

@ -0,0 +1,22 @@
use crate::models::HttpRequest::HttpRequest;
use tokio::net::TcpStream as TokioTcpStream;
use tokio::io::AsyncWriteExt;
pub async fn handle_user_request(http_request: HttpRequest, stream: &mut TokioTcpStream) {
// Placeholder for user request handling logic
let path = http_request.headers.path.clone().unwrap_or_default().join("/");
match path.as_str() {
"/api/user" => {
// Call the get_user_info function from user_controller
crate::controllers::user_controller::get_user_info(http_request, stream).await;
}
_ => {
let response = "HTTP/1.1 404 Not Found\r\n\r\n";
if let Err(e) = stream.write_all(response.as_bytes()).await {
eprintln!("Error writing response: {}", e);
}
}
}
}

24
src/services/users.rs

@ -1,4 +1,4 @@
use crate::models::user::User;
use crate::models::{ user::User, user_info::UserInfo, token::Token};
use sqlx::Row;
pub async fn register(user: User) -> Result<(), sqlx::Error> {
@ -61,4 +61,26 @@ pub async fn get_user_by_email(email: &str) -> Result<Option<User>, sqlx::Error>
};
Ok(user)
}
pub async fn get_user_profile(token: Token) -> Result<Option<UserInfo>, sqlx::Error> {
let db = crate::utils::db::establish_connection().await?;
let user_query = sqlx::query(
"SELECT id, username, email FROM users WHERE id = $1"
)
.bind(token.id)
.fetch_optional(&db)
.await?;
let user_info = if let Some(row) = user_query {
Some(UserInfo {
id: row.get("id"),
username: row.get("username"),
email: row.get("email"),
})
} else {
None
};
Ok(user_info)
}

28
src/utils/jwt.rs

@ -0,0 +1,28 @@
use crate::models::token::Token;
pub fn verify_token(token: &str) -> bool {
let token_parts: Vec<&str> = token.split('_').collect();
if token_parts.len() != 2 {
return false;
}
if token_parts[0] != std::env::var("JWT_KEY").unwrap_or_default() {
return false;
}
true
}
pub fn extract(token: &str) -> Option<Token> {
let token_parts: Vec<&str> = token.split('_').collect();
if token_parts.len() != 2 {
return None;
}
let user_info: Vec<&str> = token_parts[1].split(':').collect();
if user_info.len() != 2 {
return None;
}
Some(Token {
username: user_info[0].to_string(),
email: user_info[1].to_string()
})
}

3
src/utils/mod.rs

@ -1,2 +1,3 @@
pub mod db;
pub mod crypt;
pub mod crypt;
pub mod jwt;
Loading…
Cancel
Save