Skip to content

Commit acc36fe

Browse files
amrbashirsimonhyll
andauthored
feat(core): add option for require_literal_leading_dot, closes #6158 (#6969)
* feat(core): add option for `require_literal_leading_dot`, closes #6158 * change to `Option<bool>` * fix to tokens impl * Apply suggestions from code review Co-authored-by: Simon Hyll <hyllsimon@gmail.com> --------- Co-authored-by: Simon Hyll <hyllsimon@gmail.com>
1 parent cd3846c commit acc36fe

5 files changed

Lines changed: 90 additions & 78 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'tauri-utils': 'patch'
3+
---
4+
5+
Add option to configure `require_literal_leading_dot` on `fs` and `asset` protcol scopes.

‎core/tauri-config-schema/schema.json‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2069,6 +2069,13 @@
20692069
"items": {
20702070
"type": "string"
20712071
}
2072+
},
2073+
"requireLiteralLeadingDot": {
2074+
"description": "Whether or not paths that contain components that start with a `.` will require that `.` appears literally in the pattern; `*`, `?`, `**`, or `[...]` will not match. This is useful because such files are conventionally considered hidden on Unix systems and it might be desirable to skip them when listing files.\n\nDefaults to `false` on Unix systems and `true` on Windows",
2075+
"type": [
2076+
"boolean",
2077+
"null"
2078+
]
20722079
}
20732080
}
20742081
}

‎core/tauri-utils/src/config.rs‎

Lines changed: 38 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ use crate::TitleBarStyle;
3838

3939
pub use self::parse::parse;
4040

41+
fn default_true() -> bool {
42+
true
43+
}
44+
4145
/// An URL to open on a Tauri webview window.
4246
#[derive(PartialEq, Eq, Debug, Clone, Deserialize, Serialize)]
4347
#[cfg_attr(feature = "schema", derive(JsonSchema))]
@@ -519,23 +523,23 @@ pub enum WebviewInstallMode {
519523
/// Results in a smaller installer size, but is not recommended on Windows 7.
520524
DownloadBootstrapper {
521525
/// Instructs the installer to run the bootstrapper in silent mode. Defaults to `true`.
522-
#[serde(default = "default_webview_install_silent")]
526+
#[serde(default = "default_true")]
523527
silent: bool,
524528
},
525529
/// Embed the bootstrapper and run it.
526530
/// Requires an internet connection.
527531
/// Increases the installer size by around 1.8MB, but offers better support on Windows 7.
528532
EmbedBootstrapper {
529533
/// Instructs the installer to run the bootstrapper in silent mode. Defaults to `true`.
530-
#[serde(default = "default_webview_install_silent")]
534+
#[serde(default = "default_true")]
531535
silent: bool,
532536
},
533537
/// Embed the offline installer and run it.
534538
/// Does not require an internet connection.
535539
/// Increases the installer size by around 127MB.
536540
OfflineInstaller {
537541
/// Instructs the installer to run the installer in silent mode. Defaults to `true`.
538-
#[serde(default = "default_webview_install_silent")]
542+
#[serde(default = "default_true")]
539543
silent: bool,
540544
},
541545
/// Embed a fixed webview2 version and use it at runtime.
@@ -549,15 +553,9 @@ pub enum WebviewInstallMode {
549553
},
550554
}
551555

552-
fn default_webview_install_silent() -> bool {
553-
true
554-
}
555-
556556
impl Default for WebviewInstallMode {
557557
fn default() -> Self {
558-
Self::DownloadBootstrapper {
559-
silent: default_webview_install_silent(),
560-
}
558+
Self::DownloadBootstrapper { silent: true }
561559
}
562560
}
563561

@@ -598,7 +596,7 @@ pub struct WindowsConfig {
598596
/// For instance, if `1.2.1` is installed, the user won't be able to install app version `1.2.0` or `1.1.5`.
599597
///
600598
/// The default value of this flag is `true`.
601-
#[serde(default = "default_allow_downgrades", alias = "allow-downgrades")]
599+
#[serde(default = "default_true", alias = "allow-downgrades")]
602600
pub allow_downgrades: bool,
603601
/// Configuration for the MSI generated with WiX.
604602
pub wix: Option<WixConfig>,
@@ -615,17 +613,13 @@ impl Default for WindowsConfig {
615613
tsp: false,
616614
webview_install_mode: Default::default(),
617615
webview_fixed_runtime_path: None,
618-
allow_downgrades: default_allow_downgrades(),
616+
allow_downgrades: true,
619617
wix: None,
620618
nsis: None,
621619
}
622620
}
623621
}
624622

