From 51d043209b8aca8ceda2d51e2f92574a6c5b58f8 Mon Sep 17 00:00:00 2001 From: chip Date: Tue, 23 Jul 2024 11:23:29 +0900 Subject: [PATCH] integration tests related to recent security advisory (#9983) * test if an uninitialized iframe can call the ipc * test that calls without __TAURI_INVOKE_KEY__ fail * fix cargo manifest newline change * add comment to help unknown error message changes * license headers * add identifier and icons to config * fix clippy error * Create change-pr-9983.md * add tag to changefile * rename changefile --- .changes/ipc-invoke-key-integration-tests.md | 6 +++ Cargo.lock | 17 +++++++ Cargo.toml | 2 + core/tauri/src/window.rs | 8 +++- core/tests/invoke-key/Cargo.toml | 15 ++++++ core/tests/invoke-key/build.rs | 7 +++ core/tests/invoke-key/index.html | 7 +++ core/tests/invoke-key/src/main.rs | 24 ++++++++++ core/tests/invoke-key/src/subscriber.rs | 48 ++++++++++++++++++++ core/tests/invoke-key/tauri.conf.json | 22 +++++++++ core/tests/uninitialized-ipc/Cargo.toml | 14 ++++++ core/tests/uninitialized-ipc/build.rs | 7 +++ core/tests/uninitialized-ipc/iframe.html | 3 ++ core/tests/uninitialized-ipc/index.html | 17 +++++++ core/tests/uninitialized-ipc/src/main.rs | 24 ++++++++++ core/tests/uninitialized-ipc/tauri.conf.json | 22 +++++++++ 16 files changed, 241 insertions(+), 2 deletions(-) create mode 100644 .changes/ipc-invoke-key-integration-tests.md create mode 100644 core/tests/invoke-key/Cargo.toml create mode 100644 core/tests/invoke-key/build.rs create mode 100644 core/tests/invoke-key/index.html create mode 100644 core/tests/invoke-key/src/main.rs create mode 100644 core/tests/invoke-key/src/subscriber.rs create mode 100644 core/tests/invoke-key/tauri.conf.json create mode 100644 core/tests/uninitialized-ipc/Cargo.toml create mode 100644 core/tests/uninitialized-ipc/build.rs create mode 100644 core/tests/uninitialized-ipc/iframe.html create mode 100644 core/tests/uninitialized-ipc/index.html create mode 100644 core/tests/uninitialized-ipc/src/main.rs create mode 100644 core/tests/uninitialized-ipc/tauri.conf.json diff --git a/.changes/ipc-invoke-key-integration-tests.md b/.changes/ipc-invoke-key-integration-tests.md new file mode 100644 index 000000000000..79320f13038f --- /dev/null +++ b/.changes/ipc-invoke-key-integration-tests.md @@ -0,0 +1,6 @@ +--- +"tauri": patch:enhance +--- + +tracing for ipc invoke key errors, integration tests related +to [recent security advisory](https://github.com/tauri-apps/tauri/security/advisories/GHSA-57fm-592m-34r7) diff --git a/Cargo.lock b/Cargo.lock index 716a3532547b..0cfbe2b05a57 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1921,6 +1921,15 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "invoke-key" +version = "0.1.0" +dependencies = [ + "tauri", + "tauri-build", + "tracing", +] + [[package]] name = "io-lifetimes" version = "1.0.11" @@ -4670,6 +4679,14 @@ version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +[[package]] +name = "uninitialized-ipc" +version = "0.1.0" +dependencies = [ + "tauri", + "tauri-build", +] + [[package]] name = "universal-hash" version = "0.5.1" diff --git a/Cargo.toml b/Cargo.toml index 356d8c6c9172..9b4468875fcf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,8 @@ members = [ # integration tests "core/tests/restart", "core/tests/app-updater", + "core/tests/uninitialized-ipc", + "core/tests/invoke-key" ] exclude = [ diff --git a/core/tauri/src/window.rs b/core/tauri/src/window.rs index 87888b93eb62..5492d1e165c1 100644 --- a/core/tauri/src/window.rs +++ b/core/tauri/src/window.rs @@ -1569,11 +1569,15 @@ impl Window { return Err(Error::InvokeKey); } None => { + // this specific string is tested against in `core/tests/invoke-key`. + // if this error changes then that integration test should be updated accordingly. + let error = "received ipc message without a __TAURI_INVOKE_KEY__"; + #[cfg(feature = "tracing")] - tracing::error!("received ipc message without a __TAURI_INVOKE_KEY__"); + tracing::error!(error); #[cfg(not(feature = "tracing"))] - eprintln!("received ipc message without a __TAURI_INVOKE_KEY__"); + eprintln!("{error}"); return Err(Error::InvokeKey); } diff --git a/core/tests/invoke-key/Cargo.toml b/core/tests/invoke-key/Cargo.toml new file mode 100644 index 000000000000..02fa0c2259a6 --- /dev/null +++ b/core/tests/invoke-key/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "invoke-key" +version = "0.1.0" +edition = "2021" + +[build-dependencies] +tauri-build = { path = "../../tauri-build", features = [] } + +[dependencies] +tauri = { path = "../../tauri", features = ["tracing"] } +tracing = "0.1" + +[features] +default = ["custom-protocol"] +custom-protocol = ["tauri/custom-protocol"] diff --git a/core/tests/invoke-key/build.rs b/core/tests/invoke-key/build.rs new file mode 100644 index 000000000000..b055ec37c771 --- /dev/null +++ b/core/tests/invoke-key/build.rs @@ -0,0 +1,7 @@ +// Copyright 2019-2023 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +fn main() { + tauri_build::build() +} diff --git a/core/tests/invoke-key/index.html b/core/tests/invoke-key/index.html new file mode 100644 index 000000000000..edb8928c8258 --- /dev/null +++ b/core/tests/invoke-key/index.html @@ -0,0 +1,7 @@ + diff --git a/core/tests/invoke-key/src/main.rs b/core/tests/invoke-key/src/main.rs new file mode 100644 index 000000000000..dbb27a674dd2 --- /dev/null +++ b/core/tests/invoke-key/src/main.rs @@ -0,0 +1,24 @@ +// Copyright 2019-2023 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] + +use tauri::{command, generate_context, generate_handler, Builder}; + +mod subscriber; + +#[command] +fn error_if_called() { + std::process::exit(1) +} + +fn main() { + tracing::subscriber::set_global_default(subscriber::InvokeKeyErrorSubscriber) + .expect("unable to set tracing global subscriber"); + + Builder::default() + .invoke_handler(generate_handler![error_if_called]) + .run(generate_context!()) + .expect("error while running tauri application"); +} diff --git a/core/tests/invoke-key/src/subscriber.rs b/core/tests/invoke-key/src/subscriber.rs new file mode 100644 index 000000000000..465783b56db7 --- /dev/null +++ b/core/tests/invoke-key/src/subscriber.rs @@ -0,0 +1,48 @@ +// Copyright 2019-2023 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use std::fmt::Debug; + +use tracing::{ + field::{Field, Visit}, + span::{Attributes, Record}, + Event, Id, Level, Metadata, Subscriber, +}; + +pub struct InvokeKeyErrorSubscriber; + +impl Subscriber for InvokeKeyErrorSubscriber { + fn enabled(&self, metadata: &Metadata<'_>) -> bool { + metadata.is_event() && *metadata.level() == Level::ERROR + } + + fn new_span(&self, _: &Attributes<'_>) -> Id { + // shouldn't be called because we only enable events + unimplemented!() + } + + fn record(&self, _: &Id, _: &Record<'_>) {} + + fn record_follows_from(&self, _: &Id, _: &Id) {} + + fn event(&self, event: &Event<'_>) { + event.record(&mut InvokeKeyExitVisit) + } + + fn enter(&self, _: &Id) {} + + fn exit(&self, _: &Id) {} +} + +struct InvokeKeyExitVisit; + +impl Visit for InvokeKeyExitVisit { + fn record_str(&mut self, field: &Field, value: &str) { + if field.name() == "error" && value == "received ipc message without a __TAURI_INVOKE_KEY__" { + std::process::exit(0) + } + } + + fn record_debug(&mut self, _: &Field, _: &dyn Debug) {} +} diff --git a/core/tests/invoke-key/tauri.conf.json b/core/tests/invoke-key/tauri.conf.json new file mode 100644 index 000000000000..78d57dd2330c --- /dev/null +++ b/core/tests/invoke-key/tauri.conf.json @@ -0,0 +1,22 @@ +{ + "$schema": "../../../core/tauri-config-schema/schema.json", + "build": { + "distDir": "index.html", + "devPath": "index.html" + }, + "tauri": { + "bundle": { + "identifier": "app.tauri.tests.invoke-key", + "icon": [ + "../../../examples/.icons/32x32.png", + "../../../examples/.icons/128x128.png", + "../../../examples/.icons/128x128@2x.png", + "../../../examples/.icons/icon.icns", + "../../../examples/.icons/icon.ico" + ] + }, + "windows": [ + {} + ] + } +} diff --git a/core/tests/uninitialized-ipc/Cargo.toml b/core/tests/uninitialized-ipc/Cargo.toml new file mode 100644 index 000000000000..9258b576c838 --- /dev/null +++ b/core/tests/uninitialized-ipc/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "uninitialized-ipc" +version = "0.1.0" +edition = "2021" + +[build-dependencies] +tauri-build = { path = "../../tauri-build", features = [] } + +[dependencies] +tauri = { path = "../../tauri", features = [] } + +[features] +default = ["custom-protocol"] +custom-protocol = ["tauri/custom-protocol"] diff --git a/core/tests/uninitialized-ipc/build.rs b/core/tests/uninitialized-ipc/build.rs new file mode 100644 index 000000000000..b055ec37c771 --- /dev/null +++ b/core/tests/uninitialized-ipc/build.rs @@ -0,0 +1,7 @@ +// Copyright 2019-2023 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +fn main() { + tauri_build::build() +} diff --git a/core/tests/uninitialized-ipc/iframe.html b/core/tests/uninitialized-ipc/iframe.html new file mode 100644 index 000000000000..b915a5b7dca7 --- /dev/null +++ b/core/tests/uninitialized-ipc/iframe.html @@ -0,0 +1,3 @@ + diff --git a/core/tests/uninitialized-ipc/index.html b/core/tests/uninitialized-ipc/index.html new file mode 100644 index 000000000000..e0c3f013ddaa --- /dev/null +++ b/core/tests/uninitialized-ipc/index.html @@ -0,0 +1,17 @@ + + diff --git a/core/tests/uninitialized-ipc/src/main.rs b/core/tests/uninitialized-ipc/src/main.rs new file mode 100644 index 000000000000..b0f581045234 --- /dev/null +++ b/core/tests/uninitialized-ipc/src/main.rs @@ -0,0 +1,24 @@ +// Copyright 2019-2023 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] + +use tauri::{command, generate_context, generate_handler, http::Response, Builder}; + +const IFRAME: &[u8] = include_bytes!("../iframe.html"); + +#[command] +fn exit(code: i32) { + std::process::exit(code) +} + +fn main() { + Builder::default() + .invoke_handler(generate_handler![exit]) + .register_uri_scheme_protocol("uninitialized", |_app, _request| { + Ok(Response::new(IFRAME.into())) + }) + .run(generate_context!()) + .expect("error while running tauri application"); +} diff --git a/core/tests/uninitialized-ipc/tauri.conf.json b/core/tests/uninitialized-ipc/tauri.conf.json new file mode 100644 index 000000000000..367fbc86c6de --- /dev/null +++ b/core/tests/uninitialized-ipc/tauri.conf.json @@ -0,0 +1,22 @@ +{ + "$schema": "../../../core/tauri-config-schema/schema.json", + "build": { + "distDir": "index.html", + "devPath": "index.html" + }, + "tauri": { + "bundle": { + "identifier": "app.tauri.tests.uninitialized-ipc", + "icon": [ + "../../../examples/.icons/32x32.png", + "../../../examples/.icons/128x128.png", + "../../../examples/.icons/128x128@2x.png", + "../../../examples/.icons/icon.icns", + "../../../examples/.icons/icon.ico" + ] + }, + "windows": [ + {} + ] + } +}