Skip to content

Commit

Permalink
Use 2 spaces for tabs on backend Rust code
Browse files Browse the repository at this point in the history
  • Loading branch information
Ameobea committed Jul 29, 2024
1 parent 440e977 commit a191921
Show file tree
Hide file tree
Showing 27 changed files with 1,985 additions and 1,997 deletions.
5 changes: 1 addition & 4 deletions backend/rustfmt.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,11 @@ format_strings = true
merge_imports = true
match_block_trailing_comma = true
reorder_impl_items = true
report_todo = "Always"
report_fixme = "Always"
use_field_init_shorthand = true
use_try_shorthand = true
wrap_comments = true
match_arm_blocks = false
overflow_delimited_expr = true
edition = "2018"
normalize_doc_attributes = true
# todo: enable \/ and format project
# tab_spaces = 2
tab_spaces = 2
14 changes: 7 additions & 7 deletions backend/src/conf.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
use dotenv;

pub struct Conf {
pub auth_token: String,
pub auth_token: String,
}

lazy_static! {
pub static ref CONF: Conf = Conf::default();
pub static ref CONF: Conf = Conf::default();
}

impl Default for Conf {
fn default() -> Self {
Conf {
auth_token: dotenv::var("AUTH_TOKEN")
.expect("The `AUTH_TOKEN` environment variable must be supplied"),
}
fn default() -> Self {
Conf {
auth_token: dotenv::var("AUTH_TOKEN")
.expect("The `AUTH_TOKEN` environment variable must be supplied"),
}
}
}
271 changes: 137 additions & 134 deletions backend/src/db_util/login.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,189 +3,192 @@ use std::convert::TryFrom;
use base64::Engine;
use diesel::{prelude::*, QueryResult};
use scrypt::{
password_hash::{
rand_core::{OsRng, RngCore},
PasswordHash, PasswordHasher, PasswordVerifier, Salt, SaltString,
},
Scrypt,
password_hash::{
rand_core::{OsRng, RngCore},
PasswordHash, PasswordHasher, PasswordVerifier, Salt, SaltString,
},
Scrypt,
};

use crate::{
models::user::{MaybeLoginToken, NewLoginToken, NewUser, User},
WebSynthDbConn,
models::user::{MaybeLoginToken, NewLoginToken, NewUser, User},
WebSynthDbConn,
};

fn hash_password(password: &str) -> Result<String, scrypt::password_hash::Error> {
let salt = SaltString::generate(&mut OsRng);
let params = scrypt::Params::new(15, 2, 2, scrypt::Params::RECOMMENDED_LEN).unwrap();
let hash = Scrypt
.hash_password_customized(
password.as_bytes(),
None,
None,
params,
Salt::try_from(salt.as_ref())?,
)?
.to_string();
Ok(hash)
let salt = SaltString::generate(&mut OsRng);
let params = scrypt::Params::new(15, 2, 2, scrypt::Params::RECOMMENDED_LEN).unwrap();
let hash = Scrypt
.hash_password_customized(
password.as_bytes(),
None,
None,
params,
Salt::try_from(salt.as_ref())?,
)?
.to_string();
Ok(hash)
}

pub fn verify_password(password: &str, hash: &str) -> bool {
let hash = PasswordHash::new(hash).unwrap();
Scrypt.verify_password(password.as_bytes(), &hash).is_ok()
let hash = PasswordHash::new(hash).unwrap();
Scrypt.verify_password(password.as_bytes(), &hash).is_ok()
}

pub fn generate_login_token() -> String {
let mut rng = OsRng;
let mut bytes = [0u8; 64];
rng.fill_bytes(&mut bytes);
base64::engine::general_purpose::STANDARD.encode(&bytes)
let mut rng = OsRng;
let mut bytes = [0u8; 64];
rng.fill_bytes(&mut bytes);
base64::engine::general_purpose::STANDARD.encode(&bytes)
}

pub async fn get_user_by_username(
conn: &WebSynthDbConn,
username: String,
conn: &WebSynthDbConn,
username: String,
) -> Result<Option<User>, String> {
use crate::schema::users;

let user: Option<crate::models::user::User> = conn
.run(move |conn| -> QueryResult<Option<_>> {
users::table
.filter(users::dsl::username.eq(username))
.first(conn)
.optional()
})
.await
.map_err(|err| {
error!("DB error loading user from DB: {}", err);
String::from("DB error loading user from DB")
})?;
use crate::schema::users;

let user: Option<crate::models::user::User> = conn
.run(move |conn| -> QueryResult<Option<_>> {
users::table
.filter(users::dsl::username.eq(username))
.first(conn)
.optional()
})
.await
.map_err(|err| {
error!("DB error loading user from DB: {}", err);
String::from("DB error loading user from DB")
})?;

Ok(user)
Ok(user)
}

/// If the login token is valid, returns the ID of the logged-in user.
pub async fn validate_login_token(
conn: &WebSynthDbConn,
login_token: String,
conn: &WebSynthDbConn,
login_token: String,
) -> QueryResult<Option<i64>> {
use crate::schema::login_tokens;

conn.run(move |conn| -> QueryResult<Option<_>> {
login_tokens::table
.filter(login_tokens::dsl::token.eq(login_token))
.select(login_tokens::dsl::user_id)
.first(conn)
.optional()
use crate::schema::login_tokens;

conn
.run(move |conn| -> QueryResult<Option<_>> {
login_tokens::table
.filter(login_tokens::dsl::token.eq(login_token))
.select(login_tokens::dsl::user_id)
.first(conn)
.optional()
})
.await
}

pub async fn insert_new_user(
conn: &WebSynthDbConn,
username: String,
password: String,
conn: &WebSynthDbConn,
username: String,
password: String,
) -> QueryResult<i64> {
use crate::schema::users;

let hashed_password = hash_password(&password).map_err(|err| {
error!("Error hashing password: {}", err);
diesel::result::Error::RollbackTransaction
})?;

let username_clone = username.clone();
conn.run(move |conn| {
diesel::insert_into(users::table)
.values(NewUser {
username,
hashed_password,
})
.execute(conn)
use crate::schema::users;

let hashed_password = hash_password(&password).map_err(|err| {
error!("Error hashing password: {}", err);
diesel::result::Error::RollbackTransaction
})?;

let username_clone = username.clone();
conn
.run(move |conn| {
diesel::insert_into(users::table)
.values(NewUser {
username,
hashed_password,
})
.execute(conn)
})
.await?;

let user_id = conn
.run(move |conn| -> QueryResult<i64> {
users::table
.filter(users::dsl::username.eq(username_clone))
.select(users::dsl::id)
.first(conn)
})
.await?;
Ok(user_id)
let user_id = conn
.run(move |conn| -> QueryResult<i64> {
users::table
.filter(users::dsl::username.eq(username_clone))
.select(users::dsl::id)
.first(conn)
})
.await?;
Ok(user_id)
}

pub async fn insert_new_login_token(
conn: &WebSynthDbConn,
user_id: i64,
token: String,
conn: &WebSynthDbConn,
user_id: i64,
token: String,
) -> QueryResult<()> {
use crate::schema::login_tokens;
use crate::schema::login_tokens;

conn.run(move |conn| {
diesel::insert_into(login_tokens::table)
.values(NewLoginToken { user_id, token })
.execute(conn)
conn
.run(move |conn| {
diesel::insert_into(login_tokens::table)
.values(NewLoginToken { user_id, token })
.execute(conn)
})
.await
.map(drop)
}

#[test]
fn test_hash_password() {
let password = "password";
let hash = hash_password(password).unwrap();
assert!(verify_password(password, &hash));
let password = "password";
let hash = hash_password(password).unwrap();
assert!(verify_password(password, &hash));
}

pub async fn get_logged_in_user_id(
conn: &WebSynthDbConn,
login_token: MaybeLoginToken,
conn: &WebSynthDbConn,
login_token: MaybeLoginToken,
) -> Option<i64> {
match login_token.0 {
Some(login_token) => match validate_login_token(&conn, login_token).await {
Ok(Some(user_id)) => Some(user_id),
Ok(None) => {
warn!("Failed to validate login token");
None
},
Err(err) => {
error!("Error while validating login token: {:?}", err);
None
},
},
None => None,
}
match login_token.0 {
Some(login_token) => match validate_login_token(&conn, login_token).await {
Ok(Some(user_id)) => Some(user_id),
Ok(None) => {
warn!("Failed to validate login token");
None
},
Err(err) => {
error!("Error while validating login token: {:?}", err);
None
},
},
None => None,
}
}

pub async fn get_user_by_login_token(
conn: &WebSynthDbConn,
login_token: MaybeLoginToken,
conn: &WebSynthDbConn,
login_token: MaybeLoginToken,
) -> Option<User> {
use crate::schema::users;

let user_id = match get_logged_in_user_id(&conn, login_token).await {
Some(user_id) => user_id,
None => return None,
};

match conn
.run(move |conn| {
users::table
.filter(users::dsl::id.eq(user_id))
.first::<User>(conn)
.optional()
})
.await
{
Ok(Some(user)) => Some(user),
Ok(None) => {
warn!("Failed to get user by ID");
None
},
Err(err) => {
error!("Error while getting user by ID: {:?}", err);
None
},
}
use crate::schema::users;

let user_id = match get_logged_in_user_id(&conn, login_token).await {
Some(user_id) => user_id,
None => return None,
};

match conn
.run(move |conn| {
users::table
.filter(users::dsl::id.eq(user_id))
.first::<User>(conn)
.optional()
})
.await
{
Ok(Some(user)) => Some(user),
Ok(None) => {
warn!("Failed to get user by ID");
None
},
Err(err) => {
error!("Error while getting user by ID: {:?}", err);
None
},
}
}
Loading

0 comments on commit a191921

Please sign in to comment.