1
0
mirror of https://gitlab.com/comunic/comunicapiv3 synced 2024-11-22 13:29:21 +00:00

Upgrade password system

This commit is contained in:
Pierre HUBERT 2021-02-13 10:52:04 +01:00
parent 6396271e9c
commit 36c096d415
4 changed files with 99 additions and 23 deletions

55
Cargo.lock generated
View File

@ -469,6 +469,18 @@ version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff"
[[package]]
name = "bcrypt"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2cab630912253fb9dc92c0e2fabd0a7b51f5a5a4007177cfa31e517015b7204"
dependencies = [
"base64 0.12.3",
"blowfish",
"byteorder",
"getrandom",
]
[[package]] [[package]]
name = "bigdecimal" name = "bigdecimal"
version = "0.1.2" version = "0.1.2"
@ -496,7 +508,16 @@ dependencies = [
"block-padding", "block-padding",
"byte-tools", "byte-tools",
"byteorder", "byteorder",
"generic-array", "generic-array 0.12.3",
]
[[package]]
name = "block-cipher"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f337a3e6da609650eb74e02bc9fac7b735049f7623ab12f2e4c719316fcc7e80"
dependencies = [
"generic-array 0.14.4",
] ]
[[package]] [[package]]
@ -508,6 +529,17 @@ dependencies = [
"byte-tools", "byte-tools",
] ]
[[package]]
name = "blowfish"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f06850ba969bc59388b2cc0a4f186fc6d9d37208863b15b84ae3866ac90ac06"
dependencies = [
"block-cipher",
"byteorder",
"opaque-debug 0.3.0",
]
[[package]] [[package]]
name = "brotli-sys" name = "brotli-sys"
version = "0.3.2" version = "0.3.2"
@ -621,6 +653,7 @@ dependencies = [
"actix-rt", "actix-rt",
"actix-web", "actix-web",
"actix-web-actors", "actix-web-actors",
"bcrypt",
"bytes", "bytes",
"chrono", "chrono",
"dashmap", "dashmap",
@ -802,7 +835,7 @@ version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5"
dependencies = [ dependencies = [
"generic-array", "generic-array 0.12.3",
] ]
[[package]] [[package]]
@ -1121,6 +1154,16 @@ dependencies = [
"typenum", "typenum",
] ]
[[package]]
name = "generic-array"
version = "0.14.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817"
dependencies = [
"typenum",
"version_check",
]
[[package]] [[package]]
name = "getrandom" name = "getrandom"
version = "0.1.14" version = "0.1.14"
@ -1845,6 +1888,12 @@ version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
[[package]]
name = "opaque-debug"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
[[package]] [[package]]
name = "openssl" name = "openssl"
version = "0.10.29" version = "0.10.29"
@ -2361,7 +2410,7 @@ dependencies = [
"block-buffer", "block-buffer",
"digest", "digest",
"fake-simd", "fake-simd",
"opaque-debug", "opaque-debug 0.2.3",
] ]
[[package]] [[package]]

View File

@ -32,4 +32,5 @@ pdf = "0.6.3"
regex = "1.4.2" regex = "1.4.2"
dashmap = "3.11.10" dashmap = "3.11.10"
reqwest = { version = "0.10.6", features = ["json", "blocking"] } reqwest = { version = "0.10.6", features = ["json", "blocking"] }
webrtc-sdp = "0.3.6" webrtc-sdp = "0.3.6"
bcrypt = "0.8.0"

View File

