Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(core): add option for require_literal_leading_dot, closes #6158 #6969

Merged
merged 4 commits into from
May 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changes/config-require-literal_leading_dot.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'tauri-utils': 'patch'
---

Add option to configure `require_literal_leading_dot` on `fs` and `asset` protcol scopes.
7 changes: 7 additions & 0 deletions core/tauri-config-schema/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -2069,6 +2069,13 @@
"items": {
"type": "string"
}
},
"requireLiteralLeadingDot": {
"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",
"type": [
"boolean",
"null"
]
}
}
}
Expand Down
104 changes: 38 additions & 66 deletions core/tauri-utils/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ use crate::TitleBarStyle;

pub use self::parse::parse;

fn default_true() -> bool {
amrbashir marked this conversation as resolved.
Show resolved Hide resolved
true
}

/// An URL to open on a Tauri webview window.
#[derive(PartialEq, Eq, Debug, Clone, Deserialize, Serialize)]
#[cfg_attr(feature = "schema", derive(JsonSchema))]
Expand Down Expand Up @@ -519,23 +523,23 @@ pub enum WebviewInstallMode {
/// Results in a smaller installer size, but is not recommended on Windows 7.
DownloadBootstrapper {
/// Instructs the installer to run the bootstrapper in silent mode. Defaults to `true`.
#[serde(default = "default_webview_install_silent")]
#[serde(default = "default_true")]
silent: bool,
},
/// Embed the bootstrapper and run it.
/// Requires an internet connection.
/// Increases the installer size by around 1.8MB, but offers better support on Windows 7.
EmbedBootstrapper {
/// Instructs the installer to run the bootstrapper in silent mode. Defaults to `true`.
#[serde(default = "default_webview_install_silent")]
#[serde(default = "default_true")]
silent: bool,
},
/// Embed the offline installer and run it.
/// Does not require an internet connection.
/// Increases the installer size by around 127MB.
OfflineInstaller {
/// Instructs the installer to run the installer in silent mode. Defaults to `true`.
#[serde(default = "default_webview_install_silent")]
#[serde(default = "default_true")]
silent: bool,
},
/// Embed a fixed webview2 version and use it at runtime.
Expand All @@ -549,15 +553,9 @@ pub enum WebviewInstallMode {
},
}

fn default_webview_install_silent() -> bool {
true
}

impl Default for WebviewInstallMode {
fn default() -> Self {
Self::DownloadBootstrapper {
silent: default_webview_install_silent(),
}
Self::DownloadBootstrapper { silent: true }
}
}

Expand Down Expand Up @@ -598,7 +596,7 @@ pub struct WindowsConfig {
/// 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`.
///
/// The default value of this flag is `true`.
#[serde(default = "default_allow_downgrades", alias = "allow-downgrades")]
#[serde(default = "default_true", alias = "allow-downgrades")]
pub allow_downgrades: bool,
/// Configuration for the MSI generated with WiX.
pub wix: Option<WixConfig>,
Expand All @@ -615,17 +613,13 @@ impl Default for WindowsConfig {
tsp: false,
webview_install_mode: Default::default(),
webview_fixed_runtime_path: None,
allow_downgrades: default_allow_downgrades(),
allow_downgrades: true,
wix: None,
nsis: None,
}
}
}

fn default_allow_downgrades() -> bool {
true
}

