util.rs 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. // Copyright 2019-2022 Tauri Programme within The Commons Conservancy
  2. // SPDX-License-Identifier: Apache-2.0
  3. // SPDX-License-Identifier: MIT
  4. use std::{
  5. fs::{create_dir_all, File},
  6. io::{Cursor, Read, Write},
  7. path::{Path, PathBuf},
  8. };
  9. use log::info;
  10. use sha2::Digest;
  11. use zip::ZipArchive;
  12. #[cfg(target_os = "windows")]
  13. use crate::bundle::windows::sign::{sign, SignParams};
  14. #[cfg(target_os = "windows")]
  15. use crate::Settings;
  16. pub const WEBVIEW2_BOOTSTRAPPER_URL: &str = "https://go.microsoft.com/fwlink/p/?LinkId=2124703";
  17. pub const WEBVIEW2_X86_INSTALLER_GUID: &str = "a17bde80-b5ab-47b5-8bbb-1cbe93fc6ec9";
  18. pub const WEBVIEW2_X64_INSTALLER_GUID: &str = "aa5fd9b3-dc11-4cbc-8343-a50f57b311e1";
  19. pub const NSIS_OUTPUT_FOLDER_NAME: &str = "nsis";
  20. pub const NSIS_UPDATER_OUTPUT_FOLDER_NAME: &str = "nsis-updater";
  21. pub const WIX_OUTPUT_FOLDER_NAME: &str = "msi";
  22. pub const WIX_UPDATER_OUTPUT_FOLDER_NAME: &str = "msi-updater";
  23. pub fn download(url: &str) -> crate::Result<Vec<u8>> {
  24. info!(action = "Downloading"; "{}", url);
  25. let response = attohttpc::get(url).send()?;
  26. response.bytes().map_err(Into::into)
  27. }
  28. pub enum HashAlgorithm {
  29. #[cfg(target_os = "windows")]
  30. Sha256,
  31. Sha1,
  32. }
  33. /// Function used to download a file and checks SHA256 to verify the download.
  34. pub fn download_and_verify(
  35. url: &str,
  36. hash: &str,
  37. hash_algorithm: HashAlgorithm,
  38. ) -> crate::Result<Vec<u8>> {
  39. let data = download(url)?;
  40. info!("validating hash");
  41. match hash_algorithm {
  42. #[cfg(target_os = "windows")]
  43. HashAlgorithm::Sha256 => {
  44. let hasher = sha2::Sha256::new();
  45. verify(&data, hash, hasher)?;
  46. }
  47. HashAlgorithm::Sha1 => {
  48. let hasher = sha1::Sha1::new();
  49. verify(&data, hash, hasher)?;
  50. }
  51. }
  52. Ok(data)
  53. }
  54. fn verify(data: &Vec<u8>, hash: &str, mut hasher: impl Digest) -> crate::Result<()> {
  55. hasher.update(data);
  56. let url_hash = hasher.finalize().to_vec();
  57. let expected_hash = hex::decode(hash)?;
  58. if expected_hash == url_hash {
  59. Ok(())
  60. } else {
  61. Err(crate::Error::HashError)
  62. }
  63. }
  64. #[cfg(target_os = "windows")]
  65. pub fn try_sign(file_path: &PathBuf, settings: &Settings) -> crate::Result<()> {
  66. use tauri_utils::display_path;
  67. if let Some(certificate_thumbprint) = settings.windows().certificate_thumbprint.as_ref() {
  68. info!(action = "Signing"; "{}", display_path(file_path));
  69. sign(
  70. file_path,
  71. &SignParams {
  72. product_name: settings.product_name().into(),
  73. digest_algorithm: settings
  74. .windows()
  75. .digest_algorithm
  76. .as_ref()
  77. .map(|algorithm| algorithm.to_string())
  78. .unwrap_or_else(|| "sha256".to_string()),
  79. certificate_thumbprint: certificate_thumbprint.to_string(),
  80. timestamp_url: settings
  81. .windows()
  82. .timestamp_url
  83. .as_ref()
  84. .map(|url| url.to_string()),
  85. tsp: settings.windows().tsp,
  86. },
  87. )?;
  88. }
  89. Ok(())
  90. }
  91. /// Extracts the zips from memory into a useable path.
  92. pub fn extract_zip(data: &[u8], path: &Path) -> crate::Result<()> {
  93. let cursor = Cursor::new(data);
  94. let mut zipa = ZipArchive::new(cursor)?;
  95. for i in 0..zipa.len() {
  96. let mut file = zipa.by_index(i)?;
  97. let dest_path = path.join(file.name());
  98. if file.is_dir() {
  99. create_dir_all(&dest_path)?;
  100. continue;
  101. }
  102. let parent = dest_path.parent().expect("Failed to get parent");
  103. if !parent.exists() {
  104. create_dir_all(parent)?;
  105. }
  106. let mut buff: Vec<u8> = Vec::new();
  107. file.read_to_end(&mut buff)?;
  108. let mut fileout = File::create(dest_path).expect("Failed to open file");
  109. fileout.write_all(&buff)?;
  110. }
  111. Ok(())
  112. }
  113. pub fn remove_unc_lossy<P: AsRef<Path>>(p: P) -> PathBuf {
  114. PathBuf::from(p.as_ref().to_string_lossy().replacen(r"\\?\", "", 1))
  115. }