Merge of dev-auth #1
@@ -4,5 +4,6 @@ id INTEGER PRIMARY KEY NOT NULL,
|
|||||||
username TEXT NOT NULL,
|
username TEXT NOT NULL,
|
||||||
saltyhash text NOT NULL,
|
saltyhash text NOT NULL,
|
||||||
permissions INTEGER DEFAULT 0,
|
permissions INTEGER DEFAULT 0,
|
||||||
token TEXT NOT NULL
|
token TEXT NOT NULL,
|
||||||
|
UNIQUE(id, username)
|
||||||
)
|
)
|
||||||
53
src/main.rs
53
src/main.rs
@@ -1,6 +1,6 @@
|
|||||||
use bytes::Buf;
|
use bytes::Buf;
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Days, Utc};
|
||||||
use futures;
|
use futures;
|
||||||
use http_body_util::{BodyExt, Full};
|
use http_body_util::{BodyExt, Full};
|
||||||
use hyper::body::{Body, Incoming};
|
use hyper::body::{Body, Incoming};
|
||||||
@@ -20,7 +20,7 @@ use std::str::FromStr;
|
|||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::time::SystemTime;
|
use std::time::SystemTime;
|
||||||
use tokio::net::TcpListener;
|
use tokio::net::TcpListener;
|
||||||
use rand::distributions::Standard;
|
use rand::distributions::{DistString, Alphanumeric};
|
||||||
use argon2::{
|
use argon2::{
|
||||||
password_hash::{
|
password_hash::{
|
||||||
rand_core::OsRng,
|
rand_core::OsRng,
|
||||||
@@ -206,7 +206,7 @@ async fn post(req: Request<Incoming>, db: Arc<Mutex<SqlitePool>>) -> Result<Resp
|
|||||||
login(req, db).await
|
login(req, db).await
|
||||||
},
|
},
|
||||||
"/register" => {
|
"/register" => {
|
||||||
not_found().await
|
register(req, db).await
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
not_found().await
|
not_found().await
|
||||||
@@ -247,6 +247,9 @@ async fn login(req: Request<Incoming>, db: Arc<Mutex<SqlitePool>>) -> Result<Res
|
|||||||
return Ok(Response::builder().status(StatusCode::BAD_REQUEST).body(Full::new(Bytes::from("Bad Request"))).unwrap());
|
return Ok(Response::builder().status(StatusCode::BAD_REQUEST).body(Full::new(Bytes::from("Bad Request"))).unwrap());
|
||||||
}
|
}
|
||||||
let data = data.unwrap();
|
let data = data.unwrap();
|
||||||
|
if !check_username(&data.username) {
|
||||||
|
return Ok(Response::builder().status(StatusCode::BAD_REQUEST).body(Full::new(Bytes::from("Bad Request"))).unwrap());
|
||||||
|
}
|
||||||
let pool = db.clone().lock().unwrap().clone();
|
let pool = db.clone().lock().unwrap().clone();
|
||||||
let mut conn = pool.acquire().await.unwrap();
|
let mut conn = pool.acquire().await.unwrap();
|
||||||
let result = sqlx::query!(r#"SELECT * FROM users WHERE username=?1"#, data.username).fetch_optional(&mut *conn).await;
|
let result = sqlx::query!(r#"SELECT * FROM users WHERE username=?1"#, data.username).fetch_optional(&mut *conn).await;
|
||||||
@@ -256,7 +259,10 @@ async fn login(req: Request<Incoming>, db: Arc<Mutex<SqlitePool>>) -> Result<Res
|
|||||||
let hash = PasswordHash::new(&user.saltyhash).unwrap();
|
let hash = PasswordHash::new(&user.saltyhash).unwrap();
|
||||||
match argon.verify_password(data.password.as_bytes(), &hash) {
|
match argon.verify_password(data.password.as_bytes(), &hash) {
|
||||||
Ok(()) => {
|
Ok(()) => {
|
||||||
Ok(Response::builder().header("Set-Cookie", format!("token={}", user.token)).body(Full::new(Bytes::from("Ok"))).unwrap())
|
let date: DateTime<Utc> = DateTime::from(SystemTime::now());
|
||||||
|
let date = date.checked_add_days(Days::new(7)).unwrap();
|
||||||
|
println!("{}", date.to_rfc2822());
|
||||||
|
Ok(Response::builder().header("Set-Cookie", format!("token={}; Expires={}; Secure; HttpOnly; SameSite=Strict", user.token, date.to_rfc2822())).body(Full::new(Bytes::from("Ok"))).unwrap())
|
||||||
},
|
},
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
Ok(Response::builder().status(StatusCode::BAD_REQUEST).body(Full::new(Bytes::from("Bad Request"))).unwrap())
|
Ok(Response::builder().status(StatusCode::BAD_REQUEST).body(Full::new(Bytes::from("Bad Request"))).unwrap())
|
||||||
@@ -266,12 +272,47 @@ async fn login(req: Request<Incoming>, db: Arc<Mutex<SqlitePool>>) -> Result<Res
|
|||||||
Ok(None) => {
|
Ok(None) => {
|
||||||
Ok(Response::builder().status(StatusCode::BAD_REQUEST).body(Full::new(Bytes::from("Bad Request"))).unwrap())
|
Ok(Response::builder().status(StatusCode::BAD_REQUEST).body(Full::new(Bytes::from("Bad Request"))).unwrap())
|
||||||
}
|
}
|
||||||
Err(e) => { Ok(Response::builder().status(StatusCode::INTERNAL_SERVER_ERROR).body(Full::new(Bytes::from("Bad Request"))).unwrap()) }
|
Err(_) => { Ok(Response::builder().status(StatusCode::INTERNAL_SERVER_ERROR).body(Full::new(Bytes::from("Server Error"))).unwrap()) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn register(req: Request<Incoming>, db: Arc<Mutex<SqlitePool>>) -> Result<Response<Full<Bytes>>, Error> {
|
async fn register(req: Request<Incoming>, db: Arc<Mutex<SqlitePool>>) -> Result<Response<Full<Bytes>>, Error> {
|
||||||
todo!()
|
let body = req.into_body().collect().await;
|
||||||
|
let data: Result<Login, serde_json::Error> = from_reader(body?.aggregate().reader());
|
||||||
|
if data.is_err() {
|
||||||
|
return Ok(Response::builder().status(StatusCode::BAD_REQUEST).body(Full::new(Bytes::from("Bad Request"))).unwrap());
|
||||||
|
}
|
||||||
|
let data = data.unwrap();
|
||||||
|
if !check_username(&data.username) {
|
||||||
|
return Ok(Response::builder().status(StatusCode::BAD_REQUEST).body(Full::new(Bytes::from("Bad Request"))).unwrap());
|
||||||
|
}
|
||||||
|
let pool = db.clone().lock().unwrap().clone();
|
||||||
|
let mut conn = pool.acquire().await.unwrap();
|
||||||
|
let exists = sqlx::query!(r#"SELECT id FROM users WHERE username=?1"#, data.username).fetch_optional(&mut *conn).await;
|
||||||
|
if exists.unwrap().is_some() {
|
||||||
|
return Ok(Response::builder().status(StatusCode::BAD_REQUEST).body(Full::new(Bytes::from("Bad Request"))).unwrap());
|
||||||
|
}
|
||||||
|
let argon2 = Argon2::default();
|
||||||
|
let hash = argon2.hash_password(data.password.as_bytes(), &SaltString::generate(&mut OsRng)).unwrap().to_string();
|
||||||
|
let token = Alphanumeric.sample_string(&mut OsRng, 256);
|
||||||
|
println!("{}", token);
|
||||||
|
let result = sqlx::query!(r#"INSERT INTO users ( username, saltyhash, permissions, token) VALUES ( ?1, ?2, ?3, ?4 )"#, data.username, hash, 0, token).execute(&mut *conn).await;
|
||||||
|
match result {
|
||||||
|
Ok(_) => Ok(Response::builder().body(Full::new(Bytes::from(""))).unwrap()),
|
||||||
|
Err(_) => { Ok(Response::builder().status(StatusCode::INTERNAL_SERVER_ERROR).body(Full::new(Bytes::from("Server Error"))).unwrap()) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_username(username: &String) -> bool {
|
||||||
|
if username.len() > 21 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for x in username.chars() {
|
||||||
|
if !x.is_ascii_alphanumeric() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn not_found() -> Result<Response<Full<Bytes>>, Error> {
|
async fn not_found() -> Result<Response<Full<Bytes>>, Error> {
|
||||||
|
|||||||
Reference in New Issue
Block a user