Hashing passwords the first

This commit is contained in:
famfo 2022-05-11 11:07:01 +02:00
parent c79988b90a
commit 30275673bc
12 changed files with 161 additions and 12 deletions

30
Cargo.lock generated
View file

@ -237,6 +237,17 @@ version = "1.0.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27"
[[package]]
name = "argon2"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a27e27b63e4a34caee411ade944981136fdfa535522dc9944d6700196cbd899f"
dependencies = [
"base64ct",
"blake2",
"password-hash",
]
[[package]]
name = "arrayref"
version = "0.3.6"
@ -369,6 +380,12 @@ version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
[[package]]
name = "base64ct"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dea908e7347a8c64e378c17e30ef880ad73e3b4498346b055c2c00ea342f3179"
[[package]]
name = "bincode"
version = "1.3.3"
@ -1214,6 +1231,17 @@ dependencies = [
"windows-sys",
]
[[package]]
name = "password-hash"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e029e94abc8fb0065241c308f1ac6bc8d20f450e8f7c5f0b25cd9b8d526ba294"
dependencies = [
"base64ct",
"rand_core",
"subtle",
]
[[package]]
name = "paste"
version = "1.0.7"
@ -1728,9 +1756,9 @@ version = "0.1.0"
dependencies = [
"actix-web",
"anyhow",
"argon2",
"askama",
"async-sqlx-session",
"blake2",
"chrono",
"dotenv",
"serde",

View file

@ -14,7 +14,7 @@ tracing-subscriber = "0.3"
anyhow = "1.0"
chrono = "0.4"
dotenv = "0.15"
blake2 = "0.10"
argon2 = "0.4"
askama = "0.11"
actix-web = "4.0"

View file

@ -27,6 +27,7 @@ pub struct Config {
pub listen_addr: SocketAddr,
pub admin_pass: String,
pub connection_string: String,
pub secret: String,
pub log_level: Option<String>,
}

View file

@ -17,16 +17,18 @@
*/
use crate::templates;
use argon2::PasswordHasher;
use sqlx::postgres::{PgConnectOptions, PgConnectionInfo, PgPoolOptions};
use sqlx::Executor;
use sqlx::{ConnectOptions, PgPool};
use tracing::info;
use tracing::log::LevelFilter;
use argon2::Argon2;
pub struct Database(PgPool);
pub struct Database(PgPool, String);
impl Database {
pub async fn connect(conn_string: &str) -> anyhow::Result<Self> {
pub async fn connect(conn_string: &str, secret: &str) -> anyhow::Result<Self> {
let mut connect_options: PgConnectOptions = conn_string.parse()?;
connect_options.log_statements(LevelFilter::Debug);
info!("Connecting to the database");
@ -39,7 +41,7 @@ impl Database {
);
conn.execute(include_str!("sql/schema.sql")).await?;
Ok(Self(pool))
Ok(Self(pool, secret.to_string()))
}
pub fn pool(&self) -> PgPool {
@ -65,4 +67,25 @@ impl Database {
templates::Tasks { tasks: vec }
}
fn hash(&self, password: &str) -> Result<String, ()> {
let argon2 = Argon2::default();
let hash = argon2.hash_password(password.as_bytes(), &self.1);
if let Ok(ref hash) = hash {
if let Some(ref hash) = hash.hash {
return Ok(hash.to_string());
}
}
tracing::error!("Error hashing password: {:?}", hash);
Err(())
}
pub async fn register(&self, username: &str, password: &str) {
let hash = self.hash(password);
if let Err(ref e) = hash {
return;
}
tracing::debug!("{}", hash.unwrap());
// TODO: insert into DB
}
}

View file

@ -47,7 +47,7 @@ async fn main() -> anyhow::Result<()> {
info!(concat!("Initializing - tmtd ", env!("CARGO_PKG_VERSION")));
let (ctx, _) = broadcast::channel(1);
let database = Arc::new(Database::connect(&cfg.connection_string).await?);
let database = Arc::new(Database::connect(&cfg.connection_string, &cfg.secret).await?);
let session_store =
PostgresSessionStore::from_client(database.pool()).with_table_name("sessions");
session_store.migrate().await?;

View file

@ -37,3 +37,15 @@ pub struct SortTask {
pub category: String,
}
#[derive(Deserialize)]
pub struct Login {
pub username: String,
pub password: String,
}
#[derive(Deserialize)]
pub struct Register {
pub username: String,
pub password: String,
}

View file

@ -39,3 +39,13 @@ pub struct Task {
pub struct CreateTask();
#[derive(Template)]
#[template(path = "login.html")]
pub struct Login();
#[derive(Template)]
#[template(path = "register.html")]
pub struct Register();

View file

@ -36,6 +36,10 @@ impl App {
.route(web::get().to(task)),
web::resource("/create")
.route(web::get().to(create)),
web::resource("/login")
.route(web::get().to(login)),
web::resource("/register")
.route(web::get().to(register)),
web::resource("/api/task/create")
.app_data(web::Data::new(db.clone()))
.route(web::post().to(create_task)),
@ -45,6 +49,12 @@ impl App {
web::resource("/api/task/sort")
.app_data(web::Data::new(db.clone()))
.route(web::post().to(sort_task)),
web::resource("/api/login")
.app_data(web::Data::new(db.clone()))
.route(web::post().to(login_user)),
web::resource("/api/register")
.app_data(web::Data::new(db.clone()))
.route(web::post().to(register_user)),
))
})
.bind(addr)?
@ -65,6 +75,18 @@ async fn create() -> impl Responder {
HttpResponseBuilder::new(StatusCode::OK).body(html)
}
async fn login() -> impl Responder {
let login = templates::Login{};
let html = login.render().unwrap();
HttpResponseBuilder::new(StatusCode::OK).body(html)
}
async fn register() -> impl Responder {
let register = templates::Register{};
let html = register.render().unwrap();
HttpResponseBuilder::new(StatusCode::OK).body(html)
}
async fn create_task(req: web::Form<task::CreateTask>, db: web::Data<Arc<Database>>) -> impl Responder {
tracing::debug!("Got POST request on /api/task/create: {:#?}", req);
HttpResponse::SeeOther().insert_header(("Location", "/task")).finish()
@ -79,3 +101,16 @@ async fn sort_task(req: web::Form<task::SortTask>, db: web::Data<Arc<Database>>)
tracing::debug!("Got POST request on /api/task/sort: {:#?}", req);
HttpResponse::SeeOther().insert_header(("Location", "/task")).finish()
}
async fn login_user(req: web::Form<task::Login>, db: web::Data<Arc<Database>>) -> impl Responder {
tracing::debug!("Got POST request on /api/login");
HttpResponse::SeeOther().insert_header(("Location", "/task")).finish()
}
async fn register_user(req: web::Form<task::Register>, db: web::Data<Arc<Database>>) -> impl Responder {
tracing::debug!("Got POST request on /api/register");
let db = db.clone();
db.register(&req.username, &req.password).await;
HttpResponse::SeeOther().insert_header(("Location", "/task")).finish()
}

16
templates/login.html Normal file
View file

@ -0,0 +1,16 @@
{% extends "base.html" %}
{% block content %}
{% include "navbar.html" %}
<form action="/api/login" method="post">
<label for="Username">Username</label><br>
<input type="text" id="username" name="username" style="width:fit-content"><br>
<label for="Password">Password</label><br>
<input type="password" id="password" name="password" style="width:fit-content"><br>
<input type="submit" value="Login"><br>
</form>
{% endblock content %}

View file

@ -1,10 +1,19 @@
logo or something<br>
navbar<br>
<a href="/">home</a> |
<a href="/task">tasks</a> |
<a href="/users">users</a> |
<a href="/admin">admin panel</a>
<div>
<span style="float:left">
<a href="/">home</a> |
<a href="/task">tasks</a> |
<a href="/users">users</a> |
<a href="/admin">admin panel</a>
</span>
<span style="float:right">
<a href="/login">login</a> |
<a href="/register">register</a>
</span>
</div>
<br>
<hr>

16
templates/register.html Normal file
View file

@ -0,0 +1,16 @@
{% extends "base.html" %}
{% block content %}
{% include "navbar.html" %}
<form action="/api/register" method="post">
<label for="Username">Username</label><br>
<input type="text" id="username" name="username" style="width:fit-content"><br>
<label for="Password">Password</label><br>
<input type="password" id="password" name="password" style="width:fit-content"><br>
<input type="submit" value="Register"><br>
</form>
{% endblock content %}

View file

@ -13,14 +13,13 @@
<option value="Assigned">assigned</option>
<option value="InProgress">in progreess</option>
<option value="Done">done</option>
<input type="hidden">
<input type="submit" value="Select">
</select>
</form>
<hr>
<!-- Some only selecting specific task code here, for smarter people then me -->
<ul>
{% for task in tasks %}
{% include "task/task.html" %}