1
0

hash password

This commit is contained in:
2024-05-21 06:34:55 +03:00
parent ea4f857d6b
commit ff1e29939b
8 changed files with 71 additions and 12 deletions

39
Cargo.lock generated
View File

@@ -76,6 +76,18 @@ version = "1.0.82"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519"
[[package]]
name = "argon2"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072"
dependencies = [
"base64ct",
"blake2",
"cpufeatures",
"password-hash",
]
[[package]]
name = "async-trait"
version = "0.1.80"
@@ -215,6 +227,12 @@ version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9475866fec1451be56a3c2400fd081ff546538961565ccb5b7142cbd22bc7a51"
[[package]]
name = "base64ct"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
[[package]]
name = "bitflags"
version = "1.3.2"
@@ -227,6 +245,15 @@ version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
[[package]]
name = "blake2"
version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe"
dependencies = [
"digest",
]
[[package]]
name = "block-buffer"
version = "0.10.4"
@@ -985,6 +1012,7 @@ name = "nir"
version = "0.1.0"
dependencies = [
"anyhow",
"argon2",
"axum",
"chrono",
"derive_more",
@@ -1135,6 +1163,17 @@ dependencies = [
"windows-targets 0.48.5",
]
[[package]]
name = "password-hash"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166"
dependencies = [
"base64ct",
"rand_core",
"subtle",
]
[[package]]
name = "paste"
version = "1.0.14"

View File

@@ -5,6 +5,7 @@
[dependencies]
anyhow = "1.0.82"
argon2 = "0.5.3"
axum = { version = "0.7.5", features = ["macros", "ws"] }
chrono = { version = "0.4.38", features = ["serde"] }
derive_more = "0.99.17"

View File

@@ -1,8 +1,8 @@
CREATE TABLE IF NOT EXISTS user (
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
`avatar` VARCHAR,
`username` VARCHAR UNIQUE,
`password` VARCHAR,
`username` VARCHAR UNIQUE NOT NULL,
`password_hash` VARCHAR NOT NULL,
`last_seen` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
);

View File

@@ -48,18 +48,19 @@ impl Database {
Ok(user)
}
pub async fn create_user(&self, username: &str, password: &str) -> Result<entity::User> {
pub async fn create_user(&self, username: &str, password_hash: &str) -> Result<entity::User> {
let user = self.get_user_by_username(username).await;
if user.is_ok() {
return Err(Error::UserAlreadyExists);
}
let id =
sqlx::query_scalar("INSERT INTO user(username, password) VALUES ($1, $2) RETURNING id")
.bind(username)
.bind(password)
.fetch_one(&self.pool)
.await?;
let id = sqlx::query_scalar(
"INSERT INTO user(username, password_hash) VALUES ($1, $2) RETURNING id",
)
.bind(username)
.bind(password_hash)
.fetch_one(&self.pool)
.await?;
let user = self.get_user_by_id(id).await?;

View File

@@ -8,7 +8,7 @@ pub struct User {
pub avatar: Option<String>,
pub username: String,
#[serde(skip_serializing)]
pub password: String,
pub password_hash: String,
pub last_seen: chrono::DateTime<Utc>,
pub created_at: chrono::DateTime<Utc>,
}

View File

@@ -17,6 +17,8 @@ pub enum Error {
Database(database::Error),
#[from]
Jwt(jwt::Error),
#[from]
Hash(argon2::password_hash::Error),
#[from]
Client(ClientError),

View File

@@ -1,3 +1,4 @@
use argon2::{Argon2, PasswordHash, PasswordVerifier};
use axum::{extract::State, response::IntoResponse, Json};
use chrono::{Duration, Utc};
use serde::Deserialize;
@@ -13,7 +14,11 @@ pub async fn login(
.get_user_by_username(&payload.username)
.await?;
if user.password != payload.password {
let password_hash = PasswordHash::new(&user.password_hash)?;
if Argon2::default()
.verify_password(payload.password.as_bytes(), &password_hash)
.is_err()
{
return Err(web::Error::WrongPassword);
}

View File

@@ -1,3 +1,7 @@
use argon2::{
password_hash::{rand_core::OsRng, PasswordHasher, SaltString},
Argon2,
};
use axum::{extract::State, response::IntoResponse, Json};
use serde::Deserialize;
@@ -7,9 +11,16 @@ pub async fn register(
State(state): State<AppState>,
Json(payload): Json<RegisterPayload>,
) -> web::Result<impl IntoResponse> {
let salt = SaltString::generate(&mut OsRng);
let argon = Argon2::default();
let password_hash = argon
.hash_password(payload.password.as_bytes(), &salt)?
.to_string();
let user = state
.database
.create_user(&payload.username, &payload.password)
.create_user(&payload.username, &password_hash)
.await?;
Ok(Json(user))