Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(updater): Add .deb Package Support to Linux Updater #1991

Merged
merged 45 commits into from
Nov 26, 2024
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
72a4670
Added deb update support
jLynx Oct 31, 2024
c890ec6
WIP
jLynx Oct 31, 2024
552c7b8
WIP
jLynx Oct 31, 2024
0be9dbb
WIP
jLynx Nov 1, 2024
a0ad60b
updated logging
jLynx Nov 1, 2024
fb269f0
add tarball support
jLynx Nov 1, 2024
b178029
reverted to deb only
jLynx Nov 1, 2024
a3f8462
add tarball support
jLynx Nov 1, 2024
7f7b6fd
Removed logs
jLynx Nov 1, 2024
c88064b
removed spaces
jLynx Nov 1, 2024
9b5d30a
fixed comments
jLynx Nov 1, 2024
408ccba
Clean up comments
jLynx Nov 1, 2024
4d4f2f8
Fixed console log
jLynx Nov 1, 2024
37ec629
Removed gz support
jLynx Nov 3, 2024
f1e3c10
Merge branch 'v2' into fix/deb_update
jLynx Nov 3, 2024
3651103
Merge branch 'v2' into fix/deb_update
jLynx Nov 4, 2024
69d6a55
Merge branch 'v2' into fix/deb_update
jLynx Nov 12, 2024
be60315
Updated detection method
jLynx Nov 12, 2024
a8866b9
Fixed formatting
jLynx Nov 12, 2024
337e23e
refactor
jLynx Nov 12, 2024
af8c8d9
Merge branch 'v2' into fix/deb_update
jLynx Nov 12, 2024
d8dcfef
Added changes file
jLynx Nov 12, 2024
f9f9297
Added update with kdialog support
jLynx Nov 12, 2024
466cdae
Check if file is deb
jLynx Nov 12, 2024
7d70f62
Updated as per comments
jLynx Nov 12, 2024
ffec0ed
Added appimage implementaion
jLynx Nov 13, 2024
f79dfbf
WIP test for deb
jLynx Nov 13, 2024
7346ade
got deb running
jLynx Nov 13, 2024
5a95db8
Now runs both appimage and deb tests
jLynx Nov 13, 2024
cbb0813
Adjusted order
jLynx Nov 13, 2024
36469f2
Merge branch 'v2' into fix/deb_update
jLynx Nov 13, 2024
a13d5b4
Got the build working
jLynx Nov 13, 2024
9c4f9d8
Merge branch 'fix/deb_update' of https://github.com/jLynx/plugins-wor…
jLynx Nov 13, 2024
8f07405
Got deb tests passing
jLynx Nov 14, 2024
5622972
Attempt at buidling with GH Actions
jLynx Nov 14, 2024
cf50659
WIP GH Actions
jLynx Nov 14, 2024
44d2e77
WIP
jLynx Nov 14, 2024
6b21e88
wip
jLynx Nov 14, 2024
628a355
Reverted tests
jLynx Nov 24, 2024
cd37fc1
Reverted tests
jLynx Nov 24, 2024
a6b9da7
Reverted tests
jLynx Nov 24, 2024
9c5eaef
Merge branch 'v2' into fix/deb_update
jLynx Nov 24, 2024
338aedb
Fixed formatting
jLynx Nov 24, 2024
88b3995
Fixed formatting
jLynx Nov 25, 2024
ce46dd5
Merge branch 'v2' into fix/deb_update
jLynx Nov 25, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions plugins/updater/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ pub enum Error {
TempDirNotOnSameMountPoint,
#[error("binary for the current target not found in the archive")]
BinaryNotFoundInArchive,
#[error("Authentication failed or was cancelled")]
AuthenticationFailed,
#[error("Failed to install .deb package")]
DebInstallFailed,
#[error("invalid updater binary format")]
InvalidUpdaterFormat,
#[error(transparent)]
Expand Down
117 changes: 113 additions & 4 deletions plugins/updater/src/updater.rs
Original file line number Diff line number Diff line change
Expand Up @@ -748,7 +748,7 @@ impl Update {
}
}

