diff --git a/.changes/config.json b/.changes/config.json
index 5f5fe841d9..ec0fd74863 100644
--- a/.changes/config.json
+++ b/.changes/config.json
@@ -62,6 +62,7 @@
"dialog",
"fs",
"global-shortcut",
+ "opener",
"http",
"nfc",
"notification",
@@ -87,6 +88,7 @@
"dialog-js",
"fs-js",
"global-shortcut-js",
+ "opener-js",
"http-js",
"nfc-js",
"notification-js",
@@ -186,6 +188,14 @@
"path": "./plugins/global-shortcut",
"manager": "javascript"
},
+ "opener": {
+ "path": "./plugins/opener",
+ "manager": "rust"
+ },
+ "opener-js": {
+ "path": "./plugins/opener",
+ "manager": "javascript"
+ },
"haptics": {
"path": "./plugins/haptics",
"manager": "rust"
diff --git a/.changes/opener-initial.md b/.changes/opener-initial.md
new file mode 100644
index 0000000000..151ea9c154
--- /dev/null
+++ b/.changes/opener-initial.md
@@ -0,0 +1,6 @@
+---
+"opener": "major"
+"opener-js": "major"
+---
+
+Initial Release
diff --git a/.github/workflows/check-generated-files.yml b/.github/workflows/check-generated-files.yml
index 96bbdd05ae..d2c2c8745d 100644
--- a/.github/workflows/check-generated-files.yml
+++ b/.github/workflows/check-generated-files.yml
@@ -53,6 +53,10 @@ jobs:
- .github/workflows/check-generated-files.yml
- plugins/global-shortcut/guest-js/**
- plugins/global-shortcut/src/api-iife.js
+ opener:
+ - .github/workflows/check-generated-files.yml
+ - plugins/opener/guest-js/**
+ - plugins/opener/src/api-iife.js
haptics:
- .github/workflows/check-generated-files.yml
- plugins/haptics/guest-js/**
diff --git a/.github/workflows/lint-rust.yml b/.github/workflows/lint-rust.yml
index d9e0c50cbc..db922ef1a4 100644
--- a/.github/workflows/lint-rust.yml
+++ b/.github/workflows/lint-rust.yml
@@ -66,6 +66,9 @@ jobs:
tauri-plugin-global-shortcut:
- .github/workflows/lint-rust.yml
- plugins/global-shortcut/**
+ tauri-plugin-opener:
+ - .github/workflows/lint-rust.yml
+ - plugins/opener/**
tauri-plugin-haptics:
- .github/workflows/lint-rust.yml
- plugins/haptics/**
diff --git a/.github/workflows/test-rust.yml b/.github/workflows/test-rust.yml
index 3793160d22..595bfb7633 100644
--- a/.github/workflows/test-rust.yml
+++ b/.github/workflows/test-rust.yml
@@ -77,6 +77,10 @@ jobs:
- .github/workflows/test-rust.yml
- Cargo.toml
- plugins/global-shortcut/**
+ tauri-plugin-opener:
+ - .github/workflows/test-rust.yml
+ - Cargo.toml
+ - plugins/opener/**
tauri-plugin-haptics:
- .github/workflows/test-rust.yml
- Cargo.toml
diff --git a/Cargo.lock b/Cargo.lock
index d39baf2761..fc20705476 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -226,6 +226,7 @@ dependencies = [
"tauri-plugin-log",
"tauri-plugin-nfc",
"tauri-plugin-notification",
+ "tauri-plugin-opener",
"tauri-plugin-os",
"tauri-plugin-process",
"tauri-plugin-shell",
@@ -6696,6 +6697,26 @@ dependencies = [
"windows-version",
]
+[[package]]
+name = "tauri-plugin-opener"
+version = "1.0.0"
+dependencies = [
+ "dunce",
+ "glob",
+ "objc2-app-kit",
+ "objc2-foundation",
+ "open",
+ "schemars",
+ "serde",
+ "serde_json",
+ "tauri",
+ "tauri-plugin",
+ "thiserror 2.0.3",
+ "url",
+ "windows 0.58.0",
+ "zbus 4.4.0",
+]
+
[[package]]
name = "tauri-plugin-os"
version = "2.0.1"
diff --git a/Cargo.toml b/Cargo.toml
index 4143e048df..f1fee04357 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -21,6 +21,8 @@ url = "2"
schemars = "0.8"
dunce = "1"
specta = "=2.0.0-rc.20"
+glob = "0.3"
+zbus = "4"
#tauri-specta = "=2.0.0-rc.11"
[workspace.package]
diff --git a/README.md b/README.md
index fe4f90f2bb..f9fa736afc 100644
--- a/README.md
+++ b/README.md
@@ -22,6 +22,7 @@ This repo and all plugins require a Rust version of at least **1.77.2**
| [log](plugins/log) | Configurable logging. | ✅ | ✅ | ✅ | ✅ | ✅ |
| [nfc](plugins/nfc) | Read and write NFC tags on Android and iOS. | ? | ? | ? | ✅ | ✅ |
| [notification](plugins/notification) | Send message notifications (brief auto-expiring OS window element) to your user. Can also be used with the Notification Web API. | ✅ | ✅ | ✅ | ✅ | ✅ |
+| [opener](plugins/opener) | Open files and URLs using their default application. | ✅ | ✅ | ✅ | ? | ? |
| [os](plugins/os) | Read information about the operating system. | ✅ | ✅ | ✅ | ✅ | ✅ |
| [persisted-scope](plugins/persisted-scope) | Persist runtime scope changes on the filesystem. | ✅ | ✅ | ✅ | ? | ? |
| [positioner](plugins/positioner) | Move windows to common locations. | ✅ | ✅ | ✅ | ❌ | ❌ |
diff --git a/examples/api/package.json b/examples/api/package.json
index 53b66b37df..30f59bed03 100644
--- a/examples/api/package.json
+++ b/examples/api/package.json
@@ -19,6 +19,7 @@
"@tauri-apps/plugin-fs": "2.0.2",
"@tauri-apps/plugin-geolocation": "2.0.0",
"@tauri-apps/plugin-global-shortcut": "2.0.0",
+ "@tauri-apps/plugin-opener": "1.0.0",
"@tauri-apps/plugin-haptics": "2.0.0",
"@tauri-apps/plugin-http": "2.0.1",
"@tauri-apps/plugin-nfc": "2.0.0",
diff --git a/examples/api/src-tauri/Cargo.toml b/examples/api/src-tauri/Cargo.toml
index 6bf0161492..90d2787609 100644
--- a/examples/api/src-tauri/Cargo.toml
+++ b/examples/api/src-tauri/Cargo.toml
@@ -33,6 +33,7 @@ tauri-plugin-notification = { path = "../../../plugins/notification", version =
] }
tauri-plugin-os = { path = "../../../plugins/os", version = "2.0.1" }
tauri-plugin-process = { path = "../../../plugins/process", version = "2.0.1" }
+tauri-plugin-opener = { path = "../../../plugins/opener", version = "1.0.0" }
tauri-plugin-shell = { path = "../../../plugins/shell", version = "2.0.2" }
tauri-plugin-store = { path = "../../../plugins/store", version = "2.1.0" }
diff --git a/examples/api/src-tauri/capabilities/base.json b/examples/api/src-tauri/capabilities/base.json
index 68a22389d8..92532e7d1d 100644
--- a/examples/api/src-tauri/capabilities/base.json
+++ b/examples/api/src-tauri/capabilities/base.json
@@ -80,6 +80,11 @@
],
"deny": ["$APPDATA/db/*.stronghold"]
},
- "store:default"
+ "store:default",
+ "opener:default",
+ {
+ "identifier": "opener:allow-open-path",
+ "allow": [{ "path": "$APPDATA" }, { "path": "$APPDATA/**" }]
+ }
]
}
diff --git a/examples/api/src-tauri/src/lib.rs b/examples/api/src-tauri/src/lib.rs
index 701f673182..dc1337995c 100644
--- a/examples/api/src-tauri/src/lib.rs
+++ b/examples/api/src-tauri/src/lib.rs
@@ -36,6 +36,7 @@ pub fn run() {
.plugin(tauri_plugin_notification::init())
.plugin(tauri_plugin_os::init())
.plugin(tauri_plugin_process::init())
+ .plugin(tauri_plugin_opener::init())
.plugin(tauri_plugin_shell::init())
.plugin(tauri_plugin_store::Builder::default().build())
.setup(move |app| {
diff --git a/examples/api/src/App.svelte b/examples/api/src/App.svelte
index f93198c26b..9396f6f93c 100644
--- a/examples/api/src/App.svelte
+++ b/examples/api/src/App.svelte
@@ -1,6 +1,5 @@
+
+
+
+
+
+
+
+
diff --git a/plugins/fs/Cargo.toml b/plugins/fs/Cargo.toml
index 5d9a7efb64..7546baef11 100644
--- a/plugins/fs/Cargo.toml
+++ b/plugins/fs/Cargo.toml
@@ -34,7 +34,7 @@ thiserror = { workspace = true }
url = { workspace = true }
anyhow = "1"
uuid = { version = "1", features = ["v4"] }
-glob = "0.3"
+glob = { workspace = true }
# TODO: Remove `serialization-compat-6` in v3
notify = { version = "7", optional = true, features = [
"serde",
diff --git a/plugins/fs/build.rs b/plugins/fs/build.rs
index cb9d00dafc..935e0a81b9 100644
--- a/plugins/fs/build.rs
+++ b/plugins/fs/build.rs
@@ -16,10 +16,23 @@ mod scope;
#[serde(untagged)]
#[allow(unused)]
enum FsScopeEntry {
- /// FS scope path.
+ /// A path that can be accessed by the webview when using the fs APIs.
+ /// FS scope path pattern.
+ ///
+ /// The pattern can start with a variable that resolves to a system base directory.
+ /// The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`,
+ /// `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`,
+ /// `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$APP`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`,
+ /// `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.
Value(PathBuf),
Object {
- /// FS scope path.
+ /// A path that can be accessed by the webview when using the fs APIs.
+ ///
+ /// The pattern can start with a variable that resolves to a system base directory.
+ /// The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`,
+ /// `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`,
+ /// `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$APP`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`,
+ /// `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.
path: PathBuf,
},
}
diff --git a/plugins/opener/Cargo.toml b/plugins/opener/Cargo.toml
new file mode 100644
index 0000000000..20eee7d216
--- /dev/null
+++ b/plugins/opener/Cargo.toml
@@ -0,0 +1,65 @@
+[package]
+name = "tauri-plugin-opener"
+version = "1.0.0"
+description = "Open files and URLs using their default application."
+edition = { workspace = true }
+authors = { workspace = true }
+license = { workspace = true }
+repository = { workspace = true }
+links = "tauri-plugin-opener"
+
+[package.metadata.docs.rs]
+rustc-args = ["--cfg", "docsrs"]
+rustdoc-args = ["--cfg", "docsrs"]
+
+# Platforms supported by the plugin
+# Support levels are "full", "partial", "none", "unknown"
+# Details of the support level are left to plugin maintainer
+[package.metadata.platforms]
+windows = { level = "full", notes = "" }
+linux = { level = "full", notes = "" }
+macos = { level = "full", notes = "" }
+android = { level = "partial", notes = "Only allows to open URLs via `open`" }
+ios = { level = "partial", notes = "Only allows to open URLs via `open`" }
+
+
+[build-dependencies]
+tauri-plugin = { workspace = true, features = ["build"] }
+schemars = { workspace = true }
+serde = { workspace = true }
+
+[dependencies]
+serde = { workspace = true }
+serde_json = { workspace = true }
+tauri = { workspace = true }
+thiserror = { workspace = true }
+open = { version = "5", features = ["shellexecute-on-windows"] }
+glob = { workspace = true }
+
+[target."cfg(windows)".dependencies]
+dunce = { workspace = true }
+
+[target."cfg(windows)".dependencies.windows]
+version = "0.58"
+features = [
+ "Win32_Foundation",
+ "Win32_UI_Shell_Common",
+ "Win32_UI_WindowsAndMessaging",
+ "Win32_System_Com",
+ "Win32_System_Registry",
+]
+
+[target."cfg(any(target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"netbsd\", target_os = \"openbsd\"))".dependencies]
+zbus = { workspace = true }
+url = { workspace = true }
+
+[target."cfg(target_os = \"macos\")".dependencies.objc2-app-kit]
+version = "0.2"
+features = ["NSWorkspace"]
+
+[target."cfg(target_os = \"macos\")".dependencies.objc2-foundation]
+version = "0.2"
+features = ["NSURL", "NSArray", "NSString"]
+
+[target.'cfg(target_os = "ios")'.dependencies]
+tauri = { workspace = true, features = ["wry"] }
diff --git a/plugins/opener/LICENSE.spdx b/plugins/opener/LICENSE.spdx
new file mode 100644
index 0000000000..cdd0df5ad7
--- /dev/null
+++ b/plugins/opener/LICENSE.spdx
@@ -0,0 +1,20 @@
+SPDXVersion: SPDX-2.1
+DataLicense: CC0-1.0
+PackageName: tauri
+DataFormat: SPDXRef-1
+PackageSupplier: Organization: The Tauri Programme in the Commons Conservancy
+PackageHomePage: https://tauri.app
+PackageLicenseDeclared: Apache-2.0
+PackageLicenseDeclared: MIT
+PackageCopyrightText: 2019-2022, The Tauri Programme in the Commons Conservancy
+PackageSummary: Tauri is a rust project that enables developers to make secure
+and small desktop applications using a web frontend.
+
+PackageComment: The package includes the following libraries; see
+Relationship information.
+
+Created: 2019-05-20T09:00:00Z
+PackageDownloadLocation: git://github.com/tauri-apps/tauri
+PackageDownloadLocation: git+https://github.com/tauri-apps/tauri.git
+PackageDownloadLocation: git+ssh://github.com/tauri-apps/tauri.git
+Creator: Person: Daniel Thompson-Yvetot
\ No newline at end of file
diff --git a/plugins/opener/LICENSE_APACHE-2.0 b/plugins/opener/LICENSE_APACHE-2.0
new file mode 100644
index 0000000000..4947287f7b
--- /dev/null
+++ b/plugins/opener/LICENSE_APACHE-2.0
@@ -0,0 +1,177 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
\ No newline at end of file
diff --git a/plugins/opener/LICENSE_MIT b/plugins/opener/LICENSE_MIT
new file mode 100644
index 0000000000..4d75472566
--- /dev/null
+++ b/plugins/opener/LICENSE_MIT
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2017 - Present Tauri Apps Contributors
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
\ No newline at end of file
diff --git a/plugins/opener/README.md b/plugins/opener/README.md
new file mode 100644
index 0000000000..17cc5b63f8
--- /dev/null
+++ b/plugins/opener/README.md
@@ -0,0 +1,100 @@
+![opener](https://github.com/tauri-apps/plugins-workspace/raw/v2/plugins/opener/banner.png)
+
+
+
+| Platform | Supported |
+| -------- | --------- |
+| Linux | ✓ |
+| Windows | ✓ |
+| macOS | ✓ |
+| Android | ? |
+| iOS | ? |
+
+## Install
+
+_This plugin requires a Rust version of at least **1.77.2**_
+
+There are three general methods of installation that we can recommend.
+
+1. Use crates.io and npm (easiest, and requires you to trust that our publishing pipeline worked)
+2. Pull sources directly from Github using git tags / revision hashes (most secure)
+3. Git submodule install this repo in your tauri project and then use file protocol to ingest the source (most secure, but inconvenient to use)
+
+Install the Core plugin by adding the following to your `Cargo.toml` file:
+
+`src-tauri/Cargo.toml`
+
+```toml
+[dependencies]
+tauri-plugin-opener = "2.0.0"
+# alternatively with Git:
+tauri-plugin-opener = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v2" }
+```
+
+You can install the JavaScript Guest bindings using your preferred JavaScript package manager:
+
+> Note: Since most JavaScript package managers are unable to install packages from git monorepos we provide read-only mirrors of each plugin. This makes installation option 2 more ergonomic to use.
+
+
+
+```sh
+pnpm add @tauri-apps/plugin-opener
+# or
+npm add @tauri-apps/plugin-opener
+# or
+yarn add @tauri-apps/plugin-opener
+
+# alternatively with Git:
+pnpm add https://github.com/tauri-apps/tauri-plugin-opener#v2
+# or
+npm add https://github.com/tauri-apps/tauri-plugin-opener#v2
+# or
+yarn add https://github.com/tauri-apps/tauri-plugin-opener#v2
+```
+
+## Usage
+
+First you need to register the core plugin with Tauri:
+
+`src-tauri/src/main.rs`
+
+```rust
+fn main() {
+ tauri::Builder::default()
+ .plugin(tauri_plugin_opener::init())
+ .run(tauri::generate_context!())
+ .expect("error while running tauri application");
+}
+```
+
+Afterwards all the plugin's APIs are available through the JavaScript guest bindings:
+
+```javascript
+
+```
+
+## Contributing
+
+PRs accepted. Please make sure to read the Contributing Guide before making a pull request.
+
+## Partners
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+For the complete list of sponsors please visit our [website](https://tauri.app#sponsors) and [Open Collective](https://opencollective.com/tauri).
+
+## License
+
+Code: (c) 2015 - Present - The Tauri Programme within The Commons Conservancy.
+
+MIT or MIT/Apache 2.0 where applicable.
diff --git a/plugins/opener/SECURITY.md b/plugins/opener/SECURITY.md
new file mode 100644
index 0000000000..4f09bbacd4
--- /dev/null
+++ b/plugins/opener/SECURITY.md
@@ -0,0 +1,23 @@
+# Security Policy
+
+**Do not report security vulnerabilities through public GitHub issues.**
+
+**Please use the [Private Vulnerability Disclosure](https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing-information-about-vulnerabilities/privately-reporting-a-security-vulnerability#privately-reporting-a-security-vulnerability) feature of GitHub.**
+
+Include as much of the following information:
+
+- Type of issue (e.g. improper input parsing, privilege escalation, etc.)
+- The location of the affected source code (tag/branch/commit or direct URL)
+- Any special configuration required to reproduce the issue
+- The distribution affected or used to help us with reproduction of the issue
+- Step-by-step instructions to reproduce the issue
+- Ideally a reproduction repository
+- Impact of the issue, including how an attacker might exploit the issue
+
+We prefer to receive reports in English.
+
+## Contact
+
+Please disclose a vulnerability or security relevant issue here: [https://github.com/tauri-apps/plugins-workspace/security/advisories/new](https://github.com/tauri-apps/plugins-workspace/security/advisories/new).
+
+Alternatively, you can also contact us by email via [security@tauri.app](mailto:security@tauri.app).
diff --git a/plugins/opener/android/.gitignore b/plugins/opener/android/.gitignore
new file mode 100644
index 0000000000..c0f21ec2fd
--- /dev/null
+++ b/plugins/opener/android/.gitignore
@@ -0,0 +1,2 @@
+/build
+/.tauri
diff --git a/plugins/opener/android/build.gradle.kts b/plugins/opener/android/build.gradle.kts
new file mode 100644
index 0000000000..9dcce212e2
--- /dev/null
+++ b/plugins/opener/android/build.gradle.kts
@@ -0,0 +1,39 @@
+plugins {
+ id("com.android.library")
+ id("org.jetbrains.kotlin.android")
+}
+
+android {
+ namespace = "app.tauri.opener"
+ compileSdk = 34
+
+ defaultConfig {
+ minSdk = 24
+
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+ consumerProguardFiles("consumer-rules.pro")
+ }
+
+ buildTypes {
+ release {
+ isMinifyEnabled = false
+ proguardFiles(
+ getDefaultProguardFile("proguard-android-optimize.txt"),
+ "proguard-rules.pro"
+ )
+ }
+ }
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_1_8
+ targetCompatibility = JavaVersion.VERSION_1_8
+ }
+ kotlinOptions {
+ jvmTarget = "1.8"
+ }
+}
+
+dependencies {
+ implementation("androidx.core:core-ktx:1.9.0")
+ implementation("com.fasterxml.jackson.core:jackson-databind:2.15.3")
+ implementation(project(":tauri-android"))
+}
diff --git a/plugins/opener/android/proguard-rules.pro b/plugins/opener/android/proguard-rules.pro
new file mode 100644
index 0000000000..481bb43481
--- /dev/null
+++ b/plugins/opener/android/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/plugins/opener/android/settings.gradle b/plugins/opener/android/settings.gradle
new file mode 100644
index 0000000000..14a752e433
--- /dev/null
+++ b/plugins/opener/android/settings.gradle
@@ -0,0 +1,2 @@
+include ':tauri-android'
+project(':tauri-android').projectDir = new File('./.tauri/tauri-api')
diff --git a/plugins/opener/android/src/main/AndroidManifest.xml b/plugins/opener/android/src/main/AndroidManifest.xml
new file mode 100644
index 0000000000..9a40236b94
--- /dev/null
+++ b/plugins/opener/android/src/main/AndroidManifest.xml
@@ -0,0 +1,3 @@
+
+
+
diff --git a/plugins/opener/android/src/main/java/OpenerPlugin.kt b/plugins/opener/android/src/main/java/OpenerPlugin.kt
new file mode 100644
index 0000000000..0beeb9775d
--- /dev/null
+++ b/plugins/opener/android/src/main/java/OpenerPlugin.kt
@@ -0,0 +1,30 @@
+// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-License-Identifier: MIT
+
+package app.tauri.shell
+
+import android.app.Activity
+import android.content.Intent
+import android.net.Uri
+import app.tauri.annotation.Command
+import app.tauri.annotation.TauriPlugin
+import app.tauri.plugin.Invoke
+import app.tauri.plugin.Plugin
+import java.io.File
+
+@TauriPlugin
+class OpenerPlugin(private val activity: Activity) : Plugin(activity) {
+ @Command
+ fun open(invoke: Invoke) {
+ try {
+ val url = invoke.parseArgs(String::class.java)
+ val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ activity.applicationContext?.startActivity(intent)
+ invoke.resolve()
+ } catch (ex: Exception) {
+ invoke.reject(ex.message)
+ }
+ }
+}
\ No newline at end of file
diff --git a/plugins/opener/api-iife.js b/plugins/opener/api-iife.js
new file mode 100644
index 0000000000..30415a61e3
--- /dev/null
+++ b/plugins/opener/api-iife.js
@@ -0,0 +1 @@
+if("__TAURI__"in window){var __TAURI_PLUGIN_OPENER__=function(n){"use strict";async function e(n,e={},_){return window.__TAURI_INTERNALS__.invoke(n,e,_)}return"function"==typeof SuppressedError&&SuppressedError,n.openPath=async function(n,_){await e("plugin:opener|open_path",{path:n,with:_})},n.openUrl=async function(n,_){await e("plugin:opener|open_url",{url:n,with:_})},n.revealItemInDir=async function(n){return e("plugin:opener|reveal_item_in_dir",{path:n})},n}({});Object.defineProperty(window.__TAURI__,"opener",{value:__TAURI_PLUGIN_OPENER__})}
diff --git a/plugins/opener/build.rs b/plugins/opener/build.rs
new file mode 100644
index 0000000000..fbad4d3ac3
--- /dev/null
+++ b/plugins/opener/build.rs
@@ -0,0 +1,136 @@
+// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-License-Identifier: MIT
+
+use std::path::PathBuf;
+
+#[path = "src/scope_entry.rs"]
+#[allow(dead_code)]
+mod scope;
+
+/// Opener scope application.
+#[derive(schemars::JsonSchema)]
+#[serde(untagged)]
+#[allow(unused)]
+enum Application {
+ /// Open in default application.
+ Default,
+ /// If true, allow open with any application.
+ Enable(bool),
+ /// Allow specific application to open with.
+ App(String),
+}
+
+impl Default for Application {
+ fn default() -> Self {
+ Self::Default
+ }
+}
+
+/// Opener scope entry.
+#[derive(schemars::JsonSchema)]
+#[serde(untagged)]
+#[allow(unused)]
+enum OpenerScopeEntry {
+ Url {
+ /// A URL that can be opened by the webview when using the Opener APIs.
+ ///
+ /// Wildcards can be used following the UNIX glob pattern.
+ ///
+ /// Examples:
+ ///
+ /// - "https://*" : allows all HTTPS origin
+ ///
+ /// - "https://*.github.com/tauri-apps/tauri": allows any subdomain of "github.com" with the "tauri-apps/api" path
+ ///
+ /// - "https://myapi.service.com/users/*": allows access to any URLs that begins with "https://myapi.service.com/users/"
+ url: String,
+ /// An application to open this url with, for example: firefox.
+ #[serde(default)]
+ app: Application,
+ },
+ Path {
+ /// A path that can be opened by the webview when using the Opener APIs.
+ ///
+ /// The pattern can start with a variable that resolves to a system base directory.
+ /// The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`,
+ /// `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`,
+ /// `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$APP`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`,
+ /// `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.
+ path: PathBuf,
+ /// An application to open this path with, for example: xdg-open.
+ #[serde(default)]
+ app: Application,
+ },
+}
+
+// Ensure `OpenerScopeEntry` and `scope::EntryRaw` is kept in sync
+fn _f() {
+ match (scope::EntryRaw::Url {
+ url: String::new(),
+ app: scope::Application::Enable(true),
+ }) {
+ scope::EntryRaw::Url { url, app } => OpenerScopeEntry::Url {
+ url,
+ app: match app {
+ scope::Application::Enable(p) => Application::Enable(p),
+ scope::Application::App(p) => Application::App(p),
+ scope::Application::Default => Application::Default,
+ },
+ },
+ scope::EntryRaw::Path { path, app } => OpenerScopeEntry::Path {
+ path,
+ app: match app {
+ scope::Application::Enable(p) => Application::Enable(p),
+ scope::Application::App(p) => Application::App(p),
+ scope::Application::Default => Application::Default,
+ },
+ },
+ };
+ match (OpenerScopeEntry::Url {
+ url: String::new(),
+ app: Application::Enable(true),
+ }) {
+ OpenerScopeEntry::Url { url, app } => scope::EntryRaw::Url {
+ url,
+ app: match app {
+ Application::Enable(p) => scope::Application::Enable(p),
+ Application::App(p) => scope::Application::App(p),
+ Application::Default => scope::Application::Default,
+ },
+ },
+ OpenerScopeEntry::Path { path, app } => scope::EntryRaw::Path {
+ path,
+ app: match app {
+ Application::Enable(p) => scope::Application::Enable(p),
+ Application::App(p) => scope::Application::App(p),
+ Application::Default => scope::Application::Default,
+ },
+ },
+ };
+}
+
+const COMMANDS: &[&str] = &["open_url", "open_path", "reveal_item_in_dir"];
+
+fn main() {
+ tauri_plugin::Builder::new(COMMANDS)
+ .global_api_script_path("./api-iife.js")
+ .android_path("android")
+ .ios_path("ios")
+ .global_scope_schema(schemars::schema_for!(OpenerScopeEntry))
+ .build();
+
+ let target_os = std::env::var("CARGO_CFG_TARGET_OS").unwrap();
+ let mobile = target_os == "ios" || target_os == "android";
+ alias("desktop", !mobile);
+ alias("mobile", mobile);
+}
+
+// creates a cfg alias if `has_feature` is true.
+// `alias` must be a snake case string.
+fn alias(alias: &str, has_feature: bool) {
+ println!("cargo:rustc-check-cfg=cfg({alias})");
+ if has_feature {
+ println!("cargo:rustc-cfg={alias}");
+ }
+}
diff --git a/plugins/opener/guest-js/index.ts b/plugins/opener/guest-js/index.ts
new file mode 100644
index 0000000000..0d92596b96
--- /dev/null
+++ b/plugins/opener/guest-js/index.ts
@@ -0,0 +1,92 @@
+// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-License-Identifier: MIT
+
+/**
+ * Open files and URLs using their default application.
+ *
+ * ## Security
+ *
+ * This API has a scope configuration that forces you to restrict the files and urls to be opened.
+ *
+ * ### Restricting access to the {@link open | `open`} API
+ *
+ * On the configuration object, `open: true` means that the {@link open} API can be used with any URL,
+ * as the argument is validated with the `^((mailto:\w+)|(tel:\w+)|(https?://\w+)).+` regex.
+ * You can change that regex by changing the boolean value to a string, e.g. `open: ^https://github.com/`.
+ *
+ * @module
+ */
+
+import { invoke } from '@tauri-apps/api/core'
+
+/**
+ * Opens a url with the system's default app, or the one specified with {@linkcode openWith}.
+ *
+ * @example
+ * ```typescript
+ * import { openUrl } from '@tauri-apps/plugin-opener';
+ *
+ * // opens the given URL on the default browser:
+ * await openUrl('https://github.com/tauri-apps/tauri');
+ * // opens the given URL using `firefox`:
+ * await openUrl('https://github.com/tauri-apps/tauri', 'firefox');
+ * ```
+ *
+ * @param url The URL to open.
+ * @param openWith The app to open the URL with. If not specified, defaults to the system default application for the specified url type.
+ *
+ * @since 2.0.0
+ */
+export async function openUrl(url: string, openWith?: string): Promise {
+ await invoke('plugin:opener|open_url', {
+ url,
+ with: openWith
+ })
+}
+
+/**
+ * Opens a path with the system's default app, or the one specified with {@linkcode openWith}.
+ *
+ * @example
+ * ```typescript
+ * import { openPath } from '@tauri-apps/plugin-opener';
+ *
+ * // opens a file using the default program:
+ * await openPath('/path/to/file');
+ * // opens a file using `vlc` command on Windows.
+ * await openPath('C:/path/to/file', 'vlc');
+ * ```
+ *
+ * @param path The path to open.
+ * @param openWith The app to open the path with. If not specified, defaults to the system default application for the specified path type.
+ *
+ * @since 2.0.0
+ */
+export async function openPath(path: string, openWith?: string): Promise {
+ await invoke('plugin:opener|open_path', {
+ path,
+ with: openWith
+ })
+}
+
+/**
+ * Reveal a path the system's default explorer.
+ *
+ * #### Platform-specific:
+ *
+ * - **Android / iOS:** Unsupported.
+ *
+ * @example
+ * ```typescript
+ * import { revealItemInDir } from '@tauri-apps/plugin-opener';
+ * await revealItemInDir('/path/to/file');
+ * ```
+ *
+ * @param path The path to reveal.
+ *
+ * @since 2.0.0
+ */
+export async function revealItemInDir(path: string) {
+ return invoke('plugin:opener|reveal_item_in_dir', { path })
+}
diff --git a/plugins/opener/guest-js/init.ts b/plugins/opener/guest-js/init.ts
new file mode 100644
index 0000000000..046db99c4e
--- /dev/null
+++ b/plugins/opener/guest-js/init.ts
@@ -0,0 +1,61 @@
+// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-License-Identifier: MIT
+
+import { invoke } from '@tauri-apps/api/core'
+
+// open links with the API
+window.addEventListener('click', function (evt) {
+ // return early if
+ if (
+ // event was prevented
+ evt.defaultPrevented ||
+ // or not a left click
+ evt.button !== 0 ||
+ // or meta key pressed
+ evt.metaKey ||
+ // or al key pressed
+ evt.altKey
+ )
+ return
+
+ const a = evt
+ .composedPath()
+ .find((el) => el instanceof Node && el.nodeName.toUpperCase() === 'A') as
+ | HTMLAnchorElement
+ | undefined
+
+ // return early if
+ if (
+ // not tirggered from element
+ !a ||
+ // or doesn't have a href
+ !a.href ||
+ // or not supposed to be open in a new tab
+ !(
+ a.target === '_blank' ||
+ // or ctrl key pressed
+ evt.ctrlKey ||
+ // or shift key pressed
+ evt.shiftKey
+ )
+ )
+ return
+
+ const url = new URL(a.href)
+
+ // return early if
+ if (
+ // same origin (internal navigation)
+ url.origin === window.location.origin ||
+ // not default protocols
+ ['http:', 'https:', 'mailto:', 'tel:'].every((p) => url.protocol !== p)
+ )
+ return
+
+ evt.preventDefault()
+
+ void invoke('plugin:opener|open_url', {
+ url
+ })
+})
diff --git a/plugins/opener/ios/Package.resolved b/plugins/opener/ios/Package.resolved
new file mode 100644
index 0000000000..5f998e0e66
--- /dev/null
+++ b/plugins/opener/ios/Package.resolved
@@ -0,0 +1,16 @@
+{
+ "object": {
+ "pins": [
+ {
+ "package": "SwiftRs",
+ "repositoryURL": "https://github.com/Brendonovich/swift-rs",
+ "state": {
+ "branch": null,
+ "revision": "b5ed223fcdab165bc21219c1925dc1e77e2bef5e",
+ "version": "1.0.6"
+ }
+ }
+ ]
+ },
+ "version": 1
+}
diff --git a/plugins/opener/ios/Package.swift b/plugins/opener/ios/Package.swift
new file mode 100644
index 0000000000..8d06936e61
--- /dev/null
+++ b/plugins/opener/ios/Package.swift
@@ -0,0 +1,34 @@
+// swift-tools-version:5.3
+// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-License-Identifier: MIT
+
+import PackageDescription
+
+let package = Package(
+ name: "tauri-plugin-opener",
+ platforms: [
+ .macOS(.v10_13),
+ .iOS(.v13),
+ ],
+ products: [
+ // Products define the executables and libraries a package produces, and make them visible to other packages.
+ .library(
+ name: "tauri-plugin-opener",
+ type: .static,
+ targets: ["tauri-plugin-opener"])
+ ],
+ dependencies: [
+ .package(name: "Tauri", path: "../.tauri/tauri-api")
+ ],
+ targets: [
+ // Targets are the basic building blocks of a package. A target can define a module or a test suite.
+ // Targets can depend on other targets in this package, and on products in packages this package depends on.
+ .target(
+ name: "tauri-plugin-opener",
+ dependencies: [
+ .byName(name: "Tauri")
+ ],
+ path: "Sources")
+ ]
+)
diff --git a/plugins/opener/ios/Sources/OpenerPlugin.swift b/plugins/opener/ios/Sources/OpenerPlugin.swift
new file mode 100644
index 0000000000..39bc5725c2
--- /dev/null
+++ b/plugins/opener/ios/Sources/OpenerPlugin.swift
@@ -0,0 +1,34 @@
+// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-License-Identifier: MIT
+
+import Foundation
+
+import SwiftRs
+import Tauri
+import UIKit
+import WebKit
+
+class OpenerPlugin: Plugin {
+
+ @objc public func open(_ invoke: Invoke) throws {
+ do {
+ let urlString = try invoke.parseArgs(String.self)
+ if let url = URL(string: urlString) {
+ if #available(iOS 10, *) {
+ UIApplication.shared.open(url, options: [:])
+ } else {
+ UIApplication.shared.openURL(url)
+ }
+ }
+ invoke.resolve()
+ } catch {
+ invoke.reject(error.localizedDescription)
+ }
+ }
+}
+
+@_cdecl("init_plugin_shell")
+func initPlugin() -> Plugin {
+ return OpenerPlugin()
+}
diff --git a/plugins/opener/package.json b/plugins/opener/package.json
new file mode 100644
index 0000000000..c3dc314efb
--- /dev/null
+++ b/plugins/opener/package.json
@@ -0,0 +1,30 @@
+{
+ "name": "@tauri-apps/plugin-opener",
+ "version": "1.0.0",
+ "description": "Open files and URLs using their default application.",
+ "license": "MIT OR Apache-2.0",
+ "authors": [
+ "Tauri Programme within The Commons Conservancy"
+ ],
+ "repository": "https://github.com/tauri-apps/plugins-workspace",
+ "type": "module",
+ "types": "./dist-js/index.d.ts",
+ "main": "./dist-js/index.cjs",
+ "module": "./dist-js/index.js",
+ "exports": {
+ "types": "./dist-js/index.d.ts",
+ "import": "./dist-js/index.js",
+ "require": "./dist-js/index.cjs"
+ },
+ "scripts": {
+ "build": "rollup -c"
+ },
+ "files": [
+ "dist-js",
+ "README.md",
+ "LICENSE"
+ ],
+ "dependencies": {
+ "@tauri-apps/api": "^2.0.0"
+ }
+}
diff --git a/plugins/opener/permissions/allow-default-urls.toml b/plugins/opener/permissions/allow-default-urls.toml
new file mode 100644
index 0000000000..93495b8970
--- /dev/null
+++ b/plugins/opener/permissions/allow-default-urls.toml
@@ -0,0 +1,17 @@
+"$schema" = "schemas/schema.json"
+
+[[permission]]
+identifier = "allow-default-urls"
+description = "This enables opening `mailto:`, `tel:`, `https://` and `http://` urls using their default application."
+
+[[permission.scope.allow]]
+url = "mailto:*"
+
+[[permission.scope.allow]]
+url = "tel:*"
+
+[[permission.scope.allow]]
+url = "http://*"
+
+[[permission.scope.allow]]
+url = "https://*"
diff --git a/plugins/opener/permissions/autogenerated/commands/open_path.toml b/plugins/opener/permissions/autogenerated/commands/open_path.toml
new file mode 100644
index 0000000000..ae67b93942
--- /dev/null
+++ b/plugins/opener/permissions/autogenerated/commands/open_path.toml
@@ -0,0 +1,13 @@
+# Automatically generated - DO NOT EDIT!
+
+"$schema" = "../../schemas/schema.json"
+
+[[permission]]
+identifier = "allow-open-path"
+description = "Enables the open_path command without any pre-configured scope."
+commands.allow = ["open_path"]
+
+[[permission]]
+identifier = "deny-open-path"
+description = "Denies the open_path command without any pre-configured scope."
+commands.deny = ["open_path"]
diff --git a/plugins/opener/permissions/autogenerated/commands/open_url.toml b/plugins/opener/permissions/autogenerated/commands/open_url.toml
new file mode 100644
index 0000000000..f1e694b1b0
--- /dev/null
+++ b/plugins/opener/permissions/autogenerated/commands/open_url.toml
@@ -0,0 +1,13 @@
+# Automatically generated - DO NOT EDIT!
+
+"$schema" = "../../schemas/schema.json"
+
+[[permission]]
+identifier = "allow-open-url"
+description = "Enables the open_url command without any pre-configured scope."
+commands.allow = ["open_url"]
+
+[[permission]]
+identifier = "deny-open-url"
+description = "Denies the open_url command without any pre-configured scope."
+commands.deny = ["open_url"]
diff --git a/plugins/opener/permissions/autogenerated/commands/reveal_item_in_dir.toml b/plugins/opener/permissions/autogenerated/commands/reveal_item_in_dir.toml
new file mode 100644
index 0000000000..e669620ffd
--- /dev/null
+++ b/plugins/opener/permissions/autogenerated/commands/reveal_item_in_dir.toml
@@ -0,0 +1,13 @@
+# Automatically generated - DO NOT EDIT!
+
+"$schema" = "../../schemas/schema.json"
+
+[[permission]]
+identifier = "allow-reveal-item-in-dir"
+description = "Enables the reveal_item_in_dir command without any pre-configured scope."
+commands.allow = ["reveal_item_in_dir"]
+
+[[permission]]
+identifier = "deny-reveal-item-in-dir"
+description = "Denies the reveal_item_in_dir command without any pre-configured scope."
+commands.deny = ["reveal_item_in_dir"]
diff --git a/plugins/opener/permissions/autogenerated/reference.md b/plugins/opener/permissions/autogenerated/reference.md
new file mode 100644
index 0000000000..66c232c6fb
--- /dev/null
+++ b/plugins/opener/permissions/autogenerated/reference.md
@@ -0,0 +1,109 @@
+## Default Permission
+
+This permission set allows opening `mailto:`, `tel:`, `https://` and `http://` urls using their default application
+as well as reveal file in directories using default file explorer
+
+- `allow-open-url`
+- `allow-reveal-item-in-dir`
+- `allow-default-urls`
+
+## Permission Table
+
+
+
+Identifier |
+Description |
+
+
+
+
+
+
+`opener:allow-default-urls`
+
+ |
+
+
+This enables opening `mailto:`, `tel:`, `https://` and `http://` urls using their default application.
+
+ |
+
+
+
+
+
+`opener:allow-open-path`
+
+ |
+
+
+Enables the open_path command without any pre-configured scope.
+
+ |
+
+
+
+
+
+`opener:deny-open-path`
+
+ |
+
+
+Denies the open_path command without any pre-configured scope.
+
+ |
+
+
+
+
+
+`opener:allow-open-url`
+
+ |
+
+
+Enables the open_url command without any pre-configured scope.
+
+ |
+
+
+
+
+
+`opener:deny-open-url`
+
+ |
+
+
+Denies the open_url command without any pre-configured scope.
+
+ |
+
+
+
+
+
+`opener:allow-reveal-item-in-dir`
+
+ |
+
+
+Enables the reveal_item_in_dir command without any pre-configured scope.
+
+ |
+
+
+
+
+
+`opener:deny-reveal-item-in-dir`
+
+ |
+
+
+Denies the reveal_item_in_dir command without any pre-configured scope.
+
+ |
+
+
diff --git a/plugins/opener/permissions/default.toml b/plugins/opener/permissions/default.toml
new file mode 100644
index 0000000000..846d6e51be
--- /dev/null
+++ b/plugins/opener/permissions/default.toml
@@ -0,0 +1,10 @@
+"$schema" = "schemas/schema.json"
+
+[default]
+description = """This permission set allows opening `mailto:`, `tel:`, `https://` and `http://` urls using their default application
+as well as reveal file in directories using default file explorer"""
+permissions = [
+ "allow-open-url",
+ "allow-reveal-item-in-dir",
+ "allow-default-urls",
+]
diff --git a/plugins/opener/permissions/schemas/schema.json b/plugins/opener/permissions/schemas/schema.json
new file mode 100644
index 0000000000..b958ac6368
--- /dev/null
+++ b/plugins/opener/permissions/schemas/schema.json
@@ -0,0 +1,340 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "title": "PermissionFile",
+ "description": "Permission file that can define a default permission, a set of permissions or a list of inlined permissions.",
+ "type": "object",
+ "properties": {
+ "default": {
+ "description": "The default permission set for the plugin",
+ "anyOf": [
+ {
+ "$ref": "#/definitions/DefaultPermission"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "set": {
+ "description": "A list of permissions sets defined",
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/PermissionSet"
+ }
+ },
+ "permission": {
+ "description": "A list of inlined permissions",
+ "default": [],
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/Permission"
+ }
+ }
+ },
+ "definitions": {
+ "DefaultPermission": {
+ "description": "The default permission set of the plugin.\n\nWorks similarly to a permission with the \"default\" identifier.",
+ "type": "object",
+ "required": [
+ "permissions"
+ ],
+ "properties": {
+ "version": {
+ "description": "The version of the permission.",
+ "type": [
+ "integer",
+ "null"
+ ],
+ "format": "uint64",
+ "minimum": 1.0
+ },
+ "description": {
+ "description": "Human-readable description of what the permission does. Tauri convention is to use