Browse Source

Merge pull request from GHSA-57fm-592m-34r7

* add __TAURI_INVOKE_KEY__ to ipc calls to detect initialized frames

* move ipc key check to start of on_message

* cargo +nightly fmt

* undo Cargo.toml formatting changes

* undo Cargo.toml formatting changes

* undo Cargo.toml formatting changes

* remove merged changefiles

* undo formatting changes to js files

* undo formatting changes to js files

* Update to patched wry  release

* fix: optional chaining is not supported on older webviews (#9529)

* Revert "undo formatting changes to js files"

This reverts commit a7ef0d91ea1b183e091ea65a2b201d65522cc1d5.

* Revert "undo formatting changes to js files"

This reverts commit 0fcfd4664b915af51b71e7ea68929fd5b6cb5fc3.

* revert core.js

* inject __TAURI_INVOKE_KEY__ to __TAURI_IPC__ instead

* remove unrelated changes file

* remove left over dbg! call

* change file

---------

Co-authored-by: Tillmann <28728469+tweidinger@users.noreply.github.com>
Co-authored-by: Lucas Fernandes Nogueira <lucas@tauri.app>
chip 1 năm trước cách đây
mục cha
commit
f6d81dfe08

+ 6 - 0
.changes/ipc-only-main-frame.md

@@ -0,0 +1,6 @@
+---
+"tauri": patch:sec
+"tauri-runtime-wry": patch:sec
+---
+
+Only process IPC commands from the main frame.

+ 3 - 2
Cargo.lock

@@ -4036,6 +4036,7 @@ dependencies = [
  "encoding_rs",
  "flate2",
  "futures-util",
+ "getrandom 0.2.14",
  "glib",
  "glob",
  "gtk",
@@ -5515,9 +5516,9 @@ dependencies = [
 
 [[package]]
 name = "wry"
-version = "0.24.8"
+version = "0.24.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a04e72739ee84a218e3dbf8625888eadc874285637003ed21ab96a1bbbb538ec"
+checksum = "00711278ed357350d44c749c286786ecac644e044e4da410d466212152383b45"
 dependencies = [
  "base64 0.13.1",
  "block",

+ 1 - 1
core/tauri-runtime-wry/Cargo.toml

@@ -13,7 +13,7 @@ exclude = [ "CHANGELOG.md", "/target" ]
 readme = "README.md"
 
 [dependencies]
-wry = { version = "0.24.6", default-features = false, features = [ "file-drop", "protocol" ] }
+wry = { version = "0.24.10", default-features = false, features = [ "file-drop", "protocol" ] }
 tauri-runtime = { version = "0.14.3", path = "../tauri-runtime" }
 tauri-utils = { version = "1.5.4", path = "../tauri-utils" }
 uuid = { version = "1", features = [ "v4" ] }

+ 1 - 0
core/tauri/Cargo.toml

@@ -96,6 +96,7 @@ encoding_rs = "0.8.31"
 sys-locale = { version = "0.2.3", optional = true }
 tracing = { version = "0.1", optional = true }
 indexmap = { version = "1", features = [ "std", "serde" ], optional = true }
+getrandom = { version = "0.2", features = [ "std" ] }
 
 [target."cfg(any(target_os = \"macos\", windows, target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\"))".dependencies]
 rfd = { version = "0.10", optional = true, features = [ "gtk3", "common-controls-v6" ] }

+ 8 - 14
core/tauri/scripts/init.js

@@ -2,19 +2,19 @@
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: MIT
 
-; (function () {
+;(function() {
   __RAW_freeze_prototype__
 
-    ; (function () {
-      __RAW_hotkeys__
-    })()
+  ;(function() {
+    __RAW_hotkeys__
+  })()
 
   __RAW_pattern_script__
 
   __RAW_ipc_script__
-    ; (function () {
-      __RAW_bundle_script__
-    })()
+  ;(function() {
+    __RAW_bundle_script__
+  })()
 
   __RAW_listen_function__
 
@@ -22,11 +22,5 @@
 
   __RAW_event_initialization_script__
 
-  if (window.ipc) {
-    window.__TAURI_INVOKE__('__initialized', { url: window.location.href })
-  } else {
-    window.addEventListener('DOMContentLoaded', function () {
-      window.__TAURI_INVOKE__('__initialized', { url: window.location.href })
-    })
-  }
+  window.__TAURI_INVOKE__('__initialized', { url: window.location.href })
 })()

+ 11 - 1
core/tauri/scripts/ipc.js

@@ -7,7 +7,7 @@
  */
 
 ;
-(function () {
+(function() {
   /**
    * @type {string}
    */
@@ -18,6 +18,15 @@
    */
   const isolationOrigin = __TEMPLATE_isolation_origin__
 
+  /**
+   * A runtime generated key to ensure an IPC call comes from an initialized frame.
+   *
+   * This is declared outside the `window.__TAURI_INVOKE__` definition to prevent
+   * the key from being leaked by `window.__TAURI_INVOKE__.toString()`.
+   * @var {string} __TEMPLATE_invoke_key__
+   */
+  const __TAURI_INVOKE_KEY__ = __TEMPLATE_invoke_key__
+
   /**
    * @type {{queue: object[], ready: boolean, frame: HTMLElement | null}}
    */
@@ -85,6 +94,7 @@
   Object.defineProperty(window, '__TAURI_IPC__', {
     // todo: JSDoc this function
     value: Object.freeze((message) => {
+      message.__TAURI_INVOKE_KEY__ = __TAURI_INVOKE_KEY__
       switch (pattern) {
         case 'brownfield':
           window.__TAURI_POST_MESSAGE__(message)

+ 1 - 0
core/tauri/src/app.rs

@@ -1569,6 +1569,7 @@ impl<R: Runtime> Builder<R> {
       self.window_event_listeners,
       (self.menu, self.menu_event_listeners),
       (self.invoke_responder, self.invoke_initialization_script),
+      crate::generate_invoke_key()?,
     );
 
     let http_scheme = manager.config().tauri.security.dangerous_use_http_scheme;

+ 6 - 0
core/tauri/src/error.rs

@@ -131,6 +131,12 @@ pub enum Error {
   /// The Window's raw handle is invalid for the platform.
   #[error("Unexpected `raw_window_handle` for the current platform")]
   InvalidWindowHandle,
+  /// Something went wrong with the CSPRNG.
+  #[error("unable to generate random bytes from the operating system: {0}")]
+  Csprng(#[from] getrandom::Error),
+  /// Bad `__TAURI_INVOKE_KEY__` value received in ipc message.
+  #[error("bad __TAURI_INVOKE_KEY__ value received in ipc message")]
+  InvokeKey,
 }
 
 pub(crate) fn into_anyhow<T: std::fmt::Display>(err: T) -> anyhow::Error {

+ 5 - 0
core/tauri/src/hooks.rs

@@ -35,6 +35,7 @@ pub type OnPageLoad<R> = dyn Fn(Window<R>, PageLoadPayload) + Send + Sync + 'sta
 #[default_template("../scripts/ipc.js")]
 pub(crate) struct IpcJavascript<'a> {
   pub(crate) isolation_origin: &'a str,
+  pub(crate) invoke_key: &'a str,
 }
 
 #[cfg(feature = "isolation")]
@@ -66,6 +67,10 @@ pub struct InvokePayload {
   #[serde(rename = "__tauriModule")]
   #[doc(hidden)]
   pub tauri_module: Option<String>,
+  /// A secret key that only Tauri initialized frames have.
+  #[serde(rename = "__TAURI_INVOKE_KEY__")]
+  #[doc(hidden)]
+  pub invoke_key: Option<String>,
   /// The success callback.
   pub callback: CallbackFn,
   /// The error callback.

+ 49 - 0
core/tauri/src/lib.rs

@@ -1091,3 +1091,52 @@ mod test_utils {
     }
   }
 }
+
+/// Simple dependency-free string encoder using [Z85].
+mod z85 {
+  const TABLE: &[u8; 85] =
+    b"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-:+=^!/*?&<>()[]{}@%$#";
+
+  /// Encode bytes with [Z85].
+  ///
+  /// # Panics
+  ///
+  /// Will panic if the input bytes are not a multiple of 4.
+  pub fn encode(bytes: &[u8]) -> String {
+    assert_eq!(bytes.len() % 4, 0);
+
+    let mut buf = String::with_capacity(bytes.len() * 5 / 4);
+    for chunk in bytes.chunks_exact(4) {
+      let mut chars = [0u8; 5];
+      let mut chunk = u32::from_be_bytes(chunk.try_into().unwrap()) as usize;
+      for byte in chars.iter_mut().rev() {
+        *byte = TABLE[chunk % 85];
+        chunk /= 85;
+      }
+
+      buf.push_str(std::str::from_utf8(&chars).unwrap());
+    }
+
+    buf
+  }
+
+  #[cfg(test)]
+  mod tests {
+    #[test]
+    fn encode() {
+      assert_eq!(
+        super::encode(&[0x86, 0x4F, 0xD2, 0x6F, 0xB5, 0x59, 0xF7, 0x5B]),
+        "HelloWorld"
+      );
+    }
+  }
+}
+
+/// Generate a random 128-bit [Z85] encoded [`String`].
+///
+/// [Z85]: https://rfc.zeromq.org/spec/32/
+pub(crate) fn generate_invoke_key() -> Result<String> {
+  let mut bytes = [0u8; 16];
+  getrandom::getrandom(&mut bytes)?;
+  Ok(z85::encode(&bytes))
+}

+ 11 - 0
core/tauri/src/manager.rs

@@ -238,6 +238,8 @@ pub struct InnerWindowManager<R: Runtime> {
   invoke_initialization_script: String,
   /// Application pattern.
   pub(crate) pattern: Pattern,
+  /// A runtime generated key to ensure an IPC call comes from an initialized frame.
+  invoke_key: String,
 }
 
 impl<R: Runtime> fmt::Debug for InnerWindowManager<R> {
@@ -252,6 +254,7 @@ impl<R: Runtime> fmt::Debug for InnerWindowManager<R> {
       .field("package_info", &self.package_info)
       .field("menu", &self.menu)
       .field("pattern", &self.pattern)
+      .field("invoke_key", &self.invoke_key)
       .finish()
   }
 }
@@ -303,6 +306,7 @@ impl<R: Runtime> WindowManager<R> {
     window_event_listeners: Vec<GlobalWindowEventListener<R>>,
     (menu, menu_event_listeners): (Option<Menu>, Vec<GlobalMenuEventListener<R>>),
     (invoke_responder, invoke_initialization_script): (Arc<InvokeResponder<R>>, String),
+    invoke_key: String,
   ) -> Self {
     // generate a random isolation key at runtime
     #[cfg(feature = "isolation")]
@@ -333,6 +337,7 @@ impl<R: Runtime> WindowManager<R> {
         window_event_listeners: Arc::new(window_event_listeners),
         invoke_responder,
         invoke_initialization_script,
+        invoke_key,
       }),
     }
   }
@@ -449,6 +454,7 @@ impl<R: Runtime> WindowManager<R> {
         }
         _ => "".to_string(),
       },
+      invoke_key: self.invoke_key(),
     }
     .render_default(&Default::default())?;
 
@@ -896,6 +902,10 @@ impl<R: Runtime> WindowManager<R> {
       listeners = self.event_listeners_object_name()
     )
   }
+
+  pub(crate) fn invoke_key(&self) -> &str {
+    &self.inner.invoke_key
+  }
 }
 
 #[cfg(test)]
@@ -917,6 +927,7 @@ mod test {
       Default::default(),
       Default::default(),
       (std::sync::Arc::new(|_, _, _, _| ()), "".into()),
+      crate::generate_invoke_key().unwrap(),
     );
 
     #[cfg(custom_protocol)]

+ 34 - 19
core/tauri/src/scope/ipc.rs

@@ -171,6 +171,7 @@ impl Scope {
 #[cfg(test)]
 mod tests {
   use super::RemoteDomainAccessScope;
+  use crate::sealed::ManagerBase;
   use crate::{
     api::ipc::CallbackFn,
     test::{assert_ipc_response, mock_app, MockRuntime},
@@ -190,7 +191,7 @@ mod tests {
     (app, window)
   }
 
-  fn app_version_payload() -> InvokePayload {
+  fn app_version_payload(invoke_key: &str) -> InvokePayload {
     let callback = CallbackFn(0);
     let error = CallbackFn(1);
 
@@ -208,10 +209,11 @@ mod tests {
       callback,
       error,
       inner: serde_json::Value::Object(payload),
+      invoke_key: Some(invoke_key.into()),
     }
   }
 
-  fn plugin_test_payload() -> InvokePayload {
+  fn plugin_test_payload(invoke_key: &str) -> InvokePayload {
     let callback = CallbackFn(0);
     let error = CallbackFn(1);
 
@@ -221,19 +223,25 @@ mod tests {
       callback,
       error,
       inner: Default::default(),
+      invoke_key: Some(invoke_key.into()),
     }
   }
 
+  fn invoke_key(app: &App<MockRuntime>) -> &str {
+    app.manager().invoke_key()
+  }
+
   #[test]
   fn scope_not_defined() {
-    let (_app, mut window) = test_context(vec![RemoteDomainAccessScope::new("app.tauri.app")
+    let (app, mut window) = test_context(vec![RemoteDomainAccessScope::new("app.tauri.app")
       .add_window("other")
       .enable_tauri_api()]);
+    let invoke_key = invoke_key(&app);
 
     window.navigate("https://tauri.app".parse().unwrap());
     assert_ipc_response(
       &window,
-      app_version_payload(),
+      app_version_payload(invoke_key),
       Err(&crate::window::ipc_scope_not_found_error_message(
         "main",
         "https://tauri.app/",
@@ -243,28 +251,30 @@ mod tests {
 
   #[test]
   fn scope_not_defined_for_window() {
-    let (_app, mut window) = test_context(vec![RemoteDomainAccessScope::new("tauri.app")
+    let (app, mut window) = test_context(vec![RemoteDomainAccessScope::new("tauri.app")
       .add_window("second")
       .enable_tauri_api()]);
+    let invoke_key = invoke_key(&app);
 
     window.navigate("https://tauri.app".parse().unwrap());
     assert_ipc_response(
       &window,
-      app_version_payload(),
+      app_version_payload(invoke_key),
       Err(&crate::window::ipc_scope_window_error_message("main")),
     );
   }
 
   #[test]
   fn scope_not_defined_for_url() {
-    let (_app, mut window) = test_context(vec![RemoteDomainAccessScope::new("github.com")
+    let (app, mut window) = test_context(vec![RemoteDomainAccessScope::new("github.com")
       .add_window("main")
       .enable_tauri_api()]);
+    let invoke_key = invoke_key(&app);
 
     window.navigate("https://tauri.app".parse().unwrap());
     assert_ipc_response(
       &window,
-      app_version_payload(),
+      app_version_payload(invoke_key),
       Err(&crate::window::ipc_scope_domain_error_message(
         "https://tauri.app/",
       )),
@@ -281,18 +291,19 @@ mod tests {
         .add_window("main")
         .enable_tauri_api(),
     ]);
+    let invoke_key = invoke_key(&app);
 
     window.navigate("https://tauri.app".parse().unwrap());
     assert_ipc_response(
       &window,
-      app_version_payload(),
+      app_version_payload(invoke_key),
       Ok(app.package_info().version.to_string().as_str()),
     );
 
     window.navigate("https://blog.tauri.app".parse().unwrap());
     assert_ipc_response(
       &window,
-      app_version_payload(),
+      app_version_payload(invoke_key),
       Err(&crate::window::ipc_scope_domain_error_message(
         "https://blog.tauri.app/",
       )),
@@ -301,7 +312,7 @@ mod tests {
     window.navigate("https://sub.tauri.app".parse().unwrap());
     assert_ipc_response(
       &window,
-      app_version_payload(),
+      app_version_payload(invoke_key),
       Ok(app.package_info().version.to_string().as_str()),
     );
 
@@ -309,7 +320,7 @@ mod tests {
     window.navigate("https://dev.tauri.app".parse().unwrap());
     assert_ipc_response(
       &window,
-      app_version_payload(),
+      app_version_payload(invoke_key),
       Err(&crate::window::ipc_scope_not_found_error_message(
         "test",
         "https://dev.tauri.app/",
@@ -322,53 +333,57 @@ mod tests {
     let (app, mut window) = test_context(vec![RemoteDomainAccessScope::new("tauri.app")
       .add_window("main")
       .enable_tauri_api()]);
+    let invoke_key = invoke_key(&app);
 
     window.navigate("https://tauri.app/inner/path".parse().unwrap());
     assert_ipc_response(
       &window,
-      app_version_payload(),
+      app_version_payload(invoke_key),
       Ok(app.package_info().version.to_string().as_str()),
     );
   }
 
   #[test]
   fn tauri_api_not_allowed() {
-    let (_app, mut window) = test_context(vec![
+    let (app, mut window) = test_context(vec![
       RemoteDomainAccessScope::new("tauri.app").add_window("main")
     ]);
+    let invoke_key = invoke_key(&app);
 
     window.navigate("https://tauri.app".parse().unwrap());
     assert_ipc_response(
       &window,
-      app_version_payload(),
+      app_version_payload(invoke_key),
       Err(crate::window::IPC_SCOPE_DOES_NOT_ALLOW),
     );
   }
 
   #[test]
   fn plugin_allowed() {
-    let (_app, mut window) = test_context(vec![RemoteDomainAccessScope::new("tauri.app")
+    let (app, mut window) = test_context(vec![RemoteDomainAccessScope::new("tauri.app")
       .add_window("main")
       .add_plugin(PLUGIN_NAME)]);
+    let invoke_key = invoke_key(&app);
 
     window.navigate("https://tauri.app".parse().unwrap());
     assert_ipc_response(
       &window,
-      plugin_test_payload(),
+      plugin_test_payload(invoke_key),
       Err(&format!("plugin {PLUGIN_NAME} not found")),
     );
   }
 
   #[test]
   fn plugin_not_allowed() {
-    let (_app, mut window) = test_context(vec![
+    let (app, mut window) = test_context(vec![
       RemoteDomainAccessScope::new("tauri.app").add_window("main")
     ]);
+    let invoke_key = invoke_key(&app);
 
     window.navigate("https://tauri.app".parse().unwrap());
     assert_ipc_response(
       &window,
-      plugin_test_payload(),
+      plugin_test_payload(invoke_key),
       Err(crate::window::IPC_SCOPE_DOES_NOT_ALLOW),
     );
   }

+ 71 - 46
core/tauri/src/window.rs

@@ -31,8 +31,8 @@ use crate::{
   sealed::ManagerBase,
   sealed::RuntimeOrDispatch,
   utils::config::{WindowConfig, WindowUrl},
-  CursorIcon, EventLoopMessage, Icon, Invoke, InvokeError, InvokeMessage, InvokeResolver, Manager,
-  PageLoadPayload, Runtime, Theme, WindowEvent,
+  CursorIcon, Error, EventLoopMessage, Icon, Invoke, InvokeError, InvokeMessage, InvokeResolver,
+  Manager, Runtime, Theme, WindowEvent,
 };
 
 use serde::Serialize;
@@ -1550,9 +1550,35 @@ impl<R: Runtime> Window<R> {
     self.current_url = url;
   }
 
+  #[cfg_attr(feature = "tracing", tracing::instrument("window::on_message"))]
   /// Handles this window receiving an [`InvokeMessage`].
   pub fn on_message(self, payload: InvokePayload) -> crate::Result<()> {
     let manager = self.manager.clone();
+
+    // ensure the passed key matches what our manager should have injected
+    let expected = manager.invoke_key();
+    match payload.invoke_key.as_deref() {
+      Some(sent) if sent == expected => { /* good */ }
+      Some(sent) => {
+        #[cfg(feature = "tracing")]
+        tracing::error!("__TAURI_INVOKE_KEY__ expected {expected} but received {sent}");
+
+        #[cfg(not(feature = "tracing"))]
+        eprintln!("__TAURI_INVOKE_KEY__ expected {expected} but received {sent}");
+
+        return Err(Error::InvokeKey);
+      }
+      None => {
+        #[cfg(feature = "tracing")]
+        tracing::error!("received ipc message without a __TAURI_INVOKE_KEY__");
+
+        #[cfg(not(feature = "tracing"))]
+        eprintln!("received ipc message without a __TAURI_INVOKE_KEY__");
+
+        return Err(Error::InvokeKey);
+      }
+    }
+
     let current_url = self.url();
     let config_url = manager.get_url();
     let is_local = config_url.make_relative(&current_url).is_some();
@@ -1574,54 +1600,53 @@ impl<R: Runtime> Window<R> {
         }
       }
     };
-    match payload.cmd.as_str() {
-      "__initialized" => {
-        let payload: PageLoadPayload = serde_json::from_value(payload.inner)?;
-        manager.run_on_page_load(self, payload);
+
+    if "__initialized" == &payload.cmd {
+      let payload = serde_json::from_value(payload.inner)?;
+      manager.run_on_page_load(self, payload);
+      return Ok(());
+    }
+
+    let message = InvokeMessage::new(
+      self.clone(),
+      manager.state(),
+      payload.cmd.to_string(),
+      payload.inner,
+    );
+    let resolver = InvokeResolver::new(self, payload.callback, payload.error);
+    let invoke = Invoke { message, resolver };
+
+    if !is_local && scope.is_none() {
+      invoke.resolver.reject(scope_not_found_error_message);
+      return Ok(());
+    }
+
+    if let Some(module) = &payload.tauri_module {
+      if !is_local && scope.map(|s| !s.enables_tauri_api()).unwrap_or_default() {
+        invoke.resolver.reject(IPC_SCOPE_DOES_NOT_ALLOW);
+        return Ok(());
       }
-      _ => {
-        let message = InvokeMessage::new(
-          self.clone(),
-          manager.state(),
-          payload.cmd.to_string(),
-          payload.inner,
-        );
-        let resolver = InvokeResolver::new(self, payload.callback, payload.error);
-        let invoke = Invoke { message, resolver };
-
-        if !is_local && scope.is_none() {
-          invoke.resolver.reject(scope_not_found_error_message);
+      crate::endpoints::handle(
+        module.to_string(),
+        invoke,
+        manager.config(),
+        manager.package_info(),
+      );
+    } else if payload.cmd.starts_with("plugin:") {
+      if !is_local {
+        let command = invoke.message.command.replace("plugin:", "");
+        let plugin_name = command.split('|').next().unwrap().to_string();
+        if !scope
+          .map(|s| s.plugins().contains(&plugin_name))
+          .unwrap_or(true)
+        {
+          invoke.resolver.reject(IPC_SCOPE_DOES_NOT_ALLOW);
           return Ok(());
         }
-
-        if let Some(module) = &payload.tauri_module {
-          if !is_local && scope.map(|s| !s.enables_tauri_api()).unwrap_or_default() {
-            invoke.resolver.reject(IPC_SCOPE_DOES_NOT_ALLOW);
-            return Ok(());
-          }
-          crate::endpoints::handle(
-            module.to_string(),
-            invoke,
-            manager.config(),
-            manager.package_info(),
-          );
-        } else if payload.cmd.starts_with("plugin:") {
-          if !is_local {
-            let command = invoke.message.command.replace("plugin:", "");
-            let plugin_name = command.split('|').next().unwrap().to_string();
-            if !scope
-              .map(|s| s.plugins().contains(&plugin_name))
-              .unwrap_or(true)
-            {
-              invoke.resolver.reject(IPC_SCOPE_DOES_NOT_ALLOW);
-              return Ok(());
-            }
-          }
-          manager.extend_api(invoke);
-        } else {
-          manager.run_invoke_handler(invoke);
-        }
       }
+      manager.extend_api(invoke);
+    } else {
+      manager.run_invoke_handler(invoke);
     }
 
     Ok(())

+ 20 - 13
examples/api/src-tauri/Cargo.lock

@@ -1806,6 +1806,12 @@ version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
 
+[[package]]
+name = "heck"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
+
 [[package]]
 name = "hermit-abi"
 version = "0.1.19"
@@ -4018,7 +4024,7 @@ checksum = "69758bda2e78f098e4ccb393021a0963bb3442eac05f135c30f61b7370bbafae"
 
 [[package]]
 name = "tauri"
-version = "1.6.0"
+version = "1.6.6"
 dependencies = [
  "anyhow",
  "base64 0.21.7",
@@ -4031,10 +4037,11 @@ dependencies = [
  "encoding_rs",
  "flate2",
  "futures-util",
+ "getrandom 0.2.12",
  "glib",
  "glob",
  "gtk",
- "heck 0.4.1",
+ "heck 0.5.0",
  "http",
  "ico 0.2.0",
  "ignore",
@@ -4083,12 +4090,12 @@ dependencies = [
 
 [[package]]
 name = "tauri-build"
-version = "1.5.1"
+version = "1.5.2"
 dependencies = [
  "anyhow",
  "cargo_toml",
  "dirs-next",
- "heck 0.4.1",
+ "heck 0.5.0",
  "json-patch",
  "quote",
  "semver",
@@ -4102,7 +4109,7 @@ dependencies = [
 
 [[package]]
 name = "tauri-codegen"
-version = "1.4.2"
+version = "1.4.3"
 dependencies = [
  "base64 0.21.7",
  "brotli",
@@ -4126,9 +4133,9 @@ dependencies = [
 
 [[package]]
 name = "tauri-macros"
-version = "1.4.3"
+version = "1.4.4"
 dependencies = [
- "heck 0.4.1",
+ "heck 0.5.0",
  "proc-macro2",
  "quote",
  "syn 1.0.109",
@@ -4138,7 +4145,7 @@ dependencies = [
 
 [[package]]
 name = "tauri-runtime"
-version = "0.14.2"
+version = "0.14.3"
 dependencies = [
  "gtk",
  "http",
@@ -4157,7 +4164,7 @@ dependencies = [
 
 [[package]]
 name = "tauri-runtime-wry"
-version = "0.14.4"
+version = "0.14.7"
 dependencies = [
  "arboard",
  "cocoa 0.24.1",
@@ -4176,7 +4183,7 @@ dependencies = [
 
 [[package]]
 name = "tauri-utils"
-version = "1.5.3"
+version = "1.5.4"
 dependencies = [
  "aes-gcm",
  "brotli",
@@ -4184,7 +4191,7 @@ dependencies = [
  "dunce",
  "getrandom 0.2.12",
  "glob",
- "heck 0.4.1",
+ "heck 0.5.0",
  "html5ever",
  "infer 0.13.0",
  "json-patch",
@@ -5494,9 +5501,9 @@ dependencies = [
 
 [[package]]
 name = "wry"
-version = "0.24.7"
+version = "0.24.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ad85d0e067359e409fcb88903c3eac817c392e5d638258abfb3da5ad8ba6fc4"
+checksum = "00711278ed357350d44c749c286786ecac644e044e4da410d466212152383b45"
 dependencies = [
  "base64 0.13.1",
  "block",