diff --git a/.changes/refactor-allowlist.md b/.changes/refactor-allowlist.md new file mode 100644 index 000000000..4797f73cc --- /dev/null +++ b/.changes/refactor-allowlist.md @@ -0,0 +1,5 @@ +--- +"tauri": minor +--- + +The `allowlist` configuration now has one object per module. diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 731ca2a20..2186f7fb0 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -78,7 +78,7 @@ The code for the bundler is located in `[Tauri repo root]/cli/tauri-bundler`. Bu ### Developing Tauri Core -The code for Tauri core is located in `[Tauri repo root]/tauri`. The easiest way to test your changes is to use the `[Tauri repo root]/tauri/examples/communication` app. It automatically rebuilds and uses your local codebase. Just run `yarn tauri build` or `yarn tauri dev` in the communication app directory after making changes to test them out. To use your local changes in another project, edit its `src-tauri/Cargo.toml` file so that the `tauri` key looks like `tauri = { path = "PATH", features = [ "all-api", "cli" ] }`, where `PATH` is the relative path to `[Tauri repo root]/tauri`. +The code for Tauri core is located in `[Tauri repo root]/tauri`. The easiest way to test your changes is to use the `[Tauri repo root]/tauri/examples/communication` app. It automatically rebuilds and uses your local codebase. Just run `yarn tauri build` or `yarn tauri dev` in the communication app directory after making changes to test them out. To use your local changes in another project, edit its `src-tauri/Cargo.toml` file so that the `tauri` key looks like `tauri = { path = "PATH", features = [ "api-all", "cli" ] }`, where `PATH` is the relative path to `[Tauri repo root]/tauri`. ## Financial Contribution diff --git a/.github/workflows/core-lint-fmt.yml b/.github/workflows/core-lint-fmt.yml index e06c60825..6852488c2 100644 --- a/.github/workflows/core-lint-fmt.yml +++ b/.github/workflows/core-lint-fmt.yml @@ -62,7 +62,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - feature: [embedded-server, all-api] + feature: [embedded-server, api-all] steps: - uses: actions/checkout@v2 diff --git a/cli/core/Cargo.lock b/cli/core/Cargo.lock index 13b8c9fc6..26ca8f6c7 100755 --- a/cli/core/Cargo.lock +++ b/cli/core/Cargo.lock @@ -329,12 +329,6 @@ version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28b9d6de7f49e22cf97ad17fc4036ece69300032f45f78f30b4a4482cdc3f4a6" -[[package]] -name = "convert_case" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" - [[package]] name = "core-foundation" version = "0.9.1" @@ -1999,7 +1993,6 @@ dependencies = [ "anyhow", "clap 3.0.0-beta.2", "colored", - "convert_case", "json-patch", "notify", "once_cell", diff --git a/cli/core/Cargo.toml b/cli/core/Cargo.toml index 731046363..3c2cef4eb 100644 --- a/cli/core/Cargo.toml +++ b/cli/core/Cargo.toml @@ -21,7 +21,6 @@ serde_json = "1.0" notify = "4.0" shared_child = "0.3" toml_edit = "0.2" -convert_case = "0.4" json-patch = "0.2" schemars = "0.8" valico = "3.5" diff --git a/cli/core/config_definition.rs b/cli/core/config_definition.rs index c63b71be7..e384e8990 100644 --- a/cli/core/config_definition.rs +++ b/cli/core/config_definition.rs @@ -250,6 +250,232 @@ pub struct SecurityConfig { csp: Option, } +trait Allowlist { + fn to_features(&self) -> Vec<&str>; +} + +macro_rules! check_feature { + ($self:ident, $features:ident, $flag:ident, $feature_name: expr) => { + if $self.$flag { + $features.push($feature_name) + } + }; +} + +#[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize, JsonSchema)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +struct FsAllowlistConfig { + #[serde(default)] + all: bool, + #[serde(default)] + read_text_file: bool, + #[serde(default)] + read_binary_file: bool, + #[serde(default)] + write_file: bool, + #[serde(default)] + write_binary_file: bool, + #[serde(default)] + read_dir: bool, + #[serde(default)] + copy_file: bool, + #[serde(default)] + create_dir: bool, + #[serde(default)] + remove_dir: bool, + #[serde(default)] + remove_file: bool, + #[serde(default)] + rename_file: bool, + #[serde(default)] + path: bool, +} + +impl Allowlist for FsAllowlistConfig { + fn to_features(&self) -> Vec<&str> { + if self.all { + vec!["fs-all"] + } else { + let mut features = Vec::new(); + check_feature!(self, features, read_text_file, "fs-read-text-file"); + check_feature!(self, features, read_binary_file, "fs-read-binary-file"); + check_feature!(self, features, write_file, "fs-write-file"); + check_feature!(self, features, write_binary_file, "fs-write-binary-file"); + check_feature!(self, features, read_dir, "fs-read-dir"); + check_feature!(self, features, copy_file, "fs-copy-file"); + check_feature!(self, features, create_dir, "fs-create-dir"); + check_feature!(self, features, remove_dir, "fs-remove-dir"); + check_feature!(self, features, remove_file, "fs-remove-file"); + check_feature!(self, features, rename_file, "fs-rename-file"); + check_feature!(self, features, path, "fs-path"); + features + } + } +} + +#[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize, JsonSchema)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +struct WindowAllowlistConfig { + #[serde(default)] + all: bool, + #[serde(default)] + create: bool, +} + +impl Allowlist for WindowAllowlistConfig { + fn to_features(&self) -> Vec<&str> { + if self.all { + vec!["window-all"] + } else { + let mut features = Vec::new(); + check_feature!(self, features, create, "window-create"); + features + } + } +} + +#[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize, JsonSchema)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +struct ShellAllowlistConfig { + #[serde(default)] + all: bool, + #[serde(default)] + execute: bool, + #[serde(default)] + open: bool, +} + +impl Allowlist for ShellAllowlistConfig { + fn to_features(&self) -> Vec<&str> { + if self.all { + vec!["shell-all"] + } else { + let mut features = Vec::new(); + check_feature!(self, features, execute, "shell-execute"); + check_feature!(self, features, open, "shell-open"); + features + } + } +} + +#[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize, JsonSchema)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +struct DialogAllowlistConfig { + #[serde(default)] + all: bool, + #[serde(default)] + open: bool, + #[serde(default)] + save: bool, +} + +impl Allowlist for DialogAllowlistConfig { + fn to_features(&self) -> Vec<&str> { + if self.all { + vec!["dialog-all"] + } else { + let mut features = Vec::new(); + check_feature!(self, features, open, "dialog-open"); + check_feature!(self, features, save, "dialog-save"); + features + } + } +} + +#[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize, JsonSchema)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +struct HttpAllowlistConfig { + #[serde(default)] + all: bool, + #[serde(default)] + request: bool, +} + +impl Allowlist for HttpAllowlistConfig { + fn to_features(&self) -> Vec<&str> { + if self.all { + vec!["http-all"] + } else { + let mut features = Vec::new(); + check_feature!(self, features, request, "http-request"); + features + } + } +} + +#[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize, JsonSchema)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +struct NotificationAllowlistConfig { + #[serde(default)] + all: bool, +} + +impl Allowlist for NotificationAllowlistConfig { + fn to_features(&self) -> Vec<&str> { + if self.all { + vec!["notification-all"] + } else { + vec![] + } + } +} + +#[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize, JsonSchema)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +struct GlobalShortcutAllowlistConfig { + #[serde(default)] + all: bool, +} + +impl Allowlist for GlobalShortcutAllowlistConfig { + fn to_features(&self) -> Vec<&str> { + if self.all { + vec!["global-shortcut-all"] + } else { + vec![] + } + } +} + +#[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize, JsonSchema)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +struct AllowlistConfig { + #[serde(default)] + all: bool, + #[serde(default)] + fs: FsAllowlistConfig, + #[serde(default)] + window: WindowAllowlistConfig, + #[serde(default)] + shell: ShellAllowlistConfig, + #[serde(default)] + dialog: DialogAllowlistConfig, + #[serde(default)] + http: HttpAllowlistConfig, + #[serde(default)] + notification: NotificationAllowlistConfig, + #[serde(default)] + global_shortcut: GlobalShortcutAllowlistConfig, +} + +impl Allowlist for AllowlistConfig { + fn to_features(&self) -> Vec<&str> { + if self.all { + vec!["api-all"] + } else { + let mut features = Vec::new(); + features.extend(self.fs.to_features()); + features.extend(self.window.to_features()); + features.extend(self.shell.to_features()); + features.extend(self.dialog.to_features()); + features.extend(self.http.to_features()); + features.extend(self.notification.to_features()); + features.extend(self.global_shortcut.to_features()); + features + } + } +} + /// The Tauri configuration object. #[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] @@ -265,10 +491,17 @@ pub struct TauriConfig { #[serde(default)] pub bundle: BundleConfig, #[serde(default)] - pub allowlist: HashMap, + allowlist: AllowlistConfig, pub security: Option, } +impl TauriConfig { + #[allow(dead_code)] + pub fn features(&self) -> Vec<&str> { + self.allowlist.to_features() + } +} + /// The Build configuration object. #[derive(Debug, PartialEq, Clone, Deserialize, Serialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] diff --git a/cli/core/schema.json b/cli/core/schema.json index 37744a104..4941a9018 100644 --- a/cli/core/schema.json +++ b/cli/core/schema.json @@ -31,7 +31,47 @@ "tauri": { "description": "The Tauri configuration.", "default": { - "allowlist": {}, + "allowlist": { + "all": false, + "dialog": { + "all": false, + "open": false, + "save": false + }, + "fs": { + "all": false, + "copyFile": false, + "createDir": false, + "path": false, + "readBinaryFile": false, + "readDir": false, + "readTextFile": false, + "removeDir": false, + "removeFile": false, + "renameFile": false, + "writeBinaryFile": false, + "writeFile": false + }, + "globalShortcut": { + "all": false + }, + "http": { + "all": false, + "request": false + }, + "notification": { + "all": false + }, + "shell": { + "all": false, + "execute": false, + "open": false + }, + "window": { + "all": false, + "create": false + } + }, "bundle": { "active": false, "category": null, @@ -76,6 +116,103 @@ }, "additionalProperties": false, "definitions": { + "AllowlistConfig": { + "type": "object", + "properties": { + "all": { + "default": false, + "type": "boolean" + }, + "dialog": { + "default": { + "all": false, + "open": false, + "save": false + }, + "allOf": [ + { + "$ref": "#/definitions/DialogAllowlistConfig" + } + ] + }, + "fs": { + "default": { + "all": false, + "copyFile": false, + "createDir": false, + "path": false, + "readBinaryFile": false, + "readDir": false, + "readTextFile": false, + "removeDir": false, + "removeFile": false, + "renameFile": false, + "writeBinaryFile": false, + "writeFile": false + }, + "allOf": [ + { + "$ref": "#/definitions/FsAllowlistConfig" + } + ] + }, + "globalShortcut": { + "default": { + "all": false + }, + "allOf": [ + { + "$ref": "#/definitions/GlobalShortcutAllowlistConfig" + } + ] + }, + "http": { + "default": { + "all": false, + "request": false + }, + "allOf": [ + { + "$ref": "#/definitions/HttpAllowlistConfig" + } + ] + }, + "notification": { + "default": { + "all": false + }, + "allOf": [ + { + "$ref": "#/definitions/NotificationAllowlistConfig" + } + ] + }, + "shell": { + "default": { + "all": false, + "execute": false, + "open": false + }, + "allOf": [ + { + "$ref": "#/definitions/ShellAllowlistConfig" + } + ] + }, + "window": { + "default": { + "all": false, + "create": false + }, + "allOf": [ + { + "$ref": "#/definitions/WindowAllowlistConfig" + } + ] + } + }, + "additionalProperties": false + }, "BuildConfig": { "description": "The Build configuration object.", "type": "object", @@ -524,6 +661,24 @@ }, "additionalProperties": false }, + "DialogAllowlistConfig": { + "type": "object", + "properties": { + "all": { + "default": false, + "type": "boolean" + }, + "open": { + "default": false, + "type": "boolean" + }, + "save": { + "default": false, + "type": "boolean" + } + }, + "additionalProperties": false + }, "EmbeddedServerConfig": { "description": "The embeddedServer configuration object.", "type": "object", @@ -556,6 +711,94 @@ }, "additionalProperties": false }, + "FsAllowlistConfig": { + "type": "object", + "properties": { + "all": { + "default": false, + "type": "boolean" + }, + "copyFile": { + "default": false, + "type": "boolean" + }, + "createDir": { + "default": false, + "type": "boolean" + }, + "path": { + "default": false, + "type": "boolean" + }, + "readBinaryFile": { + "default": false, + "type": "boolean" + }, + "readDir": { + "default": false, + "type": "boolean" + }, + "readTextFile": { + "default": false, + "type": "boolean" + }, + "removeDir": { + "default": false, + "type": "boolean" + }, + "removeFile": { + "default": false, + "type": "boolean" + }, + "renameFile": { + "default": false, + "type": "boolean" + }, + "writeBinaryFile": { + "default": false, + "type": "boolean" + }, + "writeFile": { + "default": false, + "type": "boolean" + } + }, + "additionalProperties": false + }, + "GlobalShortcutAllowlistConfig": { + "type": "object", + "properties": { + "all": { + "default": false, + "type": "boolean" + } + }, + "additionalProperties": false + }, + "HttpAllowlistConfig": { + "type": "object", + "properties": { + "all": { + "default": false, + "type": "boolean" + }, + "request": { + "default": false, + "type": "boolean" + } + }, + "additionalProperties": false + }, + "NotificationAllowlistConfig": { + "type": "object", + "properties": { + "all": { + "default": false, + "type": "boolean" + } + }, + "additionalProperties": false + }, "OsxConfig": { "type": "object", "properties": { @@ -619,16 +862,75 @@ }, "additionalProperties": false }, + "ShellAllowlistConfig": { + "type": "object", + "properties": { + "all": { + "default": false, + "type": "boolean" + }, + "execute": { + "default": false, + "type": "boolean" + }, + "open": { + "default": false, + "type": "boolean" + } + }, + "additionalProperties": false + }, "TauriConfig": { "description": "The Tauri configuration object.", "type": "object", "properties": { "allowlist": { - "default": {}, - "type": "object", - "additionalProperties": { - "type": "boolean" - } + "default": { + "all": false, + "dialog": { + "all": false, + "open": false, + "save": false + }, + "fs": { + "all": false, + "copyFile": false, + "createDir": false, + "path": false, + "readBinaryFile": false, + "readDir": false, + "readTextFile": false, + "removeDir": false, + "removeFile": false, + "renameFile": false, + "writeBinaryFile": false, + "writeFile": false + }, + "globalShortcut": { + "all": false + }, + "http": { + "all": false, + "request": false + }, + "notification": { + "all": false + }, + "shell": { + "all": false, + "execute": false, + "open": false + }, + "window": { + "all": false, + "create": false + } + }, + "allOf": [ + { + "$ref": "#/definitions/AllowlistConfig" + } + ] }, "bundle": { "description": "The bundler configuration.", @@ -708,6 +1010,20 @@ }, "additionalProperties": false }, + "WindowAllowlistConfig": { + "type": "object", + "properties": { + "all": { + "default": false, + "type": "boolean" + }, + "create": { + "default": false, + "type": "boolean" + } + }, + "additionalProperties": false + }, "WindowConfig": { "description": "The window configuration object.", "type": "object", diff --git a/cli/core/src/helpers/manifest.rs b/cli/core/src/helpers/manifest.rs index 74b2a82e6..468df9f8f 100644 --- a/cli/core/src/helpers/manifest.rs +++ b/cli/core/src/helpers/manifest.rs @@ -1,6 +1,5 @@ use super::{app_paths::tauri_dir, config::ConfigHandle}; -use convert_case::{Case, Casing}; use toml_edit::{Array, Document, Value}; use std::{ @@ -27,21 +26,13 @@ pub fn rewrite_manifest(config: ConfigHandle) -> crate::Result<()> { let config = config_guard.as_ref().unwrap(); if let Some(tauri) = tauri { - let mut features: Array = Default::default(); - - let allowlist = &config.tauri.allowlist; - if *allowlist.get("all").unwrap_or(&false) { - features.push("all-api".to_string()).unwrap(); - } else { - for (feature, enabled) in allowlist.iter() { - if *enabled { - features.push(feature.to_case(Case::Kebab)).unwrap(); - } - } + let allowlist_features = config.tauri.features(); + let mut features = Array::default(); + for feature in allowlist_features { + features.push(feature).unwrap(); } - if config.tauri.cli.is_some() { - features.push("cli".to_string()).unwrap(); + features.push("cli").unwrap(); } match tauri { diff --git a/cli/tauri.js/test/jest/fixtures/app/src-tauri/Cargo.toml b/cli/tauri.js/test/jest/fixtures/app/src-tauri/Cargo.toml index acd2319a6..f5f62b961 100644 --- a/cli/tauri.js/test/jest/fixtures/app/src-tauri/Cargo.toml +++ b/cli/tauri.js/test/jest/fixtures/app/src-tauri/Cargo.toml @@ -24,7 +24,7 @@ icon = [ serde_json = "1.0.62" serde = "1.0" serde_derive = "1.0" -tauri = { path = "../../../../../../../tauri", features =["all-api"]} +tauri = { path = "../../../../../../../tauri", features =["api-all"]} [features] embedded-server = [ "tauri/embedded-server" ] diff --git a/tauri/Cargo.toml b/tauri/Cargo.toml index 03fe3c797..8a85616fc 100644 --- a/tauri/Cargo.toml +++ b/tauri/Cargo.toml @@ -15,7 +15,7 @@ edition = "2018" exclude = [ "test/fixture/**" ] [package.metadata.docs.rs] -features = [ "all-api" ] +features = [ "api-all" ] [dependencies] serde_json = "1.0" @@ -44,49 +44,52 @@ cfg_aliases = "0.1.1" [dev-dependencies] proptest = "0.10.1" serde_json = "1.0" -tauri = { path = ".", features = [ "all-api" ] } +tauri = { path = ".", features = [ "api-all" ] } serde = { version = "1.0", features = [ "derive" ] } [features] cli = [ "tauri-api/cli" ] embedded-server = [ "tiny_http" ] -all-api = [ "tauri-api/notification", "tauri-api/global-shortcut" ] +api-all = [ "tauri-api/notification", "tauri-api/global-shortcut" ] updater = [ ] # FS -read-text-file = [ ] -read-binary-file = [ ] -write-file = [ ] -write-binary-file = [ ] -read-dir = [ ] -copy-file = [ ] -create-dir = [ ] -remove-dir = [ ] -remove-file = [ ] -rename-file = [ ] -path-api = [ ] -event = [ ] +fs-all = [ ] +fs-read-text-file = [ ] +fs-read-binary-file = [ ] +fs-write-file = [ ] +fs-write-binary-file = [ ] +fs-read-dir = [ ] +fs-copy-file = [ ] +fs-create-dir = [ ] +fs-remove-dir = [ ] +fs-remove-file = [ ] +fs-rename-file = [ ] +fs-path-api = [ ] # window -window = [ ] -create-window = [ ] +window-all = [ ] +window-create = [ ] #shell -execute = [ ] -open = [ ] +shell-all = [ ] +shell-execute = [ ] +shell-open = [ ] # dialog -open-dialog = [ ] -save-dialog = [ ] +dialog-all = [ ] +dialog-open = [ ] +dialog-save = [ ] # HTTP +http-all = [ ] http-request = [ ] # notification -notification = [ "tauri-api/notification" ] +notification-all = [ "tauri-api/notification" ] # global shortcut -global-shortcut = [ "tauri-api/global-shortcut" ] +global-shortcut-all = [ "tauri-api/global-shortcut" ] [[example]] name = "communication" diff --git a/tauri/build.rs b/tauri/build.rs index 9b4ba53be..a2a1a39bc 100644 --- a/tauri/build.rs +++ b/tauri/build.rs @@ -5,45 +5,47 @@ fn main() { embedded_server: { feature = "embedded-server" }, dev: { not(feature = "embedded-server") }, - all_api: { feature = "all-api" }, + api_all: { feature = "api-all" }, // fs - read_text_file: { any(all_api, feature = "read-text-file") }, - read_binary_file: { any(all_api, feature = "read-binary-file") }, - write_file: { any(all_api, feature = "write-file") }, - write_binary_file: { any(all_api, feature = "write-binary-file") }, - read_dir: { any(all_api, feature = "read-dir") }, - copy_file: { any(all_api, feature = "copy-file") }, - create_dir: { any(all_api, feature = "create_dir") }, - remove_dir: { any(all_api, feature = "remove-dir") }, - remove_file: { any(all_api, feature = "remove-file") }, - rename_file: { any(all_api, feature = "rename-file") }, - - // js path api - path_api: { any(all_api, feature = "path-api") }, + fs_all: { any(api_all, feature = "fs-all") }, + fs_read_text_file: { any(fs_all, feature = "fs-read-text-file") }, + fs_read_binary_file: { any(fs_all, feature = "fs-read-binary-file") }, + fs_write_file: { any(fs_all, feature = "fs-write-file") }, + fs_write_binary_file: { any(fs_all, feature = "fs-write-binary-file") }, + fs_read_dir: { any(fs_all, feature = "fs-read-dir") }, + fs_copy_file: { any(fs_all, feature = "fs-copy-file") }, + fs_create_dir: { any(fs_all, feature = "fs-create_dir") }, + fs_remove_dir: { any(fs_all, feature = "fs-remove-dir") }, + fs_remove_file: { any(fs_all, feature = "fs-remove-file") }, + fs_rename_file: { any(fs_all, feature = "fs-rename-file") }, + fs_path: { any(fs_all, feature = "fs-path") }, // window - window: { any(all_api, feature = "window") }, - create_window: { any(all_api, feature = "create-window") }, + window_all: { any(api_all, feature = "window-all") }, + window_create: { any(window_all, feature = "window-create") }, // shell - open: { any(all_api, feature = "open") }, - execute: { any(all_api, feature = "execute") }, + shell_all: { any(api_all, feature = "shell-all") }, + shell_open: { any(shell_all, feature = "shell-open") }, + shell_execute: { any(shell_all, feature = "shell-execute") }, // dialog - open_dialog: { any(all_api, feature = "open-dialog") }, - save_dialog: { any(all_api, feature = "save-dialog") }, + dialog_all: { any(api_all, feature = "dialog-all") }, + dialog_open: { any(dialog_all, feature = "dialog-open") }, + dialog_save: { any(dialog_all, feature = "dialog-save") }, // http - http_request: { any(all_api, feature = "http-request") }, + http_all: { any(api_all, feature = "http-all") }, + http_request: { any(http_all, feature = "http-request") }, // cli cli: { feature = "cli" }, // notification - notification: { any(all_api, feature = "notification") }, + notification_all: { any(api_all, feature = "notification-all") }, // global shortcut - global_shortcut: { any(all_api, feature = "global_shortcut" )}, + global_shortcut_all: { any(api_all, feature = "global_shortcut-all") }, } } diff --git a/tauri/examples/api/src-tauri/Cargo.toml b/tauri/examples/api/src-tauri/Cargo.toml index c2bc6b8fa..3baa4488e 100644 --- a/tauri/examples/api/src-tauri/Cargo.toml +++ b/tauri/examples/api/src-tauri/Cargo.toml @@ -14,7 +14,7 @@ build = "src/build.rs" [dependencies] serde_json = "1.0" serde = { version = "1.0", features = [ "derive" ] } -tauri = { path = "../../..", features =["all-api", "cli"]} +tauri = { path = "../../..", features =["api-all", "cli"]} [target."cfg(windows)".build-dependencies] winres = "0.1" diff --git a/tauri/examples/communication/src-tauri/Cargo.toml b/tauri/examples/communication/src-tauri/Cargo.toml index b26a827cc..fe6b2f876 100644 --- a/tauri/examples/communication/src-tauri/Cargo.toml +++ b/tauri/examples/communication/src-tauri/Cargo.toml @@ -24,7 +24,7 @@ icon = [ [dependencies] serde_json = "1.0" serde = { version = "1.0", features = [ "derive" ] } -tauri = { path = "../../..", features =["all-api", "cli"]} +tauri = { path = "../../..", features =["api-all", "cli"]} [target."cfg(windows)".build-dependencies] winres = "0.1" diff --git a/tauri/examples/multiwindow/src-tauri/Cargo.toml b/tauri/examples/multiwindow/src-tauri/Cargo.toml index 0d75e8e4a..c19284154 100644 --- a/tauri/examples/multiwindow/src-tauri/Cargo.toml +++ b/tauri/examples/multiwindow/src-tauri/Cargo.toml @@ -22,7 +22,7 @@ icon = [ ] [dependencies] -tauri = { path = "../../..", features =["all-api"]} +tauri = { path = "../../..", features =["api-all"]} [target."cfg(windows)".build-dependencies] winres = "0.1" diff --git a/tauri/src/endpoints.rs b/tauri/src/endpoints.rs index a071bc53b..446bfb7b9 100644 --- a/tauri/src/endpoints.rs +++ b/tauri/src/endpoints.rs @@ -3,12 +3,9 @@ mod dialog; mod event; #[allow(unused_imports)] mod file_system; -#[cfg(global_shortcut)] mod global_shortcut; -#[cfg(http_request)] mod http; mod internal; -#[cfg(notification)] mod notification; mod shell; mod window; diff --git a/tauri/src/endpoints/dialog.rs b/tauri/src/endpoints/dialog.rs index 5ef4d50b0..8426a3e51 100644 --- a/tauri/src/endpoints/dialog.rs +++ b/tauri/src/endpoints/dialog.rs @@ -1,5 +1,7 @@ +#[cfg(any(dialog_open, dialog_save))] +use crate::api::dialog::FileDialogBuilder; use crate::{ - api::dialog::{ask as ask_dialog, message as message_dialog, AskResponse, FileDialogBuilder}, + api::dialog::{ask as ask_dialog, message as message_dialog, AskResponse}, app::InvokeResponse, }; use serde::Deserialize; @@ -66,16 +68,16 @@ impl Cmd { pub async fn run(self) -> crate::Result { match self { Self::OpenDialog { options } => { - #[cfg(open_dialog)] + #[cfg(dialog_open)] return open(options); - #[cfg(not(open_dialog))] - Err(crate::Error::ApiNotAllowlisted("title".to_string())); + #[cfg(not(dialog_open))] + return Err(crate::Error::ApiNotAllowlisted("dialog > open".to_string())); } Self::SaveDialog { options } => { - #[cfg(save_dialog)] + #[cfg(dialog_save)] return save(options); - #[cfg(not(save_dialog))] - Err(crate::Error::ApiNotAllowlisted("saveDialog".to_string())); + #[cfg(not(dialog_save))] + return Err(crate::Error::ApiNotAllowlisted("dialog > save".to_string())); } Self::MessageDialog { message } => { let exe = std::env::current_exe()?; @@ -106,7 +108,7 @@ impl Cmd { } /// Shows an open dialog. -#[cfg(open_dialog)] +#[cfg(dialog_open)] pub fn open(options: OpenDialogOptions) -> crate::Result { let mut dialog_builder = FileDialogBuilder::new(); if let Some(default_path) = options.default_path { @@ -127,7 +129,7 @@ pub fn open(options: OpenDialogOptions) -> crate::Result { } /// Shows a save dialog. -#[cfg(save_dialog)] +#[cfg(dialog_save)] pub fn save(options: SaveDialogOptions) -> crate::Result { let mut dialog_builder = FileDialogBuilder::new(); if let Some(default_path) = options.default_path { diff --git a/tauri/src/endpoints/file_system.rs b/tauri/src/endpoints/file_system.rs index 3bef1d828..3d909ed80 100644 --- a/tauri/src/endpoints/file_system.rs +++ b/tauri/src/endpoints/file_system.rs @@ -94,15 +94,17 @@ impl Cmd { pub async fn run(self) -> crate::Result { match self { Self::ReadTextFile { path, options } => { - #[cfg(read_text_file)] + #[cfg(fs_read_text_file)] return read_text_file(path, options).await.map(Into::into); - #[cfg(not(read_text_file))] - Err(crate::Error::ApiNotAllowlisted("readTextFile".to_string())) + #[cfg(not(fs_read_text_file))] + Err(crate::Error::ApiNotAllowlisted( + "fs > readTextFile".to_string(), + )) } Self::ReadBinaryFile { path, options } => { - #[cfg(read_binary_file)] + #[cfg(fs_read_binary_file)] return read_binary_file(path, options).await.map(Into::into); - #[cfg(not(read_binary_file))] + #[cfg(not(fs_read_binary_file))] Err(crate::Error::ApiNotAllowlisted( "readBinaryFile".to_string(), )) @@ -112,85 +114,95 @@ impl Cmd { contents, options, } => { - #[cfg(write_file)] + #[cfg(fs_write_file)] return write_file(path, contents, options).await.map(Into::into); - #[cfg(not(write_file))] - Err(crate::Error::ApiNotAllowlisted("writeFile".to_string())) + #[cfg(not(fs_write_file))] + Err(crate::Error::ApiNotAllowlisted( + "fs > writeFile".to_string(), + )) } Self::WriteBinaryFile { path, contents, options, } => { - #[cfg(write_binary_file)] + #[cfg(fs_write_binary_file)] return write_binary_file(path, contents, options) .await .map(Into::into); - #[cfg(not(write_binary_file))] + #[cfg(not(fs_write_binary_file))] Err(crate::Error::ApiNotAllowlisted( "writeBinaryFile".to_string(), )) } Self::ReadDir { path, options } => { - #[cfg(read_dir)] + #[cfg(fs_read_dir)] return read_dir(path, options).await.map(Into::into); - #[cfg(not(read_dir))] - Err(crate::Error::ApiNotAllowlisted("readDir".to_string())) + #[cfg(not(fs_read_dir))] + Err(crate::Error::ApiNotAllowlisted("fs > readDir".to_string())) } Self::CopyFile { source, destination, options, } => { - #[cfg(copy_file)] + #[cfg(fs_copy_file)] return copy_file(source, destination, options) .await .map(Into::into); - #[cfg(not(copy_file))] - Err(crate::Error::ApiNotAllowlisted("copyFile".to_string())) + #[cfg(not(fs_copy_file))] + Err(crate::Error::ApiNotAllowlisted("fs > copyFile".to_string())) } Self::CreateDir { path, options } => { - #[cfg(create_dir)] + #[cfg(fs_create_dir)] return create_dir(path, options).await.map(Into::into); - #[cfg(not(create_dir))] - Err(crate::Error::ApiNotAllowlisted("createDir".to_string())) + #[cfg(not(fs_create_dir))] + Err(crate::Error::ApiNotAllowlisted( + "fs > createDir".to_string(), + )) } Self::RemoveDir { path, options } => { - #[cfg(remove_dir)] + #[cfg(fs_remove_dir)] return remove_dir(path, options).await.map(Into::into); - #[cfg(not(remove_dir))] - Err(crate::Error::ApiNotAllowlisted("removeDir".to_string())) + #[cfg(not(fs_remove_dir))] + Err(crate::Error::ApiNotAllowlisted( + "fs > removeDir".to_string(), + )) } Self::RemoveFile { path, options } => { - #[cfg(remove_file)] + #[cfg(fs_remove_file)] return remove_file(path, options).await.map(Into::into); - #[cfg(not(remove_file))] - Err(crate::Error::ApiNotAllowlisted("removeFile".to_string())) + #[cfg(not(fs_remove_file))] + Err(crate::Error::ApiNotAllowlisted( + "fs > removeFile".to_string(), + )) } Self::RenameFile { old_path, new_path, options, } => { - #[cfg(rename_file)] + #[cfg(fs_rename_file)] return rename_file(old_path, new_path, options) .await .map(Into::into); - #[cfg(not(rename_file))] - Err(crate::Error::ApiNotAllowlisted("renameFile".to_string())) + #[cfg(not(fs_rename_file))] + Err(crate::Error::ApiNotAllowlisted( + "fs > renameFile".to_string(), + )) } Self::ResolvePath { path, directory } => { - #[cfg(path_api)] + #[cfg(fs_path)] return resolve_path_handler(path, directory).await.map(Into::into); - #[cfg(not(path_api))] - Err(crate::Error::ApiNotAllowlisted("pathApi".to_string())) + #[cfg(not(fs_path))] + Err(crate::Error::ApiNotAllowlisted("fs > pathApi".to_string())) } } } } /// Reads a directory. -#[cfg(read_dir)] +#[cfg(fs_read_dir)] pub async fn read_dir( path: PathBuf, options: Option, @@ -204,7 +216,7 @@ pub async fn read_dir( } /// Copies a file. -#[cfg(copy_file)] +#[cfg(fs_copy_file)] pub async fn copy_file( source: PathBuf, destination: PathBuf, @@ -222,7 +234,7 @@ pub async fn copy_file( } /// Creates a directory. -#[cfg(create_dir)] +#[cfg(fs_create_dir)] pub async fn create_dir(path: PathBuf, options: Option) -> crate::Result<()> { let (recursive, dir) = if let Some(options_value) = options { (options_value.recursive, options_value.dir) @@ -240,7 +252,7 @@ pub async fn create_dir(path: PathBuf, options: Option) -> } /// Removes a directory. -#[cfg(remove_dir)] +#[cfg(fs_remove_dir)] pub async fn remove_dir(path: PathBuf, options: Option) -> crate::Result<()> { let (recursive, dir) = if let Some(options_value) = options { (options_value.recursive, options_value.dir) @@ -258,7 +270,7 @@ pub async fn remove_dir(path: PathBuf, options: Option) -> } /// Removes a file -#[cfg(remove_file)] +#[cfg(fs_remove_file)] pub async fn remove_file( path: PathBuf, options: Option, @@ -269,7 +281,7 @@ pub async fn remove_file( } /// Renames a file. -#[cfg(rename_file)] +#[cfg(fs_rename_file)] pub async fn rename_file( old_path: PathBuf, new_path: PathBuf, @@ -286,7 +298,7 @@ pub async fn rename_file( } /// Writes a text file. -#[cfg(write_file)] +#[cfg(fs_write_file)] pub async fn write_file( path: PathBuf, contents: String, @@ -299,7 +311,7 @@ pub async fn write_file( } /// Writes a binary file. -#[cfg(write_binary_file)] +#[cfg(fs_write_binary_file)] pub async fn write_binary_file( path: PathBuf, contents: String, @@ -316,7 +328,7 @@ pub async fn write_binary_file( } /// Reads a text file. -#[cfg(read_text_file)] +#[cfg(fs_read_text_file)] pub async fn read_text_file( path: PathBuf, options: Option, @@ -326,7 +338,7 @@ pub async fn read_text_file( } /// Reads a binary file. -#[cfg(read_binary_file)] +#[cfg(fs_read_binary_file)] pub async fn read_binary_file( path: PathBuf, options: Option, @@ -335,6 +347,7 @@ pub async fn read_binary_file( .map_err(crate::Error::FailedToExecuteApi) } +#[cfg(fs_path)] pub async fn resolve_path_handler( path: String, directory: Option, diff --git a/tauri/src/endpoints/global_shortcut.rs b/tauri/src/endpoints/global_shortcut.rs index 6a1972d3a..76107e727 100644 --- a/tauri/src/endpoints/global_shortcut.rs +++ b/tauri/src/endpoints/global_shortcut.rs @@ -1,5 +1,6 @@ +#[cfg(global_shortcut_all)] +use crate::api::shortcuts::ShortcutManager; use crate::{ - api::shortcuts::ShortcutManager, app::{InvokeResponse, WebviewDispatcher}, async_runtime::Mutex, }; @@ -8,8 +9,10 @@ use serde::Deserialize; use std::sync::Arc; +#[cfg(global_shortcut_all)] type ShortcutManagerHandle = Arc>; +#[cfg(global_shortcut_all)] pub fn manager_handle() -> &'static ShortcutManagerHandle { static MANAGER: Lazy = Lazy::new(Default::default); &MANAGER @@ -34,6 +37,7 @@ pub enum Cmd { IsRegistered { shortcut: String }, } +#[cfg(global_shortcut_all)] fn register_shortcut( dispatcher: WebviewDispatcher, manager: &mut ShortcutManager, @@ -55,11 +59,11 @@ impl Cmd { self, webview_manager: &crate::WebviewManager, ) -> crate::Result { - #[cfg(not(global_shortcut))] + #[cfg(not(global_shortcut_all))] return Err(crate::Error::ApiNotAllowlisted( - "globalShortcut".to_string(), + "globalShortcut > all".to_string(), )); - #[cfg(global_shortcut)] + #[cfg(global_shortcut_all)] match self { Self::Register { shortcut, handler } => { let dispatcher = webview_manager.current_webview().await?.clone(); diff --git a/tauri/src/endpoints/http.rs b/tauri/src/endpoints/http.rs index dedc1a3f3..0ec7a5868 100644 --- a/tauri/src/endpoints/http.rs +++ b/tauri/src/endpoints/http.rs @@ -48,13 +48,16 @@ impl Cmd { #[cfg(http_request)] return make_request(client, *options).await.map(Into::into); #[cfg(not(http_request))] - Err(crate::Error::ApiNotAllowlisted("httpRequest".to_string())) + Err(crate::Error::ApiNotAllowlisted( + "http > request".to_string(), + )) } } } } /// Makes an HTTP request and resolves the response to the webview +#[cfg(http_request)] pub async fn make_request( client_id: ClientId, options: HttpRequestBuilder, diff --git a/tauri/src/endpoints/notification.rs b/tauri/src/endpoints/notification.rs index af44b8f29..a689f828c 100644 --- a/tauri/src/endpoints/notification.rs +++ b/tauri/src/endpoints/notification.rs @@ -1,5 +1,6 @@ use crate::app::InvokeResponse; use serde::Deserialize; +#[cfg(notification_all)] use tauri_api::{config::Config, notification::Notification}; /// The options for the notification API. @@ -29,27 +30,28 @@ impl Cmd { pub async fn run(self, context: &crate::app::Context) -> crate::Result { match self { Self::Notification { options } => { - #[cfg(notification)] + #[cfg(notification_all)] return send(options, &context.config).await.map(Into::into); - #[cfg(not(notification))] + #[cfg(not(notification_all))] Err(crate::Error::ApiNotAllowlisted("notification".to_string())) } Self::IsNotificationPermissionGranted => { - #[cfg(notification)] + #[cfg(notification_all)] return is_permission_granted().await.map(Into::into); - #[cfg(not(notification))] + #[cfg(not(notification_all))] Err(crate::Error::ApiNotAllowlisted("notification".to_string())) } Self::RequestNotificationPermission => { - #[cfg(notification)] + #[cfg(notification_all)] return request_permission().map(Into::into); - #[cfg(not(notification))] + #[cfg(not(notification_all))] Err(crate::Error::ApiNotAllowlisted("notification".to_string())) } } } } +#[cfg(notification_all)] pub async fn send(options: NotificationOptions, config: &Config) -> crate::Result { let identifier = config.tauri.bundle.identifier.clone(); let mut notification = Notification::new(identifier).title(options.title); @@ -63,6 +65,7 @@ pub async fn send(options: NotificationOptions, config: &Config) -> crate::Resul Ok(().into()) } +#[cfg(notification_all)] pub async fn is_permission_granted() -> crate::Result { let settings = crate::settings::read_settings()?; if let Some(allow_notification) = settings.allow_notification { @@ -72,6 +75,7 @@ pub async fn is_permission_granted() -> crate::Result { } } +#[cfg(notification_all)] pub fn request_permission() -> crate::Result { let mut settings = crate::settings::read_settings()?; let granted = "granted".to_string(); diff --git a/tauri/src/endpoints/shell.rs b/tauri/src/endpoints/shell.rs index 79a61f4b9..e643f0450 100644 --- a/tauri/src/endpoints/shell.rs +++ b/tauri/src/endpoints/shell.rs @@ -18,28 +18,30 @@ impl Cmd { command: _, args: _, } => { - #[cfg(execute)] + #[cfg(shell_execute)] { //TODO Ok(().into()) } - #[cfg(not(execute))] - Err(crate::Error::ApiNotAllowlisted("execute".to_string())) + #[cfg(not(shell_execute))] + Err(crate::Error::ApiNotAllowlisted( + "shell > execute".to_string(), + )) } Self::Open { uri } => { - #[cfg(open)] + #[cfg(shell_open)] { open_browser(uri); Ok(().into()) } - #[cfg(not(open))] - Err(crate::Error::ApiNotAllowlisted("open".to_string())) + #[cfg(not(shell_open))] + Err(crate::Error::ApiNotAllowlisted("shell > open".to_string())) } } } } -#[cfg(open)] +#[cfg(shell_open)] pub fn open_browser(uri: String) { #[cfg(test)] assert!(uri.contains("http://")); @@ -53,7 +55,7 @@ mod test { use proptest::prelude::*; // Test the open func to see if proper uris can be opened by the browser. proptest! { - #[cfg(open)] + #[cfg(shell_open)] #[test] fn check_open(uri in r"(http://)([\\w\\d\\.]+([\\w]{2,6})?)") { super::open_browser(uri); diff --git a/tauri/src/endpoints/window.rs b/tauri/src/endpoints/window.rs index 14b8ddcb5..eba093c49 100644 --- a/tauri/src/endpoints/window.rs +++ b/tauri/src/endpoints/window.rs @@ -84,7 +84,7 @@ pub enum Cmd { }, } -#[cfg(create_window)] +#[cfg(window_create)] #[derive(Clone, serde::Serialize)] struct WindowCreatedEvent { label: String, @@ -95,15 +95,17 @@ impl Cmd { self, webview_manager: &crate::WebviewManager, ) -> crate::Result { - if cfg!(not(window)) { - Err(crate::Error::ApiNotAllowlisted("setTitle".to_string())) + if cfg!(not(window_all)) { + Err(crate::Error::ApiNotAllowlisted("window > all".to_string())) } else { let current_webview = webview_manager.current_webview().await?; match self { Self::CreateWebview { options } => { - #[cfg(not(create_window))] - return Err(crate::Error::ApiNotAllowlisted("createWindow".to_string())); - #[cfg(create_window)] + #[cfg(not(window_create))] + return Err(crate::Error::ApiNotAllowlisted( + "window > create".to_string(), + )); + #[cfg(window_create)] { let label = options.label.to_string(); webview_manager diff --git a/tauri/src/settings.rs b/tauri/src/settings.rs index f0d6efd42..ba257a655 100644 --- a/tauri/src/settings.rs +++ b/tauri/src/settings.rs @@ -13,7 +13,7 @@ use tauri_api::{ #[derive(Default, Deserialize, Serialize)] pub struct Settings { /// Whether the user allows notifications or not. - #[cfg(notification)] + #[cfg(notification_all)] pub allow_notification: Option, }