@@ -41,7 +41,8 @@ async fn get_user_id(state: &web::Data<AppState>, recovery_key: Uuid) -> actix_w
4141 . get_result ( & mut conn)
4242 {
4343 Ok ( t) => Ok ( t) ,
44- Err ( NotFound ) => Err ( Error :: Unauthorized ) ,
44+ // Provide a clearer error than generic Unauthorized when the token does not exist or was already used.
45+ Err ( NotFound ) => Err ( Error :: InvalidRecoveryToken ) ,
4546 Err ( _err) => Err ( Error :: InternalError ) ,
4647 }
4748 } )
@@ -381,4 +382,34 @@ mod tests {
381382 assert_eq ! ( res. len( ) , 0 ) ;
382383 }
383384 }
385+
386+ #[ actix_web:: test]
387+ async fn test_invalid_recovery_token_returns_clear_error ( ) {
388+ let ( _user, _mail) = TestUser :: random ( ) . await ;
389+ // Don't start recovery so the token stays unknown.
390+ let body = RecoverySchema {
391+ recovery_key : uuid:: Uuid :: new_v4 ( ) . to_string ( ) ,
392+ new_login_key : vec ! [ ] ,
393+ new_login_salt : vec ! [ ] ,
394+ new_encrypted_secret : vec ! [ ] ,
395+ new_secret_nonce : vec ! [ ] ,
396+ new_secret_salt : vec ! [ ] ,
397+ reused_secret : true ,
398+ } ;
399+
400+ let app = App :: new ( ) . configure ( configure) . service ( recovery) ;
401+ let app = test:: init_service ( app) . await ;
402+
403+ let req = TestRequest :: post ( )
404+ . uri ( "/recovery" )
405+ . set_json ( body)
406+ . append_header ( ContentType :: json ( ) )
407+ . to_request ( ) ;
408+
409+ let resp = test:: call_service ( & app, req) . await ;
410+ assert_eq ! ( resp. status( ) , 400 ) ;
411+ let body = test:: read_body ( resp) . await ;
412+ let body_str = String :: from_utf8 ( body. to_vec ( ) ) . unwrap ( ) ;
413+ assert ! ( body_str. contains( "Recovery token unknown" ) ) ;
414+ }
384415}
0 commit comments