Skip to content

Commit

Permalink
fix: [#488] torrent without tracker keys for open tracker
Browse files Browse the repository at this point in the history
When the tracker is open (public or public whitelisted) thre tracker
user's keys should not be included in the downloaded torrent file.

It fails when the Index can't get the user's tracker keys.
  • Loading branch information
josecelano committed Feb 23, 2024
1 parent 70329ea commit 10b3670
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 63 deletions.
7 changes: 7 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,13 @@ impl Default for TrackerMode {
}
}

impl TrackerMode {
#[must_use]
pub fn is_open(&self) -> bool {
matches!(self, TrackerMode::Public | TrackerMode::Whitelisted)
}
}

/// Configuration for the associated tracker.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Tracker {
Expand Down
10 changes: 10 additions & 0 deletions src/models/torrent_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,16 @@ impl Torrent {
self.announce = Some(tracker_url.to_owned());
}

/// Adds a new tracker URL to the `announce_list` if it doesn't exist.
pub fn add_url_to_announce_list(&mut self, tracker_url: &str) {
if let Some(list) = &mut self.announce_list {
if !list.iter().any(|inner_list| inner_list.contains(&tracker_url.to_owned())) {
let vec = vec![tracker_url.to_owned()];
list.insert(0, vec);
}
}
}

/// Removes all other trackers if the torrent is private.
pub fn reset_announce_list_if_private(&mut self) {
if self.is_private() {
Expand Down
40 changes: 22 additions & 18 deletions src/services/torrent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use serde_derive::{Deserialize, Serialize};

use super::category::DbCategoryRepository;
use super::user::DbUserRepository;
use crate::config::Configuration;
use crate::config::{Configuration, TrackerMode};
use crate::databases::database::{Database, Error, Sorting};
use crate::errors::ServiceError;
use crate::models::category::CategoryId;
Expand Down Expand Up @@ -257,24 +257,20 @@ impl Index {
let mut torrent = self.torrent_repository.get_by_info_hash(info_hash).await?;

let tracker_url = self.get_tracker_url().await;
let tracker_mode = self.get_tracker_mode().await;

// Add personal tracker url or default tracker url
match opt_user_id {
Some(user_id) => {
let personal_announce_url = self
.tracker_service
.get_personal_announce_url(user_id)
.await
.unwrap_or(tracker_url);
torrent.announce = Some(personal_announce_url.clone());
if let Some(list) = &mut torrent.announce_list {
let vec = vec![personal_announce_url];
list.insert(0, vec);
}
}
None => {
torrent.announce = Some(tracker_url);
}
// code-review: should we remove all tracker URLs in the `announce_list`
// when the tracker is not open?

if tracker_mode.is_open() {
torrent.set_announce_to(&tracker_url);
} else if let Some(authenticated_user_id) = opt_user_id {
let personal_announce_url = self.tracker_service.get_personal_announce_url(authenticated_user_id).await?;
torrent.set_announce_to(&personal_announce_url);
torrent.add_url_to_announce_list(&personal_announce_url);
} else {
torrent.set_announce_to(&tracker_url);
return Ok(torrent);
}

Ok(torrent)
Expand Down Expand Up @@ -362,6 +358,9 @@ impl Index {

let tracker_url = self.get_tracker_url().await;

// todo: duplicate logic. We have to check the same when we download
// the torrent file.

// add tracker url
match opt_user_id {
Some(user_id) => {
Expand Down Expand Up @@ -513,6 +512,11 @@ impl Index {
let settings = self.configuration.settings.read().await;
settings.tracker.url.clone()
}

async fn get_tracker_mode(&self) -> TrackerMode {
let settings = self.configuration.settings.read().await;
settings.tracker.mode.clone()
}
}

pub struct DbTorrentRepository {
Expand Down
45 changes: 0 additions & 45 deletions tests/e2e/web/api/v1/contexts/torrent/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -473,15 +473,6 @@ mod for_guests {

mod for_authenticated_users {

use torrust_index::utils::parse_torrent::decode_torrent;
use torrust_index::web::api;

use crate::common::client::Client;
use crate::e2e::environment::TestEnv;
use crate::e2e::web::api::v1::contexts::torrent::asserts::{build_announce_url, get_user_tracker_key};
use crate::e2e::web::api::v1::contexts::torrent::steps::upload_random_torrent_to_index;
use crate::e2e::web::api::v1::contexts::user::steps::new_logged_in_user;

mod uploading_a_torrent {

use torrust_index::web::api;
Expand Down Expand Up @@ -779,42 +770,6 @@ mod for_authenticated_users {
}
}

#[tokio::test]
async fn it_should_allow_authenticated_users_to_download_a_torrent_with_a_personal_announce_url() {
let mut env = TestEnv::new();
env.start(api::Version::V1).await;

if !env.provides_a_tracker() {
println!("test skipped. It requires a tracker to be running.");
return;
}

// Given a previously uploaded torrent
let uploader = new_logged_in_user(&env).await;
let (test_torrent, _torrent_listed_in_index) = upload_random_torrent_to_index(&uploader, &env).await;

// And a logged in user who is going to download the torrent
let downloader = new_logged_in_user(&env).await;
let client = Client::authenticated(&env.server_socket_addr().unwrap(), &downloader.token);

// When the user downloads the torrent
let response = client.download_torrent(&test_torrent.file_info_hash()).await;

let torrent = decode_torrent(&response.bytes).expect("could not decode downloaded torrent");

// Then the torrent should have the personal announce URL
let tracker_key = get_user_tracker_key(&downloader, &env)
.await
.expect("uploader should have a valid tracker key");

let tracker_url = env.server_settings().unwrap().tracker.url;

assert_eq!(
torrent.announce.unwrap(),
build_announce_url(&tracker_url, &Some(tracker_key))
);
}

mod and_non_admins {

use torrust_index::web::api;
Expand Down

0 comments on commit 10b3670

Please sign in to comment.