625-
fn default_allow_downgrades() -> bool {
626-
true
627-
}
628-
629623
/// Configuration for tauri-bundler.
630624
///
631625
/// See more: https://tauri.app/v1/api/config#bundleconfig
@@ -901,7 +895,7 @@ pub struct WindowConfig {
901895
/// Whether the file drop is enabled or not on the webview. By default it is enabled.
902896
///
903897
/// Disabling it is required to use drag and drop on the frontend on Windows.
904-
#[serde(default = "default_file_drop_enabled", alias = "file-drop-enabled")]
898+
#[serde(default = "default_true", alias = "file-drop-enabled")]
905899
pub file_drop_enabled: bool,
906900
/// Whether or not the window starts centered or not.
907901
#[serde(default)]
@@ -929,7 +923,7 @@ pub struct WindowConfig {
929923
#[serde(alias = "max-height")]
930924
pub max_height: Option<f64>,
931925
/// Whether the window is resizable or not.
932-
#[serde(default = "default_resizable")]
926+
#[serde(default = "default_true")]
933927
pub resizable: bool,
934928
/// The window title.
935929
#[serde(default = "default_title")]
@@ -938,7 +932,7 @@ pub struct WindowConfig {
938932
#[serde(default)]
939933
pub fullscreen: bool,
940934
/// Whether the window will be initially focused or not.
941-
#[serde(default = "default_focus")]
935+
#[serde(default = "default_true")]
942936
pub focus: bool,
943937
/// Whether the window is transparent or not.
944938
///
@@ -950,10 +944,10 @@ pub struct WindowConfig {
950944
#[serde(default)]
951945
pub maximized: bool,
952946
/// Whether the window is visible or not.
953-
#[serde(default = "default_visible")]
947+
#[serde(default = "default_true")]
954948
pub visible: bool,
955949
/// Whether the window should have borders and bars.
956-
#[serde(default = "default_decorations")]
950+
#[serde(default = "default_true")]
957951
pub decorations: bool,
958952
/// Whether the window should always be on top of other windows.
959953
#[serde(default, alias = "always-on-top")]
@@ -995,7 +989,7 @@ impl Default for WindowConfig {
995989
label: default_window_label(),
996990
url: WindowUrl::default(),
997991
user_agent: None,
998-
file_drop_enabled: default_file_drop_enabled(),
992+
file_drop_enabled: true,
999993
center: false,
1000994
x: None,
1001995
y: None,
@@ -1005,14 +999,14 @@ impl Default for WindowConfig {
1005999
min_height: None,
10061000
max_width: None,
10071001
max_height: None,
1008-
resizable: default_resizable(),
1002+
resizable: true,
10091003
title: default_title(),
10101004
fullscreen: false,
10111005
focus: false,
10121006
transparent: false,
10131007
maximized: false,
1014-
visible: default_visible(),
1015-
decorations: default_decorations(),
1008+
visible: true,
1009+
decorations: true,
10161010
always_on_top: false,
10171011
content_protected: false,
10181012
skip_taskbar: false,
@@ -1038,30 +1032,10 @@ fn default_height() -> f64 {
10381032
600f64
10391033
}
10401034

1041-
fn default_resizable() -> bool {
1042-
true
1043-
}
1044-
10451035
fn default_title() -> String {
10461036
"Tauri App".to_string()
10471037
}
10481038

1049-
fn default_focus() -> bool {
1050-
true
1051-
}
1052-
1053-
fn default_visible() -> bool {
1054-
true
1055-
}
1056-
1057-
fn default_decorations() -> bool {
1058-
true
1059-
}
1060-
1061-
fn default_file_drop_enabled() -> bool {
1062-
true
1063-
}
1064-
10651039
/// A Content-Security-Policy directive source list.
10661040
/// See <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/Sources#sources>.
10671041
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
@@ -1302,12 +1276,13 @@ macro_rules! check_feature {
13021276
/// `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$APP`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`,
13031277
/// `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.
13041278
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
1305-
#[cfg_attr(feature = "schema", derive(JsonSchema))]
13061279
#[serde(untagged)]
1280+
#[cfg_attr(feature = "schema", derive(JsonSchema))]
13071281
pub enum FsAllowlistScope {
13081282
/// A list of paths that are allowed by this scope.
13091283
AllowedPaths(Vec<PathBuf>),
13101284
/// A complete scope configuration.
1285+
#[serde(rename_all = "camelCase")]
13111286
Scope {
13121287
/// A list of paths that are allowed by this scope.
13131288
#[serde(default)]
@@ -1316,6 +1291,16 @@ pub enum FsAllowlistScope {
13161291
/// This gets precedence over the [`Self::Scope::allow`] list.
13171292
#[serde(default)]
13181293
deny: Vec<PathBuf>,
1294+
/// Whether or not paths that contain components that start with a `.`
1295+
/// will require that `.` appears literally in the pattern; `*`, `?`, `**`,
1296+
/// or `[...]` will not match. This is useful because such files are
1297+
/// conventionally considered hidden on Unix systems and it might be
1298+
/// desirable to skip them when listing files.
1299+
///
1300+
/// Defaults to `false` on Unix systems and `true` on Windows
1301+
// dotfiles are not supposed to be exposed by default on unix
1302+
#[serde(alias = "require-literal-leading-dot")]
1303+
require_literal_leading_dot: Option<bool>,
13191304
},
13201305
}
13211306

@@ -2580,7 +2565,7 @@ pub struct UpdaterConfig {
25802565
#[serde(default)]
25812566
pub active: bool,
25822567
/// Display built-in dialog or use event system if disabled.
2583-
#[serde(default = "default_dialog")]
2568+
#[serde(default = "default_true")]
25842569
pub dialog: bool,
25852570
/// The updater endpoints. TLS is enforced on production.
25862571
///
@@ -2611,7 +2596,7 @@ impl<'de> Deserialize<'de> for UpdaterConfig {
26112596
struct InnerUpdaterConfig {
26122597
#[serde(default)]
26132598
active: bool,
2614-
#[serde(default = "default_dialog")]
2599+
#[serde(default = "default_true")]
26152600
dialog: bool,
26162601
endpoints: Option<Vec<UpdaterEndpoint>>,
26172602
pubkey: Option<String>,
@@ -2641,7 +2626,7 @@ impl Default for UpdaterConfig {
26412626
fn default() -> Self {
26422627
Self {
26432628
active: false,
2644-
dialog: default_dialog(),
2629+
dialog: true,
26452630
endpoints: None,
26462631
pubkey: "".into(),
26472632
windows: Default::default(),
@@ -2664,26 +2649,12 @@ pub struct SystemTrayConfig {
26642649
#[serde(default, alias = "icon-as-template")]
26652650
pub icon_as_template: bool,
26662651
/// A Boolean value that determines whether the menu should appear when the tray icon receives a left click on macOS.
2667-
#[serde(
2668-
default = "default_tray_menu_on_left_click",
2669-
alias = "menu-on-left-click"
2670-
)]
2652+
#[serde(default = "default_true", alias = "menu-on-left-click")]
26712653
pub menu_on_left_click: bool,
26722654
/// Title for MacOS tray
26732655
pub title: Option<String>,
26742656
}
26752657

2676-
fn default_tray_menu_on_left_click() -> bool {
2677-
true
2678-
}
2679-
2680-
// We enable the unnecessary_wraps because we need
2681-
// to use an Option for dialog otherwise the CLI schema will mark
2682-
// the dialog as a required field which is not as we default it to true.
2683-
fn default_dialog() -> bool {
2684-
true
2685-
}
2686-
26872658
/// Defines the URL or assets to embed in the application.
26882659
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
26892660
#[cfg_attr(feature = "schema", derive(JsonSchema))]
@@ -3709,10 +3680,11 @@ mod build {
37093680
let allowed_paths = vec_lit(allow, path_buf_lit);
37103681
quote! { #prefix::AllowedPaths(#allowed_paths) }
37113682
}
3712-
Self::Scope { allow, deny } => {
3683+
Self::Scope { allow, deny , require_literal_leading_dot} => {
37133684
let allow = vec_lit(allow, path_buf_lit);
37143685
let deny = vec_lit(deny, path_buf_lit);
3715-
quote! { #prefix::Scope { allow: #allow, deny: #deny } }
3686+
let require_literal_leading_dot = opt_lit(require_literal_leading_dot.as_ref());
3687+
quote! { #prefix::Scope { allow: #allow, deny: #deny, require_literal_leading_dot: #require_literal_leading_dot } }
37163688
}
37173689
});
37183690
}

‎core/tauri/src/scope/fs.rs‎

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ pub struct Scope {
3535
allowed_patterns: Arc<Mutex<HashSet<Pattern>>>,
3636
forbidden_patterns: Arc<Mutex<HashSet<Pattern>>>,
3737
event_listeners: Arc<Mutex<HashMap<Uuid, EventListener>>>,
38+
match_options: glob::MatchOptions,
3839
}
3940

4041
impl fmt::Debug for Scope {
@@ -106,10 +107,29 @@ impl Scope {
106107
}
107108
}
108109

110+
let require_literal_leading_dot = match scope {
111+
FsAllowlistScope::Scope {
112+
require_literal_leading_dot: Some(require),
113+
..
114+
} => *require,
115+
// dotfiles are not supposed to be exposed by default on unix
116+
#[cfg(unix)]
117+
_ => false,
118+
#[cfg(windows)]
119+
_ => true,
120+
};
121+
109122
Ok(Self {
110123
allowed_patterns: Arc::new(Mutex::new(allowed_patterns)),
111124
forbidden_patterns: Arc::new(Mutex::new(forbidden_patterns)),
112125
event_listeners: Default::default(),
126+
match_options: glob::MatchOptions {
127+
// this is needed so `/dir/*` doesn't match files within subdirectories such as `/dir/subdir/file.txt`
128+
// see: https://github.com/tauri-apps/tauri/security/advisories/GHSA-6mv3-wm7j-h4w5
129+
require_literal_separator: true,
130+
require_literal_leading_dot,
131+
..Default::default()
132+
},
113133
})
114134
}
115135

@@ -216,22 +236,12 @@ impl Scope {
216236

217237
if let Ok(path) = path {
218238
let path: PathBuf = path.components().collect();
219-
let options = glob::MatchOptions {
220-
// this is needed so `/dir/*` doesn't match files within subdirectories such as `/dir/subdir/file.txt`
221-
// see: https://github.com/tauri-apps/tauri/security/advisories/GHSA-6mv3-wm7j-h4w5
222-
require_literal_separator: true,
223-
// dotfiles are not supposed to be exposed by default
224-
#[cfg(unix)]
225-
require_literal_leading_dot: true,
226-
..Default::default()
227-
};
228-
229239
let forbidden = self
230240
.forbidden_patterns
231241
.lock()
232242
.unwrap()
233243
.iter()
234-
.any(|p| p.matches_path_with(&path, options));
244+
.any(|p| p.matches_path_with(&path, self.match_options));
235245

236246
if forbidden {
237247
false
@@ -241,7 +251,7 @@ impl Scope {
241251
.lock()
242252
.unwrap()
243253
.iter()
244-
.any(|p| p.matches_path_with(&path, options));
254+
.any(|p| p.matches_path_with(&path, self.match_options));
245255
allowed
246256
}
247257
} else {
@@ -271,6 +281,17 @@ mod tests {
271281
allowed_patterns: Default::default(),
272282
forbidden_patterns: Default::default(),
273283
event_listeners: Default::default(),
284+
match_options: glob::MatchOptions {
285+
// this is needed so `/dir/*` doesn't match files within subdirectories such as `/dir/subdir/file.txt`
286+
// see: https://github.com/tauri-apps/tauri/security/advisories/GHSA-6mv3-wm7j-h4w5
287+
require_literal_separator: true,
288+
// dotfiles are not supposed to be exposed by default on unix
289+
#[cfg(unix)]
290+
require_literal_leading_dot: false,
291+
#[cfg(windows)]
292+
require_literal_leading_dot: true,
293+
..Default::default()
294+
},
274295
}
275296
}
276297

0 commit comments

Comments
 (0)