diff options
author | Ilion Beyst <ilion.beyst@gmail.com> | 2021-12-13 22:41:20 +0100 |
---|---|---|
committer | Ilion Beyst <ilion.beyst@gmail.com> | 2021-12-13 22:41:20 +0100 |
commit | eabeb7ed7b641dea0b8e71ab33ab97b4ed7a4cda (patch) | |
tree | 9cd2f38290fa059020feb049d8a2e2e91adac68b /backend/src/db/users.rs | |
parent | 8b4440f7236b0972c1a804eea4c8305b958ad03c (diff) | |
download | planetwars.dev-eabeb7ed7b641dea0b8e71ab33ab97b4ed7a4cda.tar.xz planetwars.dev-eabeb7ed7b641dea0b8e71ab33ab97b4ed7a4cda.zip |
start implementing basic login functionality
Diffstat (limited to 'backend/src/db/users.rs')
-rw-r--r-- | backend/src/db/users.rs | 106 |
1 files changed, 106 insertions, 0 deletions
diff --git a/backend/src/db/users.rs b/backend/src/db/users.rs new file mode 100644 index 0000000..c06e5b3 --- /dev/null +++ b/backend/src/db/users.rs @@ -0,0 +1,106 @@ +use crate::{schema::users, DbConn}; +use argon2; +use diesel::{prelude::*, PgConnection}; +use rand::Rng; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Deserialize)] +pub struct Credentials<'a> { + pub username: &'a str, + pub password: &'a str, +} + +#[derive(Insertable)] +#[table_name = "users"] +pub struct NewUser<'a> { + pub username: &'a str, + pub password_hash: &'a [u8], + pub password_salt: &'a [u8], +} + +#[derive(Queryable, Debug)] +pub struct User { + pub user_id: i32, + pub username: String, + pub password_salt: Vec<u8>, + pub password_hash: Vec<u8>, +} + +// TODO: make this configurable somewhere +fn argon2_config() -> argon2::Config<'static> { + argon2::Config { + variant: argon2::Variant::Argon2i, + version: argon2::Version::Version13, + mem_cost: 4096, + time_cost: 3, + lanes: 1, + thread_mode: argon2::ThreadMode::Sequential, + // TODO: set a secret + secret: &[], + ad: &[], + hash_length: 32, + } +} + +pub fn create_user(credentials: &Credentials, conn: &PgConnection) -> QueryResult<User> { + let argon_config = argon2_config(); + + let salt: [u8; 32] = rand::thread_rng().gen(); + let hash = argon2::hash_raw(credentials.password.as_bytes(), &salt, &argon_config).unwrap(); + let new_user = NewUser { + username: &credentials.username, + password_salt: &salt, + password_hash: &hash, + }; + diesel::insert_into(users::table) + .values(&new_user) + .get_result::<User>(conn) +} + +pub fn authenticate_user(credentials: &Credentials, db_conn: &PgConnection) -> Option<User> { + let user = users::table + .filter(users::username.eq(&credentials.username)) + .first::<User>(db_conn) + .unwrap(); + + let password_matches = argon2::verify_raw( + credentials.password.as_bytes(), + &user.password_salt, + &user.password_hash, + &argon2_config(), + ) + .unwrap(); + + if password_matches { + return Some(user); + } else { + return None; + } +} + +#[test] +fn test_argon() { + let credentials = Credentials { + username: "piepkonijn", + password: "geheim123", + }; + let argon_config = argon2_config(); + + let salt: [u8; 32] = rand::thread_rng().gen(); + let hash = argon2::hash_raw(credentials.password.as_bytes(), &salt, &argon_config).unwrap(); + let new_user = NewUser { + username: &credentials.username, + password_hash: &hash, + password_salt: &salt, + }; + + let password_matches = argon2::verify_raw( + credentials.password.as_bytes(), + &new_user.password_salt, + &new_user.password_hash, + &argon2_config(), + ) + .unwrap(); + + assert!(password_matches); +} |