diff options
author | Daniel García <[email protected]> | 2021-07-15 19:15:55 +0200 |
---|---|---|
committer | Daniel García <[email protected]> | 2021-07-15 19:15:55 +0200 |
commit | e5ec245626e4a4d232b6a709338fe1e9811845e7 (patch) | |
tree | 73b4736a701948328c23c27b9880a6905b4e1cea /src/util.rs | |
parent | 3968bc8016611cdf9a84db68990f27624ab17889 (diff) | |
download | vaultwarden-e5ec245626e4a4d232b6a709338fe1e9811845e7.tar.gz vaultwarden-e5ec245626e4a4d232b6a709338fe1e9811845e7.zip |
Protect namedfile against path traversal, rocket only does it for pathbuf
Diffstat (limited to 'src/util.rs')
-rw-r--r-- | src/util.rs | 33 |
1 files changed, 32 insertions, 1 deletions
diff --git a/src/util.rs b/src/util.rs index 8512bc7b..9e216d72 100644 --- a/src/util.rs +++ b/src/util.rs @@ -5,7 +5,8 @@ use std::io::Cursor; use rocket::{ fairing::{Fairing, Info, Kind}, - http::{ContentType, Header, HeaderMap, Method, Status}, + http::{ContentType, Header, HeaderMap, Method, RawStr, Status}, + request::FromParam, response::{self, Responder}, Data, Request, Response, Rocket, }; @@ -125,6 +126,36 @@ impl<'r, R: Responder<'r>> Responder<'r> for Cached<R> { } } +pub struct SafeString(String); + +impl std::fmt::Display for SafeString { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + self.0.fmt(f) + } +} + +impl AsRef<Path> for SafeString { + #[inline] + fn as_ref(&self) -> &Path { + Path::new(&self.0) + } +} + +impl<'r> FromParam<'r> for SafeString { + type Error = (); + + #[inline(always)] + fn from_param(param: &'r RawStr) -> Result<Self, Self::Error> { + let s = param.percent_decode().map(|cow| cow.into_owned()).map_err(|_| ())?; + + if s.chars().all(|c| matches!(c, 'a'..='z' | 'A'..='Z' |'0'..='9' | '-')) { + Ok(SafeString(s)) + } else { + Err(()) + } + } +} + // Log all the routes from the main paths list, and the attachments endpoint // Effectively ignores, any static file route, and the alive endpoint const LOGGED_ROUTES: [&str; 6] = |