@@ -53,7 +53,11 @@ pub use self::{
53
53
use anyhow:: Context ;
54
54
pub use settings:: { NsisSettings , WindowsSettings , WixLanguage , WixLanguageConfig , WixSettings } ;
55
55
56
- use std:: { fmt:: Write , path:: PathBuf } ;
56
+ use std:: {
57
+ fmt:: Write ,
58
+ io:: { Seek , SeekFrom } ,
59
+ path:: PathBuf ,
60
+ } ;
57
61
58
62
/// Generated bundle metadata.
59
63
#[ derive( Debug ) ]
@@ -122,22 +126,46 @@ pub fn bundle_project(settings: &Settings) -> crate::Result<Vec<Bundle>> {
122
126
. iter ( )
123
127
. find ( |b| b. main ( ) )
124
128
. expect ( "Main binary missing in settings" ) ;
129
+ let main_binary_path = settings. binary_path ( main_binary) ;
130
+
131
+ // When packaging multiple binary types, we make a copy of the unsigned main_binary so that we can
132
+ // restore it after each package_type step. This avoids two issues:
133
+ // - modifying a signed binary without updating its PE checksum can break signature verification
134
+ // - codesigning tools should handle calculating+updating this, we just need to ensure
135
+ // (re)signing is performed after every `patch_binary()` operation
136
+ // - signing an already-signed binary can result in multiple signatures, causing verification errors
137
+ let main_binary_reset_required =
138
+ matches ! ( target_os, TargetPlatform :: Windows ) && settings. can_sign ( ) && package_types. len ( ) > 1 ;
139
+ let mut unsigned_main_binary_copy = tempfile:: tempfile ( ) ?;
140
+ if main_binary_reset_required {
141
+ let mut unsigned_main_binary = std:: fs:: File :: open ( & main_binary_path) ?;
142
+ std:: io:: copy ( & mut unsigned_main_binary, & mut unsigned_main_binary_copy) ?;
143
+ }
125
144
145
+ let mut main_binary_signed = false ;
126
146
let mut bundles = Vec :: < Bundle > :: new ( ) ;
127
147
for package_type in & package_types {
128
148
// bundle was already built! e.g. DMG already built .app
129
149
if bundles. iter ( ) . any ( |b| b. package_type == * package_type) {
130
150
continue ;
131
151
}
132
152
133
- if let Err ( e) = patch_binary ( & settings . binary_path ( main_binary ) , package_type) {
153
+ if let Err ( e) = patch_binary ( & main_binary_path , package_type) {
134
154
log:: warn!( "Failed to add bundler type to the binary: {e}. Updater plugin may not be able to update this package. This shouldn't normally happen, please report it to https://github.com/tauri-apps/tauri/issues" ) ;
135
155
}
136
156
137
157
// sign main binary for every package type after patch
138
158
if matches ! ( target_os, TargetPlatform :: Windows ) && settings. can_sign ( ) {
139
- let bin_path = settings. binary_path ( main_binary) ;
140
- windows:: sign:: try_sign ( & bin_path, settings) ?;
159
+ if main_binary_signed && main_binary_reset_required {
160
+ let mut signed_main_binary = std:: fs:: OpenOptions :: new ( )
161
+ . write ( true )
162
+ . truncate ( true )
163
+ . open ( & main_binary_path) ?;
164
+ unsigned_main_binary_copy. seek ( SeekFrom :: Start ( 0 ) ) ?;
165
+ std:: io:: copy ( & mut unsigned_main_binary_copy, & mut signed_main_binary) ?;
166
+ }
167
+ windows:: sign:: try_sign ( & main_binary_path, settings) ?;
168
+ main_binary_signed = true ;
141
169
}
142
170
143
171
let bundle_paths = match package_type {
@@ -160,6 +188,7 @@ pub fn bundle_project(settings: &Settings) -> crate::Result<Vec<Bundle>> {
160
188
161
189
#[ cfg( target_os = "windows" ) ]
162
190
PackageType :: WindowsMsi => windows:: msi:: bundle_project ( settings, false ) ?,
191
+ // note: don't restrict to windows as NSIS installers can be built in linux using cargo-xwin
163
192
PackageType :: Nsis => windows:: nsis:: bundle_project ( settings, false ) ?,
164
193
165
194
#[ cfg( target_os = "linux" ) ]
0 commit comments