@ -1,20 +1,22 @@
use bcrypt::{DEFAULT_COST, hash_with_result, verify};
use crate::constants::{PASSWORD_RESET_TOKEN_LENGTH, PASSWORD_RESET_TOKEN_LIFETIME}; use crate::constants::{PASSWORD_RESET_TOKEN_LENGTH, PASSWORD_RESET_TOKEN_LIFETIME};
use crate::constants::database_tables_names::{USER_ACCESS_TOKENS_TABLE, USERS_TABLE}; use crate::constants::database_tables_names::{USER_ACCESS_TOKENS_TABLE, USERS_TABLE};
use crate::controllers::user_ws_controller; use crate::controllers::user_ws_controller;
use crate::data::account_export::AccountExport; use crate::data::account_export::AccountExport;
use crate::data::api_client::APIClient; use crate::data::api_client::APIClient;
use crate::data::error::{ExecError, ResultBoxError}; use crate::data::error::{ExecError, Res, ResultBoxError};
use crate::data::general_settings::GeneralSettings; use crate::data::general_settings::GeneralSettings;
use crate::data::lang_settings::LangSettings; use crate::data::lang_settings::LangSettings;
use crate::data::new_account::NewAccount; use crate::data::new_account::NewAccount;
use crate::data::security_settings::SecuritySettings; use crate::data::security_settings::SecuritySettings;
use crate::data::user::{AccountImageVisibility, UserID, UserPageStatus}; use crate::data::user::{AccountImageVisibility, User, UserID, UserPageStatus};
use crate::data::user_token::UserAccessToken; use crate::data::user_token::UserAccessToken;
use crate::helpers::{comments_helper, conversations_helper, custom_emojies_helper, database, events_helper, friends_helper, groups_helper, likes_helper, movies_helper, notifications_helper, posts_helper, survey_helper, user_helper}; use crate::helpers::{comments_helper, conversations_helper, custom_emojies_helper, database, events_helper, friends_helper, groups_helper, likes_helper, movies_helper, notifications_helper, posts_helper, survey_helper, user_helper};
use crate::helpers::database::{DeleteQuery, InsertQuery, QueryInfo}; use crate::helpers::database::{DeleteQuery, InsertQuery, QueryInfo};
use crate::helpers::events_helper::Event; use crate::helpers::events_helper::Event;
use crate::helpers::likes_helper::LikeType; use crate::helpers::likes_helper::LikeType;
use crate::utils::crypt_utils::{crypt_pass, rand_str}; use crate::utils::crypt_utils::{legacy_crypt_pass, rand_str};
use crate::utils::date_utils::{mysql_date, time}; use crate::utils::date_utils::{mysql_date, time};
use crate::utils::user_data_utils::user_data_path; use crate::utils::user_data_utils::user_data_path;
@ -29,7 +31,7 @@ pub fn create(new_account: &NewAccount) -> ResultBoxError {
.add_str("prenom", &new_account.last_name) .add_str("prenom", &new_account.last_name)
.add_str("date_creation", &mysql_date()) .add_str("date_creation", &mysql_date())
.add_str("mail", &new_account.email) .add_str("mail", &new_account.email)
.add_str("password", &crypt_pass(&new_account.password)?) .add_str("password", &hash_password(&new_account.password)?)
.insert_drop_result() .insert_drop_result()
} }
@ -41,8 +43,7 @@ pub fn login_user(email: &str, password: &str, client: &APIClient) -> ResultBoxE
let user = user_helper::find_user_by_email(email)?; let user = user_helper::find_user_by_email(email)?;
// Validate user password // Validate user password
let password = crypt_pass(password)?; if !validate_password(&user, password)? {
if !user.password.eq(&password) {
return Err(ExecError::boxed_new("The user gave an invalid password!")); return Err(ExecError::boxed_new("The user gave an invalid password!"));
} }
@ -161,20 +162,16 @@ pub fn get_user_id_from_password_reset_token(token: &str) -> ResultBoxError<User
/// Check current user's password /// Check current user's password
pub fn check_user_password(user_id: &UserID, password: &str) -> ResultBoxError<bool> { pub fn check_user_password(user_id: &UserID, password: &str) -> ResultBoxError<bool> {
let crypt_pass = crypt_pass(password)?; let user = user_helper::find_user_by_id(user_id)?;
database::QueryInfo::new(USERS_TABLE) validate_password(&user, password)
.cond_user_id("ID", user_id)
.cond("password", &crypt_pass)
.exec_count()
.map(|r| r > 0)
} }
/// Change the password of a user /// Change the password of a user
pub fn change_password(user_id: &UserID, new_password: &String) -> ResultBoxError { pub fn change_password(user_id: &UserID, new_password: &str) -> ResultBoxError {
database::UpdateInfo::new(USERS_TABLE) database::UpdateInfo::new(USERS_TABLE)
.cond_user_id("ID", user_id) .cond_user_id("ID", user_id)
.set_str("password", &crypt_pass(new_password)?) .set_str("password", &hash_password(new_password)?)
.exec() .exec()
} }
@ -360,4 +357,34 @@ pub fn delete(user_id: &UserID) -> ResultBoxError {
.exec()?; .exec()?;
Ok(()) Ok(())
}
/// Hash the password to store it inside the database
fn hash_password(pass: &str) -> Res<String> {
Ok(hash_with_result(pass, DEFAULT_COST)?.to_string())
}
/// Validate user password.
///
/// If the password is encoded using the legacy method, it is automatically upgraded in case of
/// success
fn validate_password(user: &User, password: &str) -> Res<bool> {
// We check if the password use the new storage mechanism
if user.password.starts_with("$") {
return Ok(verify(password, &user.password)?);
}
// We need to upgrade the password
let crypt_pass = legacy_crypt_pass(password)?;
// If the password is not valid
if !user.password.eq(&crypt_pass) {
return Ok(false);
}
// Upgrade the password
change_password(&user.id, password)?;
Ok(true)
} }

View File

@ -22,18 +22,17 @@ pub fn sha1_str(input: &str) -> String {
/// One-way user password crypt /// One-way user password crypt
/// ///
/// This method will have to be replaced by a stronger algorithm once this implementation is /// This method is just transitional
/// completely built.
/// ///
/// It currently depends on PHP /// It currently depends on PHP
/// ///
/// ``` /// ```
/// use comunic_server::utils::crypt_utils::crypt_pass; /// use comunic_server::utils::crypt_utils::legacy_crypt_pass;
/// ///
/// let res = crypt_pass("secret").unwrap(); /// let res = legacy_crypt_pass("secret").unwrap();
/// assert_eq!(res, "e5GUe5kdeUMGs"); /// assert_eq!(res, "e5GUe5kdeUMGs");
/// ``` /// ```
pub fn crypt_pass(pass: &str) -> ResultBoxError<String> { pub fn legacy_crypt_pass(pass: &str) -> ResultBoxError<String> {
let hash = sha1_str(pass); let hash = sha1_str(pass);
let result = std::process::Command::new("/usr/bin/php") let result = std::process::Command::new("/usr/bin/php")