5
5
use std:: {
6
6
collections:: { HashMap , HashSet } ,
7
7
fmt,
8
- path:: { Path , PathBuf } ,
8
+ path:: { Path , PathBuf , MAIN_SEPARATOR } ,
9
9
sync:: { Arc , Mutex } ,
10
10
} ;
11
11
@@ -64,15 +64,19 @@ impl fmt::Debug for Scope {
64
64
}
65
65
}
66
66
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 < ( ) > {
68
72
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 ( ) ) ?) ;
70
74
#[ cfg( windows) ]
71
75
{
72
76
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 ( ) ) ?) ;
74
78
} else {
75
- list. insert ( Pattern :: new ( & format ! ( "\\ \\ ?\\ {}" , path. display( ) ) ) ?) ;
79
+ list. insert ( f ( & format ! ( "\\ \\ ?\\ {}" , path. display( ) ) ) ?) ;
76
80
}
77
81
}
78
82
Ok ( ( ) )
@@ -89,15 +93,15 @@ impl Scope {
89
93
let mut allowed_patterns = HashSet :: new ( ) ;
90
94
for path in scope. allowed_paths ( ) {
91
95
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 ) ?;
93
97
}
94
98
}
95
99
96
100
let mut forbidden_patterns = HashSet :: new ( ) ;
97
101
if let Some ( forbidden_paths) = scope. forbidden_paths ( ) {
98
102
for path in forbidden_paths {
99
103
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 ) ?;
101
105
}
102
106
}
103
107
}
@@ -139,16 +143,18 @@ impl Scope {
139
143
/// After this function has been called, the frontend will be able to use the Tauri API to read
140
144
/// the directory and all of its files and subdirectories.
141
145
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 ( ) ;
143
147
{
144
148
let mut list = self . allowed_patterns . lock ( ) . unwrap ( ) ;
145
149
146
150
// allow the directory to be read
147
- push_pattern ( & mut list, & path) ?;
151
+ push_pattern ( & mut list, & path, escaped_pattern ) ?;
148
152
// 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
+ } ) ?;
150
156
}
151
- self . trigger ( Event :: PathAllowed ( path) ) ;
157
+ self . trigger ( Event :: PathAllowed ( path. to_path_buf ( ) ) ) ;
152
158
Ok ( ( ) )
153
159
}
154
160
@@ -157,7 +163,11 @@ impl Scope {
157
163
/// After this function has been called, the frontend will be able to use the Tauri API to read the contents of this file.
158
164
pub fn allow_file < P : AsRef < Path > > ( & self , path : P ) -> crate :: Result < ( ) > {
159
165
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
+ ) ?;
161
171
self . trigger ( Event :: PathAllowed ( path. to_path_buf ( ) ) ) ;
162
172
Ok ( ( ) )
163
173
}
@@ -166,16 +176,18 @@ impl Scope {
166
176
///
167
177
/// **Note:** this takes precedence over allowed paths, so its access gets denied **always**.
168
178
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 ( ) ;
170
180
{
171
181
let mut list = self . forbidden_patterns . lock ( ) . unwrap ( ) ;
172
182
173
183
// allow the directory to be read
174
- push_pattern ( & mut list, & path) ?;
184
+ push_pattern ( & mut list, & path, escaped_pattern ) ?;
175
185
// 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
+ } ) ?;
177
189
}
178
- self . trigger ( Event :: PathForbidden ( path) ) ;
190
+ self . trigger ( Event :: PathForbidden ( path. to_path_buf ( ) ) ) ;
179
191
Ok ( ( ) )
180
192
}
181
193
@@ -184,7 +196,11 @@ impl Scope {
184
196
/// **Note:** this takes precedence over allowed paths, so its access gets denied **always**.
185
197
pub fn forbid_file < P : AsRef < Path > > ( & self , path : P ) -> crate :: Result < ( ) > {
186
198
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
+ ) ?;
188
204
self . trigger ( Event :: PathForbidden ( path. to_path_buf ( ) ) ) ;
189
205
Ok ( ( ) )
190
206
}
@@ -224,3 +240,61 @@ impl Scope {
224
240
}
225
241
}
226
242
}
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