Skip to content

Commit 9cf0390

Browse files
tweidingerlucasfernogchippers
authored
Merge commit from fork
* fix(shell): properly validate open scope * change empty regex to an impossible match --------- Co-authored-by: Lucas Nogueira <[email protected]> Co-authored-by: Chip Reed <[email protected]>
1 parent 4dd5c51 commit 9cf0390

File tree

11 files changed

+44
-11
lines changed

11 files changed

+44
-11
lines changed

.changes/fix-shell-open-scope.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"shell": patch:bug
3+
"shell-js": patch:bug
4+
---
5+
6+
Apply the default open validation regex `^((mailto:\w+)|(tel:\w+)|(https?://\w+)).+` when the open configuration is not set, preventing unchecked input from being used in this scenario (previously the plugin would skip validation when it should disable all calls). This keeps backwards compatibility while still fixing this vulnerability.
7+
The scope is no longer validated for Rust calls via `ShellExt::shell()` so if you need to block JavaScript from calling the API you can simply set `tauri.conf.json > plugins > shell > open` to `false`.

examples/api/src-tauri/capabilities/base.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@
5353
}
5454
]
5555
},
56-
"shell:allow-open",
56+
"shell:default",
5757
"shell:allow-kill",
5858
"shell:allow-stdin-write",
5959
"process:allow-exit",

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,5 +35,6 @@
3535
},
3636
"engines": {
3737
"pnpm": "^10.0.0"
38-
}
38+
},
39+
"packageManager": "[email protected]+sha512.bb45e34d50a9a76e858a95837301bfb6bd6d35aea2c5d52094fa497a467c43f5c440103ce2511e9e0a2f89c3d6071baac3358fc68ac6fb75e2ceb3d2736065e6"
3940
}

plugins/shell/permissions/autogenerated/reference.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ shell functionality is exposed by default.
55

66
#### Granted Permissions
77

8-
It allows to use the `open` functionality without any specific
8+
It allows to use the `open` functionality with a reasonable
99
scope pre-configured. It will allow opening `http(s)://`,
1010
`tel:` and `mailto:` links.
1111

plugins/shell/permissions/default.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ shell functionality is exposed by default.
77
88
#### Granted Permissions
99
10-
It allows to use the `open` functionality without any specific
10+
It allows to use the `open` functionality with a reasonable
1111
scope pre-configured. It will allow opening `http(s)://`,
1212
`tel:` and `mailto:` links.
1313
"""

plugins/shell/permissions/schemas/schema.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,7 @@
355355
"markdownDescription": "Denies the stdin_write command without any pre-configured scope."
356356
},
357357
{
358-
"description": "This permission set configures which\nshell functionality is exposed by default.\n\n#### Granted Permissions\n\nIt allows to use the `open` functionality without any specific\nscope pre-configured. It will allow opening `http(s)://`,\n`tel:` and `mailto:` links.\n\n#### This default permission set includes:\n\n- `allow-open`",
358+
"description": "This permission set configures which\nshell functionality is exposed by default.\n\n#### Granted Permissions\n\nIt allows to use the `open` functionality with a reasonable\nscope pre-configured. It will allow opening `http(s)://`,\n`tel:` and `mailto:` links.\n",
359359
"type": "string",
360360
"const": "default",
361361
"markdownDescription": "This permission set configures which\nshell functionality is exposed by default.\n\n#### Granted Permissions\n\nIt allows to use the `open` functionality without any specific\nscope pre-configured. It will allow opening `http(s)://`,\n`tel:` and `mailto:` links.\n\n#### This default permission set includes:\n\n- `allow-open`"

plugins/shell/src/commands.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -311,5 +311,5 @@ pub async fn open<R: Runtime>(
311311
path: String,
312312
with: Option<Program>,
313313
) -> crate::Result<()> {
314-
shell.open(path, with)
314+
crate::open::open(Some(&shell.open_scope), path, with)
315315
}

plugins/shell/src/config.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ pub struct Config {
1818
#[serde(untagged, deny_unknown_fields)]
1919
#[non_exhaustive]
2020
pub enum ShellAllowlistOpen {
21+
/// Shell open API allowlist is not defined by the user.
22+
/// In this case we add the default validation regex (same as [`Self::Flag(true)`]).
23+
Unset,
2124
/// If the shell open API should be enabled.
2225
///
2326
/// If enabled, the default validation regex (`^((mailto:\w+)|(tel:\w+)|(https?://\w+)).+`) is used.
@@ -35,6 +38,6 @@ pub enum ShellAllowlistOpen {
3538

3639
impl Default for ShellAllowlistOpen {
3740
fn default() -> Self {
38-
Self::Flag(false)
41+
Self::Unset
3942
}
4043
}

plugins/shell/src/lib.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ impl<R: Runtime> Shell<R> {
7575
#[deprecated(since = "2.1.0", note = "Use tauri-plugin-opener instead.")]
7676
#[allow(deprecated)]
7777
pub fn open(&self, path: impl Into<String>, with: Option<open::Program>) -> Result<()> {
78-
open::open(&self.open_scope, path.into(), with)
78+
open::open(None, path.into(), with)
7979
}
8080

8181
/// Open a (url) path with a default or specific browser opening program.
@@ -147,7 +147,8 @@ pub fn init<R: Runtime>() -> TauriPlugin<R, Option<config::Config>> {
147147
fn open_scope(open: &config::ShellAllowlistOpen) -> scope::OpenScope {
148148
let shell_scope_open = match open {
149149
config::ShellAllowlistOpen::Flag(false) => None,
150-
config::ShellAllowlistOpen::Flag(true) => {
150+
// we want to add a basic regex validation even if the config is not set
151+
config::ShellAllowlistOpen::Unset | config::ShellAllowlistOpen::Flag(true) => {
151152
Some(Regex::new(r"^((mailto:\w+)|(tel:\w+)|(https?://\w+)).+").unwrap())
152153
}
153154
config::ShellAllowlistOpen::Validate(validator) => {

plugins/shell/src/open.rs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,20 @@ impl Program {
119119
/// });
120120
/// ```
121121
#[deprecated(since = "2.1.0", note = "Use tauri-plugin-opener instead.")]
122-
pub fn open<P: AsRef<str>>(scope: &OpenScope, path: P, with: Option<Program>) -> crate::Result<()> {
123-
scope.open(path.as_ref(), with).map_err(Into::into)
122+
pub fn open<P: AsRef<str>>(
123+
scope: Option<&OpenScope>,
124+
path: P,
125+
with: Option<Program>,
126+
) -> crate::Result<()> {
127+
// validate scope if we have any (JS calls)
128+
if let Some(scope) = scope {
129+
scope.open(path.as_ref(), with).map_err(Into::into)
130+
} else {
131+
// when running directly from Rust code we don't need to validate the path
132+
match with.map(Program::name) {
133+
Some(program) => ::open::with_detached(path.as_ref(), program),
134+
None => ::open::that_detached(path.as_ref()),
135+
}
136+
.map_err(Into::into)
137+
}
124138
}

0 commit comments

Comments
 (0)