/// Linux (AppImage)
/// Linux (AppImage and Deb)
#[cfg(any(
target_os = "linux",
target_os = "dragonfly",
Expand All @@ -760,12 +760,19 @@ impl Update {
/// ### Expected structure:
/// ├── [AppName]_[version]_amd64.AppImage.tar.gz # GZ generated by tauri-bundler
/// │ └──[AppName]_[version]_amd64.AppImage # Application AppImage
/// ├── [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<()> {
if self.is_deb_package() {
amrbashir marked this conversation as resolved.
Show resolved Hide resolved
self.install_deb_update(bytes)
} else {
// Handle AppImage or other formats
self.install_appimage_update(bytes)
}
}

fn install_appimage_update(&self, bytes: &[u8]) -> Result<()> {
amrbashir marked this conversation as resolved.
Show resolved Hide resolved
use std::os::unix::fs::{MetadataExt, PermissionsExt};
let extract_path_metadata = self.extract_path.metadata()?;

Expand Down Expand Up @@ -835,6 +842,108 @@ impl Update {

Err(Error::TempDirNotOnSameMountPoint)
}

fn is_deb_package(&self) -> bool {
// Check if we're running from a .deb installation
// Typically installed in /usr/bin or /usr/local/bin
self.extract_path
.to_str()
.map(|p| p.starts_with("/usr"))
.unwrap_or(false)
}
amrbashir marked this conversation as resolved.
Show resolved Hide resolved

fn install_deb_update(&self, bytes: &[u8]) -> Result<()> {
amrbashir marked this conversation as resolved.
Show resolved Hide resolved
// Create a temporary directory
let tmp_dir = tempfile::Builder::new()
.prefix("tauri_deb_update")
.tempdir_in("/tmp")?;
amrbashir marked this conversation as resolved.
Show resolved Hide resolved

let deb_path = tmp_dir.path().join("package.deb");

// Direct .deb file
std::fs::write(&deb_path, bytes)?;

// Try different privilege escalation methods
let installation_result = self.try_install_with_privileges(&deb_path);

// Clean up
let _ = std::fs::remove_file(&deb_path);
amrbashir marked this conversation as resolved.
Show resolved Hide resolved

installation_result
}

fn try_install_with_privileges(&self, deb_path: &Path) -> Result<()> {
// 1. First try using pkexec (graphical sudo prompt)
if let Ok(status) = std::process::Command::new("pkexec")
.arg("dpkg")
.arg("-i")
.arg(deb_path)
.status()
{
if status.success() {
return Ok(());
}
}

// 2. Try zenity for a more user-friendly graphical sudo experience
if let Ok(password) = self.get_password_graphically() {
if self.install_with_sudo(deb_path, &password)? {
return Ok(());
}
}

// 3. Final fallback: terminal sudo
let status = std::process::Command::new("sudo")
.arg("dpkg")
.arg("-i")
.arg(deb_path)
.status()?;
amrbashir marked this conversation as resolved.
Show resolved Hide resolved

if status.success() {
Ok(())
} else {
Err(Error::DebInstallFailed)
}
}

fn get_password_graphically(&self) -> Result<String> {
let output = std::process::Command::new("zenity")
amrbashir marked this conversation as resolved.
Show resolved Hide resolved
.args([
"--password",
"--title=Authentication Required",
"--text=Enter your password to install the update:",
])
.output()?;

if output.status.success() {
Ok(String::from_utf8_lossy(&output.stdout).trim().to_string())
} else {
Err(Error::AuthenticationFailed)
}
}

fn install_with_sudo(&self, deb_path: &Path, password: &str) -> Result<bool> {
use std::io::Write;
use std::process::{Command, Stdio};

let mut child = Command::new("sudo")
.arg("-S") // read password from stdin
.arg("dpkg")
.arg("-i")
.arg(deb_path)
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()?;

if let Some(mut stdin) = child.stdin.take() {
// Write password to stdin
writeln!(stdin, "{}", password)?;
}

let status = child.wait()?;
Ok(status.success())
}
}

/// MacOS
Expand Down
Loading