move config, add password check
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Patrick Michl 2022-05-01 00:56:59 +02:00
parent 3b8c529183
commit c20b4c6a23
4 changed files with 57 additions and 25 deletions

View File

@ -1,6 +1,6 @@
use std::{collections::HashMap, sync::Arc}; use std::{collections::HashMap, sync::Arc};
use argon2::{password_hash::SaltString, Argon2, PasswordHasher}; use argon2::{password_hash::SaltString, Argon2, PasswordHash, PasswordHasher};
use axum::{ use axum::{
extract::Query, extract::Query,
http::StatusCode, http::StatusCode,
@ -50,12 +50,23 @@ async fn post_login(
Extension(db): Extension<SqlitePool>, Extension(db): Extension<SqlitePool>,
Json(body): Json<AuthenticationData>, Json(body): Json<AuthenticationData>,
) -> Result<Json<AuthenticationResponse>, ApiError> { ) -> Result<Json<AuthenticationResponse>, ApiError> {
let user = UserId::new("name", "server_name") match body {
AuthenticationData::Password(auth_data) => {
let user = auth_data.user().unwrap();
let user_id = UserId::new(&user, config.homeserver_name())
.ok() .ok()
.ok_or(AuthenticationError::InvalidUserId)?; .ok_or(AuthenticationError::InvalidUserId)?;
let resp = AuthenticationSuccess::new("", "", &user);
let user = User::find_by_user_id(&db, &user_id).await?;
user.password_correct(auth_data.password()).ok().ok_or(AuthenticationError::Forbidden)?;
todo!("find_or_create device for user and create a session");
let resp = AuthenticationSuccess::new("", "", &user_id);
Ok(Json(AuthenticationResponse::Success(resp))) Ok(Json(AuthenticationResponse::Success(resp)))
}
}
} }
#[tracing::instrument(skip_all)] #[tracing::instrument(skip_all)]
@ -67,7 +78,7 @@ async fn get_username_available(
let username = params let username = params
.get("username") .get("username")
.ok_or(RegistrationError::MissingUserId)?; .ok_or(RegistrationError::MissingUserId)?;
let user_id = UserId::new(username, &config.homeserver_name) let user_id = UserId::new(username, &config.homeserver_name())
.ok() .ok()
.ok_or(RegistrationError::InvalidUserId)?; .ok_or(RegistrationError::InvalidUserId)?;
let exists = User::exists(&db, &user_id).await?; let exists = User::exists(&db, &user_id).await?;
@ -87,7 +98,7 @@ async fn post_register(
let (user, device) = match &body.auth().expect("must be Some") { let (user, device) = match &body.auth().expect("must be Some") {
AuthenticationData::Password(auth_data) => { AuthenticationData::Password(auth_data) => {
let username = body.username().ok_or(RegistrationError::MissingUserId)?; let username = body.username().ok_or(RegistrationError::MissingUserId)?;
let user_id = UserId::new(username, &config.homeserver_name) let user_id = UserId::new(username, &config.homeserver_name())
.ok() .ok()
.ok_or(RegistrationError::InvalidUserId)?; .ok_or(RegistrationError::InvalidUserId)?;

27
src/config.rs Normal file
View File

@ -0,0 +1,27 @@
pub struct Config {
db_path: String,
homeserver_name: String,
}
impl Config {
/// Get a reference to the config's db path.
#[must_use]
pub fn db_path(&self) -> &str {
self.db_path.as_ref()
}
/// Get a reference to the config's homeserver name.
#[must_use]
pub fn homeserver_name(&self) -> &str {
self.homeserver_name.as_ref()
}
}
impl Default for Config {
fn default() -> Self {
Self {
db_path: "sqlite://db.sqlite3".into(),
homeserver_name: "fuckwit.dev".into(),
}
}
}

View File

@ -8,6 +8,7 @@ use axum::{
http::{Request, StatusCode}, http::{Request, StatusCode},
Extension, Router, Extension, Router,
}; };
use config::Config;
use tower_http::{ use tower_http::{
cors::CorsLayer, cors::CorsLayer,
trace::{DefaultOnRequest, DefaultOnResponse, TraceLayer}, trace::{DefaultOnRequest, DefaultOnResponse, TraceLayer},
@ -19,20 +20,7 @@ mod models;
mod requests; mod requests;
mod responses; mod responses;
mod types; mod types;
mod config;
struct Config {
db_path: String,
homeserver_name: String,
}
impl Default for Config {
fn default() -> Self {
Self {
db_path: "sqlite://db.sqlite3".into(),
homeserver_name: "fuckwit.dev".into(),
}
}
}
#[tokio::main] #[tokio::main]
async fn main() -> anyhow::Result<()> { async fn main() -> anyhow::Result<()> {
@ -44,7 +32,7 @@ async fn main() -> anyhow::Result<()> {
let config = Arc::new(Config::default()); let config = Arc::new(Config::default());
let pool = sqlx::SqlitePool::connect(&config.db_path).await?; let pool = sqlx::SqlitePool::connect(&config.db_path()).await?;
let cors = CorsLayer::new() let cors = CorsLayer::new()
.allow_origin(tower_http::cors::Any) .allow_origin(tower_http::cors::Any)

View File

@ -1,5 +1,5 @@
use crate::types::uuid::Uuid; use crate::types::uuid::Uuid;
use argon2::{password_hash::SaltString, Argon2, PasswordHasher}; use argon2::{password_hash::SaltString, Argon2, PasswordHasher, PasswordHash, PasswordVerifier};
use rand_core::OsRng; use rand_core::OsRng;
use sqlx::{encode::IsNull, sqlite::SqliteTypeInfo, FromRow, Sqlite, SqlitePool}; use sqlx::{encode::IsNull, sqlite::SqliteTypeInfo, FromRow, Sqlite, SqlitePool};
@ -68,7 +68,7 @@ impl User {
.await?) .await?)
} }
pub async fn by_user_id(conn: &SqlitePool, user_id: &UserId) -> anyhow::Result<Self> { pub async fn find_by_user_id(conn: &SqlitePool, user_id: &UserId) -> anyhow::Result<Self> {
Ok(sqlx::query_as!( Ok(sqlx::query_as!(
Self, Self,
"select uuid as 'uuid: Uuid', user_id as 'user_id: UserId', display_name, password "select uuid as 'uuid: Uuid', user_id as 'user_id: UserId', display_name, password
@ -79,6 +79,12 @@ impl User {
.await?) .await?)
} }
pub fn password_correct(&self, password: &str) -> anyhow::Result<bool> {
let password_hash = PasswordHash::new(self.password())?;
Ok(Argon2::default().verify_password(password.as_bytes(), &password_hash).is_ok())
}
/// Get the user's id. /// Get the user's id.
#[must_use] #[must_use]
pub fn uuid(&self) -> &Uuid { pub fn uuid(&self) -> &Uuid {