55use std:: {
66 collections:: { HashMap , HashSet } ,
77 fmt,
8- path:: { Path , PathBuf } ,
8+ path:: { Path , PathBuf , MAIN_SEPARATOR } ,
99 sync:: { Arc , Mutex } ,
1010} ;
1111
@@ -64,15 +64,19 @@ impl fmt::Debug for Scope {
6464 }
6565}
6666
67- fn push_pattern < P : AsRef < Path > > ( list : & mut HashSet < Pattern > , pattern : P ) -> crate :: Result < ( ) > {
67+ fn push_pattern < P : AsRef < Path > , F : Fn ( & str ) -> Result < Pattern , glob:: PatternError > > (
68+ list : & mut HashSet < Pattern > ,
69+ pattern : P ,
70+ f : F ,
71+ ) -> crate :: Result < ( ) > {
6872 let path: PathBuf = pattern. as_ref ( ) . components ( ) . collect ( ) ;
69- list. insert ( Pattern :: new ( & path. to_string_lossy ( ) ) ?) ;
73+ list. insert ( f ( & path. to_string_lossy ( ) ) ?) ;
7074 #[ cfg( windows) ]
7175 {
7276 if let Ok ( p) = std:: fs:: canonicalize ( & path) {
73- list. insert ( Pattern :: new ( & p. to_string_lossy ( ) ) ?) ;
77+ list. insert ( f ( & p. to_string_lossy ( ) ) ?) ;
7478 } else {
75- list. insert ( Pattern :: new ( & format ! ( "\\ \\ ?\\ {}" , path. display( ) ) ) ?) ;
79+ list. insert ( f ( & format ! ( "\\ \\ ?\\ {}" , path. display( ) ) ) ?) ;
7680 }
7781 }
7882 Ok ( ( ) )
@@ -89,15 +93,15 @@ impl Scope {
8993 let mut allowed_patterns = HashSet :: new ( ) ;
9094 for path in scope. allowed_paths ( ) {
9195 if let Ok ( path) = parse_path ( config, package_info, env, path) {
92- push_pattern ( & mut allowed_patterns, path) ?;
96+ push_pattern ( & mut allowed_patterns, path, Pattern :: new ) ?;
9397 }
9498 }
9599
96100 let mut forbidden_patterns = HashSet :: new ( ) ;
97101 if let Some ( forbidden_paths) = scope. forbidden_paths ( ) {
98102 for path in forbidden_paths {
99103 if let Ok ( path) = parse_path ( config, package_info, env, path) {
100- push_pattern ( & mut forbidden_patterns, path) ?;
104+ push_pattern ( & mut forbidden_patterns, path, Pattern :: new ) ?;
101105 }
102106 }
103107 }
@@ -139,16 +143,18 @@ impl Scope {
139143 /// After this function has been called, the frontend will be able to use the Tauri API to read
140144 /// the directory and all of its files and subdirectories.
141145 pub fn allow_directory < P : AsRef < Path > > ( & self , path : P , recursive : bool ) -> crate :: Result < ( ) > {
142- let path = path. as_ref ( ) . to_path_buf ( ) ;
146+ let path = path. as_ref ( ) ;
143147 {
144148 let mut list = self . allowed_patterns . lock ( ) . unwrap ( ) ;
145149
146150 // allow the directory to be read
147- push_pattern ( & mut list, & path) ?;
151+ push_pattern ( & mut list, & path, escaped_pattern ) ?;
148152 // allow its files and subdirectories to be read
149- push_pattern ( & mut list, path. join ( if recursive { "**" } else { "*" } ) ) ?;
153+ push_pattern ( & mut list, & path, |p| {
154+ escaped_pattern_with ( p, if recursive { "**" } else { "*" } )
155+ } ) ?;
150156 }
151- self . trigger ( Event :: PathAllowed ( path) ) ;
157+ self . trigger ( Event :: PathAllowed ( path. to_path_buf ( ) ) ) ;
152158 Ok ( ( ) )
153159 }
154160
@@ -157,7 +163,11 @@ impl Scope {
157163 /// After this function has been called, the frontend will be able to use the Tauri API to read the contents of this file.
158164 pub fn allow_file < P : AsRef < Path > > ( & self , path : P ) -> crate :: Result < ( ) > {
159165 let path = path. as_ref ( ) ;
160- push_pattern ( & mut self . allowed_patterns . lock ( ) . unwrap ( ) , & path) ?;
166+ push_pattern (
167+ & mut self . allowed_patterns . lock ( ) . unwrap ( ) ,
168+ & path,
169+ escaped_pattern,
170+ ) ?;
161171 self . trigger ( Event :: PathAllowed ( path. to_path_buf ( ) ) ) ;
162172 Ok ( ( ) )
163173 }
@@ -166,16 +176,18 @@ impl Scope {
166176 ///
167177 /// **Note:** this takes precedence over allowed paths, so its access gets denied **always**.
168178 pub fn forbid_directory < P : AsRef < Path > > ( & self , path : P , recursive : bool ) -> crate :: Result < ( ) > {
169- let path = path. as_ref ( ) . to_path_buf ( ) ;
179+ let path = path. as_ref ( ) ;
170180 {
171181 let mut list = self . forbidden_patterns . lock ( ) . unwrap ( ) ;
172182
173183 // allow the directory to be read
174- push_pattern ( & mut list, & path) ?;
184+ push_pattern ( & mut list, & path, escaped_pattern ) ?;
175185 // allow its files and subdirectories to be read
176- push_pattern ( & mut list, path. join ( if recursive { "**" } else { "*" } ) ) ?;
186+ push_pattern ( & mut list, & path, |p| {
187+ escaped_pattern_with ( p, if recursive { "**" } else { "*" } )
188+ } ) ?;
177189 }
178- self . trigger ( Event :: PathForbidden ( path) ) ;
190+ self . trigger ( Event :: PathForbidden ( path. to_path_buf ( ) ) ) ;
179191 Ok ( ( ) )
180192 }
181193
@@ -184,7 +196,11 @@ impl Scope {
184196 /// **Note:** this takes precedence over allowed paths, so its access gets denied **always**.
185197 pub fn forbid_file < P : AsRef < Path > > ( & self , path : P ) -> crate :: Result < ( ) > {
186198 let path = path. as_ref ( ) ;
187- push_pattern ( & mut self . forbidden_patterns . lock ( ) . unwrap ( ) , & path) ?;
199+ push_pattern (
200+ & mut self . forbidden_patterns . lock ( ) . unwrap ( ) ,
201+ & path,
202+ escaped_pattern,
203+ ) ?;
188204 self . trigger ( Event :: PathForbidden ( path. to_path_buf ( ) ) ) ;
189205 Ok ( ( ) )
190206 }
@@ -224,3 +240,61 @@ impl Scope {
224240 }
225241 }
226242}
243+
244+ fn escaped_pattern ( p : & str ) -> Result < Pattern , glob:: PatternError > {
245+ Pattern :: new ( & glob:: Pattern :: escape ( p) )
246+ }
247+
248+ fn escaped_pattern_with ( p : & str , append : & str ) -> Result < Pattern , glob:: PatternError > {
249+ Pattern :: new ( & format ! (
250+ "{}{}{}" ,
251+ glob:: Pattern :: escape( p) ,
252+ MAIN_SEPARATOR ,
253+ append
254+ ) )
255+ }
256+
257+ #[ cfg( test) ]
258+ mod tests {
259+ use super :: Scope ;
260+
261+ fn new_scope ( ) -> Scope {
262+ Scope {
263+ allowed_patterns : Default :: default ( ) ,
264+ forbidden_patterns : Default :: default ( ) ,
265+ event_listeners : Default :: default ( ) ,
266+ }
267+ }
268+
269+ #[ test]
270+ fn path_is_escaped ( ) {
271+ let scope = new_scope ( ) ;
272+ scope. allow_directory ( "/home/tauri/**" , false ) . unwrap ( ) ;
273+ assert ! ( scope. is_allowed( "/home/tauri/**" ) ) ;
274+ assert ! ( scope. is_allowed( "/home/tauri/**/file" ) ) ;
275+ assert ! ( !scope. is_allowed( "/home/tauri/anyfile" ) ) ;
276+
277+ let scope = new_scope ( ) ;
278+ scope. allow_file ( "/home/tauri/**" ) . unwrap ( ) ;
279+ assert ! ( scope. is_allowed( "/home/tauri/**" ) ) ;
280+ assert ! ( !scope. is_allowed( "/home/tauri/**/file" ) ) ;
281+ assert ! ( !scope. is_allowed( "/home/tauri/anyfile" ) ) ;
282+
283+ let scope = new_scope ( ) ;
284+ scope. allow_directory ( "/home/tauri" , true ) . unwrap ( ) ;
285+ scope. forbid_directory ( "/home/tauri/**" , false ) . unwrap ( ) ;
286+ assert ! ( !scope. is_allowed( "/home/tauri/**" ) ) ;
287+ assert ! ( !scope. is_allowed( "/home/tauri/**/file" ) ) ;
288+ assert ! ( !scope. is_allowed( "/home/tauri/**/inner/file" ) ) ;
289+ assert ! ( scope. is_allowed( "/home/tauri/inner/folder/anyfile" ) ) ;
290+ assert ! ( scope. is_allowed( "/home/tauri/anyfile" ) ) ;
291+
292+ let scope = new_scope ( ) ;
293+ scope. allow_directory ( "/home/tauri" , true ) . unwrap ( ) ;
294+ scope. forbid_file ( "/home/tauri/**" ) . unwrap ( ) ;
295+ assert ! ( !scope. is_allowed( "/home/tauri/**" ) ) ;
296+ assert ! ( scope. is_allowed( "/home/tauri/**/file" ) ) ;
297+ assert ! ( scope. is_allowed( "/home/tauri/**/inner/file" ) ) ;
298+ assert ! ( scope. is_allowed( "/home/tauri/anyfile" ) ) ;
299+ }
300+ }
0 commit comments