hash password
This commit is contained in:
39
Cargo.lock
generated
39
Cargo.lock
generated
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
);
|
||||
|
||||
@@ -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?;
|
||||
|
||||
|
||||
@@ -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>,
|
||||
}
|
||||
|
||||
@@ -17,6 +17,8 @@ pub enum Error {
|
||||
Database(database::Error),
|
||||
#[from]
|
||||
Jwt(jwt::Error),
|
||||
#[from]
|
||||
Hash(argon2::password_hash::Error),
|
||||
|
||||
#[from]
|
||||
Client(ClientError),
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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))
|
||||
|
||||
Reference in New Issue
Block a user