Lots of untested changes
This commit is contained in:
parent
27386d5d18
commit
f69823c08e
13 changed files with 169 additions and 159 deletions
|
@ -1,7 +1,5 @@
|
|||
mod post;
|
||||
mod users;
|
||||
mod vote;
|
||||
|
||||
pub use post::*;
|
||||
pub use users::*;
|
||||
pub use vote::*;
|
||||
|
|
|
@ -1,27 +1,56 @@
|
|||
use crate::jwt::token_factory;
|
||||
use crate::types::{NewPost, Post};
|
||||
use crate::db::db_new_post;
|
||||
use crate::ServerState;
|
||||
|
||||
use actix_web::web::{Data, Path};
|
||||
use actix_web::web::Data;
|
||||
use actix_web::{get, post, web::Json, HttpResponse, Responder, Result};
|
||||
use argon2::password_hash::rand_core::OsRng;
|
||||
use argon2::password_hash::SaltString;
|
||||
use argon2::password_hash::*;
|
||||
use argon2::Argon2;
|
||||
use argon2::PasswordHasher;
|
||||
use argon2::PasswordVerifier;
|
||||
use log::*;
|
||||
use log::info;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
use sqlx::FromRow;
|
||||
|
||||
// The post as it is received from the client
|
||||
// The token is used to identify the user
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct NewPost {
|
||||
pub content: String,
|
||||
pub token: String,
|
||||
}
|
||||
|
||||
// The post as it is stored in the database, with all the related metadata
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, FromRow)]
|
||||
pub struct Post {
|
||||
pub id: i64,
|
||||
pub user_id: i64,
|
||||
pub content: String,
|
||||
pub upvotes: i64,
|
||||
pub downvotes: i64,
|
||||
pub created_at: chrono::NaiveDateTime,
|
||||
pub updated_at: chrono::NaiveDateTime,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, FromRow)]
|
||||
pub struct User {
|
||||
pub id: i64,
|
||||
pub username: String,
|
||||
pub password: String,
|
||||
pub created_at: chrono::NaiveDateTime,
|
||||
pub updated_at: chrono::NaiveDateTime,
|
||||
}
|
||||
|
||||
#[get("/posts")]
|
||||
pub async fn get_posts(data: Data<ServerState>) -> impl Responder {
|
||||
HttpResponse::InternalServerError().body("Unimplemented")
|
||||
pub async fn get_posts(state: Data<ServerState>) -> Result<impl Responder> {
|
||||
let stream = sqlx::query_as!(Post, "SELECT * FROM posts");
|
||||
|
||||
let posts = stream.fetch_all(&state.pool).await.unwrap();
|
||||
Ok(HttpResponse::Ok().json(posts))
|
||||
}
|
||||
|
||||
#[post("/posts")]
|
||||
pub async fn new_post(new_post: Json<NewPost>, data: Data<ServerState>) -> impl Responder {
|
||||
let post = Post::from(new_post.into_inner());
|
||||
info!("Created post {:?}", post.uuid);
|
||||
HttpResponse::Ok().json("Post added!")
|
||||
pub async fn new_post(new_post: Json<NewPost>, state: Data<ServerState>) -> Result<impl Responder> {
|
||||
return match db_new_post(new_post.into_inner(), &state.pool).await {
|
||||
Some(post) => {
|
||||
info!("Created post {:?}", post.id);
|
||||
Ok(HttpResponse::Ok().json(post))
|
||||
}
|
||||
None => Ok(HttpResponse::InternalServerError().json("Error")),
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
use crate::jwt::token_factory;
|
||||
use crate::types::{NewPost, Post};
|
||||
use crate::ServerState;
|
||||
|
||||
use actix_web::web::{Data, Path};
|
||||
use actix_web::{get, post, web::Json, HttpResponse, Responder, Result};
|
||||
use actix_web::web::Data;
|
||||
use actix_web::{post, web::Json, HttpResponse, Responder, Result};
|
||||
use argon2::password_hash::rand_core::OsRng;
|
||||
use argon2::password_hash::SaltString;
|
||||
use argon2::password_hash::*;
|
||||
|
@ -12,7 +11,18 @@ use argon2::PasswordHasher;
|
|||
use argon2::PasswordVerifier;
|
||||
use log::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct LoginData {
|
||||
username: String,
|
||||
password: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
struct LoginResponse {
|
||||
username: String,
|
||||
token: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct RegisterData {
|
||||
|
@ -26,75 +36,81 @@ pub async fn register(
|
|||
data: Json<RegisterData>,
|
||||
state: Data<ServerState>,
|
||||
) -> Result<impl Responder> {
|
||||
let q = "SELECT password FROM users WHERE username = ?";
|
||||
let query = sqlx::query(q).bind(&data.username);
|
||||
let result = query.fetch_one(&state.pool).await.ok();
|
||||
if result.is_some() {
|
||||
// First check if the user already exists
|
||||
let exists = sqlx::query!(
|
||||
"SELECT username FROM users WHERE username = ?",
|
||||
data.username
|
||||
)
|
||||
.fetch_one(&state.pool)
|
||||
.await
|
||||
.ok()
|
||||
.map(|row| row.username);
|
||||
|
||||
// Bail out if the user already exists
|
||||
if exists.is_some() {
|
||||
info!("User \"{}\" already exists", data.username);
|
||||
return Ok(HttpResponse::BadRequest().json("Error"));
|
||||
}
|
||||
|
||||
let password = data.password.clone();
|
||||
let salt = SaltString::generate(&mut OsRng);
|
||||
let phc_hash = Argon2::default().hash_password(password.as_bytes(), &salt);
|
||||
if let Ok(phc_hash) = phc_hash {
|
||||
info!("User: {} registered", data.username);
|
||||
let phc_hash = phc_hash.to_string();
|
||||
let q = "INSERT INTO users (username, password) VALUES (?, ?)";
|
||||
let query = sqlx::query(q).bind(&data.username).bind(&phc_hash);
|
||||
query.execute(&state.pool).await.unwrap();
|
||||
} else {
|
||||
return Ok(HttpResponse::BadRequest().json("Error"));
|
||||
}
|
||||
// Unwrapping here because if this fails, we have a serious problem
|
||||
let phc_hash = Argon2::default()
|
||||
.hash_password(data.password.as_bytes(), &SaltString::generate(&mut OsRng))
|
||||
.unwrap()
|
||||
.to_string();
|
||||
|
||||
// Insert our new user into the database
|
||||
sqlx::query!(
|
||||
"INSERT INTO users (username, password) VALUES (?, ?)",
|
||||
data.username,
|
||||
phc_hash
|
||||
)
|
||||
.execute(&state.pool)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
info!("User: {} registered", data.username);
|
||||
Ok(HttpResponse::Ok().json("User registered"))
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct LoginData {
|
||||
username: String,
|
||||
password: String,
|
||||
}
|
||||
|
||||
use sqlx::Row;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
struct LoginResponse {
|
||||
username: String,
|
||||
token: String,
|
||||
}
|
||||
|
||||
#[post("/login")]
|
||||
pub async fn login(data: Json<LoginData>, state: Data<ServerState>) -> Result<impl Responder> {
|
||||
let q = "SELECT password FROM users WHERE username = ?";
|
||||
let query = sqlx::query(q).bind(&data.username);
|
||||
let result = query.fetch_one(&state.pool).await.ok();
|
||||
if let Some(row) = result {
|
||||
let phc_from_db = row.get::<String, _>("password");
|
||||
let pwhash = PasswordHash::new(&phc_from_db).unwrap_or_else(|_| {
|
||||
warn!(
|
||||
"Invalid hash for user {} fetched from database (not a valid PHC string)",
|
||||
data.username
|
||||
);
|
||||
panic!();
|
||||
});
|
||||
// let q = "SELECT password FROM users WHERE username = ?";
|
||||
// let query = sqlx::query(q).bind(&data.username);
|
||||
// let result = query.fetch_one(&state.pool).await.ok();
|
||||
|
||||
match Argon2::default().verify_password(data.password.as_bytes(), &pwhash) {
|
||||
Ok(_) => {
|
||||
info!("User {} logged in", data.username);
|
||||
let token = token_factory(&data.username).unwrap();
|
||||
println!("{:?}", token);
|
||||
return Ok(HttpResponse::Ok().json(LoginResponse {
|
||||
username: data.username.clone(),
|
||||
token: token,
|
||||
}));
|
||||
}
|
||||
Err(_) => {
|
||||
info!("User \"{}\" failed to log in", data.username);
|
||||
return Ok(HttpResponse::BadRequest().json("Error"));
|
||||
}
|
||||
}
|
||||
let uname = data.username.clone();
|
||||
let q = sqlx::query!("SELECT password FROM users WHERE username = ?", uname)
|
||||
.fetch_one(&state.pool)
|
||||
.await
|
||||
.ok();
|
||||
|
||||
if q.is_none() {
|
||||
info!("User \"{}\" failed to log in", data.username);
|
||||
return Ok(HttpResponse::BadRequest().json("Error"));
|
||||
}
|
||||
|
||||
Ok(HttpResponse::Ok().json("What happens here???"))
|
||||
let phc_password = q.unwrap().password;
|
||||
let phc_password = PasswordHash::new(&phc_password).unwrap_or_else(|_| {
|
||||
warn!(
|
||||
"Invalid hash for user {} fetched from database (not a valid PHC string)",
|
||||
data.username
|
||||
);
|
||||
panic!();
|
||||
});
|
||||
|
||||
match Argon2::default().verify_password(data.password.as_bytes(), &phc_password) {
|
||||
Ok(_) => {
|
||||
info!("User {} logged in", data.username);
|
||||
let token = token_factory(&data.username).unwrap();
|
||||
println!("{:?}", token);
|
||||
return Ok(HttpResponse::Ok().json(LoginResponse {
|
||||
username: data.username.clone(),
|
||||
token: token,
|
||||
}));
|
||||
}
|
||||
Err(_) => {
|
||||
info!("User \"{}\" failed to log in", data.username);
|
||||
return Ok(HttpResponse::BadRequest().json("Error"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
use crate::state::ServerState;
|
||||
use actix_web::web::{Data, Path};
|
||||
use actix_web::{get, post, web::Json, HttpResponse, Responder, Result};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
enum VoteDirection {
|
||||
Up,
|
||||
Down,
|
||||
}
|
||||
|
||||
#[post("vote/{uuid}")]
|
||||
pub async fn vote(params: Path<(Uuid, VoteDirection)>, data: Data<ServerState>) -> impl Responder {
|
||||
HttpResponse::InternalServerError().body("Unimplemented")
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue