@ -300,8 +300,9 @@ fn logout(cookies: &CookieJar<'_>) -> Redirect { 
				
			 
			
		
	
		
		
			
				
					 
					 
					
 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					 
					 
					#[ get( " /users " ) ]  
					 
					 
					#[ get( " /users " ) ]  
				
			 
			
		
	
		
		
			
				
					 
					 
					async   fn  get_users_json ( _token : AdminToken ,   mut   conn : DbConn )   -> Json < Value >   {  
					 
					 
					async   fn  get_users_json ( _token : AdminToken ,   mut   conn : DbConn )   -> Json < Value >   {  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					     let   mut   users_json   =   Vec ::new ( ) ;  
					 
					 
					     let   users   =   User ::get_all ( & mut   conn ) . await ;  
				
			 
			
				
				
			
		
	
		
		
			
				
					
					 
					 
					     for   u   in   User ::get_all ( & mut   conn ) . await   {  
					 
					 
					     let   mut   users_json   =   Vec ::with_capacity ( users . len ( ) ) ;  
				
			 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					 
					 
					 
					 
					 
					     for   u   in   users   {  
				
			 
			
		
	
		
		
			
				
					 
					 
					         let   mut   usr   =   u . to_json ( & mut   conn ) . await ;  
					 
					 
					         let   mut   usr   =   u . to_json ( & mut   conn ) . await ;  
				
			 
			
		
	
		
		
			
				
					 
					 
					         usr [ "UserEnabled" ]   =   json ! ( u . enabled ) ;  
					 
					 
					         usr [ "UserEnabled" ]   =   json ! ( u . enabled ) ;  
				
			 
			
		
	
		
		
			
				
					 
					 
					         usr [ "CreatedAt" ]   =   json ! ( format_naive_datetime_local ( & u . created_at ,   DT_FMT ) ) ;  
					 
					 
					         usr [ "CreatedAt" ]   =   json ! ( format_naive_datetime_local ( & u . created_at ,   DT_FMT ) ) ;  
				
			 
			
		
	
	
		
		
			
				
					
						
						
						
							
								 
							 
						
					 
					@ -313,8 +314,9 @@ async fn get_users_json(_token: AdminToken, mut conn: DbConn) -> Json<Value> { 
				
			 
			
		
	
		
		
			
				
					 
					 
					
 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					 
					 
					#[ get( " /users/overview " ) ]  
					 
					 
					#[ get( " /users/overview " ) ]  
				
			 
			
		
	
		
		
			
				
					 
					 
					async   fn  users_overview ( _token : AdminToken ,   mut   conn : DbConn )   -> ApiResult < Html < String > >   {  
					 
					 
					async   fn  users_overview ( _token : AdminToken ,   mut   conn : DbConn )   -> ApiResult < Html < String > >   {  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					     let   mut   users_json   =   Vec ::new ( ) ;  
					 
					 
					     let   users   =   User ::get_all ( & mut   conn ) . await ;  
				
			 
			
				
				
			
		
	
		
		
			
				
					
					 
					 
					     for   u   in   User ::get_all ( & mut   conn ) . await   {  
					 
					 
					     let   mut   users_json   =   Vec ::with_capacity ( users . len ( ) ) ;  
				
			 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					 
					 
					 
					 
					 
					     for   u   in   users   {  
				
			 
			
		
	
		
		
			
				
					 
					 
					         let   mut   usr   =   u . to_json ( & mut   conn ) . await ;  
					 
					 
					         let   mut   usr   =   u . to_json ( & mut   conn ) . await ;  
				
			 
			
		
	
		
		
			
				
					 
					 
					         usr [ "cipher_count" ]   =   json ! ( Cipher ::count_owned_by_user ( & u . uuid ,   & mut   conn ) . await ) ;  
					 
					 
					         usr [ "cipher_count" ]   =   json ! ( Cipher ::count_owned_by_user ( & u . uuid ,   & mut   conn ) . await ) ;  
				
			 
			
		
	
		
		
			
				
					 
					 
					         usr [ "attachment_count" ]   =   json ! ( Attachment ::count_by_user ( & u . uuid ,   & mut   conn ) . await ) ;  
					 
					 
					         usr [ "attachment_count" ]   =   json ! ( Attachment ::count_by_user ( & u . uuid ,   & mut   conn ) . await ) ;  
				
			 
			
		
	
	
		
		
			
				
					
						
							
								 
							 
						
						
							
								 
							 
						
						
					 
					@ -490,11 +492,15 @@ async fn update_revision_users(_token: AdminToken, mut conn: DbConn) -> EmptyRes 
				
			 
			
		
	
		
		
			
				
					 
					 
					
 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					 
					 
					#[ get( " /organizations/overview " ) ]  
					 
					 
					#[ get( " /organizations/overview " ) ]  
				
			 
			
		
	
		
		
			
				
					 
					 
					async   fn  organizations_overview ( _token : AdminToken ,   mut   conn : DbConn )   -> ApiResult < Html < String > >   {  
					 
					 
					async   fn  organizations_overview ( _token : AdminToken ,   mut   conn : DbConn )   -> ApiResult < Html < String > >   {  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					     let   mut   organizations_json   =   Vec ::new ( ) ;  
					 
					 
					     let   organizations   =   Organization ::get_all ( & mut   conn ) . await ;  
				
			 
			
				
				
			
		
	
		
		
			
				
					
					 
					 
					     for   o   in   Organization ::get_all ( & mut   conn ) . await   {  
					 
					 
					     let   mut   organizations_json   =   Vec ::with_capacity ( organizations . len ( ) ) ;  
				
			 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					 
					 
					 
					 
					 
					     for   o   in   organizations   {  
				
			 
			
		
	
		
		
			
				
					 
					 
					         let   mut   org   =   o . to_json ( ) ;  
					 
					 
					         let   mut   org   =   o . to_json ( ) ;  
				
			 
			
		
	
		
		
			
				
					 
					 
					         org [ "user_count" ]   =   json ! ( UserOrganization ::count_by_org ( & o . uuid ,   & mut   conn ) . await ) ;  
					 
					 
					         org [ "user_count" ]   =   json ! ( UserOrganization ::count_by_org ( & o . uuid ,   & mut   conn ) . await ) ;  
				
			 
			
		
	
		
		
			
				
					 
					 
					         org [ "cipher_count" ]   =   json ! ( Cipher ::count_by_org ( & o . uuid ,   & mut   conn ) . await ) ;  
					 
					 
					         org [ "cipher_count" ]   =   json ! ( Cipher ::count_by_org ( & o . uuid ,   & mut   conn ) . await ) ;  
				
			 
			
		
	
		
		
			
				
					 
					 
					 
					 
					 
					         org [ "collection_count" ]   =   json ! ( Collection ::count_by_org ( & o . uuid ,   & mut   conn ) . await ) ;  
				
			 
			
		
	
		
		
			
				
					 
					 
					 
					 
					 
					         org [ "group_count" ]   =   json ! ( Group ::count_by_org ( & o . uuid ,   & mut   conn ) . await ) ;  
				
			 
			
		
	
		
		
			
				
					 
					 
					 
					 
					 
					         org [ "event_count" ]   =   json ! ( Event ::count_by_org ( & o . uuid ,   & mut   conn ) . await ) ;  
				
			 
			
		
	
		
		
			
				
					 
					 
					         org [ "attachment_count" ]   =   json ! ( Attachment ::count_by_org ( & o . uuid ,   & mut   conn ) . await ) ;  
					 
					 
					         org [ "attachment_count" ]   =   json ! ( Attachment ::count_by_org ( & o . uuid ,   & mut   conn ) . await ) ;  
				
			 
			
		
	
		
		
			
				
					 
					 
					         org [ "attachment_size" ]   =   json ! ( get_display_size ( Attachment ::size_by_org ( & o . uuid ,   & mut   conn ) . await   as   i32 ) ) ;  
					 
					 
					         org [ "attachment_size" ]   =   json ! ( get_display_size ( Attachment ::size_by_org ( & o . uuid ,   & mut   conn ) . await   as   i32 ) ) ;  
				
			 
			
		
	
		
		
			
				
					 
					 
					         organizations_json . push ( org ) ;  
					 
					 
					         organizations_json . push ( org ) ;  
				
			 
			
		
	
	
		
		
			
				
					
						
							
								 
							 
						
						
							
								 
							 
						
						
					 
					@ -525,10 +531,20 @@ struct GitCommit { 
				
			 
			
		
	
		
		
			
				
					 
					 
					     sha : String ,  
					 
					 
					     sha : String ,  
				
			 
			
		
	
		
		
			
				
					 
					 
					}  
					 
					 
					}  
				
			 
			
		
	
		
		
			
				
					 
					 
					
 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					async   fn  get_github_api < T : DeserializeOwned > ( url : & str )   -> Result < T ,   Error >   {  
					 
					 
					#[ derive(Deserialize) ]  
				
			 
			
				
				
			
		
	
		
		
			
				
					
					 
					 
					     let   github_api   =   get_reqwest_client ( ) ;  
					 
					 
					struct  TimeApi   {  
				
			 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					 
					 
					 
					 
					 
					     year : u16 ,  
				
			 
			
		
	
		
		
			
				
					 
					 
					 
					 
					 
					     month : u8 ,  
				
			 
			
		
	
		
		
			
				
					 
					 
					 
					 
					 
					     day : u8 ,  
				
			 
			
		
	
		
		
			
				
					 
					 
					 
					 
					 
					     hour : u8 ,  
				
			 
			
		
	
		
		
			
				
					 
					 
					 
					 
					 
					     minute : u8 ,  
				
			 
			
		
	
		
		
			
				
					 
					 
					 
					 
					 
					     seconds : u8 ,  
				
			 
			
		
	
		
		
			
				
					 
					 
					 
					 
					 
					}  
				
			 
			
		
	
		
		
			
				
					 
					 
					 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					 
					 
					 
					 
					 
					async   fn  get_json_api < T : DeserializeOwned > ( url : & str )   -> Result < T ,   Error >   {  
				
			 
			
		
	
		
		
			
				
					 
					 
					 
					 
					 
					     let   json_api   =   get_reqwest_client ( ) ;  
				
			 
			
		
	
		
		
			
				
					 
					 
					
 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					     Ok ( github_api . get ( url ) . send ( ) . await ? . error_for_status ( ) ? . json ::< T > ( ) . await ? )  
					 
					 
					     Ok ( json _api. get ( url ) . send ( ) . await ? . error_for_status ( ) ? . json ::< T > ( ) . await ? )  
				
			 
			
				
				
			
		
	
		
		
	
		
		
			
				
					 
					 
					}  
					 
					 
					}  
				
			 
			
		
	
		
		
			
				
					 
					 
					
 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					 
					 
					async   fn  has_http_access ( )   -> bool  {  
					 
					 
					async   fn  has_http_access ( )   -> bool  {  
				
			 
			
		
	
	
		
		
			
				
					
						
						
						
							
								 
							 
						
					 
					@ -548,14 +564,13 @@ async fn get_release_info(has_http_access: bool, running_within_docker: bool) -> 
				
			 
			
		
	
		
		
			
				
					 
					 
					     // If the HTTP Check failed, do not even attempt to check for new versions since we were not able to connect with github.com anyway.
  
					 
					 
					     // If the HTTP Check failed, do not even attempt to check for new versions since we were not able to connect with github.com anyway.
  
				
			 
			
		
	
		
		
			
				
					 
					 
					     if   has_http_access   {  
					 
					 
					     if   has_http_access   {  
				
			 
			
		
	
		
		
			
				
					 
					 
					         (  
					 
					 
					         (  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					             match   get_github _api ::< GitRelease > ( "https://api.github.com/repos/dani-garcia/vaultwarden/releases/latest" )  
					 
					 
					             match   get_json _api ::< GitRelease > ( "https://api.github.com/repos/dani-garcia/vaultwarden/releases/latest" )  
				
			 
			
				
				
			
		
	
		
		
	
		
		
			
				
					 
					 
					                 . await  
					 
					 
					                 . await  
				
			 
			
		
	
		
		
			
				
					 
					 
					             {  
					 
					 
					             {  
				
			 
			
		
	
		
		
			
				
					 
					 
					                 Ok ( r )   = >   r . tag_name ,  
					 
					 
					                 Ok ( r )   = >   r . tag_name ,  
				
			 
			
		
	
		
		
			
				
					 
					 
					                 _   = >   "-" . to_string ( ) ,  
					 
					 
					                 _   = >   "-" . to_string ( ) ,  
				
			 
			
		
	
		
		
			
				
					 
					 
					             } ,  
					 
					 
					             } ,  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					             match   get_github_api ::< GitCommit > ( "https://api.github.com/repos/dani-garcia/vaultwarden/commits/main" ) . await  
					 
					 
					             match   get_json_api ::< GitCommit > ( "https://api.github.com/repos/dani-garcia/vaultwarden/commits/main" ) . await   {  
				
			 
			
				
				
			
		
	
		
		
			
				
					 
					 
					             {  
					 
					 
					 
				
			 
			
		
	
		
		
	
		
		
			
				
					 
					 
					                 Ok ( mut   c )   = >   {  
					 
					 
					                 Ok ( mut   c )   = >   {  
				
			 
			
		
	
		
		
			
				
					 
					 
					                     c . sha . truncate ( 8 ) ;  
					 
					 
					                     c . sha . truncate ( 8 ) ;  
				
			 
			
		
	
		
		
			
				
					 
					 
					                     c . sha  
					 
					 
					                     c . sha  
				
			 
			
		
	
	
		
		
			
				
					
						
						
						
							
								 
							 
						
					 
					@ -567,7 +582,7 @@ async fn get_release_info(has_http_access: bool, running_within_docker: bool) -> 
				
			 
			
		
	
		
		
			
				
					 
					 
					             if   running_within_docker   {  
					 
					 
					             if   running_within_docker   {  
				
			 
			
		
	
		
		
			
				
					 
					 
					                 "-" . to_string ( )  
					 
					 
					                 "-" . to_string ( )  
				
			 
			
		
	
		
		
			
				
					 
					 
					             }   else   {  
					 
					 
					             }   else   {  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					                 match   get_github _api ::< GitRelease > (  
					 
					 
					                 match   get_json _api ::< GitRelease > (  
				
			 
			
				
				
			
		
	
		
		
	
		
		
			
				
					 
					 
					                     "https://api.github.com/repos/dani-garcia/bw_web_builds/releases/latest" ,  
					 
					 
					                     "https://api.github.com/repos/dani-garcia/bw_web_builds/releases/latest" ,  
				
			 
			
		
	
		
		
			
				
					 
					 
					                 )  
					 
					 
					                 )  
				
			 
			
		
	
		
		
			
				
					 
					 
					                 . await  
					 
					 
					                 . await  
				
			 
			
		
	
	
		
		
			
				
					
						
						
						
							
								 
							 
						
					 
					@ -582,6 +597,24 @@ async fn get_release_info(has_http_access: bool, running_within_docker: bool) -> 
				
			 
			
		
	
		
		
			
				
					 
					 
					     }  
					 
					 
					     }  
				
			 
			
		
	
		
		
			
				
					 
					 
					}  
					 
					 
					}  
				
			 
			
		
	
		
		
			
				
					 
					 
					
 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					 
					 
					 
					 
					 
					async   fn  get_ntp_time ( has_http_access : bool )   -> String  {  
				
			 
			
		
	
		
		
			
				
					 
					 
					 
					 
					 
					     if   has_http_access   {  
				
			 
			
		
	
		
		
			
				
					 
					 
					 
					 
					 
					         if   let   Ok ( ntp_time )   =   get_json_api ::< TimeApi > ( "https://www.timeapi.io/api/Time/current/zone?timeZone=UTC" ) . await  
				
			 
			
		
	
		
		
			
				
					 
					 
					 
					 
					 
					         {  
				
			 
			
		
	
		
		
			
				
					 
					 
					 
					 
					 
					             return   format ! (  
				
			 
			
		
	
		
		
			
				
					 
					 
					 
					 
					 
					                 "{year}-{month:02}-{day:02} {hour:02}:{minute:02}:{seconds:02} UTC" ,  
				
			 
			
		
	
		
		
			
				
					 
					 
					 
					 
					 
					                 year   =   ntp_time . year ,  
				
			 
			
		
	
		
		
			
				
					 
					 
					 
					 
					 
					                 month   =   ntp_time . month ,  
				
			 
			
		
	
		
		
			
				
					 
					 
					 
					 
					 
					                 day   =   ntp_time . day ,  
				
			 
			
		
	
		
		
			
				
					 
					 
					 
					 
					 
					                 hour   =   ntp_time . hour ,  
				
			 
			
		
	
		
		
			
				
					 
					 
					 
					 
					 
					                 minute   =   ntp_time . minute ,  
				
			 
			
		
	
		
		
			
				
					 
					 
					 
					 
					 
					                 seconds   =   ntp_time . seconds  
				
			 
			
		
	
		
		
			
				
					 
					 
					 
					 
					 
					             ) ;  
				
			 
			
		
	
		
		
			
				
					 
					 
					 
					 
					 
					         }  
				
			 
			
		
	
		
		
			
				
					 
					 
					 
					 
					 
					     }  
				
			 
			
		
	
		
		
			
				
					 
					 
					 
					 
					 
					     String ::from ( "Unable to fetch NTP time." )  
				
			 
			
		
	
		
		
			
				
					 
					 
					 
					 
					 
					}  
				
			 
			
		
	
		
		
			
				
					 
					 
					 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					 
					 
					#[ get( " /diagnostics " ) ]  
					 
					 
					#[ get( " /diagnostics " ) ]  
				
			 
			
		
	
		
		
			
				
					 
					 
					async   fn  diagnostics ( _token : AdminToken ,   ip_header : IpHeader ,   mut   conn : DbConn )   -> ApiResult < Html < String > >   {  
					 
					 
					async   fn  diagnostics ( _token : AdminToken ,   ip_header : IpHeader ,   mut   conn : DbConn )   -> ApiResult < Html < String > >   {  
				
			 
			
		
	
		
		
			
				
					 
					 
					     use   chrono ::prelude ::* ;  
					 
					 
					     use   chrono ::prelude ::* ;  
				
			 
			
		
	
	
		
		
			
				
					
						
							
								 
							 
						
						
							
								 
							 
						
						
					 
					@ -610,7 +643,7 @@ async fn diagnostics(_token: AdminToken, ip_header: IpHeader, mut conn: DbConn) 
				
			 
			
		
	
		
		
			
				
					 
					 
					     // Check if we are able to resolve DNS entries
  
					 
					 
					     // Check if we are able to resolve DNS entries
  
				
			 
			
		
	
		
		
			
				
					 
					 
					     let   dns_resolved   =   match   ( "github.com" ,   0 ) . to_socket_addrs ( ) . map ( | mut   i |   i . next ( ) )   {  
					 
					 
					     let   dns_resolved   =   match   ( "github.com" ,   0 ) . to_socket_addrs ( ) . map ( | mut   i |   i . next ( ) )   {  
				
			 
			
		
	
		
		
			
				
					 
					 
					         Ok ( Some ( a ) )   = >   a . ip ( ) . to_string ( ) ,  
					 
					 
					         Ok ( Some ( a ) )   = >   a . ip ( ) . to_string ( ) ,  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					         _   = >   "Could not  resolve domain name." . to_string ( ) ,  
					 
					 
					         _   = >   "Unable to  resolve domain name." . to_string ( ) ,  
				
			 
			
				
				
			
		
	
		
		
	
		
		
			
				
					 
					 
					     } ;  
					 
					 
					     } ;  
				
			 
			
		
	
		
		
			
				
					 
					 
					
 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					 
					 
					     let   ( latest_release ,   latest_commit ,   latest_web_build )   =  
					 
					 
					     let   ( latest_release ,   latest_commit ,   latest_web_build )   =  
				
			 
			
		
	
	
		
		
			
				
					
						
							
								 
							 
						
						
							
								 
							 
						
						
					 
					@ -644,7 +677,8 @@ async fn diagnostics(_token: AdminToken, ip_header: IpHeader, mut conn: DbConn) 
				
			 
			
		
	
		
		
			
				
					 
					 
					         "host_arch" : std ::env ::consts ::ARCH ,  
					 
					 
					         "host_arch" : std ::env ::consts ::ARCH ,  
				
			 
			
		
	
		
		
			
				
					 
					 
					         "host_os" :  std ::env ::consts ::OS ,  
					 
					 
					         "host_os" :  std ::env ::consts ::OS ,  
				
			 
			
		
	
		
		
			
				
					 
					 
					         "server_time_local" : Local ::now ( ) . format ( "%Y-%m-%d %H:%M:%S %Z" ) . to_string ( ) ,  
					 
					 
					         "server_time_local" : Local ::now ( ) . format ( "%Y-%m-%d %H:%M:%S %Z" ) . to_string ( ) ,  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					         "server_time" : Utc ::now ( ) . format ( "%Y-%m-%d %H:%M:%S UTC" ) . to_string ( ) ,   // Run the date/time check as the last item to minimize the difference
  
					 
					 
					         "server_time" : Utc ::now ( ) . format ( "%Y-%m-%d %H:%M:%S UTC" ) . to_string ( ) ,   // Run the server date/time check as late as possible to minimize the time difference
  
				
			 
			
				
				
			
		
	
		
		
	
		
		
			
				
					 
					 
					 
					 
					 
					         "ntp_time" : get_ntp_time ( has_http_access ) . await ,   // Run the ntp check as late as possible to minimize the time difference
  
				
			 
			
		
	
		
		
			
				
					 
					 
					     } ) ;  
					 
					 
					     } ) ;  
				
			 
			
		
	
		
		
			
				
					 
					 
					
 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					 
					 
					     let   text   =   AdminTemplateData ::new ( "admin/diagnostics" ,   diagnostics_json ) . render ( ) ? ;  
					 
					 
					     let   text   =   AdminTemplateData ::new ( "admin/diagnostics" ,   diagnostics_json ) . render ( ) ? ;