44
55use std:: {
66 env:: temp_dir,
7- path:: { Component , Path , PathBuf } ,
7+ path:: { Component , Display , Path , PathBuf } ,
88} ;
99
1010use crate :: {
1111 plugin:: { Builder , TauriPlugin } ,
1212 Manager , Runtime ,
1313} ;
1414
15+ use serde:: { de:: Error as DeError , Deserialize , Deserializer } ;
1516use serde_repr:: { Deserialize_repr , Serialize_repr } ;
1617
1718#[ cfg( path_all) ]
@@ -29,6 +30,49 @@ pub(crate) use android::PathResolver;
2930#[ cfg( not( target_os = "android" ) ) ]
3031pub ( crate ) use desktop:: PathResolver ;
3132
33+ /// A wrapper for [`PathBuf`] that prevents path traversal.
34+ #[ derive( Clone , Debug ) ]
35+ pub struct SafePathBuf ( PathBuf ) ;
36+
37+ impl SafePathBuf {
38+ /// Validates the path for directory traversal vulnerabilities and returns a new [`SafePathBuf`] instance if it is safe.
39+ pub fn new ( path : PathBuf ) -> std:: result:: Result < Self , & ' static str > {
40+ if path. components ( ) . any ( |x| matches ! ( x, Component :: ParentDir ) ) {
41+ Err ( "cannot traverse directory, rewrite the path without the use of `../`" )
42+ } else {
43+ Ok ( Self ( path) )
44+ }
45+ }
46+
47+ #[ allow( dead_code) ]
48+ pub ( crate ) unsafe fn new_unchecked ( path : PathBuf ) -> Self {
49+ Self ( path)
50+ }
51+
52+ /// Returns an object that implements [`std::fmt::Display`] for safely printing paths.
53+ ///
54+ /// See [`PathBuf#method.display`] for more information.
55+ pub fn display ( & self ) -> Display < ' _ > {
56+ self . 0 . display ( )
57+ }
58+ }
59+
60+ impl AsRef < Path > for SafePathBuf {
61+ fn as_ref ( & self ) -> & Path {
62+ self . 0 . as_ref ( )
63+ }
64+ }
65+
66+ impl < ' de > Deserialize < ' de > for SafePathBuf {
67+ fn deserialize < D > ( deserializer : D ) -> std:: result:: Result < Self , D :: Error >
68+ where
69+ D : Deserializer < ' de > ,
70+ {
71+ let path = PathBuf :: deserialize ( deserializer) ?;
72+ SafePathBuf :: new ( path) . map_err ( DeError :: custom)
73+ }
74+ }
75+
3276/// A base directory to be used in [`resolve_directory`].
3377///
3478/// The base directory is the optional root of a file system operation.
@@ -332,3 +376,21 @@ pub(crate) fn init<R: Runtime>() -> TauriPlugin<R> {
332376 } )
333377 . build ( )
334378}
379+
380+ #[ cfg( test) ]
381+ mod test {
382+ use super :: SafePathBuf ;
383+ use quickcheck:: { Arbitrary , Gen } ;
384+
385+ use std:: path:: PathBuf ;
386+
387+ impl Arbitrary for SafePathBuf {
388+ fn arbitrary ( g : & mut Gen ) -> Self {
389+ Self ( PathBuf :: arbitrary ( g) )
390+ }
391+
392+ fn shrink ( & self ) -> Box < dyn Iterator < Item = Self > > {
393+ Box :: new ( self . 0 . shrink ( ) . map ( SafePathBuf ) )
394+ }
395+ }
396+ }
0 commit comments