6
6
7
7
#![ allow( clippy:: module_name_repetitions) ]
8
8
9
- use std:: sync:: Arc ;
9
+ use std:: { net :: IpAddr , ops :: Deref , sync:: Arc } ;
10
10
11
11
use async_graphql:: {
12
12
extensions:: Tracing ,
@@ -238,9 +238,10 @@ async fn get_requester(
238
238
activity_tracker : & BoundActivityTracker ,
239
239
mut repo : BoxRepository ,
240
240
session_info : SessionInfo ,
241
+ user_agent : Option < String > ,
241
242
token : Option < & str > ,
242
243
) -> Result < Requester , RouteError > {
243
- let requester = if let Some ( token) = token {
244
+ let entity = if let Some ( token) = token {
244
245
// If we haven't enabled undocumented_oauth2_access on the listener, we bail out
245
246
if !undocumented_oauth2_access {
246
247
return Err ( RouteError :: InvalidToken ) ;
@@ -285,7 +286,7 @@ async fn get_requester(
285
286
return Err ( RouteError :: MissingScope ) ;
286
287
}
287
288
288
- Requester :: OAuth2Session ( Box :: new ( ( session, user) ) )
289
+ RequestingEntity :: OAuth2Session ( Box :: new ( ( session, user) ) )
289
290
} else {
290
291
let maybe_session = session_info. load_session ( & mut repo) . await ?;
291
292
@@ -295,8 +296,15 @@ async fn get_requester(
295
296
. await ;
296
297
}
297
298
298
- Requester :: from ( maybe_session)
299
+ RequestingEntity :: from ( maybe_session)
299
300
} ;
301
+
302
+ let requester = Requester {
303
+ entity,
304
+ ip_address : activity_tracker. ip ( ) ,
305
+ user_agent,
306
+ } ;
307
+
300
308
repo. cancel ( ) . await ?;
301
309
Ok ( requester)
302
310
}
@@ -312,20 +320,22 @@ pub async fn post(
312
320
cookie_jar : CookieJar ,
313
321
content_type : Option < TypedHeader < ContentType > > ,
314
322
authorization : Option < TypedHeader < Authorization < Bearer > > > ,
315
- requester_fingerprint : RequesterFingerprint ,
323
+ user_agent : Option < TypedHeader < headers :: UserAgent > > ,
316
324
body : Body ,
317
325
) -> Result < impl IntoResponse , RouteError > {
318
326
let body = body. into_data_stream ( ) ;
319
327
let token = authorization
320
328
. as_ref ( )
321
329
. map ( |TypedHeader ( Authorization ( bearer) ) | bearer. token ( ) ) ;
330
+ let user_agent = user_agent. map ( |TypedHeader ( h) | h. to_string ( ) ) ;
322
331
let ( session_info, _cookie_jar) = cookie_jar. session_info ( ) ;
323
332
let requester = get_requester (
324
333
undocumented_oauth2_access,
325
334
& clock,
326
335
& activity_tracker,
327
336
repo,
328
337
session_info,
338
+ user_agent,
329
339
token,
330
340
)
331
341
. await ?;
@@ -339,7 +349,6 @@ pub async fn post(
339
349
MultipartOptions :: default ( ) ,
340
350
)
341
351
. await ?
342
- . data ( requester_fingerprint)
343
352
. data ( requester) ; // XXX: this should probably return another error response?
344
353
345
354
let span = span_for_graphql_request ( & request) ;
@@ -366,26 +375,27 @@ pub async fn get(
366
375
activity_tracker : BoundActivityTracker ,
367
376
cookie_jar : CookieJar ,
368
377
authorization : Option < TypedHeader < Authorization < Bearer > > > ,
369
- requester_fingerprint : RequesterFingerprint ,
378
+ user_agent : Option < TypedHeader < headers :: UserAgent > > ,
370
379
RawQuery ( query) : RawQuery ,
371
380
) -> Result < impl IntoResponse , FancyError > {
372
381
let token = authorization
373
382
. as_ref ( )
374
383
. map ( |TypedHeader ( Authorization ( bearer) ) | bearer. token ( ) ) ;
384
+ let user_agent = user_agent. map ( |TypedHeader ( h) | h. to_string ( ) ) ;
375
385
let ( session_info, _cookie_jar) = cookie_jar. session_info ( ) ;
376
386
let requester = get_requester (
377
387
undocumented_oauth2_access,
378
388
& clock,
379
389
& activity_tracker,
380
390
repo,
381
391
session_info,
392
+ user_agent,
382
393
token,
383
394
)
384
395
. await ?;
385
396
386
- let request = async_graphql:: http:: parse_query_string ( & query. unwrap_or_default ( ) ) ?
387
- . data ( requester)
388
- . data ( requester_fingerprint) ;
397
+ let request =
398
+ async_graphql:: http:: parse_query_string ( & query. unwrap_or_default ( ) ) ?. data ( requester) ;
389
399
390
400
let span = span_for_graphql_request ( & request) ;
391
401
let response = schema. execute ( request) . instrument ( span) . await ;
@@ -417,9 +427,40 @@ pub fn schema_builder() -> SchemaBuilder {
417
427
. register_output_type :: < CreationEvent > ( )
418
428
}
419
429
430
+ pub struct Requester {
431
+ entity : RequestingEntity ,
432
+ ip_address : Option < IpAddr > ,
433
+ user_agent : Option < String > ,
434
+ }
435
+
436
+ impl Requester {
437
+ pub fn fingerprint ( & self ) -> RequesterFingerprint {
438
+ if let Some ( ip) = self . ip_address {
439
+ RequesterFingerprint :: new ( ip)
440
+ } else {
441
+ RequesterFingerprint :: EMPTY
442
+ }
443
+ }
444
+
445
+ pub fn for_policy ( & self ) -> mas_policy:: Requester {
446
+ mas_policy:: Requester {
447
+ ip_address : self . ip_address ,
448
+ user_agent : self . user_agent . clone ( ) ,
449
+ }
450
+ }
451
+ }
452
+
453
+ impl Deref for Requester {
454
+ type Target = RequestingEntity ;
455
+
456
+ fn deref ( & self ) -> & Self :: Target {
457
+ & self . entity
458
+ }
459
+ }
460
+
420
461
/// The identity of the requester.
421
462
#[ derive( Debug , Clone , Default , PartialEq , Eq ) ]
422
- pub enum Requester {
463
+ pub enum RequestingEntity {
423
464
/// The requester presented no authentication information.
424
465
#[ default]
425
466
Anonymous ,
@@ -480,7 +521,7 @@ impl OwnerId for UserId {
480
521
}
481
522
}
482
523
483
- impl Requester {
524
+ impl RequestingEntity {
484
525
fn browser_session ( & self ) -> Option < & BrowserSession > {
485
526
match self {
486
527
Self :: BrowserSession ( session) => Some ( session) ,
@@ -532,17 +573,21 @@ impl Requester {
532
573
Self :: BrowserSession ( _) | Self :: Anonymous => false ,
533
574
}
534
575
}
576
+
577
+ fn is_unauthenticated ( & self ) -> bool {
578
+ matches ! ( self , Self :: Anonymous )
579
+ }
535
580
}
536
581
537
- impl From < BrowserSession > for Requester {
582
+ impl From < BrowserSession > for RequestingEntity {
538
583
fn from ( session : BrowserSession ) -> Self {
539
584
Self :: BrowserSession ( Box :: new ( session) )
540
585
}
541
586
}
542
587
543
- impl < T > From < Option < T > > for Requester
588
+ impl < T > From < Option < T > > for RequestingEntity
544
589
where
545
- T : Into < Requester > ,
590
+ T : Into < RequestingEntity > ,
546
591
{
547
592
fn from ( session : Option < T > ) -> Self {
548
593
session. map ( Into :: into) . unwrap_or_default ( )
0 commit comments