Skip to content

Commit bc509f4

Browse files
committed
fix: [#488] torrent without tracker keys for open tracker
Tracker HTTP URL: http://localhost:7070 - announce: "http://localhost:7070". - announce_list: "http://localhost:7070" and keeps the original URLs in the uploaded torrent. Tracker UDP URL: udp://localhost:6969 - announce: "udp://localhost:7070". - announce_list: "udp://localhost:7070" and keeps the original URLs in the uploaded torrent. Tracker HTTP URL: http://localhost:7070 - announce: "http://localhost:7070/**KEY**". - announce_list: "http://localhost:7070/**KEY**" and keeps the original URLs in the uploaded torrent. Tracker UDP URL: udp://localhost:6969 - announce: "udp://localhost:7070/**KEY**". - announce_list: "udp://localhost:7070/**KEY**" and keeps the original URLs in the uploaded torrent. It returns an 505 error if it can't get the user's tracker keys. TODO: - The application should not start with close tracker and UDP url in the configuration. - THe API should return 503 instead of 500 when it can't connect to the tracker.
1 parent 70329ea commit bc509f4

File tree

4 files changed

+53
-63
lines changed

4 files changed

+53
-63
lines changed

src/config.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,13 @@ impl Default for TrackerMode {
144144
}
145145
}
146146

147+
impl TrackerMode {
148+
#[must_use]
149+
pub fn is_open(&self) -> bool {
150+
matches!(self, TrackerMode::Public | TrackerMode::Whitelisted)
151+
}
152+
}
153+
147154
/// Configuration for the associated tracker.
148155
#[derive(Debug, Clone, Serialize, Deserialize)]
149156
pub struct Tracker {

src/models/torrent_file.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,11 +93,37 @@ impl Torrent {
9393
}
9494
}
9595

96+
/// Includes the tracker URL a the main tracker in the torrent.
97+
///
98+
/// It will be the URL in the `announce` field and also the first URL in the
99+
/// `announce_list`.
100+
///
101+
/// In practice, it's common for the `announce_list` to include the URL from
102+
/// the `announce` field as one of its entries, often in the first tier,
103+
/// to ensure that this primary tracker is always used. However, this is not
104+
/// a strict requirement of the `BitTorrent` protocol; it's more of a
105+
/// convention followed by some torrent creators for redundancy and to
106+
/// ensure better availability of trackers.
107+
pub fn include_url_as_main_tracker(&mut self, tracker_url: &str) {
108+
self.set_announce_to(tracker_url);
109+
self.add_url_to_announce_list(tracker_url);
110+
}
111+
96112
/// Sets the announce url to the tracker url.
97113
pub fn set_announce_to(&mut self, tracker_url: &str) {
98114
self.announce = Some(tracker_url.to_owned());
99115
}
100116

