fedimovies/src/mastodon_api/uploads.rs

74 lines
2 KiB
Rust
Raw Normal View History

use std::path::Path;
use crate::errors::HttpError;
use crate::utils::files::{save_file, sniff_media_type};
pub const UPLOAD_MAX_SIZE: usize = 1024 * 1024 * 5;
#[derive(thiserror::Error, Debug)]
pub enum UploadError {
#[error(transparent)]
WriteError(#[from] std::io::Error),
#[error("base64 decoding error")]
Base64DecodingError(#[from] base64::DecodeError),
#[error("file is too large")]
TooLarge,
#[error("invalid media type")]
InvalidMediaType,
}
impl From<UploadError> for HttpError {
fn from(error: UploadError) -> Self {
match error {
UploadError::WriteError(_) => HttpError::InternalError,
other_error => {
HttpError::ValidationError(other_error.to_string())
},
}
}
}
pub fn save_b64_file(
b64data: &str,
2022-12-22 21:42:14 +00:00
mut maybe_media_type: Option<String>,
output_dir: &Path,
) -> Result<(String, Option<String>), UploadError> {
let data = base64::decode(b64data)?;
if data.len() > UPLOAD_MAX_SIZE {
return Err(UploadError::TooLarge);
};
2023-01-06 01:14:01 +00:00
// Sniff media type if not provided
maybe_media_type = maybe_media_type.or(sniff_media_type(&data));
2022-12-22 21:42:14 +00:00
if maybe_media_type.as_deref() == Some("image/svg+xml") {
// Don't treat SVG files as images
maybe_media_type = None;
};
2023-01-06 01:14:01 +00:00
let file_name = save_file(
data,
output_dir,
maybe_media_type.as_deref(),
)?;
Ok((file_name, maybe_media_type))
}
pub fn save_validated_b64_file(
b64data: &str,
output_dir: &Path,
media_type_prefix: &str,
) -> Result<(String, String), UploadError> {
let data = base64::decode(b64data)?;
if data.len() > UPLOAD_MAX_SIZE {
return Err(UploadError::TooLarge);
};
let media_type = sniff_media_type(&data)
.ok_or(UploadError::InvalidMediaType)?;
if !media_type.starts_with(media_type_prefix) {
return Err(UploadError::InvalidMediaType);
};
2023-01-06 01:14:01 +00:00
let file_name = save_file(data, output_dir, Some(&media_type))?;
Ok((file_name, media_type))
}