mirror of
https://github.com/tauri-apps/tauri.git
synced 2024-09-11 16:08:21 +03:00
feat(bundler): support custom sign command on Windows (#9865)
* feat(bundler): support custom sign command on Windows closes #7188 closes #9578 * fix double quotes * fix build * fix build * clippy * Update sign.rs * clippy && replace `winreg` with `windows-registry` * remove log [skip ci] * Apply suggestions from code review * tweak arg so path with spaces work on macOS * create nsis toolset paths --------- Co-authored-by: Lucas Nogueira <lucas@tauri.app>
This commit is contained in:
parent
fc1543c65e
commit
d6d3efbd12
5
.changes/custom-sign-command.md
Normal file
5
.changes/custom-sign-command.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"tauri-bundler": "patch:feat"
|
||||||
|
---
|
||||||
|
|
||||||
|
On Windows, add option to specify a custom signing command to be used. This opens an endless possibilities, for example use `osslsigncode` on non-Windows or use hardware tokens and HSM or even using Azure Trusted Signing.
|
5
.changes/utils-sign-command.md
Normal file
5
.changes/utils-sign-command.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"tauri-utils": "patch:feat"
|
||||||
|
---
|
||||||
|
|
||||||
|
Add `sign_command` in `WindowsConfig`
|
@ -112,6 +112,7 @@
|
|||||||
"certificateThumbprint": null,
|
"certificateThumbprint": null,
|
||||||
"digestAlgorithm": null,
|
"digestAlgorithm": null,
|
||||||
"nsis": null,
|
"nsis": null,
|
||||||
|
"signCommand": null,
|
||||||
"timestampUrl": null,
|
"timestampUrl": null,
|
||||||
"tsp": false,
|
"tsp": false,
|
||||||
"webviewFixedRuntimePath": null,
|
"webviewFixedRuntimePath": null,
|
||||||
@ -1619,6 +1620,7 @@
|
|||||||
"certificateThumbprint": null,
|
"certificateThumbprint": null,
|
||||||
"digestAlgorithm": null,
|
"digestAlgorithm": null,
|
||||||
"nsis": null,
|
"nsis": null,
|
||||||
|
"signCommand": null,
|
||||||
"timestampUrl": null,
|
"timestampUrl": null,
|
||||||
"tsp": false,
|
"tsp": false,
|
||||||
"webviewFixedRuntimePath": null,
|
"webviewFixedRuntimePath": null,
|
||||||
@ -1977,6 +1979,13 @@
|
|||||||
"type": "null"
|
"type": "null"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"signCommand": {
|
||||||
|
"description": "Specify a custom command to sign the binaries. This command needs to have a `%1` in it which is just a placeholder for the binary path, which we will detect and replace before calling the command.\n\nExample: ```text sign-cli --arg1 --arg2 %1 ```\n\nBy Default we use `signtool.exe` which can be found only on Windows so if you are on another platform and want to cross-compile and sign you will need to use another tool like `osslsigncode`.",
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": false
|
"additionalProperties": false
|
||||||
|
@ -859,6 +859,20 @@ pub struct WindowsConfig {
|
|||||||
pub wix: Option<WixConfig>,
|
pub wix: Option<WixConfig>,
|
||||||
/// Configuration for the installer generated with NSIS.
|
/// Configuration for the installer generated with NSIS.
|
||||||
pub nsis: Option<NsisConfig>,
|
pub nsis: Option<NsisConfig>,
|
||||||
|
/// Specify a custom command to sign the binaries.
|
||||||
|
/// This command needs to have a `%1` in it which is just a placeholder for the binary path,
|
||||||
|
/// which we will detect and replace before calling the command.
|
||||||
|
///
|
||||||
|
/// Example:
|
||||||
|
/// ```text
|
||||||
|
/// sign-cli --arg1 --arg2 %1
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// By Default we use `signtool.exe` which can be found only on Windows so
|
||||||
|
/// if you are on another platform and want to cross-compile and sign you will
|
||||||
|
/// need to use another tool like `osslsigncode`.
|
||||||
|
#[serde(alias = "sign-command")]
|
||||||
|
pub sign_command: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for WindowsConfig {
|
impl Default for WindowsConfig {
|
||||||
@ -873,6 +887,7 @@ impl Default for WindowsConfig {
|
|||||||
allow_downgrades: true,
|
allow_downgrades: true,
|
||||||
wix: None,
|
wix: None,
|
||||||
nsis: None,
|
nsis: None,
|
||||||
|
sign_command: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@ dunce = "1"
|
|||||||
[target."cfg(target_os = \"windows\")".dependencies]
|
[target."cfg(target_os = \"windows\")".dependencies]
|
||||||
uuid = { version = "1", features = [ "v4", "v5" ] }
|
uuid = { version = "1", features = [ "v4", "v5" ] }
|
||||||
bitness = "0.4"
|
bitness = "0.4"
|
||||||
winreg = "0.52"
|
windows-registry = "0.1.1"
|
||||||
glob = "0.3"
|
glob = "0.3"
|
||||||
|
|
||||||
[target."cfg(target_os = \"windows\")".dependencies.windows-sys]
|
[target."cfg(target_os = \"windows\")".dependencies.windows-sys]
|
||||||
|
@ -63,8 +63,7 @@ pub fn bundle_project(settings: Settings) -> crate::Result<Vec<Bundle>> {
|
|||||||
log::warn!("Cross-platform compilation is experimental and does not support all features. Please use a matching host system for full compatibility.");
|
log::warn!("Cross-platform compilation is experimental and does not support all features. Please use a matching host system for full compatibility.");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
if settings.can_sign() {
|
||||||
{
|
|
||||||
// Sign windows binaries before the bundling step in case neither wix and nsis bundles are enabled
|
// Sign windows binaries before the bundling step in case neither wix and nsis bundles are enabled
|
||||||
for bin in settings.binaries() {
|
for bin in settings.binaries() {
|
||||||
let bin_path = settings.binary_path(bin);
|
let bin_path = settings.binary_path(bin);
|
||||||
@ -75,16 +74,24 @@ pub fn bundle_project(settings: Settings) -> crate::Result<Vec<Bundle>> {
|
|||||||
for bin in settings.external_binaries() {
|
for bin in settings.external_binaries() {
|
||||||
let path = bin?;
|
let path = bin?;
|
||||||
let skip = std::env::var("TAURI_SKIP_SIDECAR_SIGNATURE_CHECK").map_or(false, |v| v == "true");
|
let skip = std::env::var("TAURI_SKIP_SIDECAR_SIGNATURE_CHECK").map_or(false, |v| v == "true");
|
||||||
|
if skip {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if !skip && windows::sign::verify(&path)? {
|
#[cfg(windows)]
|
||||||
|
if windows::sign::verify(&path)? {
|
||||||
log::info!(
|
log::info!(
|
||||||
"sidecar at \"{}\" already signed. Skipping...",
|
"sidecar at \"{}\" already signed. Skipping...",
|
||||||
path.display()
|
path.display()
|
||||||
)
|
);
|
||||||
} else {
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
windows::sign::try_sign(&path, &settings)?;
|
windows::sign::try_sign(&path, &settings)?;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
|
#[cfg(not(target_os = "windows"))]
|
||||||
|
log::warn!("Signing, by default, is only supported on Windows hosts, but you can specify a custom signing command in `bundler > windows > sign_command`, for now, skipping signing the installer...");
|
||||||
}
|
}
|
||||||
|
|
||||||
for package_type in &package_types {
|
for package_type in &package_types {
|
||||||
|
@ -447,6 +447,20 @@ pub struct WindowsSettings {
|
|||||||
///
|
///
|
||||||
/// /// The default value of this flag is `true`.
|
/// /// The default value of this flag is `true`.
|
||||||
pub allow_downgrades: bool,
|
pub allow_downgrades: bool,
|
||||||
|
|
||||||
|
/// Specify a custom command to sign the binaries.
|
||||||
|
/// This command needs to have a `%1` in it which is just a placeholder for the binary path,
|
||||||
|
/// which we will detect and replace before calling the command.
|
||||||
|
///
|
||||||
|
/// Example:
|
||||||
|
/// ```text
|
||||||
|
/// sign-cli --arg1 --arg2 %1
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// By Default we use `signtool.exe` which can be found only on Windows so
|
||||||
|
/// if you are on another platform and want to cross-compile and sign you will
|
||||||
|
/// need to use another tool like `osslsigncode`.
|
||||||
|
pub sign_command: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for WindowsSettings {
|
impl Default for WindowsSettings {
|
||||||
@ -462,6 +476,7 @@ impl Default for WindowsSettings {
|
|||||||
webview_install_mode: Default::default(),
|
webview_install_mode: Default::default(),
|
||||||
webview_fixed_runtime_path: None,
|
webview_fixed_runtime_path: None,
|
||||||
allow_downgrades: true,
|
allow_downgrades: true,
|
||||||
|
sign_command: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
pub mod msi;
|
pub mod msi;
|
||||||
pub mod nsis;
|
pub mod nsis;
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
pub mod sign;
|
pub mod sign;
|
||||||
|
|
||||||
mod util;
|
mod util;
|
||||||
|
@ -798,7 +798,11 @@ pub fn build_wix_app_installer(
|
|||||||
&msi_output_path,
|
&msi_output_path,
|
||||||
)?;
|
)?;
|
||||||
rename(&msi_output_path, &msi_path)?;
|
rename(&msi_output_path, &msi_path)?;
|
||||||
|
|
||||||
|
if settings.can_sign() {
|
||||||
try_sign(&msi_path, settings)?;
|
try_sign(&msi_path, settings)?;
|
||||||
|
}
|
||||||
|
|
||||||
output_paths.push(msi_path);
|
output_paths.push(msi_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
use crate::bundle::windows::sign::{sign_command, try_sign};
|
use crate::bundle::windows::sign::{sign_command, try_sign};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
bundle::{
|
bundle::{
|
||||||
common::CommandExt,
|
common::CommandExt,
|
||||||
@ -67,6 +67,7 @@ pub fn bundle_project(settings: &Settings, updater: bool) -> crate::Result<Vec<P
|
|||||||
let nsis_toolset_path = tauri_tools_path.join("NSIS");
|
let nsis_toolset_path = tauri_tools_path.join("NSIS");
|
||||||
|
|
||||||
if !nsis_toolset_path.exists() {
|
if !nsis_toolset_path.exists() {
|
||||||
|
create_dir_all(&nsis_toolset_path)?;
|
||||||
get_and_extract_nsis(&nsis_toolset_path, &tauri_tools_path)?;
|
get_and_extract_nsis(&nsis_toolset_path, &tauri_tools_path)?;
|
||||||
} else if NSIS_REQUIRED_FILES
|
} else if NSIS_REQUIRED_FILES
|
||||||
.iter()
|
.iter()
|
||||||
@ -114,12 +115,10 @@ fn get_and_extract_nsis(nsis_toolset_path: &Path, _tauri_tools_path: &Path) -> c
|
|||||||
NSIS_TAURI_UTILS_SHA1,
|
NSIS_TAURI_UTILS_SHA1,
|
||||||
HashAlgorithm::Sha1,
|
HashAlgorithm::Sha1,
|
||||||
)?;
|
)?;
|
||||||
write(
|
|
||||||
nsis_plugins
|
let target_folder = nsis_plugins.join("x86-unicode");
|
||||||
.join("x86-unicode")
|
create_dir_all(&target_folder)?;
|
||||||
.join("nsis_tauri_utils.dll"),
|
write(target_folder.join("nsis_tauri_utils.dll"), data)?;
|
||||||
data,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -163,9 +162,6 @@ fn build_nsis_app_installer(
|
|||||||
|
|
||||||
log::info!("Target: {}", arch);
|
log::info!("Target: {}", arch);
|
||||||
|
|
||||||
#[cfg(not(target_os = "windows"))]
|
|
||||||
log::info!("Code signing is currently only supported on Windows hosts, skipping...");
|
|
||||||
|
|
||||||
let output_path = settings.project_out_directory().join("nsis").join(arch);
|
let output_path = settings.project_out_directory().join("nsis").join(arch);
|
||||||
if output_path.exists() {
|
if output_path.exists() {
|
||||||
remove_dir_all(&output_path)?;
|
remove_dir_all(&output_path)?;
|
||||||
@ -197,16 +193,9 @@ fn build_nsis_app_installer(
|
|||||||
);
|
);
|
||||||
data.insert("copyright", to_json(settings.copyright_string()));
|
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() {
|
if settings.can_sign() {
|
||||||
data.insert(
|
let sign_cmd = format!("{:?}", sign_command("%1", &settings.sign_params())?);
|
||||||
"uninstaller_sign_cmd",
|
data.insert("uninstaller_sign_cmd", to_json(sign_cmd));
|
||||||
to_json(format!(
|
|
||||||
"{:?}",
|
|
||||||
sign_command("%1", &settings.sign_params())?.0
|
|
||||||
)),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let version = settings.version_string();
|
let version = settings.version_string();
|
||||||
@ -517,9 +506,12 @@ fn build_nsis_app_installer(
|
|||||||
|
|
||||||
rename(nsis_output_path, &nsis_installer_path)?;
|
rename(nsis_output_path, &nsis_installer_path)?;
|
||||||
|
|
||||||
// Code signing is currently only supported on Windows hosts
|
if settings.can_sign() {
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
try_sign(&nsis_installer_path, settings)?;
|
try_sign(&nsis_installer_path, settings)?;
|
||||||
|
} else {
|
||||||
|
#[cfg(not(target_os = "windows"))]
|
||||||
|
log::warn!("Signing, by default, is only supported on Windows hosts, but you can specify a custom signing command in `bundler > windows > sign_command`, for now, skipping signing the installer...");
|
||||||
|
}
|
||||||
|
|
||||||
Ok(vec![nsis_installer_path])
|
Ok(vec![nsis_installer_path])
|
||||||
}
|
}
|
||||||
|
@ -3,18 +3,45 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
use crate::{
|
#[cfg(windows)]
|
||||||
bundle::{common::CommandExt, windows::util},
|
use crate::bundle::windows::util;
|
||||||
Settings,
|
use crate::{bundle::common::CommandExt, Settings};
|
||||||
};
|
use anyhow::Context;
|
||||||
use std::{
|
#[cfg(windows)]
|
||||||
path::{Path, PathBuf},
|
use std::path::PathBuf;
|
||||||
process::Command,
|
#[cfg(windows)]
|
||||||
};
|
use std::sync::OnceLock;
|
||||||
use winreg::{
|
use std::{path::Path, process::Command};
|
||||||
enums::{HKEY_LOCAL_MACHINE, KEY_READ, KEY_WOW64_32KEY},
|
|
||||||
RegKey,
|
impl Settings {
|
||||||
};
|
pub(crate) fn can_sign(&self) -> bool {
|
||||||
|
self.windows().sign_command.is_some() || 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,
|
||||||
|
sign_command: self.windows().sign_command.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct SignParams {
|
pub struct SignParams {
|
||||||
pub product_name: String,
|
pub product_name: String,
|
||||||
@ -22,35 +49,34 @@ pub struct SignParams {
|
|||||||
pub certificate_thumbprint: String,
|
pub certificate_thumbprint: String,
|
||||||
pub timestamp_url: Option<String>,
|
pub timestamp_url: Option<String>,
|
||||||
pub tsp: bool,
|
pub tsp: bool,
|
||||||
|
pub sign_command: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
fn signtool() -> Option<PathBuf> {
|
||||||
// sign code forked from https://github.com/forbjok/rust-codesign
|
// sign code forked from https://github.com/forbjok/rust-codesign
|
||||||
fn locate_signtool() -> crate::Result<PathBuf> {
|
static SIGN_TOOL: OnceLock<crate::Result<PathBuf>> = OnceLock::new();
|
||||||
|
SIGN_TOOL
|
||||||
|
.get_or_init(|| {
|
||||||
const INSTALLED_ROOTS_REGKEY_PATH: &str = r"SOFTWARE\Microsoft\Windows Kits\Installed Roots";
|
const INSTALLED_ROOTS_REGKEY_PATH: &str = r"SOFTWARE\Microsoft\Windows Kits\Installed Roots";
|
||||||
const KITS_ROOT_REGVALUE_NAME: &str = r"KitsRoot10";
|
const KITS_ROOT_REGVALUE_NAME: &str = r"KitsRoot10";
|
||||||
|
|
||||||
let installed_roots_key_path = Path::new(INSTALLED_ROOTS_REGKEY_PATH);
|
|
||||||
|
|
||||||
// Open 32-bit HKLM "Installed Roots" key
|
// Open 32-bit HKLM "Installed Roots" key
|
||||||
let installed_roots_key = RegKey::predef(HKEY_LOCAL_MACHINE)
|
let installed_roots_key = windows_registry::LOCAL_MACHINE
|
||||||
.open_subkey_with_flags(installed_roots_key_path, KEY_READ | KEY_WOW64_32KEY)
|
.open(INSTALLED_ROOTS_REGKEY_PATH)
|
||||||
.map_err(|_| crate::Error::OpenRegistry(INSTALLED_ROOTS_REGKEY_PATH.to_string()))?;
|
.map_err(|_| crate::Error::OpenRegistry(INSTALLED_ROOTS_REGKEY_PATH.to_string()))?;
|
||||||
|
|
||||||
// Get the Windows SDK root path
|
// Get the Windows SDK root path
|
||||||
let kits_root_10_path: String = installed_roots_key
|
let kits_root_10_path: String = installed_roots_key
|
||||||
.get_value(KITS_ROOT_REGVALUE_NAME)
|
.get_string(KITS_ROOT_REGVALUE_NAME)
|
||||||
.map_err(|_| crate::Error::GetRegistryValue(KITS_ROOT_REGVALUE_NAME.to_string()))?;
|
.map_err(|_| crate::Error::GetRegistryValue(KITS_ROOT_REGVALUE_NAME.to_string()))?;
|
||||||
|
|
||||||
// Construct Windows SDK bin path
|
// Construct Windows SDK bin path
|
||||||
let kits_root_10_bin_path = Path::new(&kits_root_10_path).join("bin");
|
let kits_root_10_bin_path = Path::new(&kits_root_10_path).join("bin");
|
||||||
|
|
||||||
let mut installed_kits: Vec<String> = installed_roots_key
|
let mut installed_kits: Vec<String> = installed_roots_key
|
||||||
.enum_keys()
|
.keys()
|
||||||
/* Report and ignore errors, pass on values. */
|
.map_err(|_| crate::Error::FailedToEnumerateRegKeys)?
|
||||||
.filter_map(|res| match res {
|
|
||||||
Ok(v) => Some(v),
|
|
||||||
Err(_) => None,
|
|
||||||
})
|
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
// Sort installed kits
|
// Sort installed kits
|
||||||
@ -85,13 +111,17 @@ fn locate_signtool() -> crate::Result<PathBuf> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Err(crate::Error::SignToolNotFound)
|
Err(crate::Error::SignToolNotFound)
|
||||||
|
})
|
||||||
|
.as_ref()
|
||||||
|
.ok()
|
||||||
|
.cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if binary is already signed.
|
/// Check if binary is already signed.
|
||||||
/// Used to skip sidecar binaries that are already signed.
|
/// Used to skip sidecar binaries that are already signed.
|
||||||
|
#[cfg(windows)]
|
||||||
pub fn verify(path: &Path) -> crate::Result<bool> {
|
pub fn verify(path: &Path) -> crate::Result<bool> {
|
||||||
// Construct SignTool command
|
let signtool = signtool().ok_or(crate::Error::SignToolNotFound)?;
|
||||||
let signtool = locate_signtool()?;
|
|
||||||
|
|
||||||
let mut cmd = Command::new(signtool);
|
let mut cmd = Command::new(signtool);
|
||||||
cmd.arg("verify");
|
cmd.arg("verify");
|
||||||
@ -101,9 +131,31 @@ pub fn verify(path: &Path) -> crate::Result<bool> {
|
|||||||
Ok(cmd.status()?.success())
|
Ok(cmd.status()?.success())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sign_command(path: &str, params: &SignParams) -> crate::Result<(Command, PathBuf)> {
|
pub fn sign_command_custom<P: AsRef<Path>>(path: P, command: &str) -> crate::Result<Command> {
|
||||||
// Construct SignTool command
|
let path = path.as_ref();
|
||||||
let signtool = locate_signtool()?;
|
|
||||||
|
let mut args = command.trim().split(' ');
|
||||||
|
let bin = args
|
||||||
|
.next()
|
||||||
|
.context("custom signing command doesn't contain a bin?")?;
|
||||||
|
|
||||||
|
let mut cmd = Command::new(bin);
|
||||||
|
for arg in args {
|
||||||
|
if arg == "%1" {
|
||||||
|
cmd.arg(path);
|
||||||
|
} else {
|
||||||
|
cmd.arg(arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(cmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
pub fn sign_command_default<P: AsRef<Path>>(
|
||||||
|
path: P,
|
||||||
|
params: &SignParams,
|
||||||
|
) -> crate::Result<Command> {
|
||||||
|
let signtool = signtool().ok_or(crate::Error::SignToolNotFound)?;
|
||||||
|
|
||||||
let mut cmd = Command::new(&signtool);
|
let mut cmd = Command::new(&signtool);
|
||||||
cmd.arg("sign");
|
cmd.arg("sign");
|
||||||
@ -120,17 +172,46 @@ pub fn sign_command(path: &str, params: &SignParams) -> crate::Result<(Command,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.arg(path);
|
cmd.arg(path.as_ref());
|
||||||
|
|
||||||
Ok((cmd, signtool))
|
Ok(cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sign<P: AsRef<Path>>(path: P, params: &SignParams) -> crate::Result<()> {
|
pub fn sign_command<P: AsRef<Path>>(path: P, params: &SignParams) -> crate::Result<Command> {
|
||||||
let path_str = path.as_ref().to_str().unwrap();
|
match ¶ms.sign_command {
|
||||||
|
Some(custom_command) => sign_command_custom(path, custom_command),
|
||||||
|
#[cfg(windows)]
|
||||||
|
None => sign_command_default(path, params),
|
||||||
|
|
||||||
log::info!(action = "Signing"; "{} with identity \"{}\"", path_str, params.certificate_thumbprint);
|
// should not be reachable
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
None => Ok(Command::new("")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let (mut cmd, signtool) = sign_command(path_str, params)?;
|
pub fn sign_custom<P: AsRef<Path>>(path: P, custom_command: &str) -> crate::Result<()> {
|
||||||
|
let path = path.as_ref();
|
||||||
|
|
||||||
|
log::info!(action = "Signing";"{} with a custom signing command", tauri_utils::display_path(path));
|
||||||
|
|
||||||
|
let mut cmd = sign_command_custom(path, custom_command)?;
|
||||||
|
|
||||||
|
let output = cmd.output_ok()?;
|
||||||
|
|
||||||
|
let stdout = String::from_utf8_lossy(output.stdout.as_slice()).into_owned();
|
||||||
|
log::info!("{:?}", stdout);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
pub fn sign_default<P: AsRef<Path>>(path: P, params: &SignParams) -> crate::Result<()> {
|
||||||
|
let signtool = signtool().ok_or(crate::Error::SignToolNotFound)?;
|
||||||
|
let path = path.as_ref();
|
||||||
|
|
||||||
|
log::info!(action = "Signing"; "{} with identity \"{}\"", tauri_utils::display_path(path), params.certificate_thumbprint);
|
||||||
|
|
||||||
|
let mut cmd = sign_command_default(path, params)?;
|
||||||
log::debug!("Running signtool {:?}", signtool);
|
log::debug!("Running signtool {:?}", signtool);
|
||||||
|
|
||||||
// Execute SignTool command
|
// Execute SignTool command
|
||||||
@ -142,31 +223,15 @@ pub fn sign<P: AsRef<Path>>(path: P, params: &SignParams) -> crate::Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Settings {
|
pub fn sign<P: AsRef<Path>>(path: P, params: &SignParams) -> crate::Result<()> {
|
||||||
pub(crate) fn can_sign(&self) -> bool {
|
match ¶ms.sign_command {
|
||||||
self.windows().certificate_thumbprint.is_some()
|
Some(custom_command) => sign_custom(path, custom_command),
|
||||||
}
|
#[cfg(windows)]
|
||||||
pub(crate) fn sign_params(&self) -> SignParams {
|
None => sign_default(path, params),
|
||||||
SignParams {
|
// should not be reachable, as user should either use Windows
|
||||||
product_name: self.product_name().into(),
|
// or specify a custom sign_command but we succeed anyways
|
||||||
digest_algorithm: self
|
#[cfg(not(windows))]
|
||||||
.windows()
|
None => Ok(()),
|
||||||
.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,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,6 +94,9 @@ pub enum Error {
|
|||||||
/// Failed to get registry value.
|
/// Failed to get registry value.
|
||||||
#[error("failed to get {0} value on registry")]
|
#[error("failed to get {0} value on registry")]
|
||||||
GetRegistryValue(String),
|
GetRegistryValue(String),
|
||||||
|
/// Failed to enumerate registry keys.
|
||||||
|
#[error("failed to enumerate registry keys")]
|
||||||
|
FailedToEnumerateRegKeys,
|
||||||
/// Unsupported OS bitness.
|
/// Unsupported OS bitness.
|
||||||
#[error("unsupported OS bitness")]
|
#[error("unsupported OS bitness")]
|
||||||
UnsupportedBitness,
|
UnsupportedBitness,
|
||||||
|
22
tooling/cli/Cargo.lock
generated
22
tooling/cli/Cargo.lock
generated
@ -4874,8 +4874,8 @@ dependencies = [
|
|||||||
"ureq",
|
"ureq",
|
||||||
"uuid",
|
"uuid",
|
||||||
"walkdir",
|
"walkdir",
|
||||||
|
"windows-registry",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
"winreg 0.52.0",
|
|
||||||
"zip",
|
"zip",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -5952,6 +5952,16 @@ dependencies = [
|
|||||||
"syn 2.0.52",
|
"syn 2.0.52",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-registry"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f721bc2e55efb506a1a395a545cb76c2481fb023d33b51f0050e7888716281cf"
|
||||||
|
dependencies = [
|
||||||
|
"windows-result",
|
||||||
|
"windows-targets 0.52.5",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-result"
|
name = "windows-result"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
@ -6147,16 +6157,6 @@ dependencies = [
|
|||||||
"windows-sys 0.48.0",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winreg"
|
|
||||||
version = "0.52.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"windows-sys 0.48.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winsafe"
|
name = "winsafe"
|
||||||
version = "0.0.19"
|
version = "0.0.19"
|
||||||
|
@ -112,6 +112,7 @@
|
|||||||
"certificateThumbprint": null,
|
"certificateThumbprint": null,
|
||||||
"digestAlgorithm": null,
|
"digestAlgorithm": null,
|
||||||
"nsis": null,
|
"nsis": null,
|
||||||
|
"signCommand": null,
|
||||||
"timestampUrl": null,
|
"timestampUrl": null,
|
||||||
"tsp": false,
|
"tsp": false,
|
||||||
"webviewFixedRuntimePath": null,
|
"webviewFixedRuntimePath": null,
|
||||||
@ -1619,6 +1620,7 @@
|
|||||||
"certificateThumbprint": null,
|
"certificateThumbprint": null,
|
||||||
"digestAlgorithm": null,
|
"digestAlgorithm": null,
|
||||||
"nsis": null,
|
"nsis": null,
|
||||||
|
"signCommand": null,
|
||||||
"timestampUrl": null,
|
"timestampUrl": null,
|
||||||
"tsp": false,
|
"tsp": false,
|
||||||
"webviewFixedRuntimePath": null,
|
"webviewFixedRuntimePath": null,
|
||||||
@ -1977,6 +1979,13 @@
|
|||||||
"type": "null"
|
"type": "null"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"signCommand": {
|
||||||
|
"description": "Specify a custom command to sign the binaries. This command needs to have a `%1` in it which is just a placeholder for the binary path, which we will detect and replace before calling the command.\n\nExample: ```text sign-cli --arg1 --arg2 %1 ```\n\nBy Default we use `signtool.exe` which can be found only on Windows so if you are on another platform and want to cross-compile and sign you will need to use another tool like `osslsigncode`.",
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": false
|
"additionalProperties": false
|
||||||
|
@ -1420,6 +1420,7 @@ fn tauri_config_to_bundle_settings(
|
|||||||
webview_install_mode: config.windows.webview_install_mode,
|
webview_install_mode: config.windows.webview_install_mode,
|
||||||
webview_fixed_runtime_path: config.windows.webview_fixed_runtime_path,
|
webview_fixed_runtime_path: config.windows.webview_fixed_runtime_path,
|
||||||
allow_downgrades: config.windows.allow_downgrades,
|
allow_downgrades: config.windows.allow_downgrades,
|
||||||
|
sign_command: config.windows.sign_command,
|
||||||
},
|
},
|
||||||
license: config.license.or_else(|| {
|
license: config.license.or_else(|| {
|
||||||
settings
|
settings
|
||||||
|
Loading…
Reference in New Issue
Block a user