@ -41,33 +41,17 @@ fn login(connect_data: Form<ConnectData>, conn: DbConn) -> Result<Json, BadReque 
			
		
	
		
			
				
					             let   username   =   data . get ( "username" ) . unwrap ( ) ;  
			
		
	
		
			
				
					             let   user   =   match   User ::find_by_mail ( username ,   & conn )   {  
			
		
	
		
			
				
					                 Some ( user )   = >   user ,  
			
		
	
		
			
				
					                 None   = >   err ! ( "Invalid username or password " )  
			
		
	
		
			
				
					                 None   = >   err ! ( "Username or password is incorrect. Try again. " )  
			
		
	
		
			
				
					             } ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					             // Check password
  
			
		
	
		
			
				
					             let   password   =   data . get ( "password" ) . unwrap ( ) ;  
			
		
	
		
			
				
					             if   ! user . check_valid_password ( password )   {  
			
		
	
		
			
				
					                 err ! ( "Invalid username or password " )  
			
		
	
		
			
				
					                 err ! ( "Username or password is incorrect. Try again. " )  
			
		
	
		
			
				
					             }  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					             /*  
			
		
	
		
			
				
					             //TODO: When invalid username or password, return this with a 400 BadRequest:
  
			
		
	
		
			
				
					             {  
			
		
	
		
			
				
					               "error" : "invalid_grant" ,  
			
		
	
		
			
				
					               "error_description" : "invalid_username_or_password" ,  
			
		
	
		
			
				
					               "ErrorModel" : {  
			
		
	
		
			
				
					                 "Message" : "Username or password is incorrect. Try again." ,  
			
		
	
		
			
				
					                 "ValidationErrors" : null ,  
			
		
	
		
			
				
					                 "ExceptionMessage" : null ,  
			
		
	
		
			
				
					                 "ExceptionStackTrace" : null ,  
			
		
	
		
			
				
					                 "InnerExceptionMessage" : null ,  
			
		
	
		
			
				
					                 "Object" : "error"  
			
		
	
		
			
				
					               }  
			
		
	
		
			
				
					             }  
			
		
	
		
			
				
					             * /  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					             // Check if totp code is required and the value is correct
  
			
		
	
		
			
				
					             let   totp_code   =   util ::parse_option_string ( data . get ( "twoFactorToken" ) . map ( String ::as_ref ) ) ;  
			
		
	
		
			
				
					             let   totp_code   =   util ::parse_option_string ( data . get ( "twoFactorToken" ) ) ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					             if   ! user . check_totp_code ( totp_code )   {  
			
		
	
		
			
				
					                 // Return error 400
  
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -83,19 +67,18 @@ fn login(connect_data: Form<ConnectData>, conn: DbConn) -> Result<Json, BadReque 
			
		
	
		
			
				
					             // TODO Get header Device-Type
  
			
		
	
		
			
				
					             let   device_type_num   =   0 ; // headers.device_type;
  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					             let   ( device_id ,   device_name )   =   match   data . get ( "client_id" ) . unwrap ( ) . as_ref ( )   {  
			
		
	
		
			
				
					                 "web"   = >   {   ( format ! ( "web-{}" ,   user . uuid ) ,   String ::from ( "web" ) )   }  
			
		
	
		
			
				
					                 "browser"   |   "mobile"   = >   {  
			
		
	
		
			
				
					             let   ( device_id ,   device_name )   =   match   data . is_device   {  
			
		
	
		
			
				
					                 false   = >   {   ( format ! ( "web-{}" ,   user . uuid ) ,   String ::from ( "web" ) )   }  
			
		
	
		
			
				
					                 true   = >   {  
			
		
	
		
			
				
					                     (  
			
		
	
		
			
				
					                         data . get ( "deviceidentifier" ) . unwrap ( ) . clone ( ) ,  
			
		
	
		
			
				
					                         data . get ( "devicename" ) . unwrap ( ) . clone ( ) ,  
			
		
	
		
			
				
					                     )  
			
		
	
		
			
				
					                 }  
			
		
	
		
			
				
					                 _   = >   err ! ( "Invalid client id" )  
			
		
	
		
			
				
					             } ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					             // Find device or create new
  
			
		
	
		
			
				
					             let   device   =   match   Device ::find_by_uuid ( & device_id ,   & conn )   {  
			
		
	
		
			
				
					             match   Device ::find_by_uuid ( & device_id ,   & conn )   {  
			
		
	
		
			
				
					                 Some ( device )   = >   {  
			
		
	
		
			
				
					                     // Check if valid device
  
			
		
	
		
			
				
					                     if   device . user_uuid   ! =   user . uuid   {  
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -109,10 +92,7 @@ fn login(connect_data: Form<ConnectData>, conn: DbConn) -> Result<Json, BadReque 
			
		
	
		
			
				
					                     // Create new device
  
			
		
	
		
			
				
					                     Device ::new ( device_id ,   user . uuid ,   device_name ,   device_type_num )  
			
		
	
		
			
				
					                 }  
			
		
	
		
			
				
					             } ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					             device  
			
		
	
		
			
				
					             }  
			
		
	
		
			
				
					         }  
			
		
	
		
			
				
					     } ;  
			
		
	
		
			
				
					
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -120,7 +100,6 @@ fn login(connect_data: Form<ConnectData>, conn: DbConn) -> Result<Json, BadReque 
			
		
	
		
			
				
					     let   ( access_token ,   expires_in )   =   device . refresh_tokens ( & user ) ;  
			
		
	
		
			
				
					     device . save ( & conn ) ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     // TODO: when to include :privateKey and :TwoFactorToken?
  
			
		
	
		
			
				
					     Ok ( Json ( json ! ( {  
			
		
	
		
			
				
					         "access_token" : access_token ,  
			
		
	
		
			
				
					         "expires_in" : expires_in ,  
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -134,27 +113,22 @@ fn login(connect_data: Form<ConnectData>, conn: DbConn) -> Result<Json, BadReque 
			
		
	
		
			
				
					#[ derive(Debug) ]  
			
		
	
		
			
				
					struct  ConnectData   {  
			
		
	
		
			
				
					     grant_type : GrantType ,  
			
		
	
		
			
				
					     is_device : bool ,  
			
		
	
		
			
				
					     data : HashMap < String ,   String > ,  
			
		
	
		
			
				
					}  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					#[ derive(Debug, Copy, Clone) ]  
			
		
	
		
			
				
					enum  GrantType   {   RefreshToken ,   Password   }  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					impl   ConnectData   {  
			
		
	
		
			
				
					     fn  get ( & self ,   key : & str )   -> Option < & String >   {  
			
		
	
		
			
				
					         self . data . get ( & key . to_lowercase ( ) )  
			
		
	
		
			
				
					     }  
			
		
	
		
			
				
					}  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					#[ derive(Debug, Copy, Clone) ]  
			
		
	
		
			
				
					enum  GrantType   {   RefreshToken ,   Password   }  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					const   VALUES_REFRESH : [ & str ;   1 ]   =   [ "refresh_token" ] ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					const   VALUES_PASSWORD : [ & str ;   5 ]   =   [ "client_id" ,  
			
		
	
		
			
				
					     "grant_type" ,   "password" ,   "scope" ,   "username" ] ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					const   VALUES_DEVICE : [ & str ;   3 ]   =   [ "deviceidentifier" ,  
			
		
	
		
			
				
					     "devicename" ,   "devicetype" ] ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					const   VALUES_PASSWORD : [ & str ;   5 ]   =   [ "client_id" ,   "grant_type" ,   "password" ,   "scope" ,   "username" ] ;  
			
		
	
		
			
				
					const   VALUES_DEVICE : [ & str ;   3 ]   =   [ "deviceidentifier" ,   "devicename" ,   "devicetype" ] ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					impl < 'f >   FromForm < 'f >   for   ConnectData   {  
			
		
	
		
			
				
					     type  Error   =   String ;  
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -164,62 +138,40 @@ impl<'f> FromForm<'f> for ConnectData { 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					         // Insert data into map
  
			
		
	
		
			
				
					         for   ( key ,   value )   in   items   {  
			
		
	
		
			
				
					             let   decoded_key : String  =   match   key . url_decode ( )   {  
			
		
	
		
			
				
					                 Ok ( decoded )   = >   decoded ,  
			
		
	
		
			
				
					                 Err ( _ )   = >   return   Err ( format ! ( "Error decoding key: {}" ,   value ) ) ,  
			
		
	
		
			
				
					             } ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					             let   decoded_value : String  =   match   value . url_decode ( )   {  
			
		
	
		
			
				
					                 Ok ( decoded )   = >   decoded ,  
			
		
	
		
			
				
					                 Err ( _ )   = >   return   Err ( format ! ( "Error decoding value: {}" ,   value ) ) ,  
			
		
	
		
			
				
					             match   ( key . url_decode ( ) ,   value . url_decode ( ) )   {  
			
		
	
		
			
				
					                 ( Ok ( key ) ,   Ok ( value ) )   = >   data . insert ( key . to_lowercase ( ) ,   value ) ,  
			
		
	
		
			
				
					                 _   = >   return   Err ( format ! ( "Error decoding key or value" ) ) ,  
			
		
	
		
			
				
					             } ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					             data . insert ( decoded_key . to_lowercase ( ) ,   decoded_value ) ;  
			
		
	
		
			
				
					         }  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					         // Validate needed values
  
			
		
	
		
			
				
					         let   grant_type   =  
			
		
	
		
			
				
					             match   data . get ( "grant_type" ) . map ( | s |   & s [ . . ] )   {  
			
		
	
		
			
				
					         let   ( grant_type ,   is_device )   =  
			
		
	
		
			
				
					             match   data . get ( "grant_type" ) . map ( String ::as_ref )   {  
			
		
	
		
			
				
					                 Some ( "refresh_token" )   = >   {  
			
		
	
		
			
				
					                     // Check if refresh token is proviced
  
			
		
	
		
			
				
					                     if   let   Err ( msg )   =   check_values ( & data ,   & VALUES_REFRESH )   {  
			
		
	
		
			
				
					                         return   Err ( msg ) ;  
			
		
	
		
			
				
					                     }  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					                     GrantType ::RefreshToken  
			
		
	
		
			
				
					                     check_values ( & data ,   & VALUES_REFRESH ) ? ;  
			
		
	
		
			
				
					                     ( GrantType ::RefreshToken ,   false )   // Device doesn't matter here
  
			
		
	
		
			
				
					                 }  
			
		
	
		
			
				
					                 Some ( "password" )   = >   {  
			
		
	
		
			
				
					                     // Check if basic values are provided
  
			
		
	
		
			
				
					                     if   let   Err ( msg )   =   check_values ( & data ,   & VALUES_PASSWORD )   {  
			
		
	
		
			
				
					                         return   Err ( msg ) ;  
			
		
	
		
			
				
					                     }  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					                     // Check that device values are present on device
  
			
		
	
		
			
				
					                     match   data . get ( "client_id" ) . unwrap ( ) . as_ref ( )   {  
			
		
	
		
			
				
					                         "browser"   |   "mobile"   = >   {  
			
		
	
		
			
				
					                             if   let   Err ( msg )   =   check_values ( & data ,   & VALUES_DEVICE )   {  
			
		
	
		
			
				
					                                 return   Err ( msg ) ;  
			
		
	
		
			
				
					                             }  
			
		
	
		
			
				
					                         }  
			
		
	
		
			
				
					                         _   = >   { }  
			
		
	
		
			
				
					                     }  
			
		
	
		
			
				
					                     check_values ( & data ,   & VALUES_PASSWORD ) ? ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					                     GrantType ::Password  
			
		
	
		
			
				
					                     let   is_device   =   match   data . get ( "client_id" ) . unwrap ( ) . as_ref ( )   {  
			
		
	
		
			
				
					                         "browser"   |   "mobile"   = >   check_values ( & data ,   & VALUES_DEVICE ) ? ,  
			
		
	
		
			
				
					                         _   = >   false  
			
		
	
		
			
				
					                     } ;  
			
		
	
		
			
				
					                     ( GrantType ::Password ,   is_device )  
			
		
	
		
			
				
					                 }  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					                 _   = >   return   Err ( format ! ( "Grant type not supported" ) )  
			
		
	
		
			
				
					             } ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					         Ok ( ConnectData   {   grant_type ,   data   } )  
			
		
	
		
			
				
					         Ok ( ConnectData   {   grant_type ,   is_device ,   data   } )  
			
		
	
		
			
				
					     }  
			
		
	
		
			
				
					}  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					fn  check_values ( map : & HashMap < String ,   String > ,   values : & [ & str ] )   -> Result < ( ) ,   String >   {  
			
		
	
		
			
				
					fn  check_values ( map : & HashMap < String ,   String > ,   values : & [ & str ] )   -> Result < bool ,   String >   {  
			
		
	
		
			
				
					     for   value   in   values   {  
			
		
	
		
			
				
					         if   ! map . contains_key ( * value )   {  
			
		
	
		
			
				
					             return   Err ( format ! ( "{} cannot be blank" ,   value ) ) ;  
			
		
	
		
			
				
					         }  
			
		
	
		
			
				
					     }  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     Ok ( ( ) )  
			
		
	
		
			
				
					     Ok ( true )  
			
		
	
		
			
				
					}