2023-04-03 16:11:26 +02:00
use rocket ::{
form ::Form ,
2023-04-03 17:32:41 +02:00
get ,
http ::{ Cookie , CookieJar } ,
2023-07-25 13:55:16 +02:00
outcome ::Outcome ,
2023-04-03 17:32:41 +02:00
post ,
2023-07-25 13:55:16 +02:00
request ::{ FlashMessage , FromRequest } ,
2023-04-03 17:32:41 +02:00
response ::{ Flash , Redirect } ,
2023-06-07 00:07:11 +02:00
routes ,
time ::{ Duration , OffsetDateTime } ,
2023-07-25 13:55:16 +02:00
FromForm , Request , Route , State ,
2023-04-03 16:11:26 +02:00
} ;
2023-04-04 10:44:14 +02:00
use rocket_dyn_templates ::{ context , tera , Template } ;
2023-04-03 16:11:26 +02:00
use sqlx ::SqlitePool ;
2023-04-18 12:10:11 +02:00
use crate ::model ::{
log ::Log ,
user ::{ LoginError , User } ,
} ;
2023-04-03 16:11:26 +02:00
2023-07-22 15:51:20 +02:00
#[ get( " /?<name> " ) ]
fn index ( flash : Option < FlashMessage < '_ > > , name : Option < String > ) -> Template {
2023-04-03 16:11:26 +02:00
let mut context = tera ::Context ::new ( ) ;
if let Some ( msg ) = flash {
context . insert ( " flash " , & msg . into_inner ( ) ) ;
}
2023-07-22 15:51:20 +02:00
if let Some ( n ) = name {
context . insert ( " name " , & n ) ;
}
2023-04-03 16:11:26 +02:00
Template ::render ( " auth/login " , context . into_json ( ) )
}
#[ derive(FromForm) ]
2023-05-24 12:11:55 +02:00
struct LoginForm < ' r > {
name : & ' r str ,
password : & ' r str ,
2023-04-03 16:11:26 +02:00
}
2023-07-25 13:55:16 +02:00
#[ derive(Debug) ]
pub struct UserAgent ( String ) ;
#[ rocket::async_trait ]
impl < ' r > FromRequest < ' r > for UserAgent {
type Error = std ::convert ::Infallible ;
async fn from_request (
request : & ' r Request < '_ > ,
) -> rocket ::request ::Outcome < UserAgent , Self ::Error > {
let agent = request
. headers ( )
. get_one ( " User-Agent " )
. unwrap_or ( " Unknown " )
. to_string ( ) ;
Outcome ::Success ( UserAgent ( agent ) )
}
}
2023-04-03 16:11:26 +02:00
#[ post( " / " , data = " <login> " ) ]
2023-04-03 17:32:41 +02:00
async fn login (
2023-05-24 12:11:55 +02:00
login : Form < LoginForm < '_ > > ,
2023-04-03 17:32:41 +02:00
db : & State < SqlitePool > ,
cookies : & CookieJar < '_ > ,
2023-07-25 13:55:16 +02:00
agent : UserAgent ,
2023-04-03 17:32:41 +02:00
) -> Flash < Redirect > {
2023-07-11 09:16:13 +02:00
let user = match User ::login ( db , login . name , login . password ) . await {
2023-04-03 16:11:26 +02:00
Ok ( user ) = > user ,
2023-04-04 10:44:14 +02:00
Err ( LoginError ::NoPasswordSet ( user ) ) = > {
return Flash ::warning (
Redirect ::to ( format! ( " /auth/set-pw/ {} " , user . id ) ) ,
" Setze ein neues Passwort " ,
) ;
}
2023-04-03 16:11:26 +02:00
Err ( _ ) = > {
2023-08-02 18:36:38 +02:00
return Flash ::error ( Redirect ::to ( " /auth " ) , " Falscher Benutzername/Passwort. Du bist Vereinsmitglied und der Login klappt nicht? Kontaktiere Philipp H. (Tel.nr. siehe Signalgruppe) oder schreibe eine Mail an it@rudernlinz.at! " ) ;
2023-04-03 16:11:26 +02:00
}
} ;
2023-10-13 09:43:59 +02:00
cookies . add_private ( Cookie ::new ( " loggedin_user " , format! ( " {} " , user . id ) ) ) ;
2023-04-03 17:32:41 +02:00
2023-07-26 08:29:22 +02:00
Log ::create (
db ,
format! (
" Succ login of {} with this useragent: {:?} " ,
login . name , agent
) ,
)
. await ;
2024-01-22 22:08:05 +01:00
// Check for redirect_url cookie and redirect accordingly
match cookies . get_private ( " redirect_url " ) {
Some ( redirect_cookie ) = > {
let redirect_url = redirect_cookie . value ( ) . to_string ( ) ;
cookies . remove_private ( redirect_cookie ) ; // Remove the cookie after using it
Flash ::success ( Redirect ::to ( redirect_url ) , " Login erfolgreich " )
}
None = > Flash ::success ( Redirect ::to ( " / " ) , " Login erfolgreich " ) ,
}
2023-04-03 16:11:26 +02:00
}
2023-04-04 10:44:14 +02:00
#[ get( " /set-pw/<userid> " ) ]
2023-04-04 19:49:27 +02:00
fn setpw ( userid : i32 ) -> Template {
2023-04-04 10:44:14 +02:00
Template ::render ( " auth/set-pw " , context! ( userid ) )
}
#[ derive(FromForm) ]
2023-05-24 12:11:55 +02:00
struct UpdatePw < ' r > {
2023-04-04 10:44:14 +02:00
userid : i32 ,
2023-05-24 12:11:55 +02:00
password : & ' r str ,
password_confirm : & ' r str ,
2023-04-04 10:44:14 +02:00
}
#[ post( " /set-pw " , data = " <updatepw> " ) ]
async fn updatepw (
db : & State < SqlitePool > ,
2023-05-24 12:11:55 +02:00
updatepw : Form < UpdatePw < '_ > > ,
2023-04-04 10:44:14 +02:00
cookies : & CookieJar < '_ > ,
) -> Flash < Redirect > {
let user = User ::find_by_id ( db , updatepw . userid ) . await ;
2023-08-02 18:36:38 +02:00
let Some ( user ) = user else {
return Flash ::error (
Redirect ::to ( " /auth " ) ,
format! ( " User with ID {} does not exist! " , updatepw . userid ) ,
) ;
2023-04-04 10:44:14 +02:00
} ;
if updatepw . password ! = updatepw . password_confirm {
return Flash ::error (
Redirect ::to ( format! ( " /auth/set-pw/ {} " , updatepw . userid ) ) ,
" Passwörter stimmen nicht überein! Bitte probiere es nochmal " ,
) ;
}
2023-05-24 12:11:55 +02:00
user . update_pw ( db , updatepw . password ) . await ;
2023-04-04 10:44:14 +02:00
2023-10-13 09:43:59 +02:00
let mut cookie = Cookie ::new ( " loggedin_user " , format! ( " {} " , user . id ) ) ;
2023-06-07 00:07:11 +02:00
cookie . set_expires ( OffsetDateTime ::now_utc ( ) + Duration ::weeks ( 12 ) ) ;
cookies . add_private ( cookie ) ;
2023-04-04 10:44:14 +02:00
2023-04-18 12:10:11 +02:00
Log ::create ( db , format! ( " User {} set her password. " , user . name ) ) . await ;
2023-04-04 10:44:14 +02:00
Flash ::success (
Redirect ::to ( " / " ) ,
" Passwort erfolgreich gesetzt. Du bist nun eingeloggt. " ,
)
}
2023-04-03 22:10:12 +02:00
#[ get( " /logout " ) ]
2023-07-25 13:33:12 +02:00
fn logout ( cookies : & CookieJar < '_ > , _user : User ) -> Flash < Redirect > {
2023-11-08 17:39:39 +01:00
cookies . remove_private ( Cookie ::from ( " loggedin_user " ) ) ;
2023-04-03 22:10:12 +02:00
Flash ::success ( Redirect ::to ( " /auth " ) , " Logout erfolgreich " )
}
2023-04-03 16:11:26 +02:00
pub fn routes ( ) -> Vec < Route > {
2023-04-04 10:44:14 +02:00
routes! [ index , login , logout , setpw , updatepw ]
2023-04-03 16:11:26 +02:00
}