Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 27 additions & 20 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ resolver = "3"

[package]
name = "torrust-actix"
version = "4.2.16"
version = "4.2.17"
edition = "2024"
rust-version = "1.88.0"
license = "MIT"
Expand Down Expand Up @@ -51,6 +51,7 @@ log = "0.4.33"
parking_lot = { version = "0.12.5", features = ["arc_lock", "hardware-lock-elision", "serde", "deadlock_detection"] }
percent-encoding = "2.3.2"
rcgen = "0.14.7"
ring = "0.17.14"
rustls = { version = "0.23.42", default-features = false, features = ["std", "ring"] }
rustls-pemfile = "2.2.0"
sentry = { version = "0.48.5", default-features = false, features = ["rustls", "backtrace", "contexts", "panic", "transport", "debug-images", "reqwest"] }
Expand All @@ -67,7 +68,7 @@ memcache = { version = "0.20.0", default-features = false }
thiserror = "2.0.19"
tokio = { version = "1.53.1", features = ["full"] }
rand = "0.10.2"
base64 = "0.22.1"
base64 = "0.23.0"
tokio-shutdown = "0.1.5"
toml = "1.1.3"
utoipa-swagger-ui = { version = "9.0.2", features = ["actix-web"] }
Expand Down Expand Up @@ -106,7 +107,7 @@ harness = false
name = "Torrust Actix"
identifier = "com.power2all.torrust-actix"
icon = ["icon.ico"]
version = "4.2.16"
version = "4.2.17"
copyright = "Copyright (c) 2024-2026 Power2All"
category = "Public Utility"
short_description = "BitTorrent Tracker"
Expand Down
14 changes: 13 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ It is a workspace member but is **not compiled by default** (`default-members` e

```bash
# Debian / Ubuntu
sudo apt-get install libfontconfig1-dev
sudo apt-get install libfontconfig-dev

# Fedora / RHEL
sudo dnf install fontconfig-devel
Expand Down Expand Up @@ -610,6 +610,18 @@ echo "WebRTC seeds: {$data['rtc_seeds']}";

### ChangeLog

#### v4.2.17
* Full code auditing, and found some possible security issues in the future.
* Applied a README fix about library installation on Linux (Thanks https://github.com/diederikdehaas).
* Some small version bumps, nothing special.

#### v4.2.16
* Added clearer error reporting for invalid hex-based identifiers.
* Tightened UUID and database identifier validation rules.
* Improved BEP 15 UDP request/response encoding and decoding for consistent big-endian behavior.
* Updated application/desktop/container version to 4.2.16 (including Docker image tags) and refreshed bundled dependency versions.
* Updated UDP parsing tests to match the revised packet encoding.

#### v4.2.15
* Did some further performance tweaking
* Bumped versions
Expand Down
2 changes: 1 addition & 1 deletion docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ FROM rust:alpine
RUN apk update --no-interactive
RUN apk add git musl-dev curl pkgconfig openssl-dev openssl-libs-static --no-interactive
RUN git clone https://github.com/Power2All/torrust-actix.git /app/torrust-actix
RUN cd /app/torrust-actix && git checkout tags/v4.2.16
RUN cd /app/torrust-actix && git checkout tags/v4.2.17
WORKDIR /app/torrust-actix
RUN cd /app/torrust-actix
RUN cargo build --release && rm -Rf target/release/.fingerprint target/release/build target/release/deps target/release/examples target/release/incremental
Expand Down
4 changes: 2 additions & 2 deletions docker/build.bat
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
@echo off

docker build --no-cache -t power2all/torrust-actix:v4.2.16 -t power2all/torrust-actix:latest .
docker push power2all/torrust-actix:v4.2.16
docker build --no-cache -t power2all/torrust-actix:v4.2.17 -t power2all/torrust-actix:latest .
docker push power2all/torrust-actix:v4.2.17
docker push power2all/torrust-actix:latest
9 changes: 7 additions & 2 deletions src/api/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,8 @@ pub async fn api_service_token(request: &HttpRequest, config: Arc<Configuration>
}

/// Determines the client IP, honouring the configured `real_ip` header when trusted proxies
/// are enabled; falls back to the socket peer address.
/// are enabled and the request came from a configured proxy; falls back to the socket peer
/// address.
///
/// # Errors
///
Expand All @@ -355,11 +356,15 @@ pub async fn api_service_retrieve_remote_ip(request: &HttpRequest, data: Arc<Api
if !data.trusted_proxies {
return Ok(origin_ip);
}
let explicit_proxies = !data.trusted_proxy_addrs.is_empty();
if explicit_proxies && !data.trusted_proxy_addrs.contains(&origin_ip) {
return Ok(origin_ip);
}
request.headers()
.get(&data.real_ip)
.and_then(|header| header.to_str().ok())
.and_then(|ip_str| {
validate_remote_ip(ip_str, data.trusted_proxies).ok()?;
validate_remote_ip(ip_str, explicit_proxies).ok()?;
IpAddr::from_str(ip_str).ok()
})
.map_or(Ok(origin_ip), Ok)
Expand Down
16 changes: 13 additions & 3 deletions src/common/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ use crate::common::structs::custom_error::CustomError;
use crate::common::types::QueryValues;
use crate::config::enums::compression_algorithm::CompressionAlgorithm;
use crate::config::structs::configuration::Configuration;
use crate::security::security::MAX_PERCENT_DECODED_SIZE;
use crate::security::security::{
validate_query_string_length,
MAX_PERCENT_DECODED_SIZE
};
use fern::colors::{
Color,
ColoredLevelConfig
Expand All @@ -27,11 +30,13 @@ use tokio_shutdown::Shutdown;
///
/// # Errors
///
/// Returns a [`CustomError`] when a decoded value exceeds `MAX_PERCENT_DECODED_SIZE`.
/// Returns a [`CustomError`] when the query string exceeds `MAX_QUERY_STRING_LENGTH` or a
/// decoded value exceeds `MAX_PERCENT_DECODED_SIZE`.
#[inline]
pub fn parse_query(query: Option<&str>) -> Result<HashMap<String, QueryValues>, CustomError> {
let mut queries: HashMap<String, QueryValues> = HashMap::with_capacity(12);
if let Some(result) = query {
validate_query_string_length(result)?;
for query_item in result.split('&') {
if query_item.is_empty() {
continue;
Expand Down Expand Up @@ -129,12 +134,17 @@ pub(crate) fn bin2hex(data: &[u8; 20], f: &mut Formatter) -> fmt::Result {
write!(f, "{}", std::str::from_utf8(&chars).unwrap())
}

pub struct Hex20(pub [u8; 40]);
/// A 20-byte hash rendered as 40 lowercase hex characters in a stack buffer.
///
/// The field is private: [`bin20_to_hex`] must remain the only constructor for
/// [`Hex20::as_str`] to stay sound.
pub struct Hex20([u8; 40]);

impl Hex20 {
/// Returns the hex string as `&str` (always 40 valid ASCII characters).
#[inline]
pub fn as_str(&self) -> &str {
// SAFETY: `bin20_to_hex` is the only constructor and writes only ASCII hex digits.
unsafe { std::str::from_utf8_unchecked(&self.0) }
}
}
Expand Down
4 changes: 4 additions & 0 deletions src/config/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ pub(crate) fn default_rtc_interval() -> u64 { 30 }
pub(crate) fn default_rtc_peers_timeout() -> u64 { 120 }
/// Serde default interval in seconds between key-expiry sweeps: `60`.
pub(crate) fn default_keys_cleanup_interval() -> u64 { 60 }
/// Serde default cap on peers kept per torrent per peer map: `10000`.
pub(crate) fn default_max_peers_per_torrent() -> u64 { 10_000 }
/// Serde default cap on SDP answers queued for one RtcTorrent peer: `32`.
pub(crate) fn default_max_rtc_pending_answers() -> u64 { 32 }
/// Serde default Prometheus metric namespace: `torrust_actix`.
pub(crate) fn default_prometheus_id() -> String { String::from("torrust_actix") }
/// Serde default cluster mode: standalone (no clustering).
Expand Down
Loading
Loading