Merge of dev-auth #1

Merged
AINDUSTRIES merged 28 commits from dev-auth into main 2024-10-05 13:58:45 +00:00
5 changed files with 81 additions and 11 deletions
Showing only changes of commit 8b09406339 - Show all commits

View File

@@ -22,6 +22,7 @@ chrono = { version = "0.4.38", features = ["alloc"]}
futures-util = "0.3.30" futures-util = "0.3.30"
h2 = "0.4.6" h2 = "0.4.6"
argon2 = "0.5.3" argon2 = "0.5.3"
rand = "0.8.1"
[target.'cfg(unix)'.dependencies] [target.'cfg(unix)'.dependencies]
daemonize = "0.5.0" daemonize = "0.5.0"

View File

@@ -2,8 +2,7 @@ CREATE TABLE IF NOT EXISTS users
( (
id INTEGER PRIMARY KEY NOT NULL, id INTEGER PRIMARY KEY NOT NULL,
username TEXT NOT NULL, username TEXT NOT NULL,
salt text NOT NULL, saltyhash text NOT NULL,
hash TEXT NOT NULL,
permissions INTEGER DEFAULT 0, permissions INTEGER DEFAULT 0,
token TEXT token TEXT NOT NULL
) )

View File

@@ -2,5 +2,7 @@
"/": "static/html/index.html", "/": "static/html/index.html",
"/results": "static/html/results.html", "/results": "static/html/results.html",
"/archives": "static/html/archives.html", "/archives": "static/html/archives.html",
"/favicon.ico": "static/img/favicon.ico" "/favicon.ico": "static/img/favicon.ico",
"/login": "static/html/login.html",
"/register": "static/html/register.html"
} }

View File

@@ -3,7 +3,7 @@ use bytes::Bytes;
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use futures; use futures;
use http_body_util::{BodyExt, Full}; use http_body_util::{BodyExt, Full};
use hyper::body::Incoming; use hyper::body::{Body, Incoming};
use hyper::server::conn::http1; use hyper::server::conn::http1;
use hyper::service::service_fn; use hyper::service::service_fn;
use hyper::{Error, Method, Request, Response, StatusCode}; use hyper::{Error, Method, Request, Response, StatusCode};
@@ -20,7 +20,14 @@ 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 argon2::{
password_hash::{
rand_core::OsRng,
PasswordHash, PasswordHasher, PasswordVerifier, SaltString
},
Argon2
};
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
use daemonize::Daemonize; use daemonize::Daemonize;
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
@@ -29,7 +36,7 @@ struct Player {
name: String, name: String,
} }
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize)]
struct Vote { struct Vote {
plus_player_id: i64, plus_player_id: i64,
plus_nickname: String, plus_nickname: String,
@@ -39,6 +46,19 @@ struct Vote {
minus_reason: String, minus_reason: String,
} }
#[derive(Serialize, Deserialize)]
struct User {
username: String,
saltyhash: String,
permissions: i64,
token: String
}
#[derive(Serialize, Deserialize)]
struct Login {
username: String,
password: String
}
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
struct Settings { struct Settings {
database_url: String, database_url: String,
@@ -178,13 +198,27 @@ async fn get_votes(req: &Request<Incoming>, db: Arc<Mutex<SqlitePool>>) -> Vec<V
async fn post(req: Request<Incoming>, db: Arc<Mutex<SqlitePool>>) -> Result<Response<Full<Bytes>>, Error> { async fn post(req: Request<Incoming>, db: Arc<Mutex<SqlitePool>>) -> Result<Response<Full<Bytes>>, Error> {
let path = req.uri().path(); let path = req.uri().path();
if path != "/post" { match path {
return Ok(Response::builder().status(StatusCode::BAD_REQUEST).body(Full::new(Bytes::from("Bad Request (Bad Route)"))).unwrap()); "/vote" => {
post_vote(req, db).await
},
"/login" => {
login(req, db).await
},
"/register" => {
not_found().await
},
_ => {
not_found().await
} }
}
}
async fn post_vote(req: Request<Incoming>, db: Arc<Mutex<SqlitePool>>) -> Result<Response<Full<Bytes>>, Error> {
let body = req.into_body().collect().await?; let body = req.into_body().collect().await?;
let data: Result<Vote, serde_json::Error> = from_reader(body.aggregate().reader()); let data: Result<Vote, serde_json::Error> = from_reader(body.aggregate().reader());
if data.is_err() { if data.is_err() {
return Ok(Response::builder().status(StatusCode::BAD_REQUEST).body(Full::new(Bytes::from("Bad Request (Bad Data)"))).unwrap()); return Ok(Response::builder().status(StatusCode::BAD_REQUEST).body(Full::new(Bytes::from("Bad Request"))).unwrap());
} }
let vote = data.unwrap(); let vote = data.unwrap();
let timestamp: DateTime<Utc> = DateTime::from(SystemTime::now()); let timestamp: DateTime<Utc> = DateTime::from(SystemTime::now());
@@ -206,6 +240,40 @@ async fn post(req: Request<Incoming>, db: Arc<Mutex<SqlitePool>>) -> Result<Resp
Ok(Response::builder().body(Full::new(Bytes::new())).unwrap()) Ok(Response::builder().body(Full::new(Bytes::new())).unwrap())
} }
async fn login(req: Request<Incoming>, db: Arc<Mutex<SqlitePool>>) -> Result<Response<Full<Bytes>>, Error> {
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();
let pool = db.clone().lock().unwrap().clone();
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;
match result {
Ok(Some(user)) => {
let argon = Argon2::default();
let hash = PasswordHash::new(&user.saltyhash).unwrap();
match argon.verify_password(data.password.as_bytes(), &hash) {
Ok(()) => {
Ok(Response::builder().header("Set-Cookie", format!("token={}", user.token)).body(Full::new(Bytes::from("Ok"))).unwrap())
},
Err(_) => {
Ok(Response::builder().status(StatusCode::BAD_REQUEST).body(Full::new(Bytes::from("Bad Request"))).unwrap())
}
}
},
Ok(None) => {
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()) }
}
}
async fn register(req: Request<Incoming>, db: Arc<Mutex<SqlitePool>>) -> Result<Response<Full<Bytes>>, Error> {
todo!()
}
async fn not_found() -> Result<Response<Full<Bytes>>, Error> { async fn not_found() -> Result<Response<Full<Bytes>>, Error> {
let mut file_path = env::current_dir().expect("Could not get app directory."); let mut file_path = env::current_dir().expect("Could not get app directory.");
file_path.push("static/html/404.html"); file_path.push("static/html/404.html");

View File

@@ -59,7 +59,7 @@ async function main() {
true, "warning"); true, "warning");
return; return;
} }
if (await fetch("/post", { if (await fetch("/vote", {
method: "post", body: JSON.stringify(vote) method: "post", body: JSON.stringify(vote)
}) })
.then(r => r.status) === 200) { .then(r => r.status) === 200) {