fix(server): prevent serving an already expired file

This commit is contained in:
Orhun Parmaksız 2021-11-07 00:49:31 +03:00
parent 3eee294bd9
commit f078a9afa7
No known key found for this signature in database
GPG key ID: F83424824B3E4B90
6 changed files with 49 additions and 13 deletions

24
Cargo.lock generated
View file

@ -1000,6 +1000,29 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" checksum = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a"
[[package]]
name = "lazy-regex"
version = "2.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "919a16773ebf2de27e95fc58460110932e55bb0780e23aa51fa5a6b59c9e2b3d"
dependencies = [
"lazy-regex-proc_macros",
"once_cell",
"regex",
]
[[package]]
name = "lazy-regex-proc_macros"
version = "2.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fbe6bf0a04af51c07976625d5007e75ed9b8b955befc21c77b3947733496e36"
dependencies = [
"proc-macro2",
"quote",
"regex",
"syn",
]
[[package]] [[package]]
name = "lazy_static" name = "lazy_static"
version = "1.4.0" version = "1.4.0"
@ -1528,6 +1551,7 @@ dependencies = [
"glob", "glob",
"humantime", "humantime",
"infer", "infer",
"lazy-regex",
"log", "log",
"mime", "mime",
"petname", "petname",

View file

@ -27,6 +27,7 @@ url = "2.2.2"
mime = "0.3.16" mime = "0.3.16"
regex = "1.5.4" regex = "1.5.4"
serde_regex = "1.1.0" serde_regex = "1.1.0"
lazy-regex = "2.2.1"
humantime = "2.1.0" humantime = "2.1.0"
glob = "0.3.0" glob = "0.3.0"
ring = "0.16.20" ring = "0.16.20"

View file

@ -45,9 +45,10 @@ impl<'a> TryFrom<&'a Path> for Directory {
impl Directory { impl Directory {
/// Returns the file that matches the given checksum. /// Returns the file that matches the given checksum.
pub fn get_file<S: AsRef<str>>(self, sha256sum: S) -> Option<File> { pub fn get_file<S: AsRef<str>>(self, sha256sum: S) -> Option<File> {
self.files self.files.into_iter().find(|file| {
.into_iter() file.sha256sum == sha256sum.as_ref()
.find(|file| file.sha256sum == sha256sum.as_ref()) && !util::TIMESTAMP_EXTENSION_REGEX.is_match(&file.path.to_string_lossy())
})
} }
} }

View file

@ -177,7 +177,7 @@ impl Paste {
let bytes = response.body().limit(payload_limit).await?.to_vec(); let bytes = response.body().limit(payload_limit).await?.to_vec();
let bytes_checksum = util::sha256_digest(&*bytes)?; let bytes_checksum = util::sha256_digest(&*bytes)?;
self.data = bytes; self.data = bytes;
if !config.paste.duplicate_files.unwrap_or(true) { if !config.paste.duplicate_files.unwrap_or(true) && expiry_date.is_none() {
if let Some(file) = if let Some(file) =
Directory::try_from(config.server.upload_path.as_path())?.get_file(bytes_checksum) Directory::try_from(config.server.upload_path.as_path())?.get_file(bytes_checksum)
{ {

View file

@ -106,6 +106,7 @@ async fn upload(
} }
if paste_type != PasteType::Oneshot if paste_type != PasteType::Oneshot
&& paste_type != PasteType::RemoteFile && paste_type != PasteType::RemoteFile
&& expiry_date.is_none()
&& !config.paste.duplicate_files.unwrap_or(true) && !config.paste.duplicate_files.unwrap_or(true)
{ {
let bytes_checksum = util::sha256_digest(&*bytes)?; let bytes_checksum = util::sha256_digest(&*bytes)?;

View file

@ -1,11 +1,15 @@
use actix_web::{error, Error as ActixError}; use actix_web::{error, Error as ActixError};
use glob::glob; use glob::glob;
use lazy_regex::{lazy_regex, Lazy, Regex};
use ring::digest::{Context, SHA256}; use ring::digest::{Context, SHA256};
use std::io::{BufReader, Read}; use std::io::{BufReader, Read};
use std::path::PathBuf; use std::path::PathBuf;
use std::time::Duration; use std::time::Duration;
use std::time::{SystemTime, UNIX_EPOCH}; use std::time::{SystemTime, UNIX_EPOCH};
/// Regex for matching the timestamp extension of a path.
pub static TIMESTAMP_EXTENSION_REGEX: Lazy<Regex> = lazy_regex!(r#"\.[0-9]{10,}$"#);
/// Returns the system time as [`Duration`](Duration). /// Returns the system time as [`Duration`](Duration).
pub fn get_system_time() -> Result<Duration, ActixError> { pub fn get_system_time() -> Result<Duration, ActixError> {
SystemTime::now() SystemTime::now()
@ -17,15 +21,20 @@ pub fn get_system_time() -> Result<Duration, ActixError> {
/// ///
/// The file extension is accepted as a timestamp that points to the expiry date. /// The file extension is accepted as a timestamp that points to the expiry date.
pub fn glob_match_file(mut path: PathBuf) -> Result<PathBuf, ActixError> { pub fn glob_match_file(mut path: PathBuf) -> Result<PathBuf, ActixError> {
if let Some(glob_path) = glob(&format!( path = PathBuf::from(
"{}.[0-9]*", TIMESTAMP_EXTENSION_REGEX
path.to_str() .replacen(
.ok_or_else(|| error::ErrorInternalServerError( path.to_str().ok_or_else(|| {
"file name contains invalid characters" error::ErrorInternalServerError("path contains invalid characters")
))?, })?,
)) 1,
.map_err(error::ErrorInternalServerError)? "",
.next() )
.to_string(),
);
if let Some(glob_path) = glob(&format!("{}.[0-9]*", path.to_string_lossy()))
.map_err(error::ErrorInternalServerError)?
.next()
{ {
let glob_path = glob_path.map_err(error::ErrorInternalServerError)?; let glob_path = glob_path.map_err(error::ErrorInternalServerError)?;
if let Some(extension) = glob_path if let Some(extension) = glob_path