path validation
This commit is contained in:
@@ -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?;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user