/// Configuration for tauri-bundler.
///
/// See more: https://tauri.app/v1/api/config#bundleconfig
Expand Down Expand Up @@ -901,7 +895,7 @@ pub struct WindowConfig {
/// Whether the file drop is enabled or not on the webview. By default it is enabled.
///
/// Disabling it is required to use drag and drop on the frontend on Windows.
#[serde(default = "default_file_drop_enabled", alias = "file-drop-enabled")]
#[serde(default = "default_true", alias = "file-drop-enabled")]
pub file_drop_enabled: bool,
/// Whether or not the window starts centered or not.
#[serde(default)]
Expand Down Expand Up @@ -929,7 +923,7 @@ pub struct WindowConfig {
#[serde(alias = "max-height")]
pub max_height: Option<f64>,
/// Whether the window is resizable or not.
#[serde(default = "default_resizable")]
#[serde(default = "default_true")]
pub resizable: bool,
/// The window title.
#[serde(default = "default_title")]
Expand All @@ -938,7 +932,7 @@ pub struct WindowConfig {
#[serde(default)]
pub fullscreen: bool,
/// Whether the window will be initially focused or not.
#[serde(default = "default_focus")]
#[serde(default = "default_true")]
pub focus: bool,
/// Whether the window is transparent or not.
///
Expand All @@ -950,10 +944,10 @@ pub struct WindowConfig {
#[serde(default)]
pub maximized: bool,
/// Whether the window is visible or not.
#[serde(default = "default_visible")]
#[serde(default = "default_true")]
pub visible: bool,
/// Whether the window should have borders and bars.
#[serde(default = "default_decorations")]
#[serde(default = "default_true")]
pub decorations: bool,
/// Whether the window should always be on top of other windows.
#[serde(default, alias = "always-on-top")]
Expand Down Expand Up @@ -995,7 +989,7 @@ impl Default for WindowConfig {
label: default_window_label(),
url: WindowUrl::default(),
user_agent: None,
file_drop_enabled: default_file_drop_enabled(),
file_drop_enabled: true,
center: false,
x: None,
y: None,
Expand All @@ -1005,14 +999,14 @@ impl Default for WindowConfig {
min_height: None,
max_width: None,
max_height: None,
resizable: default_resizable(),
resizable: true,
title: default_title(),
fullscreen: false,
focus: false,
transparent: false,
maximized: false,
visible: default_visible(),
decorations: default_decorations(),
visible: true,
decorations: true,
always_on_top: false,
content_protected: false,
skip_taskbar: false,
Expand All @@ -1038,30 +1032,10 @@ fn default_height() -> f64 {
600f64
}

fn default_resizable() -> bool {
true
}

fn default_title() -> String {
"Tauri App".to_string()
}

fn default_focus() -> bool {
true
}

fn default_visible() -> bool {
true
}

fn default_decorations() -> bool {
true
}

fn default_file_drop_enabled() -> bool {
true
}

/// A Content-Security-Policy directive source list.
/// See <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/Sources#sources>.
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
Expand Down Expand Up @@ -1302,12 +1276,13 @@ macro_rules! check_feature {
/// `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$APP`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`,
/// `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[cfg_attr(feature = "schema", derive(JsonSchema))]
#[serde(untagged)]
#[cfg_attr(feature = "schema", derive(JsonSchema))]
pub enum FsAllowlistScope {
/// A list of paths that are allowed by this scope.
AllowedPaths(Vec<PathBuf>),
/// A complete scope configuration.
#[serde(rename_all = "camelCase")]
Scope {
/// A list of paths that are allowed by this scope.
#[serde(default)]
Expand All @@ -1316,6 +1291,16 @@ pub enum FsAllowlistScope {
/// This gets precedence over the [`Self::Scope::allow`] list.
#[serde(default)]
deny: Vec<PathBuf>,
/// 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.
///
/// Defaults to `false` on Unix systems and `true` on Windows
// dotfiles are not supposed to be exposed by default on unix
#[serde(alias = "require-literal-leading-dot")]
require_literal_leading_dot: Option<bool>,
},
}

Expand Down Expand Up @@ -2570,7 +2555,7 @@ pub struct UpdaterConfig {
#[serde(default)]
pub active: bool,
/// Display built-in dialog or use event system if disabled.
#[serde(default = "default_dialog")]
#[serde(default = "default_true")]
pub dialog: bool,
/// The updater endpoints. TLS is enforced on production.
///
Expand Down Expand Up @@ -2601,7 +2586,7 @@ impl<'de> Deserialize<'de> for UpdaterConfig {
struct InnerUpdaterConfig {
#[serde(default)]
active: bool,
#[serde(default = "default_dialog")]
#[serde(default = "default_true")]
dialog: bool,
endpoints: Option<Vec<UpdaterEndpoint>>,
pubkey: Option<String>,
Expand Down Expand Up @@ -2631,7 +2616,7 @@ impl Default for UpdaterConfig {
fn default() -> Self {
Self {
active: false,
dialog: default_dialog(),
dialog: true,
endpoints: None,
pubkey: "".into(),
windows: Default::default(),
Expand All @@ -2654,26 +2639,12 @@ pub struct SystemTrayConfig {
#[serde(default, alias = "icon-as-template")]
pub icon_as_template: bool,
/// A Boolean value that determines whether the menu should appear when the tray icon receives a left click on macOS.
#[serde(
default = "default_tray_menu_on_left_click",
alias = "menu-on-left-click"
)]
#[serde(default = "default_true", alias = "menu-on-left-click")]
pub menu_on_left_click: bool,
/// Title for MacOS tray
pub title: Option<String>,
}

fn default_tray_menu_on_left_click() -> bool {
true
}

// We enable the unnecessary_wraps because we need
// to use an Option for dialog otherwise the CLI schema will mark
// the dialog as a required field which is not as we default it to true.
fn default_dialog() -> bool {
true
}

/// Defines the URL or assets to embed in the application.
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[cfg_attr(feature = "schema", derive(JsonSchema))]
Expand Down Expand Up @@ -3699,10 +3670,11 @@ mod build {
let allowed_paths = vec_lit(allow, path_buf_lit);
quote! { #prefix::AllowedPaths(#allowed_paths) }
}
Self::Scope { allow, deny } => {
Self::Scope { allow, deny , require_literal_leading_dot} => {
let allow = vec_lit(allow, path_buf_lit);
let deny = vec_lit(deny, path_buf_lit);
quote! { #prefix::Scope { allow: #allow, deny: #deny } }
let require_literal_leading_dot = opt_lit(require_literal_leading_dot.as_ref());
quote! { #prefix::Scope { allow: #allow, deny: #deny, require_literal_leading_dot: #require_literal_leading_dot } }
}
});
}
Expand Down
45 changes: 33 additions & 12 deletions core/tauri/src/scope/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ pub struct Scope {
allowed_patterns: Arc<Mutex<HashSet<Pattern>>>,
forbidden_patterns: Arc<Mutex<HashSet<Pattern>>>,
event_listeners: Arc<Mutex<HashMap<Uuid, EventListener>>>,
match_options: glob::MatchOptions,
}

impl fmt::Debug for Scope {
Expand Down Expand Up @@ -106,10 +107,29 @@ impl Scope {
}
}

let require_literal_leading_dot = match scope {
FsAllowlistScope::Scope {
require_literal_leading_dot: Some(require),
..
} => *require,
// dotfiles are not supposed to be exposed by default on unix
#[cfg(unix)]
amrbashir marked this conversation as resolved.
Show resolved Hide resolved
_ => false,
#[cfg(windows)]
_ => true,
};

Ok(Self {
allowed_patterns: Arc::new(Mutex::new(allowed_patterns)),
forbidden_patterns: Arc::new(Mutex::new(forbidden_patterns)),
event_listeners: Default::default(),
match_options: glob::MatchOptions {
// this is needed so `/dir/*` doesn't match files within subdirectories such as `/dir/subdir/file.txt`
// see: https://github.com/tauri-apps/tauri/security/advisories/GHSA-6mv3-wm7j-h4w5
require_literal_separator: true,
require_literal_leading_dot,
..Default::default()
},
})
}

Expand Down Expand Up @@ -216,22 +236,12 @@ impl Scope {

if let Ok(path) = path {
let path: PathBuf = path.components().collect();
let options = glob::MatchOptions {
// this is needed so `/dir/*` doesn't match files within subdirectories such as `/dir/subdir/file.txt`
// see: https://github.com/tauri-apps/tauri/security/advisories/GHSA-6mv3-wm7j-h4w5
require_literal_separator: true,
// dotfiles are not supposed to be exposed by default
#[cfg(unix)]
require_literal_leading_dot: true,
..Default::default()
};

let forbidden = self
.forbidden_patterns
.lock()
.unwrap()
.iter()
.any(|p| p.matches_path_with(&path, options));
.any(|p| p.matches_path_with(&path, self.match_options));

if forbidden {
false
Expand All @@ -241,7 +251,7 @@ impl Scope {
.lock()
.unwrap()
.iter()
.any(|p| p.matches_path_with(&path, options));
.any(|p| p.matches_path_with(&path, self.match_options));
allowed
}
} else {
Expand Down Expand Up @@ -271,6 +281,17 @@ mod tests {
allowed_patterns: Default::default(),
forbidden_patterns: Default::default(),
event_listeners: Default::default(),
match_options: glob::MatchOptions {
// this is needed so `/dir/*` doesn't match files within subdirectories such as `/dir/subdir/file.txt`
// see: https://github.com/tauri-apps/tauri/security/advisories/GHSA-6mv3-wm7j-h4w5
require_literal_separator: true,
// dotfiles are not supposed to be exposed by default on unix
#[cfg(unix)]
require_literal_leading_dot: false,
amrbashir marked this conversation as resolved.
Show resolved Hide resolved
#[cfg(windows)]
require_literal_leading_dot: true,
..Default::default()
},
}
}

Expand Down
Loading