|
|
@ -748,7 +748,7 @@ impl Update {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Linux (AppImage)
|
|
|
|
/// Linux (AppImage and Deb)
|
|
|
|
#[cfg(any(
|
|
|
|
#[cfg(any(
|
|
|
|
target_os = "linux",
|
|
|
|
target_os = "linux",
|
|
|
|
target_os = "dragonfly",
|
|
|
|
target_os = "dragonfly",
|
|
|
@ -760,13 +760,18 @@ impl Update {
|
|
|
|
/// ### Expected structure:
|
|
|
|
/// ### Expected structure:
|
|
|
|
/// ├── [AppName]_[version]_amd64.AppImage.tar.gz # GZ generated by tauri-bundler
|
|
|
|
/// ├── [AppName]_[version]_amd64.AppImage.tar.gz # GZ generated by tauri-bundler
|
|
|
|
/// │ └──[AppName]_[version]_amd64.AppImage # Application AppImage
|
|
|
|
/// │ └──[AppName]_[version]_amd64.AppImage # Application AppImage
|
|
|
|
|
|
|
|
/// ├── [AppName]_[version]_amd64.deb.tar.gz # GZ generated by tauri-bundler
|
|
|
|
|
|
|
|
/// │ └──[AppName]_[version]_amd64.deb # Debian package
|
|
|
|
/// └── ...
|
|
|
|
/// └── ...
|
|
|
|
///
|
|
|
|
|
|
|
|
/// We should have an AppImage already installed to be able to copy and install
|
|
|
|
|
|
|
|
/// the extract_path is the current AppImage path
|
|
|
|
|
|
|
|
/// tmp_dir is where our new AppImage is found
|
|
|
|
|
|
|
|
fn install_inner(&self, bytes: &[u8]) -> Result<()> {
|
|
|
|
fn install_inner(&self, bytes: &[u8]) -> Result<()> {
|
|
|
|
use std::os::unix::fs::{MetadataExt, PermissionsExt};
|
|
|
|
use std::os::unix::fs::{MetadataExt, PermissionsExt};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Check if it's a .deb package by examining the file extension
|
|
|
|
|
|
|
|
if self.extract_path.extension() == Some(OsStr::new("deb")) {
|
|
|
|
|
|
|
|
return self.install_deb(bytes);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Existing AppImage installation logic
|
|
|
|
let extract_path_metadata = self.extract_path.metadata()?;
|
|
|
|
let extract_path_metadata = self.extract_path.metadata()?;
|
|
|
|
|
|
|
|
|
|
|
|
let tmp_dir_locations = vec![
|
|
|
|
let tmp_dir_locations = vec![
|
|
|
@ -797,24 +802,20 @@ impl Update {
|
|
|
|
#[cfg(feature = "zip")]
|
|
|
|
#[cfg(feature = "zip")]
|
|
|
|
if infer::archive::is_gz(bytes) {
|
|
|
|
if infer::archive::is_gz(bytes) {
|
|
|
|
// extract the buffer to the tmp_dir
|
|
|
|
// extract the buffer to the tmp_dir
|
|
|
|
// we extract our signed archive into our final directory without any temp file
|
|
|
|
|
|
|
|
let archive = Cursor::new(bytes);
|
|
|
|
let archive = Cursor::new(bytes);
|
|
|
|
let decoder = flate2::read::GzDecoder::new(archive);
|
|
|
|
let decoder = flate2::read::GzDecoder::new(archive);
|
|
|
|
let mut archive = tar::Archive::new(decoder);
|
|
|
|
let mut archive = tar::Archive::new(decoder);
|
|
|
|
for mut entry in archive.entries()?.flatten() {
|
|
|
|
for mut entry in archive.entries()?.flatten() {
|
|
|
|
if let Ok(path) = entry.path() {
|
|
|
|
if let Ok(path) = entry.path() {
|
|
|
|
if path.extension() == Some(OsStr::new("AppImage")) {
|
|
|
|
if path.extension() == Some(OsStr::new("AppImage")) {
|
|
|
|
// if something went wrong during the extraction, we should restore previous app
|
|
|
|
|
|
|
|
if let Err(err) = entry.unpack(&self.extract_path) {
|
|
|
|
if let Err(err) = entry.unpack(&self.extract_path) {
|
|
|
|
std::fs::rename(tmp_app_image, &self.extract_path)?;
|
|
|
|
std::fs::rename(tmp_app_image, &self.extract_path)?;
|
|
|
|
return Err(err.into());
|
|
|
|
return Err(err.into());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// early finish we have everything we need here
|
|
|
|
|
|
|
|
return Ok(());
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// if we have not returned early we should restore the backup
|
|
|
|
|
|
|
|
std::fs::rename(tmp_app_image, &self.extract_path)?;
|
|
|
|
std::fs::rename(tmp_app_image, &self.extract_path)?;
|
|
|
|
return Err(Error::BinaryNotFoundInArchive);
|
|
|
|
return Err(Error::BinaryNotFoundInArchive);
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -823,7 +824,6 @@ impl Update {
|
|
|
|
.and_then(|_| std::fs::set_permissions(&self.extract_path, permissions))
|
|
|
|
.and_then(|_| std::fs::set_permissions(&self.extract_path, permissions))
|
|
|
|
{
|
|
|
|
{
|
|
|
|
Err(err) => {
|
|
|
|
Err(err) => {
|
|
|
|
// if something went wrong during the extraction, we should restore previous app
|
|
|
|
|
|
|
|
std::fs::rename(tmp_app_image, &self.extract_path)?;
|
|
|
|
std::fs::rename(tmp_app_image, &self.extract_path)?;
|
|
|
|
Err(err.into())
|
|
|
|
Err(err.into())
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -835,6 +835,46 @@ impl Update {
|
|
|
|
|
|
|
|
|
|
|
|
Err(Error::TempDirNotOnSameMountPoint)
|
|
|
|
Err(Error::TempDirNotOnSameMountPoint)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn install_deb(&self, bytes: &[u8]) -> Result<()> {
|
|
|
|
|
|
|
|
use std::process::Command;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Create a temporary directory to store the .deb file
|
|
|
|
|
|
|
|
let tmp_dir = tempfile::Builder::new()
|
|
|
|
|
|
|
|
.prefix("tauri_deb_update")
|
|
|
|
|
|
|
|
.tempdir()?;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let deb_path = tmp_dir.path().join("package.deb");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Write the .deb file to the temporary directory
|
|
|
|
|
|
|
|
std::fs::write(&deb_path, bytes)?;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// First, try using pkexec (graphical sudo prompt)
|
|
|
|
|
|
|
|
let status = Command::new("pkexec")
|
|
|
|
|
|
|
|
.arg("dpkg")
|
|
|
|
|
|
|
|
.arg("-i")
|
|
|
|
|
|
|
|
.arg(&deb_path)
|
|
|
|
|
|
|
|
.status();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
match status {
|
|
|
|
|
|
|
|
Ok(exit_status) if exit_status.success() => Ok(()),
|
|
|
|
|
|
|
|
_ => {
|
|
|
|
|
|
|
|
// If pkexec fails, try with regular sudo
|
|
|
|
|
|
|
|
// Note: This requires the user to have a terminal open
|
|
|
|
|
|
|
|
let status = Command::new("sudo")
|
|
|
|
|
|
|
|
.arg("dpkg")
|
|
|
|
|
|
|
|
.arg("-i")
|
|
|
|
|
|
|
|
.arg(&deb_path)
|
|
|
|
|
|
|
|
.status()?;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if status.success() {
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
Err(Error::DebInstallFailed)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// MacOS
|
|
|
|
/// MacOS
|
|
|
|