Skip to content

Commit

Permalink
feat(bundler/nsis): sign uninstaller, closes #7348 (#7398)
Browse files Browse the repository at this point in the history
* feat(bundler/nsis): sign uninstaller, closes #7348

* Update bundler-nsis-sign-uninstaller.md

* clippy
  • Loading branch information
amrbashir authored Jul 11, 2023
1 parent 757e959 commit 764968a
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 50 deletions.
5 changes: 5 additions & 0 deletions .changes/bundler-nsis-sign-uninstaller.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'tauri-bundler': 'minor:enhance'
---

Sign NSIS uninstaller as well.
11 changes: 7 additions & 4 deletions tooling/bundler/src/bundle/windows/msi/wix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@ use crate::bundle::{
common::CommandExt,
path_utils::{copy_file, FileOpts},
settings::Settings,
windows::util::{
download, download_and_verify, extract_zip, try_sign, HashAlgorithm, WEBVIEW2_BOOTSTRAPPER_URL,
WEBVIEW2_X64_INSTALLER_GUID, WEBVIEW2_X86_INSTALLER_GUID, WIX_OUTPUT_FOLDER_NAME,
WIX_UPDATER_OUTPUT_FOLDER_NAME,
windows::{
sign::try_sign,
util::{
download, download_and_verify, extract_zip, HashAlgorithm, WEBVIEW2_BOOTSTRAPPER_URL,
WEBVIEW2_X64_INSTALLER_GUID, WEBVIEW2_X86_INSTALLER_GUID, WIX_OUTPUT_FOLDER_NAME,
WIX_UPDATER_OUTPUT_FOLDER_NAME,
},
},
};
use anyhow::{bail, Context};
Expand Down
15 changes: 14 additions & 1 deletion tooling/bundler/src/bundle/windows/nsis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// SPDX-License-Identifier: MIT

#[cfg(target_os = "windows")]
use crate::bundle::windows::util::try_sign;
use crate::bundle::windows::sign::{sign_command, try_sign};
use crate::{
bundle::{
common::CommandExt,
Expand Down Expand Up @@ -160,6 +160,7 @@ fn build_nsis_app_installer(

info!("Target: {}", arch);

// Code signing is currently only supported on Windows hosts
#[cfg(target_os = "windows")]
{
let main_binary = settings
Expand Down Expand Up @@ -201,6 +202,18 @@ fn build_nsis_app_installer(
data.insert("short_description", to_json(settings.short_description()));
data.insert("copyright", to_json(settings.copyright_string()));

// Code signing is currently only supported on Windows hosts
#[cfg(target_os = "windows")]
if settings.can_sign() {
data.insert(
"uninstaller_sign_cmd",
to_json(format!(
"{:?}",
sign_command("%1", &settings.sign_params())?.0
)),
);
}

let version = settings.version_string();
data.insert("version", to_json(version));
data.insert(
Expand Down
62 changes: 51 additions & 11 deletions tooling/bundler/src/bundle/windows/sign.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT

use crate::bundle::common::CommandExt;
use crate::{bundle::common::CommandExt, Settings};
use bitness::{self, Bitness};
use log::{debug, info};
use std::{
Expand Down Expand Up @@ -90,18 +90,11 @@ fn locate_signtool() -> crate::Result<PathBuf> {
Err(crate::Error::SignToolNotFound)
}

pub fn sign<P: AsRef<Path>>(path: P, params: &SignParams) -> crate::Result<()> {
// Convert path to string reference, as we need to pass it as a command-line parameter to signtool
let path_str = path.as_ref().to_str().unwrap();

info!(action = "Signing"; "{} with identity \"{}\"", path_str, params.certificate_thumbprint);

pub fn sign_command(path: &str, params: &SignParams) -> crate::Result<(Command, PathBuf)> {
// Construct SignTool command
let signtool = locate_signtool()?;

debug!("Running signtool {:?}", signtool);

let mut cmd = Command::new(signtool);
let mut cmd = Command::new(&signtool);
cmd.arg("sign");
cmd.args(["/fd", &params.digest_algorithm]);
cmd.args(["/sha1", &params.certificate_thumbprint]);
Expand All @@ -116,7 +109,18 @@ pub fn sign<P: AsRef<Path>>(path: P, params: &SignParams) -> crate::Result<()> {
}
}

cmd.arg(path_str);
cmd.arg(path);

Ok((cmd, signtool))
}

pub fn sign<P: AsRef<Path>>(path: P, params: &SignParams) -> crate::Result<()> {
let path_str = path.as_ref().to_str().unwrap();

info!(action = "Signing"; "{} with identity \"{}\"", path_str, params.certificate_thumbprint);

let (mut cmd, signtool) = sign_command(path_str, params)?;
debug!("Running signtool {:?}", signtool);

// Execute SignTool command
let output = cmd.output_ok()?;
Expand All @@ -126,3 +130,39 @@ pub fn sign<P: AsRef<Path>>(path: P, params: &SignParams) -> crate::Result<()> {

Ok(())
}

impl Settings {
pub(crate) fn can_sign(&self) -> bool {
self.windows().certificate_thumbprint.is_some()
}
pub(crate) fn sign_params(&self) -> SignParams {
SignParams {
product_name: self.product_name().into(),
digest_algorithm: self
.windows()
.digest_algorithm
.as_ref()
.map(|algorithm| algorithm.to_string())
.unwrap_or_else(|| "sha256".to_string()),
certificate_thumbprint: self
.windows()
.certificate_thumbprint
.clone()
.unwrap_or_default(),
timestamp_url: self
.windows()
.timestamp_url
.as_ref()
.map(|url| url.to_string()),
tsp: self.windows().tsp,
}
}
}

pub fn try_sign(file_path: &std::path::PathBuf, settings: &Settings) -> crate::Result<()> {
if settings.can_sign() {
info!(action = "Signing"; "{}", tauri_utils::display_path(file_path));
sign(file_path, &settings.sign_params())?;
}
Ok(())
}
5 changes: 5 additions & 0 deletions tooling/bundler/src/bundle/windows/templates/installer.nsi
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ ${StrLoc}
!define WEBVIEW2INSTALLERPATH "{{webview2_installer_path}}"
!define UNINSTKEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCTNAME}"
!define MANUPRODUCTKEY "Software\${MANUFACTURER}\${PRODUCTNAME}"
!define UNINSTALLERSIGNCOMMAND "{{uninstaller_sign_cmd}}"

Name "${PRODUCTNAME}"
BrandingText "${COPYRIGHT}"
Expand All @@ -51,6 +52,10 @@ VIAddVersionKey "ProductVersion" "${VERSION}"
!addplugindir "${PLUGINSPATH}"
!endif

!if "${UNINSTALLERSIGNCOMMAND}" != ""
!uninstfinalize '${UNINSTALLERSIGNCOMMAND}'
!endif

; Handle install mode, `perUser`, `perMachine` or `both`
!if "${INSTALLMODE}" == "perMachine"
RequestExecutionLevel highest
Expand Down
34 changes: 0 additions & 34 deletions tooling/bundler/src/bundle/windows/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,6 @@ use log::info;
use sha2::Digest;
use zip::ZipArchive;

#[cfg(target_os = "windows")]
use crate::bundle::windows::sign::{sign, SignParams};
#[cfg(target_os = "windows")]
use crate::Settings;

pub const WEBVIEW2_BOOTSTRAPPER_URL: &str = "https://go.microsoft.com/fwlink/p/?LinkId=2124703";
pub const WEBVIEW2_X86_INSTALLER_GUID: &str = "a17bde80-b5ab-47b5-8bbb-1cbe93fc6ec9";
pub const WEBVIEW2_X64_INSTALLER_GUID: &str = "aa5fd9b3-dc11-4cbc-8343-a50f57b311e1";
Expand Down Expand Up @@ -75,35 +70,6 @@ fn verify(data: &Vec<u8>, hash: &str, mut hasher: impl Digest) -> crate::Result<
}
}

#[cfg(target_os = "windows")]
pub fn try_sign(file_path: &std::path::PathBuf, settings: &Settings) -> crate::Result<()> {
use tauri_utils::display_path;

if let Some(certificate_thumbprint) = settings.windows().certificate_thumbprint.as_ref() {
info!(action = "Signing"; "{}", display_path(file_path));
sign(
file_path,
&SignParams {
product_name: settings.product_name().into(),
digest_algorithm: settings
.windows()
.digest_algorithm
.as_ref()
.map(|algorithm| algorithm.to_string())
.unwrap_or_else(|| "sha256".to_string()),
certificate_thumbprint: certificate_thumbprint.to_string(),
timestamp_url: settings
.windows()
.timestamp_url
.as_ref()
.map(|url| url.to_string()),
tsp: settings.windows().tsp,
},
)?;
}
Ok(())
}

/// Extracts the zips from memory into a useable path.
pub fn extract_zip(data: &[u8], path: &Path) -> crate::Result<()> {
let cursor = Cursor::new(data);
Expand Down

0 comments on commit 764968a

Please sign in to comment.