@@ -101,12 +101,17 @@ use torrust_tracker_primitives::swarm_metadata::SwarmMetadata;
101
101
102
102
use super :: torrent:: repository:: in_memory:: InMemoryTorrentRepository ;
103
103
use super :: torrent:: repository:: persisted:: DatabasePersistentTorrentRepository ;
104
+ use crate :: error:: AnnounceError ;
105
+ use crate :: whitelist:: authorization:: WhitelistAuthorization ;
104
106
105
107
/// Handles `announce` requests from `BitTorrent` clients.
106
108
pub struct AnnounceHandler {
107
109
/// The tracker configuration.
108
110
config : Core ,
109
111
112
+ /// Service for authorizing access to whitelisted torrents.
113
+ whitelist_authorization : Arc < WhitelistAuthorization > ,
114
+
110
115
/// Repository for in-memory torrent data.
111
116
in_memory_torrent_repository : Arc < InMemoryTorrentRepository > ,
112
117
@@ -119,10 +124,12 @@ impl AnnounceHandler {
119
124
#[ must_use]
120
125
pub fn new (
121
126
config : & Core ,
127
+ whitelist_authorization : & Arc < WhitelistAuthorization > ,
122
128
in_memory_torrent_repository : & Arc < InMemoryTorrentRepository > ,
123
129
db_torrent_repository : & Arc < DatabasePersistentTorrentRepository > ,
124
130
) -> Self {
125
131
Self {
132
+ whitelist_authorization : whitelist_authorization. clone ( ) ,
126
133
config : config. clone ( ) ,
127
134
in_memory_torrent_repository : in_memory_torrent_repository. clone ( ) ,
128
135
db_torrent_repository : db_torrent_repository. clone ( ) ,
@@ -143,27 +150,23 @@ impl AnnounceHandler {
143
150
/// # Returns
144
151
///
145
152
/// An `AnnounceData` struct containing the list of peers, swarm statistics, and tracker policy.
146
- pub fn announce (
153
+ ///
154
+ /// # Errors
155
+ ///
156
+ /// Returns an error if the tracker is running in `listed` mode and the
157
+ /// torrent is not whitelisted.
158
+ pub async fn announce (
147
159
& self ,
148
160
info_hash : & InfoHash ,
149
161
peer : & mut peer:: Peer ,
150
162
remote_client_ip : & IpAddr ,
151
163
peers_wanted : & PeersWanted ,
152
- ) -> AnnounceData {
164
+ ) -> Result < AnnounceData , AnnounceError > {
153
165
// code-review: maybe instead of mutating the peer we could just return
154
166
// a tuple with the new peer and the announce data: (Peer, AnnounceData).
155
167
// It could even be a different struct: `StoredPeer` or `PublicPeer`.
156
168
157
- // code-review: in the `scrape` function we perform an authorization check.
158
- // We check if the torrent is whitelisted. Should we also check authorization here?
159
- // I think so because the `Tracker` has the responsibility for checking authentication and authorization.
160
- // The `Tracker` has delegated that responsibility to the handlers
161
- // (because we want to return a friendly error response) but that does not mean we should
162
- // double-check authorization at this domain level too.
163
- // I would propose to return a `Result<AnnounceData, Error>` here.
164
- // Besides, regarding authentication the `Tracker` is also responsible for authentication but
165
- // we are actually handling authentication at the handlers level. So I would extract that
166
- // responsibility into another authentication service.
169
+ self . whitelist_authorization . authorize ( info_hash) . await ?;
167
170
168
171
tracing:: debug!( "Before: {peer:?}" ) ;
169
172
peer. change_ip ( & assign_ip_address_to_peer ( remote_client_ip, self . config . net . external_ip ) ) ;
@@ -175,11 +178,11 @@ impl AnnounceHandler {
175
178
. in_memory_torrent_repository
176
179
. get_peers_for ( info_hash, peer, peers_wanted. limit ( ) ) ;
177
180
178
- AnnounceData {
181
+ Ok ( AnnounceData {
179
182
peers,
180
183
stats,
181
184
policy : self . config . announce_policy ,
182
- }
185
+ } )
183
186
}
184
187
185
188
/// Updates the torrent data in memory, persists statistics if needed, and
@@ -461,8 +464,10 @@ mod tests {
461
464
462
465
let mut peer = sample_peer ( ) ;
463
466
464
- let announce_data =
465
- announce_handler. announce ( & sample_info_hash ( ) , & mut peer, & peer_ip ( ) , & PeersWanted :: AsManyAsPossible ) ;
467
+ let announce_data = announce_handler
468
+ . announce ( & sample_info_hash ( ) , & mut peer, & peer_ip ( ) , & PeersWanted :: AsManyAsPossible )
469
+ . await
470
+ . unwrap ( ) ;
466
471
467
472
assert_eq ! ( announce_data. peers, vec![ ] ) ;
468
473
}
@@ -472,16 +477,21 @@ mod tests {
472
477
let ( announce_handler, _scrape_handler) = public_tracker ( ) ;
473
478
474
479
let mut previously_announced_peer = sample_peer_1 ( ) ;
475
- announce_handler. announce (
476
- & sample_info_hash ( ) ,
477
- & mut previously_announced_peer,
478
- & peer_ip ( ) ,
479
- & PeersWanted :: AsManyAsPossible ,
480
- ) ;
480
+ announce_handler
481
+ . announce (
482
+ & sample_info_hash ( ) ,
483
+ & mut previously_announced_peer,
484
+ & peer_ip ( ) ,
485
+ & PeersWanted :: AsManyAsPossible ,
486
+ )
487
+ . await
488
+ . unwrap ( ) ;
481
489
482
490
let mut peer = sample_peer_2 ( ) ;
483
- let announce_data =
484
- announce_handler. announce ( & sample_info_hash ( ) , & mut peer, & peer_ip ( ) , & PeersWanted :: AsManyAsPossible ) ;
491
+ let announce_data = announce_handler
492
+ . announce ( & sample_info_hash ( ) , & mut peer, & peer_ip ( ) , & PeersWanted :: AsManyAsPossible )
493
+ . await
494
+ . unwrap ( ) ;
485
495
486
496
assert_eq ! ( announce_data. peers, vec![ Arc :: new( previously_announced_peer) ] ) ;
487
497
}
@@ -491,24 +501,32 @@ mod tests {
491
501
let ( announce_handler, _scrape_handler) = public_tracker ( ) ;
492
502
493
503
let mut previously_announced_peer_1 = sample_peer_1 ( ) ;
494
- announce_handler. announce (
495
- & sample_info_hash ( ) ,
496
- & mut previously_announced_peer_1,
497
- & peer_ip ( ) ,
498
- & PeersWanted :: AsManyAsPossible ,
499
- ) ;
504
+ announce_handler
505
+ . announce (
506
+ & sample_info_hash ( ) ,
507
+ & mut previously_announced_peer_1,
508
+ & peer_ip ( ) ,
509
+ & PeersWanted :: AsManyAsPossible ,
510
+ )
511
+ . await
512
+ . unwrap ( ) ;
500
513
501
514
let mut previously_announced_peer_2 = sample_peer_2 ( ) ;
502
- announce_handler. announce (
503
- & sample_info_hash ( ) ,
504
- & mut previously_announced_peer_2,
505
- & peer_ip ( ) ,
506
- & PeersWanted :: AsManyAsPossible ,
507
- ) ;
515
+ announce_handler
516
+ . announce (
517
+ & sample_info_hash ( ) ,
518
+ & mut previously_announced_peer_2,
519
+ & peer_ip ( ) ,
520
+ & PeersWanted :: AsManyAsPossible ,
521
+ )
522
+ . await
523
+ . unwrap ( ) ;
508
524
509
525
let mut peer = sample_peer_3 ( ) ;
510
- let announce_data =
511
- announce_handler. announce ( & sample_info_hash ( ) , & mut peer, & peer_ip ( ) , & PeersWanted :: only ( 1 ) ) ;
526
+ let announce_data = announce_handler
527
+ . announce ( & sample_info_hash ( ) , & mut peer, & peer_ip ( ) , & PeersWanted :: only ( 1 ) )
528
+ . await
529
+ . unwrap ( ) ;
512
530
513
531
// It should return only one peer. There is no guarantee on
514
532
// which peer will be returned.
@@ -530,8 +548,10 @@ mod tests {
530
548
531
549
let mut peer = seeder ( ) ;
532
550
533
- let announce_data =
534
- announce_handler. announce ( & sample_info_hash ( ) , & mut peer, & peer_ip ( ) , & PeersWanted :: AsManyAsPossible ) ;
551
+ let announce_data = announce_handler
552
+ . announce ( & sample_info_hash ( ) , & mut peer, & peer_ip ( ) , & PeersWanted :: AsManyAsPossible )
553
+ . await
554
+ . unwrap ( ) ;
535
555
536
556
assert_eq ! ( announce_data. stats. complete, 1 ) ;
537
557
}
@@ -542,8 +562,10 @@ mod tests {
542
562
543
563
let mut peer = leecher ( ) ;
544
564
545
- let announce_data =
546
- announce_handler. announce ( & sample_info_hash ( ) , & mut peer, & peer_ip ( ) , & PeersWanted :: AsManyAsPossible ) ;
565
+ let announce_data = announce_handler
566
+ . announce ( & sample_info_hash ( ) , & mut peer, & peer_ip ( ) , & PeersWanted :: AsManyAsPossible )
567
+ . await
568
+ . unwrap ( ) ;
547
569
548
570
assert_eq ! ( announce_data. stats. incomplete, 1 ) ;
549
571
}
@@ -554,20 +576,26 @@ mod tests {
554
576
555
577
// We have to announce with "started" event because peer does not count if peer was not previously known
556
578
let mut started_peer = started_peer ( ) ;
557
- announce_handler. announce (
558
- & sample_info_hash ( ) ,
559
- & mut started_peer,
560
- & peer_ip ( ) ,
561
- & PeersWanted :: AsManyAsPossible ,
562
- ) ;
579
+ announce_handler
580
+ . announce (
581
+ & sample_info_hash ( ) ,
582
+ & mut started_peer,
583
+ & peer_ip ( ) ,
584
+ & PeersWanted :: AsManyAsPossible ,
585
+ )
586
+ . await
587
+ . unwrap ( ) ;
563
588
564
589
let mut completed_peer = completed_peer ( ) ;
565
- let announce_data = announce_handler. announce (
566
- & sample_info_hash ( ) ,
567
- & mut completed_peer,
568
- & peer_ip ( ) ,
569
- & PeersWanted :: AsManyAsPossible ,
570
- ) ;
590
+ let announce_data = announce_handler
591
+ . announce (
592
+ & sample_info_hash ( ) ,
593
+ & mut completed_peer,
594
+ & peer_ip ( ) ,
595
+ & PeersWanted :: AsManyAsPossible ,
596
+ )
597
+ . await
598
+ . unwrap ( ) ;
571
599
572
600
assert_eq ! ( announce_data. stats. downloaded, 1 ) ;
573
601
}
@@ -590,10 +618,12 @@ mod tests {
590
618
use crate :: torrent:: manager:: TorrentsManager ;
591
619
use crate :: torrent:: repository:: in_memory:: InMemoryTorrentRepository ;
592
620
use crate :: torrent:: repository:: persisted:: DatabasePersistentTorrentRepository ;
621
+ use crate :: whitelist:: authorization:: WhitelistAuthorization ;
622
+ use crate :: whitelist:: repository:: in_memory:: InMemoryWhitelist ;
593
623
594
624
#[ tokio:: test]
595
625
async fn it_should_persist_the_number_of_completed_peers_for_all_torrents_into_the_database ( ) {
596
- let mut config = configuration:: ephemeral_listed ( ) ;
626
+ let mut config = configuration:: ephemeral_public ( ) ;
597
627
598
628
config. core . tracker_policy . persistent_torrent_completed_stat = true ;
599
629
@@ -605,8 +635,11 @@ mod tests {
605
635
& in_memory_torrent_repository,
606
636
& db_torrent_repository,
607
637
) ) ;
638
+ let in_memory_whitelist = Arc :: new ( InMemoryWhitelist :: default ( ) ) ;
639
+ let whitelist_authorization = Arc :: new ( WhitelistAuthorization :: new ( & config. core , & in_memory_whitelist. clone ( ) ) ) ;
608
640
let announce_handler = Arc :: new ( AnnounceHandler :: new (
609
641
& config. core ,
642
+ & whitelist_authorization,
610
643
& in_memory_torrent_repository,
611
644
& db_torrent_repository,
612
645
) ) ;
@@ -616,11 +649,17 @@ mod tests {
616
649
let mut peer = sample_peer ( ) ;
617
650
618
651
peer. event = AnnounceEvent :: Started ;
619
- let announce_data = announce_handler. announce ( & info_hash, & mut peer, & peer_ip ( ) , & PeersWanted :: AsManyAsPossible ) ;
652
+ let announce_data = announce_handler
653
+ . announce ( & info_hash, & mut peer, & peer_ip ( ) , & PeersWanted :: AsManyAsPossible )
654
+ . await
655
+ . unwrap ( ) ;
620
656
assert_eq ! ( announce_data. stats. downloaded, 0 ) ;
621
657
622
658
peer. event = AnnounceEvent :: Completed ;
623
- let announce_data = announce_handler. announce ( & info_hash, & mut peer, & peer_ip ( ) , & PeersWanted :: AsManyAsPossible ) ;
659
+ let announce_data = announce_handler
660
+ . announce ( & info_hash, & mut peer, & peer_ip ( ) , & PeersWanted :: AsManyAsPossible )
661
+ . await
662
+ . unwrap ( ) ;
624
663
assert_eq ! ( announce_data. stats. downloaded, 1 ) ;
625
664
626
665
// Remove the newly updated torrent from memory
0 commit comments