Browse Source

fix(core): IPC remote domain check bypassed by isolation iframe usage (#6691)

Lucas Fernandes Nogueira 2 years ago
parent
commit
40f137c214
4 changed files with 35 additions and 25 deletions
  1. 1 1
      core/tauri/src/app.rs
  2. 11 0
      core/tauri/src/manager.rs
  3. 21 1
      core/tauri/src/pattern.rs
  4. 2 23
      core/tauri/src/scope/ipc.rs

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

@@ -1627,7 +1627,7 @@ impl<R: Runtime> Builder<R> {
 
     let env = Env::default();
     app.manage(Scopes {
-      ipc: IpcScope::new(&app.config(), &app.manager),
+      ipc: IpcScope::new(&app.config()),
       fs: FsScope::for_fs_api(
         &app.manager.config(),
         app.package_info(),

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

@@ -1218,9 +1218,20 @@ impl<R: Runtime> WindowManager<R> {
       }
     }
 
+    #[cfg(feature = "isolation")]
+    let pattern = self.pattern().clone();
     let current_url_ = pending.current_url.clone();
     let navigation_handler = pending.navigation_handler.take();
     pending.navigation_handler = Some(Box::new(move |url| {
+      // always allow navigation events for the isolation iframe and do not emit them for consumers
+      #[cfg(feature = "isolation")]
+      if let Pattern::Isolation { schema, .. } = &pattern {
+        if url.scheme() == schema
+          && url.domain() == Some(crate::pattern::ISOLATION_IFRAME_SRC_DOMAIN)
+        {
+          return true;
+        }
+      }
       *current_url_.lock().unwrap() = url.clone();
       if let Some(handler) = &navigation_handler {
         handler(url)

+ 21 - 1
core/tauri/src/pattern.rs

@@ -15,7 +15,7 @@ use tauri_utils::assets::{Assets, EmbeddedAssets};
 pub const ISOLATION_IFRAME_SRC_DOMAIN: &str = "localhost";
 
 /// An application pattern.
-#[derive(Debug, Clone)]
+#[derive(Debug)]
 pub enum Pattern<A: Assets = EmbeddedAssets> {
   /// The brownfield pattern.
   Brownfield(PhantomData<A>),
@@ -38,6 +38,26 @@ pub enum Pattern<A: Assets = EmbeddedAssets> {
   },
 }
 
+impl<A: Assets> Clone for Pattern<A> {
+  fn clone(&self) -> Self {
+    match self {
+      Self::Brownfield(a) => Self::Brownfield(*a),
+      #[cfg(feature = "isolation")]
+      Self::Isolation {
+        assets,
+        schema,
+        key,
+        crypto_keys,
+      } => Self::Isolation {
+        assets: assets.clone(),
+        schema: schema.clone(),
+        key: key.clone(),
+        crypto_keys: crypto_keys.clone(),
+      },
+    }
+  }
+}
+
 /// The shape of the JavaScript Pattern config
 #[derive(Debug, Serialize)]
 #[serde(rename_all = "lowercase", tag = "pattern")]

+ 2 - 23
core/tauri/src/scope/ipc.rs

@@ -4,9 +4,7 @@
 
 use std::sync::{Arc, Mutex};
 
-use crate::{manager::WindowManager, Config, Runtime, Window};
-#[cfg(feature = "isolation")]
-use crate::{pattern::ISOLATION_IFRAME_SRC_DOMAIN, sealed::ManagerBase, Pattern};
+use crate::{Config, Runtime, Window};
 use url::Url;
 
 /// IPC access configuration for a remote domain.
@@ -88,8 +86,7 @@ pub struct Scope {
 }
 
 impl Scope {
-  #[allow(unused_variables)]
-  pub(crate) fn new<R: Runtime>(config: &Config, manager: &WindowManager<R>) -> Self {
+  pub(crate) fn new(config: &Config) -> Self {
     #[allow(unused_mut)]
     let mut remote_access: Vec<RemoteDomainAccessScope> = config
       .tauri
@@ -106,17 +103,6 @@ impl Scope {
       })
       .collect();
 
-    #[cfg(feature = "isolation")]
-    if let Pattern::Isolation { schema, .. } = &manager.inner.pattern {
-      remote_access.push(RemoteDomainAccessScope {
-        scheme: Some(schema.clone()),
-        domain: ISOLATION_IFRAME_SRC_DOMAIN.into(),
-        windows: Vec::new(),
-        plugins: Vec::new(),
-        enable_tauri_api: true,
-      });
-    }
-
     Self {
       remote_access: Arc::new(Mutex::new(remote_access)),
     }
@@ -155,13 +141,6 @@ impl Scope {
     for s in &*self.remote_access.lock().unwrap() {
       #[allow(unused_mut)]
       let mut matches_window = s.windows.contains(&label);
-      // the isolation iframe is always able to access the IPC
-      #[cfg(feature = "isolation")]
-      if let Pattern::Isolation { schema, .. } = &window.manager().inner.pattern {
-        if schema == url.scheme() && url.domain() == Some(ISOLATION_IFRAME_SRC_DOMAIN) {
-          matches_window = true;
-        }
-      }
 
       let matches_scheme = s
         .scheme