2022-08-18 21:01:35 +00:00
|
|
|
use std::path::Path;
|
|
|
|
|
2022-08-18 20:15:40 +00:00
|
|
|
use crate::errors::HttpError;
|
2022-08-18 21:01:35 +00:00
|
|
|
use crate::utils::files::{save_file, sniff_media_type};
|
|
|
|
|
2022-08-18 20:15:40 +00:00
|
|
|
pub const UPLOAD_MAX_SIZE: usize = 1024 * 1024 * 5;
|
|
|
|
|
2022-08-18 21:01:35 +00:00
|
|
|
#[derive(thiserror::Error, Debug)]
|
|
|
|
pub enum UploadError {
|
|
|
|
#[error(transparent)]
|
|
|
|
WriteError(#[from] std::io::Error),
|
|
|
|
|
|
|
|
#[error("base64 decoding error")]
|
|
|
|
Base64DecodingError(#[from] base64::DecodeError),
|
|
|
|
|
2022-08-18 20:15:40 +00:00
|
|
|
#[error("file is too large")]
|
|
|
|
TooLarge,
|
|
|
|
|
2022-08-18 21:01:35 +00:00
|
|
|
#[error("invalid media type")]
|
|
|
|
InvalidMediaType,
|
|
|
|
}
|
|
|
|
|
2022-08-18 20:15:40 +00:00
|
|
|
impl From<UploadError> for HttpError {
|
|
|
|
fn from(error: UploadError) -> Self {
|
|
|
|
match error {
|
|
|
|
UploadError::WriteError(_) => HttpError::InternalError,
|
|
|
|
other_error => {
|
|
|
|
HttpError::ValidationError(other_error.to_string())
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-18 21:01:35 +00:00
|
|
|
pub fn save_b64_file(
|
|
|
|
b64data: &str,
|
2022-12-22 21:42:14 +00:00
|
|
|
mut maybe_media_type: Option<String>,
|
2022-08-18 21:01:35 +00:00
|
|
|
output_dir: &Path,
|
|
|
|
) -> Result<(String, Option<String>), UploadError> {
|
|
|
|
let data = base64::decode(b64data)?;
|
2022-08-18 20:15:40 +00:00
|
|
|
if data.len() > UPLOAD_MAX_SIZE {
|
|
|
|
return Err(UploadError::TooLarge);
|
|
|
|
};
|
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;
|
|
|
|
};
|
2022-12-21 16:05:26 +00:00
|
|
|
Ok(save_file(data, output_dir, maybe_media_type)?)
|
2022-08-18 21:01:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn save_validated_b64_file(
|
|
|
|
b64data: &str,
|
|
|
|
output_dir: &Path,
|
|
|
|
media_type_prefix: &str,
|
|
|
|
) -> Result<(String, String), UploadError> {
|
|
|
|
let data = base64::decode(b64data)?;
|
2022-08-18 20:15:40 +00:00
|
|
|
if data.len() > UPLOAD_MAX_SIZE {
|
|
|
|
return Err(UploadError::TooLarge);
|
|
|
|
};
|
2022-08-18 21:01:35 +00:00
|
|
|
let media_type = sniff_media_type(&data)
|
|
|
|
.ok_or(UploadError::InvalidMediaType)?;
|
|
|
|
if !media_type.starts_with(media_type_prefix) {
|
|
|
|
return Err(UploadError::InvalidMediaType);
|
|
|
|
};
|
|
|
|
let (file_name, _) =
|
|
|
|
save_file(data, output_dir, Some(media_type.clone()))?;
|
|
|
|
Ok((file_name, media_type))
|
|
|
|
}
|