Isolation Pattern (#43)

Co-authored-by: Ngo Iok Ui (Wu Yu Wei) <wusyong9104@gmail.com>
Co-authored-by: Lucas Fernandes Nogueira <lucas@tauri.studio>
This commit is contained in:
chip 2022-01-17 10:46:14 -03:00 committed by Lucas Nogueira
parent c077f44927
commit d5d6d2abc1
No known key found for this signature in database
GPG Key ID: 2714B66BCFB01F7F
110 changed files with 6116 additions and 857 deletions

View File

@ -0,0 +1,7 @@
---
"tauri": patch
"tauri-utils": patch
"tauri-codegen": patch
---
Added the `isolation` pattern.

5
.changes/rust-1.57.md Normal file
View File

@ -0,0 +1,5 @@
---
"tauri": patch
---
The minimum Rust version is now 1.57.

View File

@ -14,7 +14,8 @@ exclude = [
"examples/api/src-tauri",
"examples/updater/src-tauri",
"examples/resources/src-tauri",
"examples/sidecar/src-tauri"
"examples/sidecar/src-tauri",
"examples/isolation/src-tauri"
]
# default to small, optimized workspace release binaries

View File

@ -8,7 +8,7 @@ homepage = "https://tauri.studio"
repository = "https://github.com/tauri-apps/tauri/tree/dev/core/tauri-build"
description = "build time code to pair with https://crates.io/crates/tauri"
edition = "2021"
rust-version = "1.56"
rust-version = "1.57"
exclude = [ ".license_template", "CHANGELOG.md", "/target" ]
readme = "README.md"
@ -29,3 +29,4 @@ winres = "0.1"
[features]
codegen = [ "tauri-codegen", "quote" ]
isolation = ["tauri-codegen/isolation", "tauri-utils/isolation"]

View File

@ -42,6 +42,7 @@ impl CodegenContext {
/// This defaults to a file called `tauri.conf.json` inside of the current working directory of
/// the package compiling; does not need to be set manually if that config file is in the same
/// directory as your `Cargo.toml`.
#[must_use]
pub fn config_path(mut self, config_path: impl Into<PathBuf>) -> Self {
self.config_path = config_path.into();
self
@ -58,6 +59,7 @@ impl CodegenContext {
/// Defaults to `tauri-build-context.rs`.
///
/// [`tauri::include_codegen_context!`]: https://docs.rs/tauri/0.12/tauri/macro.include_codegen_context.html
#[must_use]
pub fn out_file(mut self, filename: PathBuf) -> Self {
self.out_file = filename;
self
@ -65,6 +67,7 @@ impl CodegenContext {
/// Run the codegen in a `dev` context, meaning that Tauri is using a dev server or local file for development purposes,
/// usually with the `tauri dev` CLI command.
#[must_use]
pub fn dev(mut self) -> Self {
self.dev = true;
self

View File

@ -43,6 +43,7 @@ impl WindowsAttributes {
/// Sets the icon to use on the window. Currently only used on Windows.
/// It must be in `ico` format. Defaults to `icons/icon.ico`.
#[must_use]
pub fn window_icon_path<P: AsRef<Path>>(mut self, window_icon_path: P) -> Self {
self.window_icon_path = window_icon_path.as_ref().into();
self
@ -50,6 +51,7 @@ impl WindowsAttributes {
/// Sets the sdk dir for windows. Currently only used on Windows. This must be a vaild UTF-8
/// path. Defaults to whatever the `winres` crate determines is best.
#[must_use]
pub fn sdk_dir<P: AsRef<Path>>(mut self, sdk_dir: P) -> Self {
self.sdk_dir = Some(sdk_dir.as_ref().into());
self
@ -70,6 +72,7 @@ impl Attributes {
}
/// Sets the icon to use on the window. Currently only used on Windows.
#[must_use]
pub fn windows_attributes(mut self, windows_attributes: WindowsAttributes) -> Self {
self.windows_attributes = windows_attributes;
self

View File

@ -8,7 +8,7 @@ homepage = "https://tauri.studio"
repository = "https://github.com/tauri-apps/tauri/tree/dev/core/tauri-codegen"
description = "code generation meant to be consumed inside of `tauri` through `tauri-build` or `tauri-macros`"
edition = "2021"
rust-version = "1.56"
rust-version = "1.57"
exclude = [ ".license_template", "CHANGELOG.md", "/target" ]
readme = "README.md"
@ -25,7 +25,9 @@ thiserror = "1"
walkdir = "2"
zstd = { version = "0.9", optional = true }
regex = "1"
uuid = { version = "0.8", features = [ "v4" ] }
[features]
default = [ "compression" ]
compression = [ "zstd", "tauri-utils/compression" ]
isolation = ["tauri-utils/isolation"]

View File

@ -2,11 +2,18 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
use crate::embedded_assets::{AssetOptions, EmbeddedAssets, EmbeddedAssetsError};
use std::ffi::OsStr;
use std::path::{Path, PathBuf};
use proc_macro2::TokenStream;
use quote::quote;
use std::path::{Path, PathBuf};
use tauri_utils::config::{AppUrl, Config, WindowUrl};
use sha2::{Digest, Sha256};
use tauri_utils::assets::AssetKey;
use tauri_utils::config::{AppUrl, Config, PatternKind, WindowUrl};
use tauri_utils::html::{inject_nonce_token, parse as parse_html, NodeRef, PatternObject};
use crate::embedded_assets::{AssetOptions, CspHashes, EmbeddedAssets, EmbeddedAssetsError};
/// Necessary data needed by [`context_codegen`] to generate code for a Tauri application context.
pub struct ContextData {
@ -16,6 +23,81 @@ pub struct ContextData {
pub root: TokenStream,
}
fn load_csp(document: &mut NodeRef, key: &AssetKey, csp_hashes: &mut CspHashes) {
#[cfg(target_os = "linux")]
::tauri_utils::html::inject_csp_token(document);
inject_nonce_token(document);
if let Ok(inline_script_elements) = document.select("script:not(empty)") {
let mut scripts = Vec::new();
for inline_script_el in inline_script_elements {
let script = inline_script_el.as_node().text_contents();
let mut hasher = Sha256::new();
hasher.update(&script);
let hash = hasher.finalize();
scripts.push(format!("'sha256-{}'", base64::encode(&hash)));
}
csp_hashes
.inline_scripts
.entry(key.clone().into())
.or_default()
.append(&mut scripts);
}
}
fn map_core_assets(
options: &AssetOptions,
) -> impl Fn(&AssetKey, &Path, &mut Vec<u8>, &mut CspHashes) -> Result<(), EmbeddedAssetsError> {
#[allow(unused_variables)]
let pattern = PatternObject::from(&options.pattern);
let csp = options.csp;
move |key, path, input, csp_hashes| {
if path.extension() == Some(OsStr::new("html")) {
let mut document = parse_html(String::from_utf8_lossy(input).into_owned());
if csp {
load_csp(&mut document, key, csp_hashes);
#[cfg(feature = "isolation")]
if let PatternObject::Isolation { .. } = &pattern {
// create the csp for the isolation iframe styling now, to make the runtime less complex
let mut hasher = Sha256::new();
hasher.update(tauri_utils::pattern::isolation::IFRAME_STYLE);
let hash = hasher.finalize();
csp_hashes
.styles
.push(format!("'sha256-{}'", base64::encode(&hash)));
}
}
*input = document.to_string().as_bytes().to_vec();
}
Ok(())
}
}
#[cfg(feature = "isolation")]
fn map_isolation(
_options: &AssetOptions,
dir: PathBuf,
) -> impl Fn(&AssetKey, &Path, &mut Vec<u8>, &mut CspHashes) -> Result<(), EmbeddedAssetsError> {
move |_key, path, input, _csp_hashes| {
if path.extension() == Some(OsStr::new("html")) {
let mut isolation_html =
tauri_utils::html::parse(String::from_utf8_lossy(input).into_owned());
// this is appended, so no need to reverse order it
tauri_utils::html::inject_codegen_isolation_script(&mut isolation_html);
// temporary workaround for windows not loading assets
tauri_utils::html::inline_isolation(&mut isolation_html, &dir);
*input = isolation_html.to_string().as_bytes().to_vec()
}
Ok(())
}
}
/// Build a `tauri::Context` for including in application code.
pub fn context_codegen(data: ContextData) -> Result<TokenStream, EmbeddedAssetsError> {
let ContextData {
@ -25,7 +107,8 @@ pub fn context_codegen(data: ContextData) -> Result<TokenStream, EmbeddedAssetsE
root,
} = data;
let mut options = AssetOptions::new();
let mut options = AssetOptions::new(config.tauri.pattern.clone())
.freeze_prototype(config.tauri.security.freeze_prototype);
let csp = if dev {
config
.tauri
@ -64,7 +147,7 @@ pub fn context_codegen(data: ContextData) -> Result<TokenStream, EmbeddedAssetsE
path
)
}
EmbeddedAssets::new(assets_path, options)?
EmbeddedAssets::new(assets_path, map_core_assets(&options))?
}
_ => unimplemented!(),
},
@ -73,7 +156,7 @@ pub fn context_codegen(data: ContextData) -> Result<TokenStream, EmbeddedAssetsE
.iter()
.map(|p| config_parent.join(p))
.collect::<Vec<_>>(),
options,
map_core_assets(&options),
)?,
_ => unimplemented!(),
};
@ -180,7 +263,31 @@ pub fn context_codegen(data: ContextData) -> Result<TokenStream, EmbeddedAssetsE
#[cfg(not(target_os = "macos"))]
let info_plist = quote!(());
// double braces are purposeful to force the code into a block expression
let pattern = match &options.pattern {
PatternKind::Brownfield => quote!(#root::Pattern::Brownfield(std::marker::PhantomData)),
#[cfg(feature = "isolation")]
PatternKind::Isolation { dir } => {
let dir = config_parent.join(dir);
if !dir.exists() {
panic!(
"The isolation dir configuration is set to `{:?}` but this path doesn't exist",
dir
)
}
let key = uuid::Uuid::new_v4().to_string();
let assets = EmbeddedAssets::new(dir.clone(), map_isolation(&options, dir))?;
let schema = options.isolation_schema;
quote!(#root::Pattern::Isolation {
assets: ::std::sync::Arc::new(#assets),
schema: #schema.into(),
key: #key.into(),
crypto_keys: std::boxed::Box::new(::tauri::utils::pattern::isolation::Keys::new().expect("unable to generate cryptographically secure keys for Tauri \"Isolation\" Pattern")),
})
}
};
Ok(quote!(#root::Context::new(
#config,
::std::sync::Arc::new(#assets),
@ -188,6 +295,7 @@ pub fn context_codegen(data: ContextData) -> Result<TokenStream, EmbeddedAssetsE
#system_tray_icon,
#package_info,
#info_plist,
#pattern
)))
}

View File

@ -4,18 +4,14 @@
use proc_macro2::TokenStream;
use quote::{quote, ToTokens, TokenStreamExt};
use regex::RegexSet;
use sha2::{Digest, Sha256};
use std::{
collections::HashMap,
ffi::OsStr,
fs::File,
path::{Path, PathBuf},
};
use tauri_utils::{
assets::AssetKey,
html::{inject_invoke_key_token, inject_nonce_token, parse as parse_html},
};
use tauri_utils::assets::AssetKey;
use tauri_utils::config::PatternKind;
use thiserror::Error;
use walkdir::{DirEntry, WalkDir};
@ -143,12 +139,14 @@ impl RawEmbeddedAssets {
}
/// Holds all hashes that we will apply on the CSP tag/header.
#[derive(Default)]
struct CspHashes {
#[derive(Debug, Default)]
pub struct CspHashes {
/// Scripts that are part of the asset collection (JS or MJS files).
scripts: Vec<String>,
pub(crate) scripts: Vec<String>,
/// Inline scripts (`<script>code</script>`). Maps a HTML path to a list of hashes.
inline_scripts: HashMap<String, Vec<String>>,
pub(crate) inline_scripts: HashMap<String, Vec<String>>,
/// A list of hashes of the contents of all `style` elements.
pub(crate) styles: Vec<String>,
}
impl CspHashes {
@ -181,20 +179,38 @@ impl CspHashes {
/// Options used to embed assets.
#[derive(Default)]
pub struct AssetOptions {
csp: bool,
pub(crate) csp: bool,
pub(crate) pattern: PatternKind,
pub(crate) freeze_prototype: bool,
#[cfg(feature = "isolation")]
pub(crate) isolation_schema: String,
}
impl AssetOptions {
/// Creates the default asset options.
pub fn new() -> Self {
Self::default()
pub fn new(pattern: PatternKind) -> Self {
Self {
csp: false,
pattern,
freeze_prototype: true,
#[cfg(feature = "isolation")]
isolation_schema: format!("isolation-{}", uuid::Uuid::new_v4()),
}
}
/// Instruct the asset handler to inject the CSP token to HTML files.
#[must_use]
pub fn with_csp(mut self) -> Self {
self.csp = true;
self
}
/// Instruct the asset handler to include a script to freeze the `Object.prototype` on all HTML files.
#[must_use]
pub fn freeze_prototype(mut self, freeze: bool) -> Self {
self.freeze_prototype = freeze;
self
}
}
impl EmbeddedAssets {
@ -203,18 +219,27 @@ impl EmbeddedAssets {
/// [`Assets`]: tauri_utils::assets::Assets
pub fn new(
input: impl Into<EmbeddedAssetsInput>,
options: AssetOptions,
map: impl Fn(&AssetKey, &Path, &mut Vec<u8>, &mut CspHashes) -> Result<(), EmbeddedAssetsError>,
) -> Result<Self, EmbeddedAssetsError> {
// we need to pre-compute all files now, so that we can inject data from all files into a few
let RawEmbeddedAssets {
paths,
mut csp_hashes,
} = RawEmbeddedAssets::new(input.into())?;
let RawEmbeddedAssets { paths, csp_hashes } = RawEmbeddedAssets::new(input.into())?;
let assets = paths
.into_iter()
.map(|(prefix, entry)| Self::compress_file(&prefix, entry.path(), &options, &mut csp_hashes))
.collect::<Result<_, _>>()?;
struct CompressState {
csp_hashes: CspHashes,
assets: HashMap<AssetKey, (PathBuf, PathBuf)>,
}
let CompressState { assets, csp_hashes } = paths.into_iter().try_fold(
CompressState {
csp_hashes,
assets: HashMap::new(),
},
move |mut state, (prefix, entry)| {
let (key, asset) = Self::compress_file(&prefix, entry.path(), &map, &mut state.csp_hashes)?;
state.assets.insert(key, asset);
Ok(state)
},
)?;
Ok(Self { assets, csp_hashes })
}
@ -234,7 +259,7 @@ impl EmbeddedAssets {
fn compress_file(
prefix: &Path,
path: &Path,
options: &AssetOptions,
map: &impl Fn(&AssetKey, &Path, &mut Vec<u8>, &mut CspHashes) -> Result<(), EmbeddedAssetsError>,
csp_hashes: &mut CspHashes,
) -> Result<Asset, EmbeddedAssetsError> {
let mut input = std::fs::read(path).map_err(|error| EmbeddedAssetsError::AssetRead {
@ -251,75 +276,8 @@ impl EmbeddedAssets {
path: path.to_owned(),
})?;
if path.extension() == Some(OsStr::new("html")) {
let mut document = parse_html(String::from_utf8_lossy(&input).into_owned());
if options.csp {
#[cfg(target_os = "linux")]
::tauri_utils::html::inject_csp_token(&mut document);
inject_nonce_token(&mut document);
if let Ok(inline_script_elements) = document.select("script:not(empty)") {
let mut scripts = Vec::new();
for inline_script_el in inline_script_elements {
let script = inline_script_el.as_node().text_contents();
let mut hasher = Sha256::new();
hasher.update(&script);
let hash = hasher.finalize();
scripts.push(format!("'sha256-{}'", base64::encode(&hash)));
}
csp_hashes
.inline_scripts
.insert(key.clone().into(), scripts);
}
}
inject_invoke_key_token(&mut document);
input = document.to_string().as_bytes().to_vec();
} else {
let is_javascript = ["js", "cjs", "mjs"]
.iter()
.any(|e| path.extension() == Some(OsStr::new(e)));
if is_javascript {
let js = String::from_utf8_lossy(&input).into_owned();
input = if RegexSet::new(&[
// import keywords
"import\\{",
"import \\{",
"import\\*",
"import \\*",
"import (\"|');?$",
"import\\(",
"import (.|\n)+ from (\"|')([A-Za-z/\\.@-]+)(\"|')",
// export keywords
"export\\{",
"export \\{",
"export\\*",
"export \\*",
"export (default|class|let|const|function|async)",
])
.unwrap()
.is_match(&js)
{
format!(
r#"
const __TAURI_INVOKE_KEY__ = __TAURI__INVOKE_KEY_TOKEN__;
{}
"#,
js
)
.as_bytes()
.to_vec()
} else {
format!(
r#"(function () {{
const __TAURI_INVOKE_KEY__ = __TAURI__INVOKE_KEY_TOKEN__;
{}
}})()"#,
js
)
.as_bytes()
.to_vec()
};
}
}
// perform any caller-requested input manipulation
map(&key, path, &mut input, csp_hashes)?;
// we must canonicalize the base of our paths to allow long paths on windows
let out_dir = std::env::var("OUT_DIR")
@ -404,6 +362,11 @@ impl ToTokens for EmbeddedAssets {
global_hashes.append_all(quote!(CspHash::Script(#hash),));
}
for style_hash in &self.csp_hashes.styles {
let hash = style_hash.as_str();
global_hashes.append_all(quote!(CspHash::Style(#hash),));
}
let mut html_hashes = TokenStream::new();
for (path, hashes) in &self.csp_hashes.inline_scripts {
let key = path.as_str();

View File

@ -8,7 +8,7 @@ homepage = "https://tauri.studio"
repository = "https://github.com/tauri-apps/tauri"
description = "Macros for the tauri crate."
edition = "2021"
rust-version = "1.56"
rust-version = "1.57"
exclude = [ ".license_template", "CHANGELOG.md", "/target" ]
readme = "README.md"
@ -25,3 +25,4 @@ tauri-codegen = { version = "1.0.0-beta.4", default-features = false, path = "..
[features]
custom-protocol = [ ]
compression = [ "tauri-codegen/compression" ]
isolation = ["tauri-codegen/isolation"]

View File

@ -8,7 +8,7 @@ homepage = "https://tauri.studio"
repository = "https://github.com/tauri-apps/tauri"
description = "Wry bindings to the Tauri runtime"
edition = "2021"
rust-version = "1.56"
rust-version = "1.57"
exclude = [ ".license_template", "CHANGELOG.md", "/target" ]
readme = "README.md"

View File

@ -8,7 +8,7 @@ homepage = "https://tauri.studio"
repository = "https://github.com/tauri-apps/tauri"
description = "Runtime for Tauri applications"
edition = "2021"
rust-version = "1.56"
rust-version = "1.57"
exclude = [ ".license_template", "CHANGELOG.md", "/target" ]
readme = "README.md"

View File

@ -168,7 +168,8 @@ impl Builder {
}
/// Set the HTTP mimetype for this response.
pub fn mimetype(self, mimetype: &str) -> Builder {
#[must_use]
pub fn mimetype(self, mimetype: &str) -> Self {
self.and_then(move |mut head| {
head.mimetype = Some(mimetype.to_string());
Ok(head)
@ -176,7 +177,8 @@ impl Builder {
}
/// Set the HTTP status for this response.
pub fn status<T>(self, status: T) -> Builder
#[must_use]
pub fn status<T>(self, status: T) -> Self
where
StatusCode: TryFrom<T>,
<StatusCode as TryFrom<T>>::Error: Into<crate::Error>,
@ -193,7 +195,8 @@ impl Builder {
/// will be returned from `Builder::build`.
///
/// By default this is HTTP/1.1
pub fn version(self, version: Version) -> Builder {
#[must_use]
pub fn version(self, version: Version) -> Self {
self.and_then(move |mut head| {
head.version = version;
Ok(head)
@ -205,7 +208,8 @@ impl Builder {
/// This function will append the provided key/value as a header to the
/// internal `HeaderMap` being constructed. Essentially this is equivalent
/// to calling `HeaderMap::append`.
pub fn header<K, V>(self, key: K, value: V) -> Builder
#[must_use]
pub fn header<K, V>(self, key: K, value: V) -> Self
where
HeaderName: TryFrom<K>,
<HeaderName as TryFrom<K>>::Error: Into<crate::Error>,

View File

@ -57,6 +57,7 @@ impl SystemTray {
}
/// Sets the tray icon. Must be a [`Icon::File`] on Linux and a [`Icon::Raw`] on Windows and macOS.
#[must_use]
pub fn with_icon(mut self, icon: Icon) -> Self {
self.icon.replace(icon);
self
@ -64,12 +65,14 @@ impl SystemTray {
/// Sets the tray icon as template.
#[cfg(target_os = "macos")]
#[must_use]
pub fn with_icon_as_template(mut self, is_template: bool) -> Self {
self.icon_as_template = is_template;
self
}
/// Sets the menu to show when the system tray is right clicked.
#[must_use]
pub fn with_menu(mut self, menu: menu::SystemTrayMenu) -> Self {
self.menu.replace(menu);
self

View File

@ -206,18 +206,21 @@ impl Menu {
}
/// Adds the custom menu item to the menu.
#[must_use]
pub fn add_item(mut self, item: CustomMenuItem) -> Self {
self.items.push(MenuEntry::CustomItem(item));
self
}
/// Adds a native item to the menu.
#[must_use]
pub fn add_native_item(mut self, item: MenuItem) -> Self {
self.items.push(MenuEntry::NativeItem(item));
self
}
/// Adds an entry with submenu.
#[must_use]
pub fn add_submenu(mut self, submenu: Submenu) -> Self {
self.items.push(MenuEntry::Submenu(submenu));
self
@ -255,6 +258,7 @@ impl CustomMenuItem {
}
/// Assign a keyboard shortcut to the menu action.
#[must_use]
pub fn accelerator<T: Into<String>>(mut self, accelerator: T) -> Self {
self.keyboard_accelerator.replace(accelerator.into());
self
@ -262,6 +266,7 @@ impl CustomMenuItem {
#[cfg(target_os = "macos")]
#[cfg_attr(doc_cfg, doc(cfg(target_os = "macos")))]
#[must_use]
/// A native image do render on the menu item.
pub fn native_image(mut self, image: NativeImage) -> Self {
self.native_image.replace(image);
@ -269,12 +274,14 @@ impl CustomMenuItem {
}
/// Mark the item as disabled.
#[must_use]
pub fn disabled(mut self) -> Self {
self.enabled = false;
self
}
/// Mark the item as selected.
#[must_use]
pub fn selected(mut self) -> Self {
self.selected = true;
self
@ -320,18 +327,21 @@ impl SystemTrayMenu {
}
/// Adds the custom menu item to the system tray menu.
#[must_use]
pub fn add_item(mut self, item: CustomMenuItem) -> Self {
self.items.push(SystemTrayMenuEntry::CustomItem(item));
self
}
/// Adds a native item to the system tray menu.
#[must_use]
pub fn add_native_item(mut self, item: SystemTrayMenuItem) -> Self {
self.items.push(SystemTrayMenuEntry::NativeItem(item));
self
}
/// Adds an entry with submenu.
#[must_use]
pub fn add_submenu(mut self, submenu: SystemTraySubmenu) -> Self {
self.items.push(SystemTrayMenuEntry::Submenu(submenu));
self

View File

@ -36,18 +36,21 @@ impl WebviewAttributes {
}
/// Sets the init script.
#[must_use]
pub fn initialization_script(mut self, script: &str) -> Self {
self.initialization_scripts.push(script.to_string());
self
}
/// Data directory for the webview.
#[must_use]
pub fn data_directory(mut self, data_directory: PathBuf) -> Self {
self.data_directory.replace(data_directory);
self
}
/// Disables the file drop handler. This is required to use drag and drop APIs on the front end on Windows.
#[must_use]
pub fn disable_file_drop_handler(mut self) -> Self {
self.file_drop_handler_enabled = false;
self
@ -57,6 +60,7 @@ impl WebviewAttributes {
///
/// **macOS** doesn't provide such method and is always enabled by default,
/// but you still need to add menu item accelerators to use shortcuts.
#[must_use]
pub fn enable_clipboard_access(mut self) -> Self {
self.clipboard = true;
self
@ -80,39 +84,51 @@ pub trait WindowBuilder: WindowBuilderBase {
fn with_config(config: WindowConfig) -> Self;
/// Sets the menu for the window.
#[must_use]
fn menu(self, menu: Menu) -> Self;
/// Show window in the center of the screen.
#[must_use]
fn center(self) -> Self;
/// The initial position of the window's.
#[must_use]
fn position(self, x: f64, y: f64) -> Self;
/// Window size.
#[must_use]
fn inner_size(self, min_width: f64, min_height: f64) -> Self;
/// Window min inner size.
#[must_use]
fn min_inner_size(self, min_width: f64, min_height: f64) -> Self;
/// Window max inner size.
#[must_use]
fn max_inner_size(self, max_width: f64, max_height: f64) -> Self;
/// Whether the window is resizable or not.
#[must_use]
fn resizable(self, resizable: bool) -> Self;
/// The title of the window in the title bar.
#[must_use]
fn title<S: Into<String>>(self, title: S) -> Self;
/// Whether to start the window in fullscreen or not.
#[must_use]
fn fullscreen(self, fullscreen: bool) -> Self;
/// Whether the window will be initially hidden or focused.
#[must_use]
fn focus(self) -> Self;
/// Whether the window should be maximized upon creation.
#[must_use]
fn maximized(self, maximized: bool) -> Self;
/// Whether the window should be immediately visible upon creation.
#[must_use]
fn visible(self, visible: bool) -> Self;
/// Whether the the window should be transparent. If this is true, writing colors
@ -122,18 +138,22 @@ pub trait WindowBuilder: WindowBuilderBase {
doc_cfg,
doc(cfg(any(not(target_os = "macos"), feature = "macos-private-api")))
)]
#[must_use]
fn transparent(self, transparent: bool) -> Self;
/// Whether the window should have borders and bars.
#[must_use]
fn decorations(self, decorations: bool) -> Self;
/// Whether the window should always be on top of other windows.
#[must_use]
fn always_on_top(self, always_on_top: bool) -> Self;
/// Sets the window icon.
fn icon(self, icon: Icon) -> crate::Result<Self>;
/// Sets whether or not the window icon should be added to the taskbar.
#[must_use]
fn skip_taskbar(self, skip: bool) -> Self;
/// Sets a parent to the window to be created.
@ -142,6 +162,7 @@ pub trait WindowBuilder: WindowBuilderBase {
///
/// For more information, see <https://docs.microsoft.com/en-us/windows/win32/winmsg/window-features#child-windows>
#[cfg(windows)]
#[must_use]
fn parent_window(self, parent: HWND) -> Self;
/// Set an owner to the window to be created.
@ -153,6 +174,7 @@ pub trait WindowBuilder: WindowBuilderBase {
///
/// For more information, see <https://docs.microsoft.com/en-us/windows/win32/winmsg/window-features#owned-windows>
#[cfg(windows)]
#[must_use]
fn owner_window(self, owner: HWND) -> Self;
/// Whether the icon was set or not.

View File

@ -168,6 +168,7 @@ impl<R: Runtime> PendingWindow<R> {
}
}
#[must_use]
pub fn set_menu(mut self, menu: Menu) -> Self {
let mut menu_ids = HashMap::new();
get_menu_ids(&mut menu_ids, &menu);

View File

@ -7,7 +7,7 @@ homepage = "https://tauri.studio"
repository = "https://github.com/tauri-apps/tauri"
description = "Utilities for Tauri"
edition = "2021"
rust-version = "1.56"
rust-version = "1.57"
exclude = [ ".license_template", "CHANGELOG.md", "/target" ]
readme = "README.md"
@ -24,6 +24,13 @@ proc-macro2 = { version = "1.0", optional = true }
quote = { version = "1.0", optional = true }
schemars = { version = "0.8", features = ["url"], optional = true }
serde_with = "1.10"
sha2 = "0.9"
base64 = "0.13"
aes-gcm = { version = "0.9", optional = true }
ring = { version = "0.16", optional = true, features = ["std"] }
once_cell = { version = "1.8", optional = true }
serialize-to-javascript = { git = "https://github.com/chippers/serialize-to-javascript" }
[target."cfg(target_os = \"linux\")".dependencies]
heck = "0.4"
@ -32,3 +39,4 @@ heck = "0.4"
build = [ "proc-macro2", "quote" ]
compression = [ "zstd" ]
schema = ["schemars"]
isolation = [ "aes-gcm", "ring", "once_cell" ]

View File

@ -81,6 +81,9 @@ impl<P: AsRef<Path>> From<P> for AssetKey {
pub enum CspHash<'a> {
/// The `script-src` directive.
Script(&'a str),
/// The `style-src` directive.
Style(&'a str),
}
impl CspHash<'_> {
@ -88,6 +91,7 @@ impl CspHash<'_> {
pub fn directive(&self) -> &'static str {
match self {
Self::Script(_) => "script-src",
Self::Style(_) => "style-src",
}
}
@ -95,6 +99,7 @@ impl CspHash<'_> {
pub fn hash(&self) -> &str {
match self {
Self::Script(hash) => hash,
Self::Style(hash) => hash,
}
}
}

View File

@ -36,8 +36,8 @@ pub enum WindowUrl {
App(PathBuf),
}
impl std::fmt::Display for WindowUrl {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
impl fmt::Display for WindowUrl {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::External(url) => write!(f, "{}", url),
Self::App(path) => write!(f, "{}", path.display()),
@ -542,7 +542,7 @@ fn default_file_drop_enabled() -> bool {
/// Security configuration.
#[skip_serializing_none]
#[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize)]
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[cfg_attr(feature = "schema", derive(JsonSchema))]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct SecurityConfig {
@ -557,6 +557,23 @@ pub struct SecurityConfig {
/// This is a really important part of the configuration since it helps you ensure your WebView is secured.
/// See <https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP>.
pub dev_csp: Option<String>,
/// Freeze the `Object.prototype` when using the custom protocol.
#[serde(default = "default_freeze_prototype")]
pub freeze_prototype: bool,
}
impl Default for SecurityConfig {
fn default() -> Self {
Self {
csp: None,
dev_csp: None,
freeze_prototype: default_freeze_prototype(),
}
}
}
fn default_freeze_prototype() -> bool {
true
}
/// Defines an allowlist type.
@ -1292,12 +1309,37 @@ fn default_window_config() -> Vec<WindowConfig> {
vec![Default::default()]
}
/// The application pattern.
#[skip_serializing_none]
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
#[serde(rename_all = "lowercase", tag = "use", content = "options")]
#[cfg_attr(feature = "schema", derive(JsonSchema))]
pub enum PatternKind {
/// Brownfield pattern.
Brownfield,
/// Isolation pattern. Recommended for security purposes.
#[cfg(feature = "isolation")]
Isolation {
/// The dir containing the index.html file that contains the secure isolation application.
dir: PathBuf,
},
}
impl Default for PatternKind {
fn default() -> Self {
Self::Brownfield
}
}
/// The Tauri configuration object.
#[skip_serializing_none]
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[cfg_attr(feature = "schema", derive(JsonSchema))]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct TauriConfig {
/// The pattern to use.
#[serde(default)]
pub pattern: PatternKind,
/// The windows configuration.
#[serde(default = "default_window_config")]
pub windows: Vec<WindowConfig>,
@ -1325,6 +1367,7 @@ pub struct TauriConfig {
impl Default for TauriConfig {
fn default() -> Self {
Self {
pattern: Default::default(),
windows: default_window_config(),
cli: None,
bundle: BundleConfig::default(),
@ -1338,6 +1381,20 @@ impl Default for TauriConfig {
}
impl TauriConfig {
/// Returns all Cargo features.
#[allow(dead_code)]
pub fn all_features() -> Vec<&'static str> {
let mut features = AllowlistConfig::all_features();
features.extend(vec![
"cli",
"updater",
"system-tray",
"macos-private-api",
"isolation",
]);
features
}
/// Returns the enabled Cargo features.
#[allow(dead_code)]
pub fn features(&self) -> Vec<&str> {
@ -1354,6 +1411,10 @@ impl TauriConfig {
if self.macos_private_api {
features.push("macos-private-api");
}
#[cfg(feature = "isolation")]
if let PatternKind::Isolation { .. } = self.pattern {
features.push("isolation");
}
features.sort_unstable();
features
}
@ -1964,6 +2025,21 @@ mod build {
}
}
impl ToTokens for PatternKind {
fn to_tokens(&self, tokens: &mut TokenStream) {
let prefix = quote! { ::tauri::utils::config::PatternKind };
tokens.append_all(match self {
Self::Brownfield => quote! { #prefix::Brownfield },
#[cfg(feature = "isolation")]
Self::Isolation { dir } => {
let dir = path_buf_lit(dir);
quote! { #prefix::Isolation { dir: #dir } }
}
})
}
}
impl ToTokens for WindowsConfig {
fn to_tokens(&self, tokens: &mut TokenStream) {
let webview_fixed_runtime_path = opt_lit(
@ -2082,8 +2158,9 @@ mod build {
fn to_tokens(&self, tokens: &mut TokenStream) {
let csp = opt_str_lit(self.csp.as_ref());
let dev_csp = opt_str_lit(self.dev_csp.as_ref());
let freeze_prototype = self.freeze_prototype;
literal_struct!(tokens, SecurityConfig, csp, dev_csp);
literal_struct!(tokens, SecurityConfig, csp, dev_csp, freeze_prototype);
}
}
@ -2151,6 +2228,7 @@ mod build {
impl ToTokens for TauriConfig {
fn to_tokens(&self, tokens: &mut TokenStream) {
let pattern = &self.pattern;
let windows = vec_lit(&self.windows, identity);
let cli = opt_lit(self.cli.as_ref());
let bundle = &self.bundle;
@ -2163,6 +2241,7 @@ mod build {
literal_struct!(
tokens,
TauriConfig,
pattern,
windows,
cli,
bundle,
@ -2234,6 +2313,7 @@ mod test {
// create a tauri config.
let tauri = TauriConfig {
pattern: Default::default(),
windows: vec![WindowConfig {
label: "main".to_string(),
url: WindowUrl::default(),
@ -2283,6 +2363,7 @@ mod test {
security: SecurityConfig {
csp: None,
dev_csp: None,
freeze_prototype: true,
},
allowlist: AllowlistConfig::default(),
system_tray: None,

View File

@ -4,8 +4,18 @@
//! The module to process HTML in Tauri.
use std::path::{Path, PathBuf};
use html5ever::{interface::QualName, namespace_url, ns, tendril::TendrilSink, LocalName};
use kuchiki::{Attribute, ExpandedName, NodeRef};
pub use kuchiki::NodeRef;
use kuchiki::{Attribute, ExpandedName};
use serde::Serialize;
#[cfg(feature = "isolation")]
use serialize_to_javascript::DefaultTemplate;
use crate::config::PatternKind;
#[cfg(feature = "isolation")]
use crate::pattern::isolation::IsolationJavascriptCodegen;
/// The token used on the CSP tag content.
pub const CSP_TOKEN: &str = "__TAURI_CSP__";
@ -13,14 +23,25 @@ pub const CSP_TOKEN: &str = "__TAURI_CSP__";
pub const SCRIPT_NONCE_TOKEN: &str = "__TAURI_SCRIPT_NONCE__";
/// The token used for style nonces.
pub const STYLE_NONCE_TOKEN: &str = "__TAURI_STYLE_NONCE__";
/// The token used for the invoke key.
pub const INVOKE_KEY_TOKEN: &str = "__TAURI__INVOKE_KEY_TOKEN__";
/// Parses the given HTML string.
pub fn parse(html: String) -> NodeRef {
kuchiki::parse_html().one(html)
}
fn with_head<F: FnOnce(&NodeRef)>(document: &mut NodeRef, f: F) {
if let Ok(ref node) = document.select_first("head") {
f(node.as_node())
} else {
let node = NodeRef::new_element(
QualName::new(None, ns!(html), LocalName::from("head")),
None,
);
f(&node);
document.prepend(node)
}
}
fn inject_nonce(document: &mut NodeRef, selector: &str, token: &str) {
if let Ok(scripts) = document.select(selector) {
for target in scripts {
@ -43,88 +64,11 @@ pub fn inject_nonce_token(document: &mut NodeRef) {
inject_nonce(document, "style", STYLE_NONCE_TOKEN);
}
/// Injects the invoke key token to each script on the document.
///
/// The invoke key token is replaced at runtime with the actual invoke key value.
pub fn inject_invoke_key_token(document: &mut NodeRef) {
let mut targets = vec![];
if let Ok(scripts) = document.select("script") {
for target in scripts {
targets.push(target);
}
for target in targets {
let node = target.as_node();
let element = node.as_element().unwrap();
let attrs = element.attributes.borrow();
// if the script is external (has `src`), we won't inject the token
if attrs.get("src").is_some() {
continue;
}
let replacement_node = match attrs.get("type") {
Some("module") | Some("application/ecmascript") => {
let replacement_node = NodeRef::new_element(
QualName::new(None, ns!(html), "script".into()),
element
.attributes
.borrow()
.clone()
.map
.into_iter()
.collect::<Vec<_>>(),
);
let script = node.text_contents();
replacement_node.append(NodeRef::new_text(format!(
r#"
const __TAURI_INVOKE_KEY__ = {token};
{script}
"#,
token = INVOKE_KEY_TOKEN,
script = script
)));
replacement_node
}
Some("application/javascript") | None => {
let replacement_node = NodeRef::new_element(
QualName::new(None, ns!(html), "script".into()),
element
.attributes
.borrow()
.clone()
.map
.into_iter()
.collect::<Vec<_>>(),
);
let script = node.text_contents();
replacement_node.append(NodeRef::new_text(
script.replace("__TAURI_INVOKE_KEY__", INVOKE_KEY_TOKEN),
));
replacement_node
}
_ => {
continue;
}
};
node.insert_after(replacement_node);
node.detach();
}
}
}
/// Injects a content security policy to the HTML.
pub fn inject_csp(document: &mut NodeRef, csp: &str) {
if let Ok(ref head) = document.select_first("head") {
head.as_node().append(create_csp_meta_tag(csp));
} else {
let head = NodeRef::new_element(
QualName::new(None, ns!(html), LocalName::from("head")),
None,
);
with_head(document, |head| {
head.append(create_csp_meta_tag(csp));
document.prepend(head);
}
});
}
/// Injects a content security policy token to the HTML.
@ -154,9 +98,101 @@ fn create_csp_meta_tag(csp: &str) -> NodeRef {
)
}
/// The shape of the JavaScript Pattern config
#[derive(Debug, Serialize)]
#[serde(rename_all = "lowercase", tag = "pattern")]
pub enum PatternObject {
/// Brownfield pattern.
Brownfield,
/// Isolation pattern. Recommended for security purposes.
Isolation {
/// Which `IsolationSide` this `PatternObject` is getting injected into
side: IsolationSide,
},
}
impl From<&PatternKind> for PatternObject {
fn from(pattern_kind: &PatternKind) -> Self {
match pattern_kind {
PatternKind::Brownfield => Self::Brownfield,
#[cfg(feature = "isolation")]
PatternKind::Isolation { .. } => Self::Isolation {
side: IsolationSide::default(),
},
}
}
}
/// Where the JavaScript is injected to
#[derive(Debug, Serialize)]
#[serde(rename_all = "lowercase")]
pub enum IsolationSide {
/// Original frame, the Brownfield application
Original,
/// Secure frame, the isolation security application
Secure,
}
impl Default for IsolationSide {
fn default() -> Self {
Self::Original
}
}
/// Injects the Isolation JavaScript to a codegen time document.
///
/// Note: This function is not considered part of the stable API.
#[cfg(feature = "isolation")]
pub fn inject_codegen_isolation_script(document: &mut NodeRef) {
with_head(document, |head| {
let script = NodeRef::new_element(QualName::new(None, ns!(html), "script".into()), None);
script.append(NodeRef::new_text(
IsolationJavascriptCodegen {}
.render_default(&Default::default())
.expect("unable to render codegen isolation script template"),
));
head.prepend(script);
});
}
/// Temporary workaround for Windows not allowing requests
///
/// Note: this does not prevent path traversal due to the isolation application expectation that it
/// is secure.
pub fn inline_isolation(document: &mut NodeRef, dir: &Path) {
for script in document
.select("script[src]")
.expect("unable to parse document for scripts")
{
let src = {
let attributes = script.attributes.borrow();
attributes
.get(LocalName::from("src"))
.expect("script with src attribute has no src value")
.to_string()
};
let mut path = PathBuf::from(src);
if path.has_root() {
path = path
.strip_prefix("/")
.expect("Tauri \"Isolation\" Pattern only supports relative or absolute (`/`) paths.")
.into();
}
let file = std::fs::read_to_string(dir.join(path)).expect("unable to find isolation file");
script.as_node().append(NodeRef::new_text(file));
let mut attributes = script.attributes.borrow_mut();
attributes.remove(LocalName::from("src"));
}
}
#[cfg(test)]
mod tests {
use kuchiki::traits::*;
#[test]
fn csp() {
let htmls = vec![

View File

@ -10,6 +10,9 @@ pub mod config;
pub mod html;
pub mod platform;
/// Application pattern.
pub mod pattern;
/// `tauri::App` package information.
#[derive(Debug, Clone)]
pub struct PackageInfo {
@ -112,4 +115,7 @@ pub enum Error {
/// IO error
#[error("{0}")]
Io(#[from] std::io::Error),
/// Invalid pattern.
#[error("invalid pattern `{0}`. Expected either `brownfield` or `isolation`.")]
InvalidPattern(String),
}

View File

@ -0,0 +1,115 @@
// Copyright 2019-2021 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
/**
* IMPORTANT: See ipc.js for the main frame implementation.
* main frame -> isolation frame = isolation payload
* isolation frame -> main frame = isolation message
*/
;(async function () {
/**
* Sends the message to the isolation frame.
* @param {any} message
*/
function sendMessage(message) {
window.parent.postMessage(message, '*')
}
/**
* @type {Uint8Array} - Injected by Tauri during runtime
*/
const aesGcmKeyRaw = new Uint8Array(__TEMPLATE_runtime_aes_gcm_key__)
/**
* @type {CryptoKey}
*/
const aesGcmKey = await window.crypto.subtle.importKey(
'raw',
aesGcmKeyRaw,
'AES-GCM',
true,
['encrypt']
)
/**
* @param {object} data
* @return {Promise<{nonce: number[], payload: number[]}>}
*/
async function encrypt(data) {
let algorithm = Object.create(null)
algorithm.name = 'AES-GCM'
algorithm.iv = window.crypto.getRandomValues(new Uint8Array(12))
let encoder = new TextEncoder()
let payloadRaw = encoder.encode(JSON.stringify(data))
return window.crypto.subtle
.encrypt(algorithm, aesGcmKey, payloadRaw)
.then((payload) => {
let result = Object.create(null)
result.nonce = Array.from(new Uint8Array(algorithm.iv))
result.payload = Array.from(new Uint8Array(payload))
return result
})
}
/**
* Detect if a message event is a valid isolation payload.
*
* @param {MessageEvent<object>} event - a message event that is expected to be an isolation payload
* @return boolean
*/
function isIsolationPayload(event) {
return (
typeof event.data === 'object' &&
'callback' in event.data &&
'error' in event.data
)
}
/**
* Handle incoming payload events.
* @param {MessageEvent<any>} event
*/
async function payloadHandler(event) {
if (!isIsolationPayload(event)) {
return
}
let data = event.data
if (typeof window.__TAURI_ISOLATION_HOOK__ === 'function') {
// await even if it's not async so that we can support async ones
data = await window.__TAURI_ISOLATION_HOOK__(data)
}
const encrypted = await encrypt(data)
sendMessage(encrypted)
}
window.addEventListener('message', payloadHandler, false)
/**
* @type {number} - How many milliseconds to wait between ready checks
*/
const readyIntervalMs = 50
/**
* Wait until this Isolation context is ready to receive messages, and let the main frame know.
*/
function waitUntilReady() {
// consider either a function or an explicitly set null value as the ready signal
if (
typeof window.__TAURI_ISOLATION_HOOK__ === 'function' ||
window.__TAURI_ISOLATION_HOOK__ === null
) {
sendMessage('__TAURI_ISOLATION_READY__')
} else {
setTimeout(waitUntilReady, readyIntervalMs)
}
}
setTimeout(waitUntilReady, readyIntervalMs)
})()

View File

@ -0,0 +1,164 @@
// Copyright 2019-2021 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
use std::array::TryFromSliceError;
use std::borrow::Cow;
use std::fmt::{Debug, Formatter};
use std::string::FromUtf8Error;
use aes_gcm::aead::Aead;
use aes_gcm::{aead::NewAead, Aes256Gcm, Nonce};
use once_cell::sync::OnceCell;
use ring::error::Unspecified;
use ring::rand::SystemRandom;
use serialize_to_javascript::{default_template, Template};
/// Cryptographically secure pseudo-random number generator.
static RNG: OnceCell<SystemRandom> = OnceCell::new();
/// The style for the isolation iframe.
pub const IFRAME_STYLE: &str = "#__tauri_isolation__ { display: none !important }";
/// Errors that can occur during Isolation keys generation.
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum Error {
/// Something went wrong with the CSPRNG.
#[error("Unspecified CSPRNG error")]
Csprng,
/// Something went wrong with decryping an AES-GCM payload
#[error("AES-GCM")]
Aes,
/// Nonce was not 96 bits
#[error("Nonce: {0}")]
NonceSize(#[from] TryFromSliceError),
/// Payload was not valid utf8
#[error("{0}")]
Utf8(#[from] FromUtf8Error),
/// Invalid json format
#[error("{0}")]
Json(#[from] serde_json::Error),
}
impl From<Unspecified> for Error {
fn from(_: Unspecified) -> Self {
Self::Csprng
}
}
/// A formatted AES-GCM cipher instance along with the key used to initialize it.
#[derive(Clone)]
pub struct AesGcmPair {
raw: [u8; 32],
key: Aes256Gcm,
}
impl Debug for AesGcmPair {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "AesGcmPair(...)")
}
}
impl AesGcmPair {
fn new() -> Result<Self, Error> {
let rng = RNG.get_or_init(SystemRandom::new);
let raw: [u8; 32] = ring::rand::generate(rng)?.expose();
let key = aes_gcm::Key::from_slice(&raw);
Ok(Self {
raw,
key: Aes256Gcm::new(key),
})
}
/// The raw value used to create the AES-GCM key
pub fn raw(&self) -> &[u8; 32] {
&self.raw
}
/// The formatted AES-GCM key
pub fn key(&self) -> &Aes256Gcm {
&self.key
}
}
/// All cryptographic keys required for Isolation encryption
#[derive(Debug, Clone)]
pub struct Keys {
/// AES-GCM key
aes_gcm: AesGcmPair,
}
impl Keys {
/// Securely generate required keys for Isolation encryption.
pub fn new() -> Result<Self, Error> {
AesGcmPair::new()
.map(|aes_gcm| Self { aes_gcm })
.map_err(Into::into)
}
/// The AES-GCM data (and raw data).
pub fn aes_gcm(&self) -> &AesGcmPair {
&self.aes_gcm
}
/// Decrypts a message using the generated keys.
pub fn decrypt(&self, raw: RawIsolationPayload<'_>) -> Result<String, Error> {
let RawIsolationPayload { nonce, payload } = raw;
let nonce: [u8; 12] = nonce.as_ref().try_into()?;
let bytes = self
.aes_gcm
.key
.decrypt(Nonce::from_slice(&nonce), payload.as_ref())
.map_err(|_| self::Error::Aes)?;
String::from_utf8(bytes).map_err(Into::into)
}
}
/// Raw representation of
#[derive(Debug, serde::Deserialize)]
pub struct RawIsolationPayload<'a> {
nonce: Cow<'a, [u8]>,
payload: Cow<'a, [u8]>,
}
impl<'a> TryFrom<&'a str> for RawIsolationPayload<'a> {
type Error = Error;
fn try_from(value: &'a str) -> Result<Self, Self::Error> {
serde_json::from_str(value).map_err(Into::into)
}
}
/// The Isolation JavaScript template meant to be injected during codegen.
///
/// Note: This struct is not considered part of the stable API
#[derive(Template)]
#[default_template("isolation.js")]
pub struct IsolationJavascriptCodegen {
// this template intentionally does not include the runtime field
}
/// The Isolation JavaScript template meant to be injected during runtime.
///
/// Note: This struct is not considered part of the stable API
#[derive(Template)]
#[default_template("isolation.js")]
pub struct IsolationJavascriptRuntime<'a> {
/// The key used on the Rust backend and the Isolation Javascript
pub runtime_aes_gcm_key: &'a [u8; 32],
}
#[cfg(test)]
mod test {
#[test]
fn create_keys() -> Result<(), Box<dyn std::error::Error>> {
let _ = super::Keys::new()?;
Ok(())
}
}

View File

@ -0,0 +1,7 @@
// Copyright 2019-2021 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
/// Handling the Tauri "Isolation" Pattern.
#[cfg(feature = "isolation")]
pub mod isolation;

View File

@ -3,7 +3,7 @@ authors = ["Tauri Programme within The Commons Conservancy"]
categories = ["gui", "web-programming"]
description = "Make tiny, secure apps for all desktop platforms with Tauri"
edition = "2021"
rust-version = "1.56"
rust-version = "1.57"
exclude = [
"/test",
"/.scripts",
@ -77,6 +77,7 @@ epi = { git = "https://github.com/wusyong/egui", branch = "tao", optional = true
regex = "1.5"
glob = "0.3"
data-url = "0.1"
serialize-to-javascript = { git = "https://github.com/chippers/serialize-to-javascript" }
[target."cfg(any(target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\"))".dependencies]
glib = "0.14"
@ -99,10 +100,14 @@ tauri = {path = "."}
tokio-test = "0.4.2"
tokio = { version = "1.15", features = [ "full" ] }
[target."cfg(windows)".dev-dependencies]
webview2-com = "0.7.0"
[features]
default = [ "wry", "compression" ]
compression = [ "tauri-macros/compression", "tauri-utils/compression" ]
wry = ["tauri-runtime-wry"]
isolation = ["tauri-utils/isolation", "tauri-macros/isolation"]
custom-protocol = ["tauri-macros/custom-protocol"]
updater = ["minisign-verify", "base64", "dialog-ask"]
http-api = ["attohttpc"]
@ -233,10 +238,12 @@ path = "../../examples/helloworld/src-tauri/src/main.rs"
[[example]]
name = "multiwindow"
path = "../../examples/multiwindow/src-tauri/src/main.rs"
required-features = [ "window-create" ]
[[example]]
name = "navigation"
path = "../../examples/navigation/src-tauri/src/main.rs"
required-features = [ "window-create" ]
[[example]]
name = "splashscreen"
@ -249,3 +256,8 @@ path = "../../examples/state/src-tauri/src/main.rs"
[[example]]
name = "streaming"
path = "../../examples/streaming/src-tauri/src/main.rs"
[[example]]
name = "isolation"
path = "../../examples/isolation/src-tauri/src/main.rs"
required-features = [ "isolation" ]

File diff suppressed because one or more lines are too long

View File

@ -8,7 +8,9 @@
}
if (!window.__TAURI__) {
window.__TAURI__ = {}
Object.defineProperty(window, '__TAURI__', {
value: {}
})
}
window.__TAURI__.transformCallback = function transformCallback(
@ -33,7 +35,20 @@
return identifier
}
window.__TAURI_INVOKE__ = function invoke(cmd, args = {}, key = null) {
const ipcQueue = []
let isWaitingForIpc = false
function waitForIpc() {
if ('__TAURI_IPC__' in window) {
for (const action of ipcQueue) {
action()
}
} else {
setTimeout(waitForIpc, 50)
}
}
window.__TAURI_INVOKE__ = function invoke(cmd, args = {}) {
return new Promise(function (resolve, reject) {
var callback = window.__TAURI__.transformCallback(function (r) {
resolve(r)
@ -52,25 +67,21 @@
return reject(new Error('Invalid argument type.'))
}
if (
document.readyState === 'complete' ||
document.readyState === 'interactive'
) {
window.__TAURI_POST_MESSAGE__(cmd, {
const action = () => {
window.__TAURI_IPC__({
...args,
callback: callback,
error: error,
__invokeKey: key || __TAURI_INVOKE_KEY__
callback,
error: error
})
}
if (window.__TAURI_IPC__) {
action()
} else {
window.addEventListener('DOMContentLoaded', function () {
window.__TAURI_POST_MESSAGE__(cmd, {
...args,
callback: callback,
error: error,
__invokeKey: key || __TAURI_INVOKE_KEY__
})
})
ipcQueue.push(action)
if (!isWaitingForIpc) {
waitForIpc()
isWaitingForIpc = true
}
}
})
}
@ -88,17 +99,13 @@
target.href.startsWith('http') &&
target.target === '_blank'
) {
window.__TAURI_INVOKE__(
'tauri',
{
__tauriModule: 'Shell',
message: {
cmd: 'open',
path: target.href
}
},
_KEY_VALUE_
)
window.__TAURI_INVOKE__('tauri', {
__tauriModule: 'Shell',
message: {
cmd: 'open',
path: target.href
}
})
e.preventDefault()
}
break
@ -129,43 +136,35 @@
document.addEventListener('mousedown', (e) => {
if (e.target.hasAttribute('data-tauri-drag-region') && e.buttons === 1) {
// start dragging if the element has a `tauri-drag-region` data attribute and maximize on double-clicking it
window.__TAURI_INVOKE__(
'tauri',
{
__tauriModule: 'Window',
message: {
cmd: 'manage',
data: {
cmd: {
type: e.detail === 2 ? '__toggleMaximize' : 'startDragging'
}
window.__TAURI_INVOKE__('tauri', {
__tauriModule: 'Window',
message: {
cmd: 'manage',
data: {
cmd: {
type: e.detail === 2 ? '__toggleMaximize' : 'startDragging'
}
}
},
_KEY_VALUE_
)
}
})
}
})
window.__TAURI_INVOKE__(
'tauri',
{
__tauriModule: 'Event',
message: {
cmd: 'listen',
event: 'tauri://window-created',
handler: window.__TAURI__.transformCallback(function (event) {
if (event.payload) {
var windowLabel = event.payload.label
window.__TAURI__.__windows.push({
label: windowLabel
})
}
})
}
},
_KEY_VALUE_
)
window.__TAURI_INVOKE__('tauri', {
__tauriModule: 'Event',
message: {
cmd: 'listen',
event: 'tauri://window-created',
handler: window.__TAURI__.transformCallback(function (event) {
if (event.payload) {
var windowLabel = event.payload.label
window.__TAURI__.__windows.push({
label: windowLabel
})
}
})
}
})
let permissionSettable = false
let permissionValue = 'default'
@ -174,16 +173,12 @@
if (window.Notification.permission !== 'default') {
return Promise.resolve(window.Notification.permission === 'granted')
}
return window.__TAURI_INVOKE__(
'tauri',
{
__tauriModule: 'Notification',
message: {
cmd: 'isNotificationPermissionGranted'
}
},
_KEY_VALUE_
)
return window.__TAURI_INVOKE__('tauri', {
__tauriModule: 'Notification',
message: {
cmd: 'isNotificationPermissionGranted'
}
})
}
function setNotificationPermission(value) {
@ -194,16 +189,12 @@
function requestPermission() {
return window
.__TAURI_INVOKE__(
'tauri',
{
__tauriModule: 'Notification',
message: {
cmd: 'requestNotificationPermission'
}
},
_KEY_VALUE_
)
.__TAURI_INVOKE__('tauri', {
__tauriModule: 'Notification',
message: {
cmd: 'requestNotificationPermission'
}
})
.then(function (permission) {
setNotificationPermission(permission)
return permission
@ -215,20 +206,18 @@
Object.freeze(options)
}
return window.__TAURI_INVOKE__(
'tauri', {
__tauriModule: 'Notification',
message: {
cmd: 'notification',
options: typeof options === 'string' ?
{
title: options
} :
options
}
},
_KEY_VALUE_
)
return window.__TAURI_INVOKE__('tauri', {
__tauriModule: 'Notification',
message: {
cmd: 'notification',
options:
typeof options === 'string'
? {
title: options
}
: options
}
})
}
window.Notification = function (title, options) {
@ -264,51 +253,39 @@
})
window.alert = function (message) {
window.__TAURI_INVOKE__(
'tauri',
{
__tauriModule: 'Dialog',
message: {
cmd: 'messageDialog',
message: message
}
},
_KEY_VALUE_
)
window.__TAURI_INVOKE__('tauri', {
__tauriModule: 'Dialog',
message: {
cmd: 'messageDialog',
message: message
}
})
}
window.confirm = function (message) {
return window.__TAURI_INVOKE__(
'tauri',
{
__tauriModule: 'Dialog',
message: {
cmd: 'confirmDialog',
message: message
}
},
_KEY_VALUE_
)
return window.__TAURI_INVOKE__('tauri', {
__tauriModule: 'Dialog',
message: {
cmd: 'confirmDialog',
message: message
}
})
}
// window.print works on Linux/Windows; need to use the API on macOS
if (navigator.userAgent.includes('Mac')) {
window.print = function () {
return window.__TAURI_INVOKE__(
'tauri',
{
__tauriModule: 'Window',
message: {
cmd: 'manage',
data: {
cmd: {
type: 'print'
}
return window.__TAURI_INVOKE__('tauri', {
__tauriModule: 'Window',
message: {
cmd: 'manage',
data: {
cmd: {
type: 'print'
}
}
},
_KEY_VALUE_
)
}
})
}
}
})()

View File

@ -0,0 +1,5 @@
// Copyright 2019-2021 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
Object.freeze(Object.prototype)

View File

@ -0,0 +1,26 @@
;(function () {
if (window.location.origin.startsWith(__TEMPLATE_origin__)) {
__RAW_freeze_prototype__
__RAW_pattern_script__
__RAW_ipc_script__
;(function () {
__RAW_bundle_script__
})()
__RAW_core_script__
__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 })
})
}
__RAW_plugin_initialization_script__
}
})()

153
core/tauri/scripts/ipc.js Normal file
View File

@ -0,0 +1,153 @@
// Copyright 2019-2021 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
/**
* @typedef {{callback: string, error: string, data: *}} IsolationPayload - a valid isolation payload
*/
;
(function () {
/**
* @type {string}
*/
const pattern = window.__TAURI_PATTERN__.pattern
/**
* @type {string}
*/
const isolationOrigin = __TEMPLATE_isolation_origin__
/**
* @type {{queue: object[], ready: boolean, frame: HTMLElement | null}}
*/
const isolation = Object.create(null)
isolation.queue = []
isolation.ready = false
isolation.frame = null
/**
* Detects if a message event is a valid isolation message.
*
* @param {MessageEvent<object>} event - a message event that is expected to be an isolation message
* @return {boolean} - if the event was a valid isolation message
*/
function isIsolationMessage(event) {
return (
typeof event.data === 'object' &&
'nonce' in event.data &&
'payload' in event.data
)
}
/**
* Detects if data is able to transform into an isolation payload.
*
* @param {object} data - object that is expected to contain at least a callback and error identifier
* @return {boolean} - if the data is able to transform into an isolation payload
*/
function isIsolationPayload(data) {
return typeof data === 'object' && 'callback' in data && 'error' in data
}
/**
* Sends a properly formatted message to the isolation frame.
*
* @param {IsolationPayload} data - data that has been validated to be an isolation payload
*/
function sendIsolationMessage(data) {
// set the frame dom element if it's not been set before
if (!isolation.frame) {
const frame = document.querySelector('iframe#__tauri_isolation__')
if (frame.src.startsWith(isolationOrigin)) {
isolation.frame = frame
} else {
console.error(
'Tauri IPC found an isolation iframe, but it had the wrong origin'
)
}
}
// ensure we have the target to send the message to
if (!isolation.frame || !isolation.frame.contentWindow) {
console.error(
'Tauri "Isolation" Pattern could not find the Isolation iframe window'
)
return
}
isolation.frame.contentWindow.postMessage(
data,
'*' /* todo: set this to the secure origin */
)
}
Object.defineProperty(window, '__TAURI_IPC__', {
// todo: JSDoc this function
value: Object.freeze((message) => {
switch (pattern) {
case 'brownfield':
window.__TAURI_POST_MESSAGE__(message)
break
case 'isolation':
if (!isIsolationPayload(message)) {
console.error(
'Tauri "Isolation" Pattern found an invalid isolation message payload',
message
)
break
}
if (isolation.ready) {
sendIsolationMessage(message)
} else {
isolation.queue.push(message)
}
break
case 'error':
console.error(
'Tauri IPC found a Tauri Pattern, but it was an error. Check for other log messages to find the cause.'
)
break
default:
console.error(
'Tauri IPC did not find a Tauri Pattern that it understood.'
)
break
}
})
})
/**
* IMPORTANT: See isolation_secure.js for the isolation frame implementation.
* main frame -> isolation frame = isolation payload
* isolation frame -> main frame = isolation message
*/
if (pattern === 'isolation') {
window.addEventListener(
'message',
(event) => {
// watch for the isolation frame being ready and flush any queued messages
if (event.data === '__TAURI_ISOLATION_READY__') {
isolation.ready = true
for (const message of isolation.queue) {
sendIsolationMessage(message)
}
isolation.queue = []
return
}
if (isIsolationMessage(event)) {
window.__TAURI_POST_MESSAGE__(event.data)
}
},
false
)
}
})()

View File

@ -0,0 +1,15 @@
// Copyright 2019-2021 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
window.addEventListener('DOMContentLoaded', () => {
let style = document.createElement('style')
style.textContent = __TEMPLATE_style__
document.head.append(style)
let iframe = document.createElement('iframe')
iframe.id = '__tauri_isolation__'
iframe.sandbox.add('allow-scripts')
iframe.src = __TEMPLATE_isolation_src__
document.body.append(iframe)
})

View File

@ -0,0 +1,21 @@
// Copyright 2019-2021 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
;(function () {
function __tauriDeepFreeze(object) {
const props = Object.getOwnPropertyNames(object)
for (const prop of props) {
if (typeof object[name] === 'object') {
__tauriDeepFreeze(object[name])
}
}
return Object.freeze(object)
}
Object.defineProperty(window, '__TAURI_PATTERN__', {
value: __tauriDeepFreeze(__TEMPLATE_pattern__)
})
})()

View File

@ -47,24 +47,28 @@ impl FileDialogBuilder {
}
/// Add file extension filter. Takes in the name of the filter, and list of extensions
#[must_use]
pub fn add_filter(mut self, name: impl AsRef<str>, extensions: &[&str]) -> Self {
self.0 = self.0.add_filter(name.as_ref(), extensions);
self
}
/// Set starting directory of the dialog.
#[must_use]
pub fn set_directory<P: AsRef<Path>>(mut self, directory: P) -> Self {
self.0 = self.0.set_directory(directory);
self
}
/// Set starting file name of the dialog.
#[must_use]
pub fn set_file_name(mut self, file_name: &str) -> Self {
self.0 = self.0.set_file_name(file_name);
self
}
/// Sets the parent window of the dialog.
#[must_use]
pub fn set_parent<W: raw_window_handle::HasRawWindowHandle>(mut self, parent: &W) -> Self {
self.0 = self.0.set_parent(parent);
self

View File

@ -29,12 +29,14 @@ impl ClientBuilder {
}
/// Sets the maximum number of redirections.
#[must_use]
pub fn max_redirections(mut self, max_redirections: usize) -> Self {
self.max_redirections = Some(max_redirections);
self
}
/// Sets the connection timeout.
#[must_use]
pub fn connect_timeout(mut self, connect_timeout: u64) -> Self {
self.connect_timeout = Some(connect_timeout);
self
@ -294,30 +296,35 @@ impl HttpRequestBuilder {
}
/// Sets the request parameters.
#[must_use]
pub fn query(mut self, query: HashMap<String, String>) -> Self {
self.query = Some(query);
self
}
/// Sets the request headers.
#[must_use]
pub fn headers(mut self, headers: HashMap<String, String>) -> Self {
self.headers = Some(headers);
self
}
/// Sets the request body.
#[must_use]
pub fn body(mut self, body: Body) -> Self {
self.body = Some(body);
self
}
/// Sets the general request timeout.
#[must_use]
pub fn timeout(mut self, timeout: u64) -> Self {
self.timeout = Some(timeout);
self
}
/// Sets the type of the response. Interferes with the way we read the response.
#[must_use]
pub fn response_type(mut self, response_type: ResponseType) -> Self {
self.response_type = Some(response_type);
self

View File

@ -43,18 +43,21 @@ impl Notification {
}
/// Sets the notification body.
#[must_use]
pub fn body(mut self, body: impl Into<String>) -> Self {
self.body = Some(body.into());
self
}
/// Sets the notification title.
#[must_use]
pub fn title(mut self, title: impl Into<String>) -> Self {
self.title = Some(title.into());
self
}
/// Sets the notification icon.
#[must_use]
pub fn icon(mut self, icon: impl Into<String>) -> Self {
self.icon = Some(icon.into());
self

View File

@ -134,8 +134,7 @@ pub fn parse<P: AsRef<Path>>(
let mut p = PathBuf::new();
let mut components = path.as_ref().components();
if let Some(Component::Normal(str)) = components.next() {
if let Some(base_directory) = BaseDirectory::from_variable(&str.to_string_lossy().into_owned())
{
if let Some(base_directory) = BaseDirectory::from_variable(&str.to_string_lossy()) {
p.push(resolve_path(
config,
package_info,

View File

@ -192,6 +192,7 @@ impl Command {
}
/// Appends arguments to the command.
#[must_use]
pub fn args<I, S>(mut self, args: I) -> Self
where
I: IntoIterator<Item = S>,
@ -204,18 +205,21 @@ impl Command {
}
/// Clears the entire environment map for the child process.
#[must_use]
pub fn env_clear(mut self) -> Self {
self.env_clear = true;
self
}
/// Adds or updates multiple environment variable mappings.
#[must_use]
pub fn envs(mut self, env: HashMap<String, String>) -> Self {
self.env = env;
self
}
/// Sets the working directory for the child process.
#[must_use]
pub fn current_dir(mut self, current_dir: PathBuf) -> Self {
self.current_dir.replace(current_dir);
self

View File

@ -36,7 +36,6 @@ impl FromStr for Program {
type Err = super::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
#[allow(clippy::match_str_case_mismatch)]
let p = match s.to_lowercase().as_str() {
"open" => Self::Open,
"start" => Self::Start,

View File

@ -676,7 +676,7 @@ impl<R: Runtime> Builder<R> {
invoke_handler: Box::new(|_| ()),
invoke_responder: Arc::new(window_invoke_responder),
invoke_initialization_script:
"Object.defineProperty(window, '__TAURI_POST_MESSAGE__', { value: (command, args) => window.ipc.notify(JSON.stringify({{ ...args, command }})) })".into(),
"Object.defineProperty(window, '__TAURI_POST_MESSAGE__', { value: (message) => window.ipc.postMessage(JSON.stringify(message)) })".into(),
on_page_load: Box::new(|_, _| ()),
pending_windows: Default::default(),
plugins: PluginStore::default(),
@ -693,6 +693,7 @@ impl<R: Runtime> Builder<R> {
}
/// Defines the JS message handler callback.
#[must_use]
pub fn invoke_handler<F>(mut self, invoke_handler: F) -> Self
where
F: Fn(Invoke<R>) + Send + Sync + 'static,
@ -706,7 +707,7 @@ impl<R: Runtime> Builder<R> {
/// The `responder` is a function that will be called when a command has been executed and must send a response to the JS layer.
///
/// The `initialization_script` is a script that initializes `window.__TAURI_POST_MESSAGE__`.
/// That function must take the `command: string` and `args: object` types and send a message to the backend.
/// That function must take the `message: object` argument and send it to the backend.
pub fn invoke_system<F>(mut self, initialization_script: String, responder: F) -> Self
where
F: Fn(Window<R>, InvokeResponse, CallbackFn, CallbackFn) + Send + Sync + 'static,
@ -717,6 +718,7 @@ impl<R: Runtime> Builder<R> {
}
/// Defines the setup hook.
#[must_use]
pub fn setup<F>(mut self, setup: F) -> Self
where
F: FnOnce(&mut App<R>) -> Result<(), Box<dyn std::error::Error + Send>> + Send + 'static,
@ -726,6 +728,7 @@ impl<R: Runtime> Builder<R> {
}
/// Defines the page load hook.
#[must_use]
pub fn on_page_load<F>(mut self, on_page_load: F) -> Self
where
F: Fn(Window<R>, PageLoadPayload) + Send + Sync + 'static,
@ -735,6 +738,7 @@ impl<R: Runtime> Builder<R> {
}
/// Adds a plugin to the runtime.
#[must_use]
pub fn plugin<P: Plugin<R> + 'static>(mut self, plugin: P) -> Self {
self.plugins.register(plugin);
self
@ -815,6 +819,7 @@ impl<R: Runtime> Builder<R> {
/// .expect("error while running tauri application");
/// }
/// ```
#[must_use]
pub fn manage<T>(self, state: T) -> Self
where
T: Send + Sync + 'static,
@ -829,6 +834,7 @@ impl<R: Runtime> Builder<R> {
}
/// Creates a new webview window.
#[must_use]
pub fn create_window<F>(mut self, label: impl Into<String>, url: WindowUrl, setup: F) -> Self
where
F: FnOnce(
@ -854,18 +860,21 @@ impl<R: Runtime> Builder<R> {
/// Adds the icon configured on `tauri.conf.json` to the system tray with the specified menu items.
#[cfg(feature = "system-tray")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "system-tray")))]
#[must_use]
pub fn system_tray(mut self, system_tray: tray::SystemTray) -> Self {
self.system_tray.replace(system_tray);
self
}
/// Sets the menu to use on all windows.
#[must_use]
pub fn menu(mut self, menu: Menu) -> Self {
self.menu.replace(menu);
self
}
/// Registers a menu event handler for all windows.
#[must_use]
pub fn on_menu_event<F: Fn(WindowMenuEvent<R>) + Send + Sync + 'static>(
mut self,
handler: F,
@ -875,6 +884,7 @@ impl<R: Runtime> Builder<R> {
}
/// Registers a window event handler for all windows.
#[must_use]
pub fn on_window_event<F: Fn(GlobalWindowEvent<R>) + Send + Sync + 'static>(
mut self,
handler: F,
@ -886,6 +896,7 @@ impl<R: Runtime> Builder<R> {
/// Registers a system tray event handler.
#[cfg(feature = "system-tray")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "system-tray")))]
#[must_use]
pub fn on_system_tray_event<
F: Fn(&AppHandle<R>, tray::SystemTrayEvent) + Send + Sync + 'static,
>(
@ -905,6 +916,7 @@ impl<R: Runtime> Builder<R> {
///
/// * `uri_scheme` The URI scheme to register, such as `example`.
/// * `protocol` the protocol associated with the given URI scheme. It's a function that takes an URL such as `example://localhost/asset.css`.
#[must_use]
pub fn register_uri_scheme_protocol<
N: Into<String>,
H: Fn(&AppHandle<R>, &HttpRequest) -> Result<HttpResponse, Box<dyn std::error::Error>>
@ -1245,16 +1257,16 @@ impl Default for Builder<crate::Wry> {
mod tests {
#[test]
fn is_send_sync() {
crate::test::assert_send::<super::AppHandle>();
crate::test::assert_sync::<super::AppHandle>();
crate::test_utils::assert_send::<super::AppHandle>();
crate::test_utils::assert_sync::<super::AppHandle>();
#[cfg(feature = "wry")]
{
crate::test::assert_send::<super::AssetResolver<crate::Wry>>();
crate::test::assert_sync::<super::AssetResolver<crate::Wry>>();
crate::test_utils::assert_send::<super::AssetResolver<crate::Wry>>();
crate::test_utils::assert_sync::<super::AssetResolver<crate::Wry>>();
}
crate::test::assert_send::<super::PathResolver>();
crate::test::assert_sync::<super::PathResolver>();
crate::test_utils::assert_send::<super::PathResolver>();
crate::test_utils::assert_sync::<super::PathResolver>();
}
}

View File

@ -279,6 +279,7 @@ where
runtime.spawn_blocking(func)
}
#[allow(dead_code)]
pub(crate) fn safe_block_on<F>(task: F) -> F::Output
where
F: Future + Send + 'static,

View File

@ -19,7 +19,7 @@ impl Cmd {
#[module_command_handler(cli, "CLI definition not set under tauri.conf.json > tauri > cli (https://tauri.studio/docs/api/config#tauri.cli)")]
fn cli_matches<R: Runtime>(context: InvokeContext<R>) -> crate::Result<InvokeResponse> {
if let Some(cli) = &context.config.tauri.cli {
crate::api::cli::get_matches(cli, context.package_info)
crate::api::cli::get_matches(cli, &context.package_info)
.map(Into::into)
.map_err(Into::into)
} else {

View File

@ -15,6 +15,7 @@ use serde::{
};
use tauri_macros::{module_command_handler, CommandModule};
use std::fmt::{Debug, Formatter};
use std::{
fs,
fs::File,
@ -334,8 +335,21 @@ fn resolve_path<R: Runtime>(
#[cfg(test)]
mod tests {
use super::{BaseDirectory, DirOperationOptions, FileOperationOptions, SafePathBuf};
use quickcheck::{Arbitrary, Gen};
use std::path::PathBuf;
impl Arbitrary for super::SafePathBuf {
fn arbitrary(g: &mut Gen) -> Self {
Self(PathBuf::arbitrary(g))
}
fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
Box::new(self.0.shrink().map(SafePathBuf))
}
}
impl Arbitrary for BaseDirectory {
fn arbitrary(g: &mut Gen) -> Self {
if bool::arbitrary(g) {
@ -363,12 +377,6 @@ mod tests {
}
}
impl Arbitrary for SafePathBuf {
fn arbitrary(g: &mut Gen) -> Self {
SafePathBuf(std::path::PathBuf::arbitrary(g))
}
}
#[tauri_macros::module_command_test(fs_read_file, "fs > readFile")]
#[quickcheck_macros::quickcheck]
fn read_file(path: SafePathBuf, options: Option<FileOperationOptions>) {

View File

@ -96,6 +96,10 @@ pub enum Error {
/// Program not allowed by the scope.
#[error("program not allowed on the configured shell scope: {0}")]
ProgramNotAllowed(PathBuf),
/// An error happened inside the isolation pattern.
#[cfg(feature = "isolation")]
#[error("isolation pattern error: {0}")]
IsolationPattern(#[from] tauri_utils::pattern::isolation::Error),
}
impl From<serde_json::Error> for Error {

View File

@ -10,6 +10,7 @@ use crate::{
};
use serde::{Deserialize, Serialize};
use serde_json::Value as JsonValue;
use serialize_to_javascript::{default_template, Template};
use std::{future::Future, sync::Arc};
use tauri_macros::default_runtime;
@ -28,6 +29,21 @@ pub type InvokeResponder<R> =
/// A closure that is run once every time a window is created and loaded.
pub type OnPageLoad<R> = dyn Fn(Window<R>, PageLoadPayload) + Send + Sync + 'static;
// todo: why is this derive broken but the output works manually?
#[derive(Template)]
#[default_template("../scripts/ipc.js")]
pub(crate) struct IpcJavascript<'a> {
pub(crate) isolation_origin: &'a str,
}
#[cfg(feature = "isolation")]
#[derive(Template)]
#[default_template("../scripts/isolation.js")]
pub(crate) struct IsolationJavascript<'a> {
pub(crate) isolation_src: &'a str,
pub(crate) style: &'a str,
}
/// The payload for the [`OnPageLoad`] hook.
#[derive(Debug, Clone, Deserialize)]
pub struct PageLoadPayload {
@ -45,7 +61,7 @@ impl PageLoadPayload {
#[derive(Debug, Deserialize)]
pub struct InvokePayload {
/// The invoke command.
pub command: String,
pub cmd: String,
#[serde(rename = "__tauriModule")]
#[doc(hidden)]
pub tauri_module: Option<String>,
@ -53,9 +69,6 @@ pub struct InvokePayload {
pub callback: CallbackFn,
/// The error callback.
pub error: CallbackFn,
/// The invoke key.
#[serde(rename = "__invokeKey")]
pub key: u32,
/// The payload of the message.
#[serde(flatten)]
pub inner: JsonValue,

View File

@ -11,6 +11,7 @@
//! The following are a list of [Cargo features](https://doc.rust-lang.org/stable/cargo/reference/manifest.html#the-features-section) that can be enabled or disabled:
//!
//! - **wry** *(enabled by default)*: Enables the [wry](https://github.com/tauri-apps/wry) runtime. Only disable it if you want a custom runtime.
//! - **isolation**: Enables the isolation pattern. Enabled by default if the `tauri > pattern > use` config option is set to `isolation` on the `tauri.conf.json` file.
//! - **custom-protocol**: Feature managed by the Tauri CLI. When enabled, Tauri assumes a production environment instead of a development one.
//! - **updater**: Enables the application auto updater. Enabled by default if the `updater` config is defined on the `tauri.conf.json` file.
//! - **http-api**: Enables the [`api::http`] module.
@ -144,6 +145,7 @@ mod error;
mod event;
mod hooks;
mod manager;
mod pattern;
pub mod plugin;
pub mod window;
pub use tauri_runtime as runtime;
@ -255,6 +257,8 @@ macro_rules! tauri_build_context {
};
}
pub use pattern::Pattern;
/// User supplied data required inside of a Tauri application.
///
/// # Stability
@ -267,6 +271,7 @@ pub struct Context<A: Assets> {
pub(crate) system_tray_icon: Option<Icon>,
pub(crate) package_info: PackageInfo,
pub(crate) _info_plist: (),
pub(crate) pattern: Pattern,
}
impl<A: Assets> fmt::Debug for Context<A> {
@ -276,6 +281,7 @@ impl<A: Assets> fmt::Debug for Context<A> {
.field("default_window_icon", &self.default_window_icon)
.field("system_tray_icon", &self.system_tray_icon)
.field("package_info", &self.package_info)
.field("pattern", &self.pattern)
.finish()
}
}
@ -341,6 +347,12 @@ impl<A: Assets> Context<A> {
&mut self.package_info
}
/// The application pattern.
#[inline(always)]
pub fn pattern(&self) -> &Pattern {
&self.pattern
}
/// Create a new [`Context`] from the minimal required items.
#[inline(always)]
pub fn new(
@ -350,6 +362,7 @@ impl<A: Assets> Context<A> {
system_tray_icon: Option<Icon>,
package_info: PackageInfo,
info_plist: (),
pattern: Pattern,
) -> Self {
Self {
config,
@ -358,6 +371,7 @@ impl<A: Assets> Context<A> {
system_tray_icon,
package_info,
_info_plist: info_plist,
pattern,
}
}
}
@ -503,7 +517,7 @@ pub(crate) mod sealed {
pub mod test;
#[cfg(test)]
mod tests {
mod test_utils {
use proptest::prelude::*;
pub fn assert_send<T: Send>() {}

View File

@ -2,6 +2,35 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
use std::{
borrow::Cow,
collections::{HashMap, HashSet},
fmt,
fs::create_dir_all,
sync::{Arc, Mutex, MutexGuard},
};
use regex::{Captures, Regex};
use serde::Serialize;
use serde_json::Value as JsonValue;
use serialize_to_javascript::{default_template, DefaultTemplate, Template};
use url::Url;
use tauri_macros::default_runtime;
#[cfg(feature = "isolation")]
use tauri_utils::pattern::isolation::RawIsolationPayload;
use tauri_utils::{
assets::{AssetKey, CspHash},
html::{inject_csp, parse as parse_html, SCRIPT_NONCE_TOKEN, STYLE_NONCE_TOKEN},
};
#[cfg(target_os = "windows")]
use crate::api::path::{resolve_path, BaseDirectory};
use crate::app::{GlobalMenuEventListener, WindowMenuEvent};
use crate::hooks::IpcJavascript;
#[cfg(feature = "isolation")]
use crate::hooks::IsolationJavascript;
use crate::pattern::{format_real_schema, PatternJavascript};
use crate::{
app::{AppHandle, GlobalWindowEvent, GlobalWindowEventListener},
event::{is_event_name_valid, Event, EventHandler, Listeners},
@ -21,36 +50,14 @@ use crate::{
config::{AppUrl, Config, WindowUrl},
PackageInfo,
},
Context, Invoke, StateManager, Window,
Context, Invoke, Pattern, StateManager, Window,
};
#[cfg(any(target_os = "linux", target_os = "windows"))]
use crate::api::path::{resolve_path, BaseDirectory};
use crate::app::{GlobalMenuEventListener, WindowMenuEvent};
use crate::{runtime::menu::Menu, MenuEvent};
use regex::{Captures, Regex};
use serde::Serialize;
use serde_json::Value as JsonValue;
use std::{
borrow::Cow,
collections::{HashMap, HashSet},
fmt,
fs::create_dir_all,
sync::{Arc, Mutex, MutexGuard},
};
use tauri_macros::default_runtime;
use tauri_utils::{
assets::{AssetKey, CspHash},
html::{
inject_csp, parse as parse_html, CSP_TOKEN, INVOKE_KEY_TOKEN, SCRIPT_NONCE_TOKEN,
STYLE_NONCE_TOKEN,
},
};
use url::Url;
const WINDOW_RESIZED_EVENT: &str = "tauri://resize";
const WINDOW_MOVED_EVENT: &str = "tauri://move";
const WINDOW_CLOSE_REQUESTED_EVENT: &str = "tauri://close-requested";
@ -67,6 +74,71 @@ struct CspHashStrings {
style: String,
}
/// Sets the CSP value to the asset HTML if needed (on Linux).
/// Returns the CSP string for access on the response header (on Windows and macOS).
fn set_csp<R: Runtime>(
asset: &mut String,
assets: Arc<dyn Assets>,
asset_path: &AssetKey,
#[allow(unused_variables)] manager: &WindowManager<R>,
mut csp: String,
) -> String {
let hash_strings =
assets
.csp_hashes(asset_path)
.fold(CspHashStrings::default(), |mut acc, hash| {
match hash {
CspHash::Script(hash) => {
acc.script.push(' ');
acc.script.push_str(hash);
}
CspHash::Style(hash) => {
acc.style.push(' ');
acc.style.push_str(hash);
}
_csp_hash => {
#[cfg(debug_assertions)]
eprintln!("Unknown CspHash variant encountered: {:?}", _csp_hash)
}
}
acc
});
replace_csp_nonce(
asset,
SCRIPT_NONCE_TOKEN,
&mut csp,
"script-src",
hash_strings.script,
);
replace_csp_nonce(
asset,
STYLE_NONCE_TOKEN,
&mut csp,
"style-src",
hash_strings.style,
);
#[cfg(feature = "isolation")]
if let Pattern::Isolation { schema, .. } = &manager.inner.pattern {
let default_src = format!("default-src {}", format_real_schema(schema));
if csp.contains("default-src") {
csp = csp.replace("default-src", &default_src);
} else {
csp.push_str("; ");
csp.push_str(&default_src);
}
}
#[cfg(target_os = "linux")]
{
*asset = asset.replacen(tauri_utils::html::CSP_TOKEN, &csp, 1);
}
csp
}
fn replace_csp_nonce(
asset: &mut String,
token: &str,
@ -141,6 +213,8 @@ pub struct InnerWindowManager<R: Runtime> {
invoke_responder: Arc<InvokeResponder<R>>,
/// The script that initializes the invoke system.
invoke_initialization_script: String,
/// Application pattern.
pattern: Pattern,
}
impl<R: Runtime> fmt::Debug for InnerWindowManager<R> {
@ -152,6 +226,7 @@ impl<R: Runtime> fmt::Debug for InnerWindowManager<R> {
.field("default_window_icon", &self.default_window_icon)
.field("package_info", &self.package_info)
.field("menu", &self.menu)
.field("pattern", &self.pattern)
.finish()
}
}
@ -181,14 +256,12 @@ pub struct CustomProtocol<R: Runtime> {
#[derive(Debug)]
pub struct WindowManager<R: Runtime> {
pub inner: Arc<InnerWindowManager<R>>,
invoke_keys: Arc<Mutex<Vec<u32>>>,
}
impl<R: Runtime> Clone for WindowManager<R> {
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
invoke_keys: self.invoke_keys.clone(),
}
}
}
@ -196,7 +269,7 @@ impl<R: Runtime> Clone for WindowManager<R> {
impl<R: Runtime> WindowManager<R> {
#[allow(clippy::too_many_arguments)]
pub(crate) fn with_handlers(
context: Context<impl Assets>,
#[allow(unused_mut)] mut context: Context<impl Assets>,
plugins: PluginStore<R>,
invoke_handler: Box<InvokeHandler<R>>,
on_page_load: Box<OnPageLoad<R>>,
@ -206,6 +279,12 @@ impl<R: Runtime> WindowManager<R> {
(menu, menu_event_listeners): (Option<Menu>, Vec<GlobalMenuEventListener<R>>),
(invoke_responder, invoke_initialization_script): (Arc<InvokeResponder<R>>, String),
) -> Self {
// generate a random isolation key at runtime
#[cfg(feature = "isolation")]
if let Pattern::Isolation { ref mut key, .. } = &mut context.pattern {
*key = uuid::Uuid::new_v4().to_string();
}
Self {
inner: Arc::new(InnerWindowManager {
windows: Mutex::default(),
@ -218,6 +297,7 @@ impl<R: Runtime> WindowManager<R> {
assets: context.assets,
default_window_icon: context.default_window_icon,
package_info: context.package_info,
pattern: context.pattern,
uri_scheme_protocols,
menu,
menu_event_listeners: Arc::new(menu_event_listeners),
@ -225,10 +305,13 @@ impl<R: Runtime> WindowManager<R> {
invoke_responder,
invoke_initialization_script,
}),
invoke_keys: Default::default(),
}
}
pub(crate) fn pattern(&self) -> &Pattern {
&self.inner.pattern
}
/// Get a locked handle to the windows.
pub(crate) fn windows_lock(&self) -> MutexGuard<'_, HashMap<String, Window<R>>> {
self.inner.windows.lock().expect("poisoned window manager")
@ -268,10 +351,18 @@ impl<R: Runtime> WindowManager<R> {
}
}
fn generate_invoke_key(&self) -> u32 {
let key = rand::random();
self.invoke_keys.lock().unwrap().push(key);
key
/// Get the origin as it will be seen in the webview.
fn get_browser_origin(&self) -> Cow<'_, str> {
match self.base_path() {
AppUrl::Url(WindowUrl::External(url)) => {
let mut url = url.to_string();
if url.ends_with('/') {
url.pop();
}
Cow::Owned(url)
}
_ => Cow::Owned(format_real_schema("tauri")),
}
}
fn csp(&self) -> Option<String> {
@ -289,13 +380,6 @@ impl<R: Runtime> WindowManager<R> {
}
}
/// Checks whether the invoke key is valid or not.
///
/// An invoke key is valid if it was generated by this manager instance.
pub(crate) fn verify_invoke_key(&self, key: u32) -> bool {
self.invoke_keys.lock().unwrap().contains(&key)
}
fn prepare_pending_window(
&self,
mut pending: PendingWindow<R>,
@ -311,39 +395,48 @@ impl<R: Runtime> WindowManager<R> {
.expect("poisoned plugin store")
.initialization_script();
let mut webview_attributes = pending.webview_attributes;
webview_attributes =
webview_attributes.initialization_script(&self.inner.invoke_initialization_script);
if is_init_global {
webview_attributes = webview_attributes.initialization_script(&format!(
"(function () {{
const __TAURI_INVOKE_KEY__ = {key};
{bundle_script}
}})()",
key = self.generate_invoke_key(),
bundle_script = include_str!("../scripts/bundle.js"),
));
let pattern_init = PatternJavascript {
pattern: self.pattern().into(),
}
.render_default(&Default::default())?;
let ipc_init = IpcJavascript {
isolation_origin: &match self.pattern() {
#[cfg(feature = "isolation")]
Pattern::Isolation { schema, .. } => crate::pattern::format_real_schema(schema),
_ => "".to_string(),
},
}
.render_default(&Default::default())?;
let mut webview_attributes = pending.webview_attributes;
webview_attributes = webview_attributes
.initialization_script(&self.inner.invoke_initialization_script)
.initialization_script(&self.initialization_script(&ipc_init,&pattern_init,&plugin_init, is_init_global)?)
.initialization_script(&format!(
r#"
if (!window.__TAURI__) {{
window.__TAURI__ = {{}}
Object.defineProperty(window, '__TAURI__', {{
value: {{}}
}})
}}
window.__TAURI__.__windows = {window_labels_array}.map(function (label) {{ return {{ label: label }} }});
window.__TAURI__.__currentWindow = {{ label: {current_window_label} }}
"#,
window_labels_array = serde_json::to_string(pending_labels)?,
current_window_label = serde_json::to_string(&label)?,
))
.initialization_script(&self.initialization_script(&plugin_init));
#[cfg(dev)]
{
webview_attributes = webview_attributes.initialization_script(&format!(
"window.__TAURI_INVOKE_KEY__ = {}",
self.generate_invoke_key()
));
#[cfg(feature = "isolation")]
if let Pattern::Isolation { schema, .. } = self.pattern() {
webview_attributes = webview_attributes.initialization_script(
&IsolationJavascript {
isolation_src: &crate::pattern::format_real_schema(schema),
style: tauri_utils::pattern::isolation::IFRAME_STYLE,
}
.render_default(&Default::default())?,
);
}
pending.webview_attributes = webview_attributes;
@ -492,14 +585,76 @@ impl<R: Runtime> WindowManager<R> {
});
}
#[cfg(feature = "isolation")]
if let Pattern::Isolation {
assets,
schema,
key: _,
crypto_keys,
} = &self.inner.pattern
{
let assets = assets.clone();
let schema_ = schema.clone();
let url_base = format!("{}://localhost", schema_);
let aes_gcm_key = *crypto_keys.aes_gcm().raw();
pending.register_uri_scheme_protocol(schema, move |request| {
match request_to_path(request, &url_base).as_str() {
"index.html" => match assets.get(&"index.html".into()) {
Some(asset) => {
let asset = String::from_utf8_lossy(asset.as_ref());
let template = tauri_utils::pattern::isolation::IsolationJavascriptRuntime {
runtime_aes_gcm_key: &aes_gcm_key,
};
match template.render(asset.as_ref(), &Default::default()) {
Ok(asset) => HttpResponseBuilder::new()
.mimetype("text/html")
.body(asset.as_bytes().to_vec()),
Err(_) => HttpResponseBuilder::new()
.status(500)
.mimetype("text/plain")
.body(Vec::new()),
}
}
None => HttpResponseBuilder::new()
.status(404)
.mimetype("text/plain")
.body(Vec::new()),
},
_ => HttpResponseBuilder::new()
.status(404)
.mimetype("text/plain")
.body(Vec::new()),
}
});
}
Ok(pending)
}
fn prepare_ipc_handler(&self, app_handle: AppHandle<R>) -> WebviewIpcHandler<R> {
let manager = self.clone();
Box::new(move |window, request| {
Box::new(move |window, #[allow(unused_mut)] mut request| {
let window = Window::new(manager.clone(), window, app_handle.clone());
#[cfg(feature = "isolation")]
if let Pattern::Isolation { crypto_keys, .. } = manager.pattern() {
match RawIsolationPayload::try_from(request.as_str())
.and_then(|raw| crypto_keys.decrypt(raw))
{
Ok(json) => request = json,
Err(e) => {
let error: crate::Error = e.into();
let _ = window.eval(&format!(
r#"console.error({})"#,
JsonValue::String(error.to_string())
));
return;
}
}
}
match serde_json::from_str::<InvokePayload>(&request) {
Ok(message) => {
let _ = window.on_message(message);
@ -530,7 +685,6 @@ impl<R: Runtime> WindowManager<R> {
// skip leading `/`
path.chars().skip(1).collect::<String>()
};
let is_javascript = path.ends_with(".js") || path.ends_with(".cjs") || path.ends_with(".mjs");
let is_html = path.ends_with(".html");
let mut asset_path = AssetKey::from(path.as_str());
@ -558,48 +712,16 @@ impl<R: Runtime> WindowManager<R> {
match asset_response {
Ok(asset) => {
let final_data = if is_javascript || is_html {
let final_data = if is_html {
let mut asset = String::from_utf8_lossy(&asset).into_owned();
asset = asset.replacen(INVOKE_KEY_TOKEN, &self.generate_invoke_key().to_string(), 1);
if is_html {
if let Some(mut csp) = self.csp() {
let hash_strings = self.inner.assets.csp_hashes(&asset_path).fold(
CspHashStrings::default(),
|mut acc, hash| {
match hash {
CspHash::Script(hash) => {
acc.script.push(' ');
acc.script.push_str(hash);
}
csp_hash => {
#[cfg(debug_assertions)]
eprintln!("Unknown CspHash variant encountered: {:?}", csp_hash)
}
}
acc
},
);
replace_csp_nonce(
&mut asset,
SCRIPT_NONCE_TOKEN,
&mut csp,
"script-src",
hash_strings.script,
);
replace_csp_nonce(
&mut asset,
STYLE_NONCE_TOKEN,
&mut csp,
"style-src",
hash_strings.style,
);
asset = asset.replace(CSP_TOKEN, &csp);
csp_header.replace(csp);
}
if let Some(csp) = self.csp() {
csp_header.replace(set_csp(
&mut asset,
self.inner.assets.clone(),
&asset_path,
&self,
csp,
));
}
asset.as_bytes().to_vec()
@ -659,26 +781,57 @@ impl<R: Runtime> WindowManager<R> {
})
}
fn initialization_script(&self, plugin_initialization_script: &str) -> String {
let key = self.generate_invoke_key();
format!(
r#"
{core_script}
{event_initialization_script}
if (document.readyState === 'complete') {{
window.__TAURI_INVOKE__("__initialized", {{ url: window.location.href }}, {key})
}} else {{
window.addEventListener('DOMContentLoaded', function () {{
window.__TAURI_INVOKE__("__initialized", {{ url: window.location.href }}, {key})
}})
}}
{plugin_initialization_script}
"#,
key = key,
core_script = include_str!("../scripts/core.js").replace("_KEY_VALUE_", &key.to_string()),
event_initialization_script = self.event_initialization_script(),
plugin_initialization_script = plugin_initialization_script
)
fn initialization_script(
&self,
ipc_script: &str,
pattern_script: &str,
plugin_initialization_script: &str,
with_global_tauri: bool,
) -> crate::Result<String> {
#[derive(Template)]
#[default_template("../scripts/init.js")]
struct InitJavascript<'a> {
origin: Cow<'a, str>,
#[raw]
pattern_script: &'a str,
#[raw]
ipc_script: &'a str,
#[raw]
bundle_script: &'a str,
#[raw]
core_script: &'a str,
#[raw]
event_initialization_script: &'a str,
#[raw]
plugin_initialization_script: &'a str,
#[raw]
freeze_prototype: &'a str,
}
let bundle_script = if with_global_tauri {
include_str!("../scripts/bundle.js")
} else {
""
};
let freeze_prototype = if self.inner.config.tauri.security.freeze_prototype {
include_str!("../scripts/freeze_prototype.js")
} else {
""
};
InitJavascript {
origin: self.get_browser_origin(),
pattern_script,
ipc_script,
bundle_script,
core_script: include_str!("../scripts/core.js"),
event_initialization_script: &self.event_initialization_script(),
plugin_initialization_script,
freeze_prototype,
}
.render_default(&Default::default())
.map_err(Into::into)
}
fn event_initialization_script(&self) -> String {
@ -702,9 +855,10 @@ impl<R: Runtime> WindowManager<R> {
#[cfg(test)]
mod test {
use super::WindowManager;
use crate::{generate_context, plugin::PluginStore, StateManager, Wry};
use super::WindowManager;
#[test]
fn check_get_url() {
let context = generate_context!("test/fixture/src-tauri/tauri.conf.json", crate);
@ -1029,3 +1183,31 @@ struct ScaleFactorChanged {
fn on_menu_event<R: Runtime>(window: &Window<R>, event: &MenuEvent) -> crate::Result<()> {
window.emit_and_trigger(MENU_EVENT, event.menu_item_id.clone())
}
#[cfg(feature = "isolation")]
fn request_to_path(request: &tauri_runtime::http::Request, replace: &str) -> String {
let mut path = request
.uri()
.split(&['?', '#'][..])
// ignore query string
.next()
.unwrap()
.to_string()
.replace(replace, "");
if path.ends_with('/') {
path.pop();
}
let path = percent_encoding::percent_decode(path.as_bytes())
.decode_utf8_lossy()
.to_string();
if path.is_empty() {
// if the url has no path, we should load `index.html`
"index.html".to_string()
} else {
// skip leading `/`
path.chars().skip(1).collect()
}
}

94
core/tauri/src/pattern.rs Normal file
View File

@ -0,0 +1,94 @@
// Copyright 2019-2021 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
use std::marker::PhantomData;
#[cfg(feature = "isolation")]
use std::sync::Arc;
use serde::Serialize;
use serialize_to_javascript::{default_template, Template};
use tauri_utils::assets::{Assets, EmbeddedAssets};
/// An application pattern.
#[derive(Debug, Clone)]
pub enum Pattern<A: Assets = EmbeddedAssets> {
/// The brownfield pattern.
Brownfield(PhantomData<A>),
/// Isolation pattern. Recommended for security purposes.
#[cfg(feature = "isolation")]
Isolation {
/// The HTML served on `isolation://index.html`.
assets: Arc<A>,
/// The schema used for the isolation frames.
schema: String,
/// A random string used to ensure that the message went through the isolation frame.
///
/// This should be regenerated at runtime.
key: String,
/// Cryptographically secure keys
crypto_keys: Box<tauri_utils::pattern::isolation::Keys>,
},
}
/// The shape of the JavaScript Pattern config
#[derive(Debug, Serialize)]
#[serde(rename_all = "lowercase", tag = "pattern")]
pub(crate) enum PatternObject {
/// Brownfield pattern.
Brownfield,
/// Isolation pattern. Recommended for security purposes.
#[cfg(feature = "isolation")]
Isolation {
/// Which `IsolationSide` this `PatternObject` is getting injected into
side: IsolationSide,
},
}
impl From<&Pattern> for PatternObject {
fn from(pattern: &Pattern) -> Self {
match pattern {
Pattern::Brownfield(_) => Self::Brownfield,
#[cfg(feature = "isolation")]
Pattern::Isolation { .. } => Self::Isolation {
side: IsolationSide::default(),
},
}
}
}
/// Where the JavaScript is injected to
#[derive(Debug, Serialize)]
#[serde(rename_all = "lowercase")]
pub(crate) enum IsolationSide {
/// Original frame, the Brownfield application
Original,
/// Secure frame, the isolation security application
#[allow(dead_code)]
Secure,
}
impl Default for IsolationSide {
fn default() -> Self {
Self::Original
}
}
#[derive(Template)]
#[default_template("../scripts/pattern.js")]
pub(crate) struct PatternJavascript {
pub(crate) pattern: PatternObject,
}
#[allow(dead_code)]
pub(crate) fn format_real_schema(schema: &str) -> String {
if cfg!(windows) {
format!("https://{}.localhost", schema)
} else {
format!("{}://localhost", schema)
}
}

View File

@ -12,14 +12,17 @@ use tauri_runtime::{
dpi::{PhysicalPosition, PhysicalSize, Position, Size},
DetachedWindow, MenuEvent, PendingWindow, WindowEvent,
},
ActivationPolicy, ClipboardManager, Dispatch, GlobalShortcutManager, Icon, Result, RunEvent,
RunIteration, Runtime, RuntimeHandle, UserAttentionType,
ClipboardManager, Dispatch, GlobalShortcutManager, Icon, Result, RunEvent, Runtime,
RuntimeHandle, UserAttentionType,
};
#[cfg(feature = "system-tray")]
use tauri_runtime::{SystemTray, SystemTrayEvent};
use tauri_utils::config::WindowConfig;
use uuid::Uuid;
#[cfg(windows)]
use webview2_com::Windows::Win32::Foundation::HWND;
use std::{
collections::HashMap,
fmt,
@ -60,6 +63,7 @@ impl RuntimeHandle for MockRuntimeHandle {
context: self.context.clone(),
},
menu_ids: Default::default(),
js_event_listeners: Default::default(),
})
}
@ -534,6 +538,7 @@ impl Runtime for MockRuntime {
context: self.context.clone(),
},
menu_ids: Default::default(),
js_event_listeners: Default::default(),
})
}
@ -551,10 +556,13 @@ impl Runtime for MockRuntime {
#[cfg(target_os = "macos")]
#[cfg_attr(doc_cfg, doc(cfg(target_os = "macos")))]
fn set_activation_policy(&mut self, activation_policy: ActivationPolicy) {}
fn set_activation_policy(&mut self, activation_policy: tauri_runtime::ActivationPolicy) {}
#[cfg(any(target_os = "windows", target_os = "macos"))]
fn run_iteration<F: Fn(RunEvent) + 'static>(&mut self, callback: F) -> RunIteration {
fn run_iteration<F: Fn(RunEvent) + 'static>(
&mut self,
callback: F,
) -> tauri_runtime::RunIteration {
Default::default()
}

View File

@ -9,10 +9,10 @@ pub use mock_runtime::*;
use std::{borrow::Cow, sync::Arc};
use crate::Manager;
use crate::{Manager, Pattern};
use tauri_utils::{
assets::{AssetKey, Assets, CspHash},
config::{CliConfig, Config, TauriConfig},
config::{CliConfig, Config, PatternKind, TauriConfig},
};
pub struct NoopAsset {
@ -40,6 +40,7 @@ pub fn mock_context<A: Assets>(assets: A) -> crate::Context<A> {
config: Config {
package: Default::default(),
tauri: TauriConfig {
pattern: PatternKind::Brownfield,
windows: vec![Default::default()],
cli: Some(CliConfig {
description: None,
@ -65,8 +66,11 @@ pub fn mock_context<A: Assets>(assets: A) -> crate::Context<A> {
package_info: crate::PackageInfo {
name: "test".into(),
version: "0.1.0".into(),
authors: "Tauri".into(),
description: "Tauri test".into(),
},
_info_plist: (),
pattern: Pattern::Brownfield(std::marker::PhantomData),
}
}

View File

@ -11,8 +11,7 @@ use crate::api::{
use base64::decode;
use http::StatusCode;
use minisign_verify::{PublicKey, Signature};
use tauri_utils::platform::current_exe;
use tauri_utils::Env;
use tauri_utils::{platform::current_exe, Env};
use std::{
collections::HashMap,
@ -552,7 +551,7 @@ fn copy_files_and_run<R: Read + Seek>(
let mut extractor = Extract::from_cursor(archive_buffer, ArchiveFormat::Zip);
// extract the msi
extractor.extract_into(&tmp_dir);
extractor.extract_into(&tmp_dir)?;
let paths = read_dir(&tmp_dir)?;
// This consumes the TempDir without deleting directory on the filesystem,
@ -648,7 +647,7 @@ fn copy_files_and_run<R: Read + Seek>(archive_buffer: R, extract_path: &Path) ->
.tempdir()?;
// create backup of our current app
Move::from_source(extract_path).to_dest(&tmp_dir.path())?;
Move::from_source(extract_path).to_dest(tmp_dir.path())?;
// extract all the files
for file in all_files {
@ -666,7 +665,7 @@ fn copy_files_and_run<R: Read + Seek>(archive_buffer: R, extract_path: &Path) ->
std::fs::remove_file(file)?;
}
}
Move::from_source(&tmp_dir.path()).to_dest(extract_path)?;
Move::from_source(tmp_dir.path()).to_dest(extract_path)?;
return Err(Error::Extract(err.to_string()));
}
@ -776,7 +775,7 @@ where
mod test {
use super::*;
#[cfg(target_os = "macos")]
use std::{env, fs::File};
use std::fs::File;
macro_rules! block {
($e:expr) => {

View File

@ -226,7 +226,7 @@ impl<R: Runtime> Window<R> {
/// How to handle this window receiving an [`InvokeMessage`].
pub fn on_message(self, payload: InvokePayload) -> crate::Result<()> {
let manager = self.manager.clone();
match payload.command.as_str() {
match payload.cmd.as_str() {
"__initialized" => {
let payload: PageLoadPayload = serde_json::from_value(payload.inner)?;
manager.run_on_page_load(self, payload);
@ -235,25 +235,19 @@ impl<R: Runtime> Window<R> {
let message = InvokeMessage::new(
self.clone(),
manager.state(),
payload.command.to_string(),
payload.cmd.to_string(),
payload.inner,
);
let resolver = InvokeResolver::new(self, payload.callback, payload.error);
let invoke = Invoke { message, resolver };
if manager.verify_invoke_key(payload.key) {
if let Some(module) = &payload.tauri_module {
let module = module.to_string();
crate::endpoints::handle(module, invoke, manager.config(), manager.package_info());
} else if payload.command.starts_with("plugin:") {
manager.extend_api(invoke);
} else {
manager.run_invoke_handler(invoke);
}
if let Some(module) = &payload.tauri_module {
let module = module.to_string();
crate::endpoints::handle(module, invoke, manager.config(), manager.package_info());
} else if payload.cmd.starts_with("plugin:") {
manager.extend_api(invoke);
} else {
panic!(
r#"The invoke key "{}" is invalid. This means that an external, possible malicious script is trying to access the system interface."#,
payload.key
);
manager.run_invoke_handler(invoke);
}
}
}
@ -718,7 +712,7 @@ impl<R: Runtime> Window<R> {
mod tests {
#[test]
fn window_is_send_sync() {
crate::test::assert_send::<super::Window>();
crate::test::assert_sync::<super::Window>();
crate::test_utils::assert_send::<super::Window>();
crate::test_utils::assert_sync::<super::Window>();
}
}

View File

@ -107,7 +107,7 @@ fn create_symlink(original: &Path, link: PathBuf) -> io::Result<Symlink> {
Ok(()) => Ok(Symlink::Created(link)),
Err(e) => match e.raw_os_error() {
Some(ERROR_PRIVILEGE_NOT_HELD) => Ok(Symlink::Privilege),
_ => Err(e.into()),
_ => Err(e),
},
};
}

View File

@ -34,9 +34,9 @@ dependencies = [
[[package]]
name = "anyhow"
version = "1.0.44"
version = "1.0.51"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61604a8f862e1d5c3229fdd78f8b02c68dcf73a4c4b05fd636d12240aaa242c1"
checksum = "8b26702f315f53b6071259e15dd9d64528213b44d61de1ec926eca7715d62203"
[[package]]
name = "arrayref"
@ -103,9 +103,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "blake3"
version = "1.1.0"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2607a74355ce2e252d0c483b2d8a348e1bba36036e786ccc2dcd777213c86ffd"
checksum = "526c210b4520e416420759af363083471656e819a75e831b8d2c9d5a584f2413"
dependencies = [
"arrayref",
"arrayvec",
@ -199,9 +199,9 @@ dependencies = [
[[package]]
name = "cc"
version = "1.0.71"
version = "1.0.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79c2681d6594606957bbb8631c4b90a7fcaaa72cdb714743a437b156d6a7eedd"
checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee"
dependencies = [
"jobserver",
]
@ -252,18 +252,6 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e"
[[package]]
name = "chrono"
version = "0.4.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
dependencies = [
"libc",
"num-integer",
"num-traits",
"winapi",
]
[[package]]
name = "cocoa"
version = "0.24.0"
@ -295,12 +283,6 @@ dependencies = [
"objc",
]
[[package]]
name = "const-sha1"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb58b6451e8c2a812ad979ed1d83378caa5e927eef2622017a45f251457c2c9d"
[[package]]
name = "constant_time_eq"
version = "0.1.5"
@ -406,9 +388,9 @@ dependencies = [
[[package]]
name = "crc32fast"
version = "1.2.1"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a"
checksum = "738c290dfaea84fc1ca15ad9c168d083b05a714e1efddd8edaab678dc28d2836"
dependencies = [
"cfg-if 1.0.0",
]
@ -465,7 +447,7 @@ checksum = "754b69d351cdc2d8ee09ae203db831e005560fc6030da058f86ad60c92a9cb0a"
dependencies = [
"cssparser-macros",
"dtoa-short",
"itoa",
"itoa 0.4.8",
"matches",
"phf 0.8.0",
"proc-macro2",
@ -484,6 +466,12 @@ dependencies = [
"syn",
]
[[package]]
name = "cty"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35"
[[package]]
name = "darling"
version = "0.10.2"
@ -496,12 +484,12 @@ dependencies = [
[[package]]
name = "darling"
version = "0.13.0"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "757c0ded2af11d8e739c4daea1ac623dd1624b06c844cf3f5a39f1bdbd99bb12"
checksum = "d0d720b8683f8dd83c65155f0530560cba68cd2bf395f6513a483caee57ff7f4"
dependencies = [
"darling_core 0.13.0",
"darling_macro 0.13.0",
"darling_core 0.13.1",
"darling_macro 0.13.1",
]
[[package]]
@ -520,9 +508,9 @@ dependencies = [
[[package]]
name = "darling_core"
version = "0.13.0"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c34d8efb62d0c2d7f60ece80f75e5c63c1588ba68032740494b0b9a996466e3"
checksum = "7a340f241d2ceed1deb47ae36c4144b2707ec7dd0b649f894cb39bb595986324"
dependencies = [
"fnv",
"ident_case",
@ -545,20 +533,20 @@ dependencies = [
[[package]]
name = "darling_macro"
version = "0.13.0"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ade7bff147130fe5e6d39f089c6bd49ec0250f35d70b2eebf72afdfc919f15cc"
checksum = "72c41b3b7352feb3211a0d743dc5700a4e3b60f51bd2b368892d1e0f9a95f44b"
dependencies = [
"darling_core 0.13.0",
"darling_core 0.13.1",
"quote",
"syn",
]
[[package]]
name = "data-url"
version = "0.1.0"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d33fe99ccedd6e84bc035f1931bb2e6be79739d6242bd895e7311c886c50dc9c"
checksum = "3a30bfce702bcfa94e906ef82421f2c0e61c076ad76030c16ee5d2e9a32fe193"
dependencies = [
"matches",
]
@ -596,14 +584,14 @@ dependencies = [
[[package]]
name = "derive_more"
version = "0.99.16"
version = "0.99.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40eebddd2156ce1bb37b20bbe5151340a31828b1f2d22ba4141f3531710e38df"
checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321"
dependencies = [
"convert_case",
"proc-macro2",
"quote",
"rustc_version",
"rustc_version 0.4.0",
"syn",
]
@ -672,9 +660,9 @@ checksum = "53dd2e43a7d32952a6054141ee0d75183958620e84e5eab045de362dff13dc99"
[[package]]
name = "fastrand"
version = "1.5.0"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b394ed3d285a429378d3b384b9eb1285267e7df4b166df24b7a6939a04dc392e"
checksum = "779d043b6a0b90cc4c0ed7ee380a6504394cee7efd7db050e3774eee387324b2"
dependencies = [
"instant",
]
@ -686,7 +674,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e1c54951450cbd39f3dbcf1005ac413b49487dabf18a720ad2383eccfeffb92"
dependencies = [
"memoffset",
"rustc_version",
"rustc_version 0.3.3",
]
[[package]]
@ -756,9 +744,9 @@ dependencies = [
[[package]]
name = "futures"
version = "0.3.17"
version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a12aa0eb539080d55c3f2d45a67c3b58b6b0773c1a3ca2dfec66d58c97fd66ca"
checksum = "28560757fe2bb34e79f907794bb6b22ae8b0e5c669b638a1132f2592b19035b4"
dependencies = [
"futures-channel",
"futures-core",
@ -771,9 +759,9 @@ dependencies = [
[[package]]
name = "futures-channel"
version = "0.3.17"
version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5da6ba8c3bb3c165d3c7319fc1cc8304facf1fb8db99c5de877183c08a273888"
checksum = "ba3dda0b6588335f360afc675d0564c17a77a2bda81ca178a4b6081bd86c7f0b"
dependencies = [
"futures-core",
"futures-sink",
@ -781,15 +769,15 @@ dependencies = [
[[package]]
name = "futures-core"
version = "0.3.17"
version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88d1c26957f23603395cd326b0ffe64124b818f4449552f960d815cfba83a53d"
checksum = "d0c8ff0461b82559810cdccfde3215c3f373807f5e5232b71479bff7bb2583d7"
[[package]]
name = "futures-executor"
version = "0.3.17"
version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45025be030969d763025784f7f355043dc6bc74093e4ecc5000ca4dc50d8745c"
checksum = "29d6d2ff5bb10fb95c85b8ce46538a2e5f5e7fdc755623a7d4529ab8a4ed9d2a"
dependencies = [
"futures-core",
"futures-task",
@ -798,9 +786,9 @@ dependencies = [
[[package]]
name = "futures-io"
version = "0.3.17"
version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "522de2a0fe3e380f1bc577ba0474108faf3f6b18321dbf60b3b9c39a75073377"
checksum = "b1f9d34af5a1aac6fb380f735fe510746c38067c5bf16c7fd250280503c971b2"
[[package]]
name = "futures-lite"
@ -819,12 +807,10 @@ dependencies = [
[[package]]
name = "futures-macro"
version = "0.3.17"
version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18e4a4b95cea4b4ccbcf1c5675ca7c4ee4e9e75eb79944d07defde18068f79bb"
checksum = "6dbd947adfffb0efc70599b3ddcf7b5597bb5fa9e245eb99f62b3a5f7bb8bd3c"
dependencies = [
"autocfg",
"proc-macro-hack",
"proc-macro2",
"quote",
"syn",
@ -832,23 +818,22 @@ dependencies = [
[[package]]
name = "futures-sink"
version = "0.3.17"
version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "36ea153c13024fe480590b3e3d4cad89a0cfacecc24577b68f86c6ced9c2bc11"
checksum = "e3055baccb68d74ff6480350f8d6eb8fcfa3aa11bdc1a1ae3afdd0514617d508"
[[package]]
name = "futures-task"
version = "0.3.17"
version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d3d00f4eddb73e498a54394f228cd55853bdf059259e8e7bc6e69d408892e99"
checksum = "6ee7c6485c30167ce4dfb83ac568a849fe53274c831081476ee13e0dce1aad72"
[[package]]
name = "futures-util"
version = "0.3.17"
version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "36568465210a3a6ee45e1f165136d68671471a501e632e9a98d96872222b5481"
checksum = "d9b5cf40b47a271f77a8b1bec03ca09044d99d2372c0de244e66430761127164"
dependencies = [
"autocfg",
"futures-channel",
"futures-core",
"futures-io",
@ -858,8 +843,6 @@ dependencies = [
"memchr",
"pin-project-lite",
"pin-utils",
"proc-macro-hack",
"proc-macro-nested",
"slab",
]
@ -1209,7 +1192,7 @@ checksum = "1323096b05d41827dadeaee54c9981958c0f94e670bc94ed80037d1a7b8b186b"
dependencies = [
"bytes",
"fnv",
"itoa",
"itoa 0.4.8",
]
[[package]]
@ -1292,9 +1275,9 @@ dependencies = [
[[package]]
name = "itertools"
version = "0.10.1"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69ddb889f9d0d08a67338271fa9b62996bc788c7796a5c18cf057420aaed5eaf"
checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3"
dependencies = [
"either",
]
@ -1306,10 +1289,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
[[package]]
name = "javascriptcore-rs"
version = "0.15.1"
name = "itoa"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9644bfae308588f4e57616bd8402b982dbcd68d1934c0848e2869ffcc03b562"
checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35"
[[package]]
name = "javascriptcore-rs"
version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e207780c1d1cd3c36056695e44010a19dd481574a2106cd2540edda4128a9794"
dependencies = [
"bitflags",
"glib",
@ -1318,9 +1307,9 @@ dependencies = [
[[package]]
name = "javascriptcore-rs-sys"
version = "0.3.1"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79a4f53f580ab519a92d142d6dbcff5fd59b8e9634f965bdeb892383d787165e"
checksum = "2adf2de824b178d76c6017da59f4e7e95de49a766b584c59d47821a6c3dce9e2"
dependencies = [
"glib-sys 0.14.0",
"gobject-sys 0.14.0",
@ -1363,9 +1352,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.106"
version = "0.2.112"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a60553f9a9e039a333b4e9b20573b9e9b9c0bb3a11e201ccc48ef4283456d673"
checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125"
[[package]]
name = "lock_api"
@ -1387,9 +1376,9 @@ dependencies = [
[[package]]
name = "loom"
version = "0.5.2"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2b9df80a3804094bf49bb29881d18f6f05048db72127e84e09c26fc7c2324f5"
checksum = "edc5c7d328e32cc4954e8e01193d7f0ef5ab257b5090b70a964e099a36034309"
dependencies = [
"cfg-if 1.0.0",
"generator",
@ -1431,9 +1420,9 @@ dependencies = [
[[package]]
name = "matchers"
version = "0.0.1"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f099785f7595cc4b4553a174ce30dd7589ef93391ff414dbb67f62392b9e0ce1"
checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558"
dependencies = [
"regex-automata",
]
@ -1452,9 +1441,9 @@ checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
[[package]]
name = "memoffset"
version = "0.6.4"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9"
checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
dependencies = [
"autocfg",
]
@ -1520,9 +1509,9 @@ dependencies = [
[[package]]
name = "ndk-sys"
version = "0.2.1"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c44922cb3dbb1c70b5e5f443d63b64363a898564d739ba5198e3a9138442868d"
checksum = "e1bcdd74c20ad5d95aacd60ef9ba40fdf77f767051040541df557b7a9b2a2121"
[[package]]
name = "new_debug_unreachable"
@ -1568,9 +1557,9 @@ dependencies = [
[[package]]
name = "num_cpus"
version = "1.13.0"
version = "1.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1"
dependencies = [
"hermit-abi",
"libc",
@ -1578,9 +1567,9 @@ dependencies = [
[[package]]
name = "num_enum"
version = "0.5.4"
version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9bd055fb730c4f8f4f57d45d35cd6b3f0980535b056dc7ff119cee6a66ed6f"
checksum = "085fe377a4b2805c0fbc09484415ec261174614b7f080b0e0d520456ac421a67"
dependencies = [
"derivative",
"num_enum_derive",
@ -1588,9 +1577,9 @@ dependencies = [
[[package]]
name = "num_enum_derive"
version = "0.5.4"
version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "486ea01961c4a818096de679a8b740b26d9033146ac5291b1c98557658f8cdd9"
checksum = "5249369707a1e07b39f78d98c8f34e00aca7dcb053812fdbb5ad7be82c1bba38"
dependencies = [
"proc-macro-crate 1.1.0",
"proc-macro2",
@ -1628,9 +1617,9 @@ dependencies = [
[[package]]
name = "once_cell"
version = "1.8.0"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56"
checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5"
[[package]]
name = "opaque-debug"
@ -1722,9 +1711,9 @@ dependencies = [
[[package]]
name = "phf"
version = "0.10.0"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9fc3db1018c4b59d7d582a739436478b6035138b6aecbce989fc91c3e98409f"
checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259"
dependencies = [
"phf_macros 0.10.0",
"phf_shared 0.10.0",
@ -1821,9 +1810,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "pkg-config"
version = "0.3.22"
version = "0.3.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12295df4f294471248581bc09bef3c38a5e46f1e36d6a37353621a0c6c357e1f"
checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe"
[[package]]
name = "png"
@ -1910,17 +1899,11 @@ version = "0.5.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
[[package]]
name = "proc-macro-nested"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086"
[[package]]
name = "proc-macro2"
version = "1.0.32"
version = "1.0.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43"
checksum = "2f84e92c0f7c9d58328b85a78557813e4bd845130db68d7184635344399423b1"
dependencies = [
"unicode-xid",
]
@ -2027,11 +2010,21 @@ dependencies = [
[[package]]
name = "raw-window-handle"
version = "0.3.3"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a441a7a6c80ad6473bd4b74ec1c9a4c951794285bf941c2126f607c72e48211"
checksum = "e28f55143d0548dad60bb4fbdc835a3d7ac6acc3324506450c5fdd6e42903a76"
dependencies = [
"libc",
"raw-window-handle 0.4.2",
]
[[package]]
name = "raw-window-handle"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fba75eee94a9d5273a68c9e1e105d9cffe1ef700532325788389e5a83e2522b7"
dependencies = [
"cty",
]
[[package]]
@ -2130,16 +2123,25 @@ dependencies = [
]
[[package]]
name = "rustversion"
version = "1.0.5"
name = "rustc_version"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61b3909d758bb75c79f23d4736fac9433868679d3ad2ea7a61e3c25cfda9a088"
checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
dependencies = [
"semver 1.0.4",
]
[[package]]
name = "rustversion"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f"
[[package]]
name = "ryu"
version = "1.0.5"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f"
[[package]]
name = "same-file"
@ -2208,18 +2210,18 @@ dependencies = [
[[package]]
name = "serde"
version = "1.0.130"
version = "1.0.132"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913"
checksum = "8b9875c23cf305cd1fd7eb77234cbb705f21ea6a72c637a5c6db5fe4b8e7f008"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.130"
version = "1.0.132"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b"
checksum = "ecc0db5cb2556c0e558887d9bbdcf6ac4471e83ff66cf696e5419024d1606276"
dependencies = [
"proc-macro2",
"quote",
@ -2228,11 +2230,11 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.68"
version = "1.0.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f690853975602e1bfe1ccbf50504d67174e3bcf340f23b5ea9992e0587a52d8"
checksum = "bcbd0344bc6533bc7ec56df11d42fb70f1b912351c0825ccb7211b59d8af7cf5"
dependencies = [
"itoa",
"itoa 1.0.1",
"ryu",
"serde",
]
@ -2265,7 +2267,27 @@ version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12e47be9471c72889ebafb5e14d5ff930d89ae7a67bbdb5f8abb564f845a927e"
dependencies = [
"darling 0.13.0",
"darling 0.13.1",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serialize-to-javascript"
version = "0.1.0"
source = "git+https://github.com/chippers/serialize-to-javascript#38d5026f371bfba4f5197ed143a6667a09375fbd"
dependencies = [
"serde",
"serde_json",
"serialize-to-javascript-impl",
]
[[package]]
name = "serialize-to-javascript-impl"
version = "0.1.0"
source = "git+https://github.com/chippers/serialize-to-javascript#38d5026f371bfba4f5197ed143a6667a09375fbd"
dependencies = [
"proc-macro2",
"quote",
"syn",
@ -2427,9 +2449,9 @@ dependencies = [
[[package]]
name = "syn"
version = "1.0.81"
version = "1.0.82"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2afee18b8beb5a596ecb4a2dce128c719b4ba399d34126b9e4396e3f9860966"
checksum = "8daf5dd0bb60cbd4137b1b587d2fc0ae729bc07cf01cd70b36a1ed5ade3b9d59"
dependencies = [
"proc-macro2",
"quote",
@ -2485,7 +2507,7 @@ dependencies = [
[[package]]
name = "tao"
version = "0.5.2"
source = "git+https://github.com/tauri-apps/tao?branch=next#97cd0497ae827903f7d67aa1c991a77a397c9cb8"
source = "git+https://github.com/tauri-apps/tao?branch=next#9f699a345788fbb08bc483a3f335ca4a94339676"
dependencies = [
"bitflags",
"cairo-rs",
@ -2512,20 +2534,19 @@ dependencies = [
"ndk-sys",
"objc",
"parking_lot",
"raw-window-handle",
"raw-window-handle 0.3.4",
"scopeguard",
"serde",
"unicode-segmentation",
"webview2-com-sys",
"windows",
"x11-dl",
]
[[package]]
name = "tar"
version = "0.4.37"
version = "0.4.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6f5515d3add52e0bbdcad7b83c388bb36ba7b754dda3b5f5bc2d38640cdba5c"
checksum = "4b55807c0344e1e6c04d7c965f5289c39a8d94ae23ed5c0b57aabac549f871c6"
dependencies = [
"filetime",
"libc",
@ -2553,12 +2574,13 @@ dependencies = [
"once_cell",
"percent-encoding",
"rand 0.8.4",
"raw-window-handle",
"raw-window-handle 0.3.4",
"regex",
"semver 1.0.4",
"serde",
"serde_json",
"serde_repr",
"serialize-to-javascript",
"state",
"tar",
"tauri-macros",
@ -2587,6 +2609,7 @@ dependencies = [
"sha2",
"tauri-utils",
"thiserror",
"uuid",
"walkdir",
"zstd",
]
@ -2615,7 +2638,7 @@ dependencies = [
"tauri-utils",
"thiserror",
"uuid",
"webview2-com-sys",
"webview2-com",
]
[[package]]
@ -2630,6 +2653,7 @@ dependencies = [
"tauri-utils",
"uuid",
"webview2-com",
"windows",
"wry",
]
@ -2637,15 +2661,18 @@ dependencies = [
name = "tauri-utils"
version = "1.0.0-beta.3"
dependencies = [
"base64",
"heck",
"html5ever",
"kuchiki",
"phf 0.10.0",
"phf 0.10.1",
"proc-macro2",
"quote",
"serde",
"serde_json",
"serde_with",
"serialize-to-javascript",
"sha2",
"thiserror",
"url",
"zstd",
@ -2723,9 +2750,9 @@ dependencies = [
[[package]]
name = "tinyvec"
version = "1.5.0"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f83b2a3d4d9091d0abd7eba4dc2710b1718583bd4d8992e2190720ea38f391f7"
checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2"
dependencies = [
"tinyvec_macros",
]
@ -2738,11 +2765,10 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
[[package]]
name = "tokio"
version = "1.13.0"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "588b2d10a336da58d877567cd8fb8a14b463e2104910f8132cd054b4b96e29ee"
checksum = "fbbf1c778ec206785635ce8ad57fe52b3009ae9e0c9f574a728f3049d3e55838"
dependencies = [
"autocfg",
"bytes",
"memchr",
"num_cpus",
@ -2801,36 +2827,22 @@ dependencies = [
"tracing-core",
]
[[package]]
name = "tracing-serde"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb65ea441fbb84f9f6748fd496cf7f63ec9af5bca94dd86456978d055e8eb28b"
dependencies = [
"serde",
"tracing-core",
]
[[package]]
name = "tracing-subscriber"
version = "0.2.25"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71"
checksum = "245da694cc7fc4729f3f418b304cb57789f1bed2a78c575407ab8a23f53cb4d3"
dependencies = [
"ansi_term",
"chrono",
"lazy_static",
"matchers",
"regex",
"serde",
"serde_json",
"sharded-slab",
"smallvec",
"thread_local",
"tracing",
"tracing-core",
"tracing-log",
"tracing-serde",
]
[[package]]
@ -2949,9 +2961,9 @@ checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
[[package]]
name = "webkit2gtk"
version = "0.15.2"
version = "0.15.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ca90927b3d0625c84c7de59b70174cc6384237d0599f2b8e510a7ee10509d1d"
checksum = "d5725e8ede878b7c00419066868085b83fb7d01eea904c1a0bd0159ad3ce0ba3"
dependencies = [
"bitflags",
"cairo-rs",
@ -2972,9 +2984,9 @@ dependencies = [
[[package]]
name = "webkit2gtk-sys"
version = "0.15.1"
version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b0e5e08218be3884e56aff0aedcb9e222b311be53214eb6019200caf9b52815"
checksum = "b34314407e381b88a72610d0f4eeff1552cbf8ee5420dbe84749fa26aa11b4e3"
dependencies = [
"atk-sys",
"bitflags",
@ -2995,9 +3007,9 @@ dependencies = [
[[package]]
name = "webview2-com"
version = "0.4.0"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2294dee38668da0d71019097dddc6cef525fde7aa4784243dd83f0752e08aa5"
checksum = "abdc9ca7cebd96a1005d5ba1e9d70c61c0f6c276a41cddaeecb7842d436ab3bc"
dependencies = [
"webview2-com-macros",
"webview2-com-sys",
@ -3006,9 +3018,9 @@ dependencies = [
[[package]]
name = "webview2-com-macros"
version = "0.3.0"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2eba35fdbb8fbc8de7e7479532a356dbbf2754d8a6e9c9fbfa430896cbb1ca89"
checksum = "07bca4b354035275764ea4ca8d6bfa74cc5b0e8126e7cd675ee327574b59e13d"
dependencies = [
"proc-macro2",
"quote",
@ -3017,9 +3029,9 @@ dependencies = [
[[package]]
name = "webview2-com-sys"
version = "0.4.0"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14690dcb8b57c5238c4502cfc321f858fa1306edd4109e8e1d7ddee0c29b06a5"
checksum = "73472d7f0e9038b58204cb3f582ee138a8c181719dc6825ea03371ad085c6058"
dependencies = [
"regex",
"serde",
@ -3061,30 +3073,53 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows"
version = "0.19.0"
version = "0.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef84dd25f4c69a271b1bba394532bf400523b43169de21dfc715e8f8e491053d"
checksum = "e46c474738425c090573ecf5472d54ee5f78132e6195d0bbfcc2aabc0ed29f37"
dependencies = [
"const-sha1",
"windows_aarch64_msvc",
"windows_gen",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_macros",
"windows_reader",
"windows_x86_64_gnu",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_gen"
version = "0.19.0"
name = "windows_aarch64_msvc"
version = "0.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac7bb21b8ff5e801232b72a6ff554b4cc0cef9ed9238188c3ca78fe3968a7e5d"
checksum = "3022d174000fcaeb6f95933fb04171ea0e21b9289ac57fe4400bfa148e41df79"
[[package]]
name = "windows_gen"
version = "0.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54e0f0e40e950724f92de0f714817c7030a88161738b9b1c58d62c817246fe1c"
dependencies = [
"windows_quote",
"windows_reader",
]
[[package]]
name = "windows_macros"
version = "0.19.0"
name = "windows_i686_gnu"
version = "0.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5566b8c51118769e4a9094a688bf1233a3f36aacbfc78f3b15817fe0b6e0442f"
checksum = "03b1584eebf06654708eab4301152032c13c1e47f4a754ffc93c733f10993e85"
[[package]]
name = "windows_i686_msvc"
version = "0.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f49df16591e9ad429997ec57d462b0cc45168f639d03489e8c2e933ea9c389d7"
[[package]]
name = "windows_macros"
version = "0.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6103bcf1a7396d66f6f08a2d67d8a2ab34efaf4b1d7567301af2c002507c8c3b"
dependencies = [
"syn",
"windows_gen",
@ -3094,20 +3129,32 @@ dependencies = [
[[package]]
name = "windows_quote"
version = "0.19.0"
version = "0.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4af8236a9493c38855f95cdd11b38b342512a5df4ee7473cffa828b5ebb0e39c"
checksum = "e414df8d5dd2013f2317fdc414d3ad035effcb7aef1f16bf508ac5743154835a"
[[package]]
name = "windows_reader"
version = "0.19.0"
version = "0.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c8d5cf83fb08083438c5c46723e6206b2970da57ce314f80b57724439aaacab"
checksum = "8132c9fb77903d852ea20053af816bd15c088a6e8d283b8283e80353347bb6b9"
[[package]]
name = "windows_x86_64_gnu"
version = "0.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2cb06177184100374f97d5e7261ee0b6adefa8ee32e38f87518ca22b519bb80e"
[[package]]
name = "windows_x86_64_msvc"
version = "0.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3c27bcbb33ddbed3569e36c14775c99f72b97c72ce49f81d128637fb48a061f"
[[package]]
name = "wry"
version = "0.12.2"
source = "git+ssh://git@github.com/tauri-sec/wry?branch=next#0f9eb9b1b9288b5be443bced0e8fa58a2479c491"
source = "git+ssh://git@github.com/tauri-sec/wry?branch=next#c60bb8f49e971237a1e9ed73fad2cec38dc7c9db"
dependencies = [
"cocoa",
"core-graphics 0.22.3",

View File

@ -72,7 +72,7 @@ to the Cargo Manifest (`Cargo.toml`) so that Cargo knows to pull in our dependen
name = "hello-tauri-webdriver"
version = "0.1.0"
edition = "2021"
rust-version = "1.56"
rust-version = "1.57"
# Needed to set up some things for Tauri at build time
[build-dependencies]

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -5,8 +5,8 @@
<link rel="stylesheet" href="/global.css" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Svelte + Vite App</title>
<script type="module" crossorigin src="/assets/index.ab727ab4.js"></script>
<link rel="modulepreload" href="/assets/vendor.32016365.js">
<script type="module" crossorigin src="/assets/index.4b6f33f7.js"></script>
<link rel="modulepreload" href="/assets/vendor.3a672f03.js">
<link rel="stylesheet" href="/assets/index.b706bb41.css">
</head>

View File

@ -0,0 +1,10 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Isolation Secure Script</title>
</head>
<body>
<script src="index.js"></script>
</body>
</html>

View File

@ -0,0 +1,4 @@
window.__TAURI_ISOLATION_HOOK__= (payload) => {
console.log('hook', payload)
return payload
}

View File

@ -14,6 +14,41 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234"
[[package]]
name = "aead"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b613b8e1e3cf911a086f53f03bf286f52fd7a7258e4fa606f0ef220d39d8877"
dependencies = [
"generic-array",
]
[[package]]
name = "aes"
version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8"
dependencies = [
"cfg-if 1.0.0",
"cipher",
"cpufeatures",
"opaque-debug",
]
[[package]]
name = "aes-gcm"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df5f85a83a7d8b0442b6aa7b504b8212c1733da07b98aae43d4bc21b2cb3cdf6"
dependencies = [
"aead",
"aes",
"cipher",
"ctr",
"ghash",
"subtle",
]
[[package]]
name = "aho-corasick"
version = "0.7.18"
@ -295,9 +330,9 @@ dependencies = [
[[package]]
name = "cargo_toml"
version = "0.10.1"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6d613611c914a7db07f28526941ce1e956d2f977b0c5e2014fbfa42230d420f"
checksum = "363c7cfaa15f101415c4ac9e68706ca4a2277773932828b33f96e59d28c68e62"
dependencies = [
"serde",
"serde_derive",
@ -372,6 +407,15 @@ dependencies = [
"winapi",
]
[[package]]
name = "cipher"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7"
dependencies = [
"generic-array",
]
[[package]]
name = "clap"
version = "3.0.4"
@ -418,16 +462,6 @@ dependencies = [
"objc",
]
[[package]]
name = "combine"
version = "4.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2b2f5d0ee456f3928812dfc8c6d9a1d592b98678f6d56db9b0cd2b7bc6c8db5"
dependencies = [
"bytes",
"memchr",
]
[[package]]
name = "concurrent-queue"
version = "1.2.2"
@ -629,6 +663,15 @@ dependencies = [
"syn",
]
[[package]]
name = "ctr"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea"
dependencies = [
"cipher",
]
[[package]]
name = "cty"
version = "0.2.2"
@ -705,6 +748,15 @@ dependencies = [
"syn",
]
[[package]]
name = "data-url"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a30bfce702bcfa94e906ef82421f2c0e61c076ad76030c16ee5d2e9a32fe193"
dependencies = [
"matches",
]
[[package]]
name = "deflate"
version = "0.7.20"
@ -1156,6 +1208,16 @@ dependencies = [
"wasi 0.10.2+wasi-snapshot-preview1",
]
[[package]]
name = "ghash"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1583cc1656d7839fd3732b80cf4f38850336cdb9b8ded1cd399ca62958de3c99"
dependencies = [
"opaque-debug",
"polyval",
]
[[package]]
name = "gio"
version = "0.14.8"
@ -1527,15 +1589,6 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "kstring"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b310ccceade8121d7d77fee406160e457c2f4e7c7982d589da3499bc7ea4526"
dependencies = [
"serde",
]
[[package]]
name = "kuchiki"
version = "0.8.1"
@ -2240,6 +2293,18 @@ dependencies = [
"winapi",
]
[[package]]
name = "polyval"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8419d2b623c7c0896ff2d5d96e2cb4ede590fed28fcc34934f4c33c036e620a1"
dependencies = [
"cfg-if 1.0.0",
"cpufeatures",
"opaque-debug",
"universal-hash",
]
[[package]]
name = "ppv-lite86"
version = "0.2.16"
@ -2548,6 +2613,21 @@ dependencies = [
"windows 0.29.0",
]
[[package]]
name = "ring"
version = "0.16.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc"
dependencies = [
"cc",
"libc",
"once_cell",
"spin",
"untrusted",
"web-sys",
"winapi",
]
[[package]]
name = "rust-argon2"
version = "0.8.3"
@ -2765,6 +2845,26 @@ dependencies = [
"syn",
]
[[package]]
name = "serialize-to-javascript"
version = "0.1.0"
source = "git+https://github.com/chippers/serialize-to-javascript#38d5026f371bfba4f5197ed143a6667a09375fbd"
dependencies = [
"serde",
"serde_json",
"serialize-to-javascript-impl",
]
[[package]]
name = "serialize-to-javascript-impl"
version = "0.1.0"
source = "git+https://github.com/chippers/serialize-to-javascript#38d5026f371bfba4f5197ed143a6667a09375fbd"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "servo_arc"
version = "0.1.1"
@ -2849,6 +2949,12 @@ dependencies = [
"system-deps 5.0.0",
]
[[package]]
name = "spin"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
[[package]]
name = "stable_deref_trait"
version = "1.2.0"
@ -3054,6 +3160,7 @@ dependencies = [
"bincode",
"cfg_aliases",
"clap",
"data-url",
"dirs-next",
"either",
"embed_plist",
@ -3080,6 +3187,7 @@ dependencies = [
"serde",
"serde_json",
"serde_repr",
"serialize-to-javascript",
"shared_child",
"state",
"tar",
@ -3102,6 +3210,7 @@ dependencies = [
"anyhow",
"cargo_toml",
"serde_json",
"tauri-codegen",
"tauri-utils",
"winres",
]
@ -3112,7 +3221,6 @@ version = "1.0.0-beta.4"
dependencies = [
"base64",
"blake3",
"kuchiki",
"proc-macro2",
"quote",
"regex",
@ -3121,6 +3229,7 @@ dependencies = [
"sha2",
"tauri-utils",
"thiserror",
"uuid",
"walkdir",
"zstd",
]
@ -3129,7 +3238,7 @@ dependencies = [
name = "tauri-macros"
version = "1.0.0-beta.5"
dependencies = [
"heck",
"heck 0.3.3",
"proc-macro2",
"quote",
"syn",
@ -3173,15 +3282,21 @@ dependencies = [
name = "tauri-utils"
version = "1.0.0-beta.3"
dependencies = [
"aes-gcm",
"base64",
"heck 0.4.0",
"html5ever",
"kuchiki",
"once_cell",
"phf 0.10.1",
"proc-macro2",
"quote",
"ring",
"serde",
"serde_json",
"serde_with",
"serialize-to-javascript",
"sha2",
"thiserror",
"url",
"zstd",
@ -3320,18 +3435,6 @@ dependencies = [
"tracing-core",
]
[[package]]
name = "tracing"
version = "0.1.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105"
dependencies = [
"cfg-if 1.0.0",
"pin-project-lite",
"tracing-attributes",
"tracing-core",
]
[[package]]
name = "tracing-attributes"
version = "0.1.18"
@ -3420,6 +3523,22 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "universal-hash"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05"
dependencies = [
"generic-array",
"subtle",
]
[[package]]
name = "untrusted"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
[[package]]
name = "url"
version = "2.2.2"

View File

@ -3,16 +3,16 @@ name = "api"
version = "0.1.0"
description = "An example Tauri Application showcasing the api"
edition = "2021"
rust-version = "1.56"
rust-version = "1.57"
license = "Apache-2.0 OR MIT"
[build-dependencies]
tauri-build = { path = "../../../core/tauri-build" }
tauri-build = { path = "../../../core/tauri-build", features = ["isolation"] }
[dependencies]
serde_json = "1.0"
serde = { version = "1.0", features = [ "derive" ] }
tauri = { path = "../../../core/tauri", features = ["api-all", "cli", "macos-private-api", "system-tray", "updater"] }
tauri = { path = "../../../core/tauri", features = ["api-all", "cli", "isolation", "macos-private-api", "system-tray", "updater"] }
[features]
default = [ "custom-protocol" ]

View File

@ -10,6 +10,12 @@
"version": "../package.json"
},
"tauri": {
"pattern": {
"use": "isolation",
"options": {
"dir": "../isolation-dist/"
}
},
"macOSPrivateApi": true,
"cli": {
"description": "Tauri API example",

View File

@ -3,7 +3,7 @@ name = "commands"
version = "0.1.0"
description = "A simple Tauri Application showcasing the commands API"
edition = "2021"
rust-version = "1.56"
rust-version = "1.57"
[build-dependencies]
tauri-build = { path = "../../../core/tauri-build", features = [ "codegen" ] }

View File

@ -3,7 +3,7 @@ name = "helloworld"
version = "0.1.0"
description = "A very simple Tauri Appplication"
edition = "2021"
rust-version = "1.56"
rust-version = "1.57"
[build-dependencies]
tauri-build = { path = "../../../core/tauri-build", features = [ "codegen" ] }

View File

@ -48,9 +48,6 @@
],
"security": {
"csp": "default-src 'self'"
},
"updater": {
"active": false
}
}
}

84
examples/isolation/dist/index.html vendored Normal file
View File

@ -0,0 +1,84 @@
<!DOCTYPE html>
<html lang="en-US">
<head>
<script>
// malicious
window.__TAURI_PATTERN__ = Object.freeze({pattern: "malicious"});
</script>
<script>
// malicious defineProperty
Object.defineProperty(window, "__TAURI_PATTERN__", {value: Object.freeze({pattern: "malicious"})});
</script>
<meta charset="UTF-8">
<title>Hello Tauri!</title>
<style>
body {
/* Add a nice colorscheme to our page and text */
background-color: #222831;
color: #ececec;
/* Make the body tag the exact size of the window */
margin: 0;
height: 100vh;
width: 100vw;
/* Vertically and horizontally center children of the body tag */
display: flex;
justify-content: center;
align-items: center;
}
div {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
</style>
<script type="text/javascript">console.log("inline", window.__TAURI_PATTERN__);</script>
</head>
<body>
<div>
<h1>Hello, Tauri!</h1>
<pre><code></code></pre>
<div>
<button id="ping">ping</button>
<span id="pong"></span></div>
</div>
<script>
const code = document.querySelector("code");
const obj = {};
function updateCode(key, value) {
obj[key] = value;
code.innerText = JSON.stringify(obj, null, 2);
}
const cb = window.__TAURI__.transformCallback(v => updateCode('response', v));
const error = window.__TAURI__.transformCallback(e => updateCode('response', e));
window.ipc.postMessage(JSON.stringify({
cmd: "ping",
callback: cb,
error,
}));
updateCode('__TAURI_PATTERN__', window.__TAURI_PATTERN__);
</script>
<!-- set up click handlers on our ping command button -->
<script>
const ping = document.querySelector("#ping")
const pong = document.querySelector('#pong')
ping.addEventListener("click", () => {
window.__TAURI_INVOKE__("ping")
.then(() => {
pong.innerText = `ok: ${Date.now()}`
})
.catch(() => {
pong.innerText = `error: ${Date.now()}`
})
})
</script>
</body>
</html>

1
examples/isolation/dist/linked.js vendored Normal file
View File

@ -0,0 +1 @@
console.log("linked", window.__TAURI_PATTERN__);

View File

@ -0,0 +1,10 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Isolation Secure Script</title>
</head>
<body>
<script src="index.js"></script>
</body>
</html>

View File

@ -0,0 +1,4 @@
window.__TAURI_ISOLATION_HOOK__= (payload) => {
console.log('hook', payload)
return payload
}

View File

@ -0,0 +1,10 @@
{
"name": "isolation",
"license": "Apache-2.0 OR MIT",
"scripts": {
"tauri": "node ../../tooling/cli.js/bin/tauri"
},
"dependencies": {
"@tauri-apps/api": "../../tooling/api/dist"
}
}

View File

@ -0,0 +1,5 @@
# Generated by Cargo
# will have compiled files and executables
/target/
WixTools
.cargo

View File

@ -0,0 +1 @@
../../../.license_template

3448
examples/isolation/src-tauri/Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,21 @@
[package]
name = "app"
version = "0.1.0"
description = "An example Tauri Application showcasing the isolation pattern"
edition = "2021"
license = "Apache-2.0 OR MIT"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[build-dependencies]
tauri-build = { path = "../../../core/tauri-build", features = [ "isolation" ] }
[dependencies]
serde_json = "1.0"
serde = { version = "1.0", features = ["derive"] }
tauri = { path = "../../../core/tauri", features = [ "isolation" ] }
[features]
default = [ "custom-protocol", "isolation" ]
isolation = [ "tauri/isolation", "tauri-build/isolation" ]
custom-protocol = [ "tauri/custom-protocol" ]

View File

@ -0,0 +1 @@
../../../LICENSE_APACHE-2.0

View File

@ -0,0 +1 @@
../../../LICENSE_MIT

View File

@ -0,0 +1,13 @@
// Copyright 2019-2021 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
use tauri_build::{try_build, Attributes, WindowsAttributes};
fn main() {
try_build(
Attributes::new()
.windows_attributes(WindowsAttributes::new().window_icon_path("../../.icons/icon.ico")),
)
.expect("could not build tauri application");
}

View File

@ -0,0 +1,30 @@
// Copyright 2019-2021 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
#![cfg_attr(
all(not(debug_assertions), target_os = "windows"),
windows_subsystem = "windows"
)]
use std::time::Instant;
#[tauri::command]
fn ping() {
dbg!(format!("ping: {:?}", Instant::now()));
}
#[cfg(not(feature = "isolation"))]
fn main() {
compile_error!("Feature `isolation` is required to run this example");
}
#[cfg(feature = "isolation")]
fn main() {
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![ping])
.run(tauri::generate_context!(
"../../examples/isolation/src-tauri/tauri.conf.json"
))
.expect("error while running tauri application");
}

View File

@ -0,0 +1,71 @@
{
"package": {
"productName": "isolation",
"version": "0.1.0"
},
"build": {
"distDir": "../dist",
"devPath": "../dist",
"beforeDevCommand": "",
"beforeBuildCommand": "",
"withGlobalTauri": true
},
"tauri": {
"pattern": {
"use": "isolation",
"options": {
"dir": "../isolation-dist"
}
},
"bundle": {
"active": true,
"targets": "all",
"identifier": "com.tauri.isolation",
"icon": [
"../../.icons/32x32.png",
"../../.icons/128x128.png",
"../../.icons/128x128@2x.png",
"../../.icons/icon.icns",
"../../.icons/icon.ico"
],
"resources": [],
"externalBin": [],
"copyright": "",
"category": "DeveloperTool",
"shortDescription": "",
"longDescription": "",
"deb": {
"depends": [],
"useBootstrapper": false
},
"macOS": {
"frameworks": [],
"minimumSystemVersion": "",
"useBootstrapper": false,
"exceptionDomain": "",
"signingIdentity": null,
"entitlements": null
},
"windows": {
"certificateThumbprint": null,
"digestAlgorithm": "sha256",
"timestampUrl": ""
}
},
"updater": {
"active": false
},
"windows": [
{
"title": "Isolation",
"width": 800,
"height": 600,
"resizable": true,
"fullscreen": false
}
],
"security": {
"csp": "default-src blob: data: filesystem: ws: wss: http: https: tauri: 'unsafe-eval' 'unsafe-inline' 'self' img-src: 'self'"
}
}
}

View File

@ -0,0 +1,13 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@tauri-apps/api@../../tooling/api/dist":
version "1.0.0-beta.8"
dependencies:
type-fest "2.5.1"
type-fest@2.5.1:
version "2.5.1"
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.5.1.tgz#17ba4f36a6abfabf0a92005d045dca77564607b0"
integrity sha512-JDcsxbLR6Z6OcL7TnGAAAGQrY4g7Q4EEALMT4Kp6FQuIc0JLQvOF3l7ejFvx8o5GmLlfMseTWUL++sYFP+o8kw==

View File

@ -3,7 +3,7 @@ name = "multiwindow"
version = "0.1.0"
description = "An example Tauri Multi-Window Application"
edition = "2021"
rust-version = "1.56"
rust-version = "1.57"
license = "Apache-2.0 OR MIT"
[build-dependencies]

View File

@ -3,7 +3,7 @@ name = "navigation"
version = "0.1.0"
description = "A very simple Tauri Appplication with navigation"
edition = "2021"
rust-version = "1.56"
rust-version = "1.57"
[build-dependencies]
tauri-build = { path = "../../../core/tauri-build", features = [ "codegen" ] }

View File

@ -3,7 +3,7 @@ name = "resources"
version = "0.1.0"
description = "A Tauri application that uses Node.js with app resources"
edition = "2021"
rust-version = "1.56"
rust-version = "1.57"
[build-dependencies]
tauri-build = { path = "../../../core/tauri-build", features = [ "codegen" ] }

View File

@ -3,7 +3,7 @@ name = "sidecar"
version = "0.1.0"
description = "A Tauri application with a sidecar binary"
edition = "2021"
rust-version = "1.56"
rust-version = "1.57"
[build-dependencies]
tauri-build = { path = "../../../core/tauri-build", features = [ "codegen" ] }

View File

@ -3,7 +3,7 @@ name = "splashscreen"
version = "0.1.0"
description = "An example Tauri Application with a splashscreen"
edition = "2021"
rust-version = "1.56"
rust-version = "1.57"
license = "Apache-2.0 OR MIT"
[build-dependencies]

View File

@ -3,7 +3,7 @@ name = "state"
version = "0.1.0"
description = "A simple Tauri Appplication showcase the state functionality"
edition = "2021"
rust-version = "1.56"
rust-version = "1.57"
[build-dependencies]
tauri-build = { path = "../../../core/tauri-build", features = [ "codegen" ] }

View File

@ -3,7 +3,7 @@ name = "streaming"
version = "0.1.0"
description = "A very simple Tauri Appplication"
edition = "2021"
rust-version = "1.56"
rust-version = "1.57"
[build-dependencies]
tauri-build = { path = "../../../core/tauri-build", features = [ "codegen" ] }

View File

@ -3,7 +3,7 @@ name = "updater-example"
version = "0.1.0"
description = "A very simple Tauri Appplication"
edition = "2021"
rust-version = "1.56"
rust-version = "1.57"
license = "Apache-2.0 OR MIT"
[build-dependencies]

View File

@ -19,5 +19,8 @@
"covector": "^0.5.3",
"husky": "^6.0.0",
"prettier": "^2.2.1"
},
"dependencies": {
"typescript": "^4.5.4"
}
}

View File

@ -13,17 +13,13 @@
declare global {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
interface Window {
__TAURI_POST_MESSAGE__: (
command: string,
args?: { [key: string]: unknown }
) => void
__TAURI_IPC__: (message: any) => void,
ipc: {
postMessage: (args: string) => void
}
}
}
// the `__TAURI_INVOKE_KEY__` variable is injected at runtime by Tauri
// eslint-disable-next-line @typescript-eslint/naming-convention
declare let __TAURI_INVOKE_KEY__: number
/** @ignore */
function uid(): number {
return window.crypto.getRandomValues(new Uint32Array(1))[0]
@ -80,12 +76,14 @@ async function invoke<T>(cmd: string, args: InvokeArgs = {}): Promise<T> {
Reflect.deleteProperty(window, callback)
}, true)
window.__TAURI_POST_MESSAGE__(cmd, {
__invokeKey: __TAURI_INVOKE_KEY__,
callback,
error,
...args
})
window.__TAURI_IPC__(
{
cmd,
callback,
error,
...args
}
)
})
}

View File

@ -5,7 +5,7 @@ name = "tauri_bench"
version = "0.1.0"
authors = [ "Tauri Programme within The Commons Conservancy" ]
edition = "2021"
rust-version = "1.56"
rust-version = "1.57"
license = "Apache-2.0 OR MIT"
description = "Cross-platform WebView rendering library"
repository = "https://github.com/tauri-apps/wry"

View File

@ -3,7 +3,7 @@ name = "bench_cpu_intensive"
version = "0.1.0"
description = "A very simple Tauri Appplication"
edition = "2021"
rust-version = "1.56"
rust-version = "1.57"
[build-dependencies]
tauri-build = { path = "../../../../../core/tauri-build", features = [ "codegen" ] }

View File

@ -3,7 +3,7 @@ name = "bench_files_transfer"
version = "0.1.0"
description = "A very simple Tauri Appplication"
edition = "2021"
rust-version = "1.56"
rust-version = "1.57"
[build-dependencies]
tauri-build = { path = "../../../../../core/tauri-build", features = [ "codegen" ] }

View File

@ -3,7 +3,7 @@ name = "bench_helloworld"
version = "0.1.0"
description = "A very simple Tauri Appplication"
edition = "2021"
rust-version = "1.56"
rust-version = "1.57"
[build-dependencies]
tauri-build = { path = "../../../../../core/tauri-build", features = [ "codegen" ] }

View File

@ -13,7 +13,7 @@ keywords = [ "bundle", "cargo", "tauri" ]
repository = "https://github.com/tauri-apps/tauri"
description = "Wrap rust executables in OS-specific app bundles for Tauri"
edition = "2021"
rust-version = "1.56"
rust-version = "1.57"
exclude = [
".license_template",
"CHANGELOG.md",

View File

@ -8,7 +8,7 @@ authors = [ "Tauri Programme within The Commons Conservancy" ]
license = ""
repository = ""
edition = "2021"
rust-version = "1.56"
rust-version = "1.57"
[package.metadata.bundle]
identifier = "com.tauri.dev"

View File

@ -14,6 +14,41 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234"
[[package]]
name = "aead"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b613b8e1e3cf911a086f53f03bf286f52fd7a7258e4fa606f0ef220d39d8877"
dependencies = [
"generic-array 0.14.4",
]
[[package]]
name = "aes"
version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8"
dependencies = [
"cfg-if 1.0.0",
"cipher",
"cpufeatures",
"opaque-debug 0.3.0",
]
[[package]]
name = "aes-gcm"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df5f85a83a7d8b0442b6aa7b504b8212c1733da07b98aae43d4bc21b2cb3cdf6"
dependencies = [
"aead",
"aes",
"cipher",
"ctr",
"ghash",
"subtle",
]
[[package]]
name = "aho-corasick"
version = "0.7.18"
@ -112,6 +147,15 @@ dependencies = [
"generic-array 0.14.5",
]
[[package]]
name = "block-buffer"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1d36a02058e76b040de25a4464ba1c80935655595b661505c8b39b664828b95"
dependencies = [
"generic-array 0.14.4",
]
[[package]]
name = "block-padding"
version = "0.1.5"
@ -410,6 +454,15 @@ dependencies = [
"syn",
]
[[package]]
name = "ctr"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea"
dependencies = [
"cipher",
]
[[package]]
name = "darling"
version = "0.13.1"
@ -501,6 +554,18 @@ dependencies = [
"subtle",
]
[[package]]
name = "digest"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b697d66081d42af4fba142d56918a3cb21dc8eb63372c6b85d14f44fb9c5979b"
dependencies = [
"block-buffer 0.10.0",
"crypto-common",
"generic-array 0.14.4",
"subtle",
]
[[package]]
name = "dirs-next"
version = "2.0.0"
@ -720,6 +785,16 @@ dependencies = [
"wasi 0.10.2+wasi-snapshot-preview1",
]
[[package]]
name = "ghash"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1583cc1656d7839fd3732b80cf4f38850336cdb9b8ded1cd399ca62958de3c99"
dependencies = [
"opaque-debug 0.3.0",
"polyval",
]
[[package]]
name = "gif"
version = "0.11.3"
@ -1586,6 +1661,18 @@ dependencies = [
"miniz_oxide 0.3.7",
]
[[package]]
name = "polyval"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8419d2b623c7c0896ff2d5d96e2cb4ede590fed28fcc34934f4c33c036e620a1"
dependencies = [
"cfg-if 1.0.0",
"cpufeatures",
"opaque-debug 0.3.0",
"universal-hash",
]
[[package]]
name = "ppv-lite86"
version = "0.2.16"
@ -1961,7 +2048,7 @@ dependencies = [
"hmac",
"pbkdf2",
"salsa20",
"sha2",
"sha2 0.10.0",
]
[[package]]
@ -2088,6 +2175,26 @@ dependencies = [
"syn",
]
[[package]]
name = "serialize-to-javascript"
version = "0.1.0"
source = "git+https://github.com/chippers/serialize-to-javascript#38d5026f371bfba4f5197ed143a6667a09375fbd"
dependencies = [
"serde",
"serde_json",
"serialize-to-javascript-impl",
]
[[package]]
name = "serialize-to-javascript-impl"
version = "0.1.0"
source = "git+https://github.com/chippers/serialize-to-javascript#38d5026f371bfba4f5197ed143a6667a09375fbd"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "servo_arc"
version = "0.1.1"
@ -2127,6 +2234,17 @@ dependencies = [
"digest 0.10.1",
]
[[package]]
name = "sha2"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "900d964dd36bb15bcf2f2b35694c072feab74969a54f2bbeec7a2d725d2bdcb6"
dependencies = [
"cfg-if 1.0.0",
"cpufeatures",
"digest 0.10.1",
]
[[package]]
name = "shared_child"
version = "1.0.0"
@ -2261,7 +2379,7 @@ dependencies = [
"regex",
"serde",
"serde_json",
"sha2",
"sha2 0.9.8",
"strsim",
"tar",
"tempfile",
@ -2320,6 +2438,8 @@ dependencies = [
name = "tauri-utils"
version = "1.0.0-beta.3"
dependencies = [
"aes-gcm",
"base64",
"heck",
"html5ever",
"kuchiki",
@ -2328,6 +2448,8 @@ dependencies = [
"serde",
"serde_json",
"serde_with",
"serialize-to-javascript",
"sha2 0.9.8",
"thiserror",
"url",
]
@ -2522,6 +2644,16 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "universal-hash"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05"
dependencies = [
"generic-array 0.14.4",
"subtle",
]
[[package]]
name = "untrusted"
version = "0.7.1"

Some files were not shown because too many files have changed in this diff Show More