mirror of
https://github.com/Jackzmc/storage.git
synced 2025-05-05 16:53:20 +00:00
Use new login method for normal login
This commit is contained in:
parent
fe17ca5633
commit
3f222dfd3c
5 changed files with 47 additions and 35 deletions
|
@ -10,9 +10,9 @@ use rocket_session_store::memory::MemoryStore;
|
|||
use sqlx::{query, query_as, Pool, QueryBuilder};
|
||||
use uuid::Uuid;
|
||||
use crate::config::AppConfig;
|
||||
use crate::consts::ENCRYPTION_ROUNDS;
|
||||
use crate::consts::{DISABLE_LOGIN_CHECK, ENCRYPTION_ROUNDS};
|
||||
use crate::{LoginSessionData, SessionData, DB};
|
||||
use crate::models::user::{UserAuthError, UserModel};
|
||||
use crate::models::user::{UserAuthError, UserModel, UserModelWithPassword};
|
||||
|
||||
pub struct UserManager {
|
||||
pool: DB,
|
||||
|
@ -36,7 +36,7 @@ pub enum FindUserOption {
|
|||
|
||||
#[derive(Hash)]
|
||||
pub struct SSOData {
|
||||
pub provider_id: String,
|
||||
pub(crate) provider_id: String,
|
||||
pub(crate) sub: String
|
||||
}
|
||||
|
||||
|
@ -111,7 +111,7 @@ impl UserManager {
|
|||
})
|
||||
}
|
||||
|
||||
pub async fn login_user(&self, user: UserModel, ip_address: IpAddr, sessions: Session<'_, SessionData>) {
|
||||
pub async fn login_user_session(&self, user: UserModel, ip_address: IpAddr, sessions: &Session<'_, SessionData>) {
|
||||
sessions.set(SessionData {
|
||||
csrf_token: None,
|
||||
login: Some(LoginSessionData {
|
||||
|
@ -120,4 +120,30 @@ impl UserManager {
|
|||
}),
|
||||
}).await.unwrap();
|
||||
}
|
||||
|
||||
pub async fn login_normal_user(&self, email_or_usrname: &str, password: &str, ip: IpAddr, session: &Session<'_, SessionData>) -> Result<UserModel, UserAuthError> {
|
||||
let user = query_as!(UserModelWithPassword,
|
||||
"select id, username, password, created_at, email, name from storage.users where email = $1 OR username = $1", email_or_usrname
|
||||
)
|
||||
.fetch_optional(&self.pool)
|
||||
.await
|
||||
.map_err(|e| UserAuthError::DatabaseError(e))?;
|
||||
let Some(user) = user else {
|
||||
return Err(UserAuthError::UserNotFound);
|
||||
};
|
||||
if let Some(db_password) = user.password {
|
||||
if !*DISABLE_LOGIN_CHECK || bcrypt::verify(password, &db_password).map_err(|e| UserAuthError::EncryptionError(e))? {
|
||||
let model = UserModel {
|
||||
id: user.id,
|
||||
email: user.email,
|
||||
username: user.username,
|
||||
created_at: user.created_at,
|
||||
name: user.name
|
||||
};
|
||||
self.login_user_session(model.clone(), ip, session).await;
|
||||
return Ok(model)
|
||||
}
|
||||
}
|
||||
Err(UserAuthError::PasswordInvalid)
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
use std::error::Error;
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::net::IpAddr;
|
||||
use bcrypt::BcryptError;
|
||||
use chrono::NaiveDateTime;
|
||||
use rocket::form::Context;
|
||||
|
@ -9,9 +10,11 @@ use rocket::form::error::Entity;
|
|||
use rocket::response::Responder;
|
||||
use rocket::serde::Serialize;
|
||||
use rocket::serde::uuid::Uuid;
|
||||
use rocket_session_store::Session;
|
||||
use sqlx::{query_as, FromRow};
|
||||
use crate::consts::{DISABLE_LOGIN_CHECK, ENCRYPTION_ROUNDS};
|
||||
use crate::{LoginSessionData, SessionData, DB};
|
||||
use crate::managers::user::UsersState;
|
||||
use crate::models::repo::RepoModel;
|
||||
use crate::util::JsonErrorResponse;
|
||||
|
||||
|
@ -95,22 +98,11 @@ pub async fn get_user(pool: &DB, user_id: &str) -> Result<Option<UserModel>, any
|
|||
.fetch_optional(pool)
|
||||
.await.map_err(anyhow::Error::from)
|
||||
}
|
||||
/// Validates user login form, returning Some on success or None (with ctx containing errors) on failure
|
||||
pub async fn validate_user_form(ctx: &mut Context<'_>, pool: &DB) -> Option<UserModel> {
|
||||
/// Validates user login form
|
||||
pub async fn try_login_user_form(ctx: &mut Context<'_>, users: &UsersState, ip: IpAddr, session: &Session<'_, SessionData>) -> Result<UserModel, UserAuthError> {
|
||||
let username = ctx.field_value("username").unwrap();
|
||||
let password = ctx.field_value("password").unwrap(); // TODO: no unwrap
|
||||
match validate_user(pool, username, password).await {
|
||||
Ok(u) => Some(u),
|
||||
Err(UserAuthError::PasswordInvalid | UserAuthError::UserNotFound) => {
|
||||
ctx.push_error(form::Error::validation("Username or password is incorrect").with_entity(Entity::Form));
|
||||
None
|
||||
},
|
||||
Err(e) => {
|
||||
ctx.push_error(form::Error::custom(e));
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
users.login_normal_user(username, password, ip, session).await
|
||||
}
|
||||
pub async fn validate_user(pool: &DB, email_or_usrname: &str, password: &str) -> Result<UserModel, UserAuthError> {
|
||||
let user = query_as!(UserModelWithPassword,
|
||||
|
|
|
@ -9,7 +9,7 @@ use rocket::http::uri::{Origin, Reference, Uri};
|
|||
use rocket::response::Redirect;
|
||||
use rocket_dyn_templates::{context, Template};
|
||||
use rocket_session_store::Session;
|
||||
use crate::models::user::{validate_user, validate_user_form, UserAuthError, UserModel};
|
||||
use crate::models::user::{validate_user, try_login_user_form, UserAuthError, UserModel};
|
||||
use crate::{GlobalMetadata, LoginSessionData, SessionData, DB};
|
||||
use crate::guards::AuthUser;
|
||||
use crate::routes::ui;
|
||||
|
|
|
@ -8,7 +8,8 @@ use rocket_session_store::Session;
|
|||
use crate::{GlobalMetadata, LoginSessionData, SessionData, DB};
|
||||
use crate::config::AppConfig;
|
||||
use crate::consts::{APP_METADATA, DISABLE_LOGIN_CHECK};
|
||||
use crate::models::user::validate_user_form;
|
||||
use crate::managers::user::UsersState;
|
||||
use crate::models::user::try_login_user_form;
|
||||
use crate::routes::ui::auth::HackyRedirectBecauseRocketBug;
|
||||
use crate::util::{set_csrf, validate_csrf_form};
|
||||
|
||||
|
@ -19,6 +20,7 @@ pub async fn page(
|
|||
return_to: Option<String>,
|
||||
logged_out: Option<bool>,
|
||||
settings: &State<AppConfig>,
|
||||
|
||||
) -> Template {
|
||||
// TODO: redirect if already logged in
|
||||
let csrf_token = set_csrf(&session).await;
|
||||
|
@ -48,29 +50,21 @@ struct LoginForm<'r> {
|
|||
|
||||
#[post("/auth/login?<return_to>", data = "<form>")]
|
||||
pub async fn handler(
|
||||
pool: &State<DB>,
|
||||
route: &Route,
|
||||
ip_addr: IpAddr,
|
||||
session: Session<'_, SessionData>,
|
||||
mut form: Form<Contextual<'_, LoginForm<'_>>>,
|
||||
users: &State<UsersState>,
|
||||
settings: &State<AppConfig>,
|
||||
return_to: Option<String>,
|
||||
) -> Result<HackyRedirectBecauseRocketBug, Template> {
|
||||
trace!("handler");
|
||||
if !*DISABLE_LOGIN_CHECK {
|
||||
validate_csrf_form(&mut form.context, &session).await;
|
||||
}
|
||||
let user = validate_user_form(&mut form.context, &pool).await;
|
||||
validate_csrf_form(&mut form.context, &session).await;
|
||||
let user = try_login_user_form(&mut form.context, users.inner(), ip_addr, &session).await.ok();
|
||||
// TODO: use new users fetch user
|
||||
trace!("check form");
|
||||
if form.context.status() == Status::Ok {
|
||||
if let Some(submission) = &form.value {
|
||||
session.set(SessionData {
|
||||
csrf_token: None,
|
||||
login: Some(LoginSessionData {
|
||||
user: user.expect("failed to acquire user but no errors"), // if validate_user_form returned None, form had errors, this shouldnt run,
|
||||
ip_address: ip_addr,
|
||||
}),
|
||||
}).await.unwrap();
|
||||
if let Some(_) = &form.value {
|
||||
let mut return_to_path = return_to.unwrap_or("/".to_string());
|
||||
if return_to_path == "" { return_to_path.push_str("/"); }
|
||||
debug!("returning user to {:?}", return_to_path);
|
||||
|
|
|
@ -101,7 +101,7 @@ async fn callback_handler(sso: &State<SSOState>, ip: IpAddr, code: String, state
|
|||
}
|
||||
|
||||
#[get("/auth/sso/cb?<code>&<state>")]
|
||||
pub async fn callback(sessions: Session<'_, SessionData>, config: &State<AppConfig>, users: &State<UsersState>, ip: IpAddr, sso: &State<SSOState>, code: String, state: String) -> Result<HackyRedirectBecauseRocketBug, (Status, Template)> {
|
||||
pub async fn callback(session: Session<'_, SessionData>, config: &State<AppConfig>, users: &State<UsersState>, ip: IpAddr, sso: &State<SSOState>, code: String, state: String) -> Result<HackyRedirectBecauseRocketBug, (Status, Template)> {
|
||||
let (userinfo, provider_id, return_to) = callback_handler(sso, ip, code, state).await
|
||||
.map_err(|e| (Status::InternalServerError, Template::render("errors/500", context! {
|
||||
error: e.to_string()
|
||||
|
@ -141,7 +141,7 @@ pub async fn callback(sessions: Session<'_, SessionData>, config: &State<AppConf
|
|||
}
|
||||
}
|
||||
let user = user.unwrap();
|
||||
users.login_user(user, ip, sessions).await;
|
||||
users.login_user_session(user, ip, &session).await;
|
||||
debug!("user={:?}\nemail={:?}\nname={:?}", userinfo.subject(), userinfo.email(), userinfo.name());
|
||||
// TODO: login user to session, prob through UserManager/users
|
||||
let return_to = return_to.unwrap_or("/".to_string());
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue