6
6
7
7
use std:: sync:: { Arc , LazyLock } ;
8
8
9
- use axum:: {
10
- Json ,
11
- extract:: { State , rejection:: JsonRejection } ,
12
- response:: IntoResponse ,
13
- } ;
14
- use axum_extra:: { extract:: WithRejection , typed_header:: TypedHeader } ;
9
+ use axum:: { Json , extract:: State , response:: IntoResponse } ;
10
+ use axum_extra:: typed_header:: TypedHeader ;
15
11
use chrono:: Duration ;
16
12
use hyper:: StatusCode ;
17
13
use mas_axum_utils:: sentry:: SentryEventID ;
@@ -34,7 +30,7 @@ use serde_with::{DurationMilliSeconds, serde_as, skip_serializing_none};
34
30
use thiserror:: Error ;
35
31
use zeroize:: Zeroizing ;
36
32
37
- use super :: MatrixError ;
33
+ use super :: { MatrixError , MatrixJsonBody } ;
38
34
use crate :: {
39
35
BoundActivityTracker , Limiter , METER , RequesterFingerprint , impl_from_error_for_route,
40
36
passwords:: PasswordManager , rate_limit:: PasswordCheckLimitedError ,
@@ -206,9 +202,6 @@ pub enum RouteError {
206
202
#[ error( "invalid login token" ) ]
207
203
InvalidLoginToken ,
208
204
209
- #[ error( transparent) ]
210
- InvalidJsonBody ( #[ from] JsonRejection ) ,
211
-
212
205
#[ error( "failed to provision device" ) ]
213
206
ProvisionDeviceFailed ( #[ source] anyhow:: Error ) ,
214
207
}
@@ -230,26 +223,6 @@ impl IntoResponse for RouteError {
230
223
error : "Too many login attempts" ,
231
224
status : StatusCode :: TOO_MANY_REQUESTS ,
232
225
} ,
233
- Self :: InvalidJsonBody ( JsonRejection :: MissingJsonContentType ( _) ) => MatrixError {
234
- errcode : "M_NOT_JSON" ,
235
- error : "Invalid Content-Type header: expected application/json" ,
236
- status : StatusCode :: BAD_REQUEST ,
237
- } ,
238
- Self :: InvalidJsonBody ( JsonRejection :: JsonSyntaxError ( _) ) => MatrixError {
239
- errcode : "M_NOT_JSON" ,
240
- error : "Body is not a valid JSON document" ,
241
- status : StatusCode :: BAD_REQUEST ,
242
- } ,
243
- Self :: InvalidJsonBody ( JsonRejection :: JsonDataError ( _) ) => MatrixError {
244
- errcode : "M_BAD_JSON" ,
245
- error : "JSON fields are not valid" ,
246
- status : StatusCode :: BAD_REQUEST ,
247
- } ,
248
- Self :: InvalidJsonBody ( _) => MatrixError {
249
- errcode : "M_UNKNOWN" ,
250
- error : "Unknown error while parsing JSON body" ,
251
- status : StatusCode :: BAD_REQUEST ,
252
- } ,
253
226
Self :: Unsupported => MatrixError {
254
227
errcode : "M_UNKNOWN" ,
255
228
error : "Invalid login type" ,
@@ -300,7 +273,7 @@ pub(crate) async fn post(
300
273
State ( limiter) : State < Limiter > ,
301
274
requester : RequesterFingerprint ,
302
275
user_agent : Option < TypedHeader < headers:: UserAgent > > ,
303
- WithRejection ( Json ( input) , _ ) : WithRejection < Json < RequestBody > , RouteError > ,
276
+ MatrixJsonBody ( input) : MatrixJsonBody < RequestBody > ,
304
277
) -> Result < impl IntoResponse , RouteError > {
305
278
let user_agent = user_agent. map ( |ua| UserAgent :: parse ( ua. as_str ( ) . to_owned ( ) ) ) ;
306
279
let login_type = input. credentials . login_type ( ) ;
@@ -662,12 +635,12 @@ mod tests {
662
635
response. assert_status ( StatusCode :: BAD_REQUEST ) ;
663
636
let body: serde_json:: Value = response. json ( ) ;
664
637
665
- insta:: assert_json_snapshot!( body, @r### "
638
+ insta:: assert_json_snapshot!( body, @r#"
666
639
{
667
640
"errcode": "M_NOT_JSON",
668
- "error": "Invalid Content-Type header: expected application/json "
641
+ "error": "Body is not a valid JSON document "
669
642
}
670
- "### ) ;
643
+ "# ) ;
671
644
672
645
// Missing keys in body
673
646
let request = Request :: post ( "/_matrix/client/v3/login" ) . json ( serde_json:: json!( { } ) ) ;
@@ -902,6 +875,37 @@ mod tests {
902
875
assert_eq ! ( body, old_body) ;
903
876
}
904
877
878
+ /// Test that we can send a login request without a Content-Type header
879
+ #[ sqlx:: test( migrator = "mas_storage_pg::MIGRATOR" ) ]
880
+ async fn test_no_content_type ( pool : PgPool ) {
881
+ setup ( ) ;
882
+ let state = TestState :: from_pool ( pool) . await . unwrap ( ) ;
883
+
884
+ user_with_password ( & state, "alice" , "password" ) . await ;
885
+ // Try without a Content-Type header
886
+ let mut request = Request :: post ( "/_matrix/client/v3/login" ) . json ( serde_json:: json!( {
887
+ "type" : "m.login.password" ,
888
+ "identifier" : {
889
+ "type" : "m.id.user" ,
890
+ "user" : "alice" ,
891
+ } ,
892
+ "password" : "password" ,
893
+ } ) ) ;
894
+ request. headers_mut ( ) . remove ( hyper:: header:: CONTENT_TYPE ) ;
895
+
896
+ let response = state. request ( request) . await ;
897
+ response. assert_status ( StatusCode :: OK ) ;
898
+
899
+ let body: serde_json:: Value = response. json ( ) ;
900
+ insta:: assert_json_snapshot!( body, @r###"
901
+ {
902
+ "access_token": "mct_16tugBE5Ta9LIWoSJaAEHHq2g3fx8S_alcBB4",
903
+ "device_id": "ZGpSvYQqlq",
904
+ "user_id": "@alice:example.com"
905
+ }
906
+ "### ) ;
907
+ }
908
+
905
909
/// Test that a user can login with a password using the Matrix
906
910
/// compatibility API, using a MXID as identifier
907
911
#[ sqlx:: test( migrator = "mas_storage_pg::MIGRATOR" ) ]
0 commit comments