path validation

This commit is contained in:
2025-11-12 20:42:15 +01:00
parent a8235fe52a
commit d9f8a342e6
3 changed files with 208 additions and 15 deletions
+18 -10
View File
@@ -1,5 +1,6 @@
#![allow(clippy::missing_errors_doc)]
mod path_validation;
mod peer;
use std::{
@@ -32,7 +33,10 @@ use tokio::{
};
use uuid::Uuid;
use crate::peer::{send_game_file_chunk, send_game_file_data};
use crate::{
path_validation::validate_game_file_path,
peer::{send_game_file_chunk, send_game_file_data},
};
/// Initialize and start the peer system
/// This function replaces the main.rs entry point and allows the peer to be started from other crates
@@ -348,11 +352,13 @@ async fn prepare_game_storage(
file_descs: &[GameFileDescription],
) -> eyre::Result<()> {
for desc in file_descs {
let path = games_folder.join(&desc.relative_path);
// Validate the path to prevent directory traversal
let validated_path = validate_game_file_path(games_folder, &desc.relative_path)?;
if desc.is_dir {
tokio::fs::create_dir_all(&path).await?;
tokio::fs::create_dir_all(&validated_path).await?;
} else {
if let Some(parent) = path.parent() {
if let Some(parent) = validated_path.parent() {
tokio::fs::create_dir_all(parent).await?;
}
let file_size = desc.file_size().unwrap_or(0);
@@ -360,7 +366,7 @@ async fn prepare_game_storage(
.create(true)
.truncate(true)
.write(true)
.open(&path)
.open(&validated_path)
.await?;
file.set_len(file_size).await?;
}
@@ -450,12 +456,13 @@ async fn download_chunk(
tx.close().await?;
let path = base_dir.join(&chunk.relative_path);
// Validate the path to prevent directory traversal
let validated_path = validate_game_file_path(base_dir, &chunk.relative_path)?;
let mut file = OpenOptions::new()
.create(true)
.write(true)
.truncate(false)
.open(&path)
.open(&validated_path)
.await?;
if chunk.length == 0 && chunk.offset == 0 {
// fallback-to-whole-file path replaces any existing partial data
@@ -493,7 +500,7 @@ async fn download_chunk(
file.flush().await?;
// Verify file integrity by checking the file size
verify_chunk_integrity(&path, chunk.offset, chunk.length).await?;
verify_chunk_integrity(&validated_path, chunk.offset, chunk.length).await?;
Ok(())
}
@@ -534,12 +541,13 @@ async fn download_whole_file(
.await?;
tx.close().await?;
let path = base_dir.join(&desc.relative_path);
// Validate the path to prevent directory traversal
let validated_path = validate_game_file_path(base_dir, &desc.relative_path)?;
let mut file = OpenOptions::new()
.create(true)
.truncate(true)
.write(true)
.open(&path)
.open(&validated_path)
.await?;
file.seek(std::io::SeekFrom::Start(0)).await?;