117+
/// Adds a new tracker URL to the `announce_list` if it doesn't exist.
118+
pub fn add_url_to_announce_list(&mut self, tracker_url: &str) {
119+
if let Some(list) = &mut self.announce_list {
120+
if !list.iter().any(|inner_list| inner_list.contains(&tracker_url.to_owned())) {
121+
let vec = vec![tracker_url.to_owned()];
122+
list.insert(0, vec);
123+
}
124+
}
125+
}
126+
101127
/// Removes all other trackers if the torrent is private.
102128
pub fn reset_announce_list_if_private(&mut self) {
103129
if self.is_private() {

src/services/torrent.rs

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use serde_derive::{Deserialize, Serialize};
66

77
use super::category::DbCategoryRepository;
88
use super::user::DbUserRepository;
9-
use crate::config::Configuration;
9+
use crate::config::{Configuration, TrackerMode};
1010
use crate::databases::database::{Database, Error, Sorting};
1111
use crate::errors::ServiceError;
1212
use crate::models::category::CategoryId;
@@ -257,24 +257,18 @@ impl Index {
257257
let mut torrent = self.torrent_repository.get_by_info_hash(info_hash).await?;
258258

259259
let tracker_url = self.get_tracker_url().await;
260+
let tracker_mode = self.get_tracker_mode().await;
260261

261-
// Add personal tracker url or default tracker url
262-
match opt_user_id {
263-
Some(user_id) => {
264-
let personal_announce_url = self
265-
.tracker_service
266-
.get_personal_announce_url(user_id)
267-
.await
268-
.unwrap_or(tracker_url);
269-
torrent.announce = Some(personal_announce_url.clone());
270-
if let Some(list) = &mut torrent.announce_list {
271-
let vec = vec![personal_announce_url];
272-
list.insert(0, vec);
273-
}
274-
}
275-
None => {
276-
torrent.announce = Some(tracker_url);
277-
}
262+
// code-review: should we remove all tracker URLs in the `announce_list`
263+
// when the tracker is not open?
264+
265+
if tracker_mode.is_open() {
266+
torrent.include_url_as_main_tracker(&tracker_url);
267+
} else if let Some(authenticated_user_id) = opt_user_id {
268+
let personal_announce_url = self.tracker_service.get_personal_announce_url(authenticated_user_id).await?;
269+
torrent.include_url_as_main_tracker(&personal_announce_url);
270+
} else {
271+
torrent.include_url_as_main_tracker(&tracker_url);
278272
}
279273

280274
Ok(torrent)
@@ -362,6 +356,9 @@ impl Index {
362356

363357
let tracker_url = self.get_tracker_url().await;
364358

359+
// todo: duplicate logic. We have to check the same when we download
360+
// the torrent file.
361+
365362
// add tracker url
366363
match opt_user_id {
367364
Some(user_id) => {
@@ -513,6 +510,11 @@ impl Index {
513510
let settings = self.configuration.settings.read().await;
514511
settings.tracker.url.clone()
515512
}
513+
514+
async fn get_tracker_mode(&self) -> TrackerMode {
515+
let settings = self.configuration.settings.read().await;
516+
settings.tracker.mode.clone()
517+
}
516518
}
517519

518520
pub struct DbTorrentRepository {

tests/e2e/web/api/v1/contexts/torrent/contract.rs

Lines changed: 0 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -473,15 +473,6 @@ mod for_guests {
473473

474474
mod for_authenticated_users {
475475

476-
use torrust_index::utils::parse_torrent::decode_torrent;
477-
use torrust_index::web::api;
478-
479-
use crate::common::client::Client;
480-
use crate::e2e::environment::TestEnv;
481-
use crate::e2e::web::api::v1::contexts::torrent::asserts::{build_announce_url, get_user_tracker_key};
482-
use crate::e2e::web::api::v1::contexts::torrent::steps::upload_random_torrent_to_index;
483-
use crate::e2e::web::api::v1::contexts::user::steps::new_logged_in_user;
484-
485476
mod uploading_a_torrent {
486477

487478
use torrust_index::web::api;
@@ -779,42 +770,6 @@ mod for_authenticated_users {
779770
}
780771
}
781772

782-
#[tokio::test]
783-
async fn it_should_allow_authenticated_users_to_download_a_torrent_with_a_personal_announce_url() {
784-
let mut env = TestEnv::new();
785-
env.start(api::Version::V1).await;
786-
787-
if !env.provides_a_tracker() {
788-
println!("test skipped. It requires a tracker to be running.");
789-
return;
790-
}
791-
792-
// Given a previously uploaded torrent
793-
let uploader = new_logged_in_user(&env).await;
794-
let (test_torrent, _torrent_listed_in_index) = upload_random_torrent_to_index(&uploader, &env).await;
795-
796-
// And a logged in user who is going to download the torrent
797-
let downloader = new_logged_in_user(&env).await;
798-
let client = Client::authenticated(&env.server_socket_addr().unwrap(), &downloader.token);
799-
800-
// When the user downloads the torrent
801-
let response = client.download_torrent(&test_torrent.file_info_hash()).await;
802-
803-
let torrent = decode_torrent(&response.bytes).expect("could not decode downloaded torrent");
804-
805-
// Then the torrent should have the personal announce URL
806-
let tracker_key = get_user_tracker_key(&downloader, &env)
807-
.await
808-
.expect("uploader should have a valid tracker key");
809-
810-
let tracker_url = env.server_settings().unwrap().tracker.url;
811-
812-
assert_eq!(
813-
torrent.announce.unwrap(),
814-
build_announce_url(&tracker_url, &Some(tracker_key))
815-
);
816-
}
817-
818773
mod and_non_admins {
819774

820775
use torrust_index::web::api;

0 commit comments

Comments
 (0)