removed verbose comments

This commit is contained in:
Mercurio 2025-05-28 22:40:43 +02:00
parent 197be28e46
commit 0f9b390ced
6 changed files with 1 additions and 76 deletions

View file

@ -50,20 +50,17 @@ impl File {
encryption_key: Option<String>,
encryption_iv: Option<String>,
) -> Result<Self, AppError> {
// Validate parent directory if provided
if let Some(parent_id) = dto.parent_id {
let parent = Self::find_by_id(pool, parent_id).await?;
if parent.file_type != FileType::Directory {
return Err(AppError::NotADirectory);
}
// Check if user has access to parent directory
if parent.owner_id != owner_id {
// TODO: Check if user has write permission through sharing
return Err(AppError::AccessDenied);
}
}
// Check for duplicate filename in the same directory
let existing_file = sqlx::query!("SELECT id FROM files WHERE name = $1 AND parent_id IS NOT DISTINCT FROM $2 AND owner_id = $3",
dto.name, dto.parent_id, owner_id)
.fetch_optional(pool)
@ -73,7 +70,6 @@ impl File {
return Err(AppError::FileAlreadyExists);
}
// Create the file record
let file = sqlx::query_as!(File,
r#"INSERT INTO files (id, name, file_type, mime_type, size, owner_id, parent_id, encryption_key, encryption_iv, created_at, updated_at)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
@ -101,20 +97,17 @@ impl File {
dto: CreateDirectoryDto,
owner_id: Uuid,
) -> Result<Self, AppError> {
// Validate parent directory if provided
if let Some(parent_id) = dto.parent_id {
let parent = Self::find_by_id(pool, parent_id).await?;
if parent.file_type != FileType::Directory {
return Err(AppError::NotADirectory);
}
// Check if user has access to parent directory
if parent.owner_id != owner_id {
// TODO: Check if user has write permission through sharing
return Err(AppError::AccessDenied);
}
}
// Check for duplicate directory name in the same parent
let existing_dir = sqlx::query!("SELECT id FROM files WHERE name = $1 AND parent_id IS NOT DISTINCT FROM $2 AND owner_id = $3 AND file_type = 'directory'",
dto.name, dto.parent_id, owner_id)
.fetch_optional(pool)
@ -124,7 +117,6 @@ impl File {
return Err(AppError::DirectoryAlreadyExists);
}
// Create the directory record
let directory = sqlx::query_as!(File,
r#"INSERT INTO files (id, name, file_type, mime_type, size, owner_id, parent_id, encryption_key, encryption_iv, created_at, updated_at)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
@ -165,17 +157,13 @@ impl File {
directory_id: Option<Uuid>,
user_id: Uuid,
) -> Result<Vec<Self>, AppError> {
// If directory_id is None, list files at root level for the user
let files = if let Some(dir_id) = directory_id {
// Verify directory exists and user has access
let directory = Self::find_by_id(pool, dir_id).await?;
if directory.file_type != FileType::Directory {
return Err(AppError::NotADirectory);
}
// Check if user has access to this directory
if directory.owner_id != user_id {
// TODO: Check if user has read permission through sharing
return Err(AppError::AccessDenied);
}
@ -187,7 +175,6 @@ impl File {
.fetch_all(pool)
.await?
} else {
// List root level files for the user
sqlx::query_as!(File,
r#"SELECT id, name, file_type as "file_type: FileType", mime_type, size, owner_id, parent_id, encryption_key, encryption_iv, created_at, updated_at
FROM files WHERE parent_id IS NULL AND owner_id = $1 ORDER BY file_type, name"#,
@ -205,27 +192,20 @@ impl File {
id: Uuid,
user_id: Uuid,
) -> Result<(), AppError> {
// Find the file/directory
let file = Self::find_by_id(pool, id).await?;
// Check if user has permission to delete
if file.owner_id != user_id {
// TODO: Check if user has write permission through sharing
return Err(AppError::AccessDenied);
}
// If it's a directory, recursively delete all contents
if file.file_type == FileType::Directory {
// Get all files in this directory
let files_in_dir = Self::list_directory(pool, Some(id), user_id).await?;
// Recursively delete each file/subdirectory
for file in files_in_dir {
Self::delete(pool, file.id, user_id).await?;
}
}
// Delete the file/directory record
sqlx::query!("DELETE FROM files WHERE id = $1", id)
.execute(pool)
.await?;
@ -236,11 +216,9 @@ impl File {
pub async fn get_file_path(pool: &PgPool, id: Uuid) -> Result<String, AppError> {
let file = Self::find_by_id(pool, id).await?;
// Build the path by traversing parent directories
let mut path_parts = vec![file.name.clone()];
let mut current_parent_id = file.parent_id;
// Prevent infinite loops by limiting depth
let mut depth = 0;
const MAX_DEPTH: usize = 100;
@ -255,10 +233,7 @@ impl File {
depth += 1;
}
// Reverse to get the correct order (root -> leaf)
path_parts.reverse();
// Join with path separator
Ok(path_parts.join("/"))
}
}

View file

@ -92,7 +92,6 @@ async fn upload_file(
return Err(AppError::StorageQuotaExceeded("Storage quota exceeded".to_string()));
}
// Create storage service
let storage_service = StorageService::new(&config.storage_path);
// Create file record in database
@ -122,29 +121,22 @@ async fn download_file(
Extension(encryption_service): Extension<EncryptionService>,
Path(id): Path<Uuid>,
) -> Result<impl IntoResponse, AppError> {
// Get file metadata
let file = FileModel::find_by_id(&pool, id).await?;
// Check if user has access to this file
if file.owner_id != auth_user.id {
return Err(AppError::AccessDenied("You don't have access to this file".to_string()));
}
// Check if it's a file (not a directory)
if file.file_type != FileType::File {
return Err(AppError::InvalidInput("Cannot download a directory".to_string()));
}
// Create storage service
let storage_service = StorageService::new(&config.storage_path);
// Read encrypted file from disk
let encrypted_data = storage_service.read_file(auth_user.id, file.id).await?;
// Decrypt file
let decrypted_data = encryption_service.decrypt(&encrypted_data)?;
// Set up response headers
let mut headers = HeaderMap::new();
headers.insert(
axum::http::header::CONTENT_TYPE,
@ -155,7 +147,6 @@ async fn download_file(
format!("attachment; filename=\"{}\"", file.name).parse().unwrap(),
);
// Create a stream from the decrypted data
let stream = tokio_util::io::ReaderStream::new(std::io::Cursor::new(decrypted_data));
let body = StreamBody::new(stream);
@ -177,27 +168,16 @@ async fn delete_file(
Extension(config): Extension<Arc<Config>>,
Path(id): Path<Uuid>,
) -> Result<StatusCode, AppError> {
// Get file metadata
let file = FileModel::find_by_id(&pool, id).await?;
// Check if user has access to this file
if file.owner_id != auth_user.id {
return Err(AppError::AccessDenied("You don't have access to this file".to_string()));
}
// Create storage service
let storage_service = StorageService::new(&config.storage_path);
// Delete file or directory
if file.file_type == FileType::Directory {
// For directories, recursively delete all contents
FileModel::delete_directory_recursive(&pool, id, auth_user.id, &storage_service).await?;
} else {
// For files, delete the file from storage and update user quota
storage_service.delete_file(auth_user.id, file.id).await?;
FileModel::delete(&pool, id).await?;
// Update user storage used
crate::models::user::User::update_storage_used(&pool, auth_user.id, -file.size).await?;
}

View file

@ -24,13 +24,8 @@ async fn list_shares(
auth_user: AuthUser,
Extension(pool): Extension<PgPool>,
) -> Result<Json<Vec<ShareResponse>>, AppError> {
// Get shares owned by the user
let owned_shares = Share::list_by_owner(&pool, auth_user.id).await?;
// Get shares shared with the user
let received_shares = Share::list_by_recipient(&pool, auth_user.id).await?;
// Combine and get full details for each share
let mut share_responses = Vec::new();
for share in owned_shares {
@ -61,8 +56,6 @@ async fn get_share(
Path(id): Path<Uuid>,
) -> Result<Json<ShareResponse>, AppError> {
let share = Share::find_by_id(&pool, id).await?;
// Check if user has access to this share
if share.owner_id != auth_user.id && share.recipient_id != Some(auth_user.id) {
return Err(AppError::AccessDenied("You don't have access to this share".to_string()));
}
@ -85,8 +78,6 @@ async fn access_shared_file(
Path(access_key): Path<String>,
) -> Result<Json<ShareResponse>, AppError> {
let share = Share::find_by_access_key(&pool, &access_key).await?;
// Check if share is valid (not expired)
if let Some(expires_at) = share.expires_at {
if expires_at < time::OffsetDateTime::now_utc() {
return Err(AppError::AccessDenied("This share has expired".to_string()));

View file

@ -36,7 +36,6 @@ async fn update_password(
Extension(pool): Extension<PgPool>,
Json(update_dto): Json<UpdatePasswordDto>,
) -> Result<StatusCode, AppError> {
// Verify current password
let user = User::find_by_id(&pool, auth_user.id).await?;
let is_valid = crate::utils::password::verify_password(
&update_dto.current_password,
@ -47,10 +46,8 @@ async fn update_password(
return Err(AppError::AuthenticationError("Current password is incorrect".to_string()));
}
// Hash new password
let new_password_hash = crate::utils::password::hash_password(&update_dto.new_password)?;
// Update password in database
sqlx::query!(
r#"
UPDATE users

View file

@ -10,12 +10,9 @@ pub struct EncryptionService {
impl EncryptionService {
pub fn new(master_key: &str) -> Self {
// Decode the base64 master key
let key_bytes = general_purpose::STANDARD
.decode(master_key)
.expect("Invalid master key format");
// Create the cipher
let cipher = Aes256Gcm::new_from_slice(&key_bytes)
.expect("Invalid key length");
@ -23,17 +20,12 @@ impl EncryptionService {
}
pub fn encrypt(&self, data: &[u8]) -> Result<Vec<u8>, AppError> {
// Generate a random 12-byte nonce
let mut nonce_bytes = [0u8; 12];
OsRng.fill_bytes(&mut nonce_bytes);
let nonce = Nonce::from_slice(&nonce_bytes);
// Encrypt the data
let ciphertext = self.cipher
.encrypt(nonce, data)
.map_err(|e| AppError::EncryptionError(e.to_string()))?;
// Combine nonce and ciphertext
let mut result = Vec::with_capacity(nonce_bytes.len() + ciphertext.len());
result.extend_from_slice(&nonce_bytes);
result.extend_from_slice(&ciphertext);
@ -42,15 +34,12 @@ impl EncryptionService {
}
pub fn decrypt(&self, data: &[u8]) -> Result<Vec<u8>, AppError> {
// Extract nonce and ciphertext
if data.len() < 12 {
return Err(AppError::EncryptionError("Invalid encrypted data format".to_string()));
}
let nonce = Nonce::from_slice(&data[..12]);
let ciphertext = &data[12..];
// Decrypt the data
let plaintext = self.cipher
.decrypt(nonce, ciphertext)
.map_err(|e| AppError::EncryptionError(e.to_string()))?;
@ -59,11 +48,9 @@ impl EncryptionService {
}
pub fn generate_master_key() -> String {
// Generate a random 32-byte key
let mut key = [0u8; 32];
OsRng.fill_bytes(&mut key);
// Encode as base64
general_purpose::STANDARD.encode(key)
}
}

View file

@ -18,13 +18,12 @@ impl StorageService {
pub async fn save_file(&self, user_id: Uuid, file_id: Uuid, data: &[u8]) -> Result<(), AppError> {
let file_path = self.get_file_path(user_id, file_id);
// Ensure the directory exists
if let Some(parent) = file_path.parent() {
fs::create_dir_all(parent).await
.map_err(|e| AppError::IoError(e.to_string()))?;
}
// Write the file
fs::write(&file_path, data).await
.map_err(|e| AppError::IoError(e.to_string()))?;
@ -34,7 +33,6 @@ impl StorageService {
pub async fn read_file(&self, user_id: Uuid, file_id: Uuid) -> Result<Vec<u8>, AppError> {
let file_path = self.get_file_path(user_id, file_id);
// Read the file
let data = fs::read(&file_path).await
.map_err(|e| AppError::IoError(e.to_string()))?;
@ -44,12 +42,10 @@ impl StorageService {
pub async fn delete_file(&self, user_id: Uuid, file_id: Uuid) -> Result<(), AppError> {
let file_path = self.get_file_path(user_id, file_id);
// Check if file exists
if !file_path.exists() {
return Ok(());
}
// Delete the file
fs::remove_file(&file_path).await
.map_err(|e| AppError::IoError(e.to_string()))?;
@ -59,7 +55,6 @@ impl StorageService {
pub async fn create_user_directory(&self, user_id: Uuid) -> Result<(), AppError> {
let dir_path = self.get_user_directory(user_id);
// Create the directory if it doesn't exist
if !dir_path.exists() {
fs::create_dir_all(&dir_path).await
.map_err(|e| AppError::IoError(e.to_string()))?;