fix: adjust feature flags, wrong zip usage (#367)

pull/368/head
Lucas Fernandes Nogueira 2 years ago committed by GitHub
parent 7ae7167fbe
commit caf8456864
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -22,7 +22,7 @@ tauri-plugin-log = { path = "../../../plugins/log" }
tauri-plugin-fs = { path = "../../../plugins/fs" } tauri-plugin-fs = { path = "../../../plugins/fs" }
tauri-plugin-clipboard = { path = "../../../plugins/clipboard" } tauri-plugin-clipboard = { path = "../../../plugins/clipboard" }
tauri-plugin-dialog = { path = "../../../plugins/dialog" } tauri-plugin-dialog = { path = "../../../plugins/dialog" }
tauri-plugin-http = { path = "../../../plugins/http", features = [ "http-multipart" ] } tauri-plugin-http = { path = "../../../plugins/http", features = [ "multipart" ] }
tauri-plugin-notification = { path = "../../../plugins/notification", features = [ "windows7-compat" ] } tauri-plugin-notification = { path = "../../../plugins/notification", features = [ "windows7-compat" ] }
tauri-plugin-os = { path = "../../../plugins/os" } tauri-plugin-os = { path = "../../../plugins/os" }
tauri-plugin-process = { path = "../../../plugins/process" } tauri-plugin-process = { path = "../../../plugins/process" }

@ -48,44 +48,44 @@
} }
}, },
"fs": { "fs": {
"scope": { "scope": {
"allow": ["$APPDATA/db/**", "$DOWNLOAD/**", "$RESOURCE/**"], "allow": ["$APPDATA/db/**", "$DOWNLOAD/**", "$RESOURCE/**"],
"deny": ["$APPDATA/db/*.stronghold"] "deny": ["$APPDATA/db/*.stronghold"]
}
},
"shell": {
"open": true,
"scope": [
{
"name": "sh",
"cmd": "sh",
"args": [
"-c",
{
"validator": "\\S+"
}
]
},
{
"name": "cmd",
"cmd": "cmd",
"args": [
"/C",
{
"validator": "\\S+"
}
]
}
]
},
"http": {
"scope": ["http://localhost:3003"]
},
"updater": {
"endpoints": [
"https://tauri-update-server.vercel.app/update/{{target}}/{{current_version}}"
]
} }
},
"shell": {
"open": true,
"scope": [
{
"name": "sh",
"cmd": "sh",
"args": [
"-c",
{
"validator": "\\S+"
}
]
},
{
"name": "cmd",
"cmd": "cmd",
"args": [
"/C",
{
"validator": "\\S+"
}
]
}
]
},
"http": {
"scope": ["http://localhost:3003"]
},
"updater": {
"endpoints": [
"https://tauri-update-server.vercel.app/update/{{target}}/{{current_version}}"
]
}
}, },
"tauri": { "tauri": {
"pattern": { "pattern": {

@ -3,13 +3,13 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
window.alert = function (message) { window.alert = function (message) {
window.__TAURI_INVOKE__('plugin:dialog|message', { window.__TAURI_INVOKE__("plugin:dialog|message", {
message: message.toString() message: message.toString(),
}) });
} };
window.confirm = function (message) { window.confirm = function (message) {
return window.__TAURI_INVOKE__('plugin:dialog|confirm', { return window.__TAURI_INVOKE__("plugin:dialog|confirm", {
message: message.toString() message: message.toString(),
}) });
} };

@ -19,7 +19,7 @@ http = "0.2"
reqwest = { version = "0.11", default-features = false, features = [ "json", "stream" ] } reqwest = { version = "0.11", default-features = false, features = [ "json", "stream" ] }
[features] [features]
http-multipart = [ "reqwest/multipart" ] multipart = [ "reqwest/multipart" ]
native-tls = [ "reqwest/native-tls" ] native-tls = [ "reqwest/native-tls" ]
native-tls-vendored = [ "reqwest/native-tls-vendored" ] native-tls-vendored = [ "reqwest/native-tls-vendored" ]
rustls-tls = [ "reqwest/rustls-tls" ] rustls-tls = [ "reqwest/rustls-tls" ]

@ -103,7 +103,7 @@ class Body {
* and the value is either a string or a file object. * and the value is either a string or a file object.
* *
* By default it sets the `application/x-www-form-urlencoded` Content-Type header, * By default it sets the `application/x-www-form-urlencoded` Content-Type header,
* but you can set it to `multipart/form-data` if the Cargo feature `http-multipart` is enabled. * but you can set it to `multipart/form-data` if the Cargo feature `multipart` is enabled.
* *
* Note that a file path must be allowed in the `fs` allowlist scope. * Note that a file path must be allowed in the `fs` allowlist scope.
* @example * @example

@ -91,7 +91,7 @@ impl Client {
headers: &mut Option<HeaderMap>, headers: &mut Option<HeaderMap>,
form_body: FormBody, form_body: FormBody,
) -> crate::Result<reqwest::RequestBuilder> { ) -> crate::Result<reqwest::RequestBuilder> {
#[cfg(feature = "http-multipart")] #[cfg(feature = "multipart")]
if matches!( if matches!(
headers headers
.as_ref() .as_ref()

@ -2,39 +2,38 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
;(function () { (function () {
// open <a href="..."> links with the API // open <a href="..."> links with the API
function openLinks() { function openLinks() {
document.querySelector('body').addEventListener( document.querySelector("body").addEventListener("click", function (e) {
'click', var target = e.target;
function (e) { while (target != null) {
var target = e.target if (target.matches("a")) {
while (target != null) { if (
if (target.matches('a')) { target.href &&
if ( ["http://", "https://", "mailto:", "tel:"].some((v) =>
target.href && target.href.startsWith(v)
(['http://', 'https://', 'mailto:', 'tel:'].some(v => target.href.startsWith(v))) && ) &&
target.target === '_blank' target.target === "_blank"
) { ) {
window.__TAURI_INVOKE__('plugin:shell|open', { window.__TAURI_INVOKE__("plugin:shell|open", {
path: target.href path: target.href,
}) });
e.preventDefault() e.preventDefault();
}
break
} }
target = target.parentElement break;
} }
target = target.parentElement;
} }
) });
} }
if ( if (
document.readyState === 'complete' || document.readyState === "complete" ||
document.readyState === 'interactive' document.readyState === "interactive"
) { ) {
openLinks() openLinks();
} else { } else {
window.addEventListener('DOMContentLoaded', openLinks, true) window.addEventListener("DOMContentLoaded", openLinks, true);
} }
})() })();

@ -26,6 +26,8 @@ tempfile = "3"
flate2 = "1" flate2 = "1"
tar = "0.4" tar = "0.4"
ignore = "0.4" ignore = "0.4"
[target."cfg(target_os = \"windows\")".dependencies]
zip = { version = "0.6", default-features = false } zip = { version = "0.6", default-features = false }
[dev-dependencies] [dev-dependencies]

@ -84,6 +84,10 @@ pub enum Error {
/// Ignore error. /// Ignore error.
#[error("failed to walkdir: {0}")] #[error("failed to walkdir: {0}")]
Ignore(#[from] ignore::Error), Ignore(#[from] ignore::Error),
/// Zip error.
#[cfg(windows)]
#[error(transparent)]
ZipError(#[from] zip::result::ZipError),
} }
impl Serialize for Error { impl Serialize for Error {

@ -5,8 +5,8 @@
use std::{ use std::{
borrow::Cow, borrow::Cow,
fs, fs,
io::{self, Cursor, Read, Seek}, io::{self, Read, Seek},
path::{self, Path, PathBuf}, path::{self, Path},
}; };
use crate::{Error, Result}; use crate::{Error, Result};
@ -46,10 +46,20 @@ pub enum ArchiveFormat {
/// Tar archive. /// Tar archive.
Tar(Option<Compression>), Tar(Option<Compression>),
/// Zip archive. /// Zip archive.
#[allow(dead_code)] #[cfg(windows)]
Zip, Zip,
} }
impl ArchiveFormat {
fn compression(self) -> Option<Compression> {
match self {
Self::Tar(c) => c,
#[allow(unreachable_patterns)]
_ => None,
}
}
}
/// The supported compression types. /// The supported compression types.
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive] #[non_exhaustive]
@ -59,8 +69,9 @@ pub enum Compression {
} }
/// The zip entry. /// The zip entry.
#[cfg(windows)]
pub struct ZipEntry { pub struct ZipEntry {
path: PathBuf, path: std::path::PathBuf,
is_dir: bool, is_dir: bool,
file_contents: Vec<u8>, file_contents: Vec<u8>,
} }
@ -73,7 +84,7 @@ pub enum Entry<'a, R: Read> {
Tar(Box<tar::Entry<'a, R>>), Tar(Box<tar::Entry<'a, R>>),
/// An entry of a zip archive. /// An entry of a zip archive.
#[non_exhaustive] #[non_exhaustive]
#[allow(dead_code)] #[cfg(windows)]
Zip(ZipEntry), Zip(ZipEntry),
} }
@ -82,6 +93,7 @@ impl<'a, R: Read> Entry<'a, R> {
pub fn path(&self) -> Result<Cow<'_, Path>> { pub fn path(&self) -> Result<Cow<'_, Path>> {
match self { match self {
Self::Tar(e) => e.path().map_err(Into::into), Self::Tar(e) => e.path().map_err(Into::into),
#[cfg(windows)]
Self::Zip(e) => Ok(Cow::Borrowed(&e.path)), Self::Zip(e) => Ok(Cow::Borrowed(&e.path)),
} }
} }
@ -113,6 +125,7 @@ impl<'a, R: Read> Entry<'a, R> {
} }
} }
} }
#[cfg(windows)]
Self::Zip(entry) => { Self::Zip(entry) => {
if entry.is_dir { if entry.is_dir {
// this is a directory, lets create it // this is a directory, lets create it
@ -126,7 +139,10 @@ impl<'a, R: Read> Entry<'a, R> {
} }
} else { } else {
let mut out_file = fs::File::create(into_path)?; let mut out_file = fs::File::create(into_path)?;
io::copy(&mut Cursor::new(entry.file_contents), &mut out_file)?; io::copy(
&mut std::io::Cursor::new(entry.file_contents),
&mut out_file,
)?;
} }
} }
} }
@ -158,11 +174,7 @@ impl<'a, R: Read + Seek> Extract<'a, R> {
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
eprintln!("Could not seek to start of the file"); eprintln!("Could not seek to start of the file");
} }
let compression = if let ArchiveFormat::Tar(compression) = archive_format { let compression = archive_format.compression();
compression
} else {
None
};
Extract { Extract {
reader: match compression { reader: match compression {
Some(Compression::Gz) => { Some(Compression::Gz) => {
@ -198,28 +210,26 @@ impl<'a, R: Read + Seek> Extract<'a, R> {
} }
} }
#[cfg(windows)]
ArchiveFormat::Zip => { ArchiveFormat::Zip => {
#[cfg(feature = "fs-extract-api")] let mut archive = zip::ZipArchive::new(self.reader.get_mut())?;
{ let file_names = archive
let mut archive = zip::ZipArchive::new(self.reader.get_mut())?; .file_names()
let file_names = archive .map(|f| f.to_string())
.file_names() .collect::<Vec<String>>();
.map(|f| f.to_string()) for path in file_names {
.collect::<Vec<String>>(); let mut zip_file = archive.by_name(&path)?;
for path in file_names { let is_dir = zip_file.is_dir();
let mut zip_file = archive.by_name(&path)?; let mut file_contents = Vec::new();
let is_dir = zip_file.is_dir(); zip_file.read_to_end(&mut file_contents)?;
let mut file_contents = Vec::new(); let stop = f(Entry::Zip(ZipEntry {
zip_file.read_to_end(&mut file_contents)?; path: path.into(),
let stop = f(Entry::Zip(ZipEntry { is_dir,
path: path.into(), file_contents,
is_dir, }))
file_contents, .map_err(Into::into)?;
})) if stop {
.map_err(Into::into)?; break;
if stop {
break;
}
} }
} }
} }
@ -239,34 +249,32 @@ impl<'a, R: Read + Seek> Extract<'a, R> {
archive.unpack(into_dir)?; archive.unpack(into_dir)?;
} }
#[cfg(windows)]
ArchiveFormat::Zip => { ArchiveFormat::Zip => {
#[cfg(feature = "fs-extract-api")] let mut archive = zip::ZipArchive::new(self.reader.get_mut())?;
{ for i in 0..archive.len() {
let mut archive = zip::ZipArchive::new(self.reader.get_mut())?; let mut file = archive.by_index(i)?;
for i in 0..archive.len() { // Decode the file name from raw bytes instead of using file.name() directly.
let mut file = archive.by_index(i)?; // file.name() uses String::from_utf8_lossy() which may return messy characters
// Decode the file name from raw bytes instead of using file.name() directly. // such as: 爱交易.app/, that does not work as expected.
// file.name() uses String::from_utf8_lossy() which may return messy characters // Here we require the file name must be a valid UTF-8.
// such as: 爱交易.app/, that does not work as expected. let file_name = String::from_utf8(file.name_raw().to_vec())?;
// Here we require the file name must be a valid UTF-8. let out_path = into_dir.join(file_name);
let file_name = String::from_utf8(file.name_raw().to_vec())?; if file.is_dir() {
let out_path = into_dir.join(file_name); fs::create_dir_all(&out_path)?;
if file.is_dir() { } else {
fs::create_dir_all(&out_path)?; if let Some(out_path_parent) = out_path.parent() {
} else { fs::create_dir_all(out_path_parent)?;
if let Some(out_path_parent) = out_path.parent() {
fs::create_dir_all(out_path_parent)?;
}
let mut out_file = fs::File::create(&out_path)?;
io::copy(&mut file, &mut out_file)?;
} }
// Get and Set permissions let mut out_file = fs::File::create(&out_path)?;
#[cfg(unix)] io::copy(&mut file, &mut out_file)?;
{ }
use std::os::unix::fs::PermissionsExt; // Get and Set permissions
if let Some(mode) = file.unix_mode() { #[cfg(unix)]
fs::set_permissions(&out_path, fs::Permissions::from_mode(mode))?; {
} use std::os::unix::fs::PermissionsExt;
if let Some(mode) = file.unix_mode() {
fs::set_permissions(&out_path, fs::Permissions::from_mode(mode))?;
} }
} }
} }

@ -319,7 +319,7 @@ class WebviewWindowHandle {
/** The window label. It is a unique identifier for the window, can be used to reference it later. */ /** The window label. It is a unique identifier for the window, can be used to reference it later. */
label: WindowLabel; label: WindowLabel;
/** Local event listeners. */ /** Local event listeners. */
listeners: Record<string, Array<EventCallback<any>>>; listeners: Record<string, Array<EventCallback<unknown>>>;
constructor(label: WindowLabel) { constructor(label: WindowLabel) {
this.label = label; this.label = label;

@ -2,16 +2,16 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
document.addEventListener('mousedown', (e) => { document.addEventListener("mousedown", (e) => {
if (e.target.hasAttribute('data-tauri-drag-region') && e.buttons === 1) { if (e.target.hasAttribute("data-tauri-drag-region") && e.buttons === 1) {
// prevents text cursor // prevents text cursor
e.preventDefault() e.preventDefault();
// fix #2549: double click on drag region edge causes content to maximize without window sizing change // fix #2549: double click on drag region edge causes content to maximize without window sizing change
// https://github.com/tauri-apps/tauri/issues/2549#issuecomment-1250036908 // https://github.com/tauri-apps/tauri/issues/2549#issuecomment-1250036908
e.stopImmediatePropagation() e.stopImmediatePropagation();
// start dragging if the element has a `tauri-drag-region` data attribute and maximize on double-clicking it // start dragging if the element has a `tauri-drag-region` data attribute and maximize on double-clicking it
const cmd = e.detail === 2 ? 'internal_toggle_maximize' : 'start_dragging' const cmd = e.detail === 2 ? "internal_toggle_maximize" : "start_dragging";
window.__TAURI_INVOKE__('plugin:window|' + cmd) window.__TAURI_INVOKE__("plugin:window|" + cmd);
} }
}) });

@ -3,5 +3,5 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
window.print = function () { window.print = function () {
return window.__TAURI_INVOKE__('plugin:window|print') return window.__TAURI_INVOKE__("plugin:window|print");
} };

@ -2,25 +2,25 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
;(function () { (function () {
function toggleDevtoolsHotkey() { function toggleDevtoolsHotkey() {
const isHotkey = navigator.appVersion.includes('Mac') const isHotkey = navigator.appVersion.includes("Mac")
? event => event.metaKey && event.altKey && event.key === 'I' ? (event) => event.metaKey && event.altKey && event.key === "I"
: event => event.ctrlKey && event.shiftKey && event.key === 'I' : (event) => event.ctrlKey && event.shiftKey && event.key === "I";
document.addEventListener('keydown', event => { document.addEventListener("keydown", (event) => {
if (isHotkey(event)) { if (isHotkey(event)) {
window.__TAURI_INVOKE__('plugin:window|internal_toggle_devtools'); window.__TAURI_INVOKE__("plugin:window|internal_toggle_devtools");
} }
}) });
} }
if ( if (
document.readyState === 'complete' || document.readyState === "complete" ||
document.readyState === 'interactive' document.readyState === "interactive"
) { ) {
toggleDevtoolsHotkey() toggleDevtoolsHotkey();
} else { } else {
window.addEventListener('DOMContentLoaded', toggleDevtoolsHotkey, true) window.addEventListener("DOMContentLoaded", toggleDevtoolsHotkey, true);
} }
})() })();

Loading…
Cancel
Save