@@ -18,6 +18,8 @@ use std::{
1818 time:: { SystemTime , UNIX_EPOCH } ,
1919} ;
2020
21+ #[ cfg( target_os = "macos" ) ]
22+ use std:: fs:: rename;
2123#[ cfg( not( target_os = "macos" ) ) ]
2224use std:: process:: Command ;
2325
@@ -230,7 +232,7 @@ impl<'a> UpdateBuilder<'a> {
230232 } else {
231233 // we expect it to fail if we can't find the executable path
232234 // without this path we can't continue the update process.
233- env:: current_exe ( ) . expect ( "Can't access current executable path." )
235+ env:: current_exe ( ) ?
234236 } ;
235237
236238 // Did the target is provided by the config?
@@ -479,17 +481,16 @@ impl Update {
479481// We should have an AppImage already installed to be able to copy and install
480482// the extract_path is the current AppImage path
481483// tmp_dir is where our new AppImage is found
482-
483484#[ cfg( target_os = "linux" ) ]
484485fn copy_files_and_run ( tmp_dir : tempfile:: TempDir , extract_path : PathBuf ) -> Result {
485486 // we delete our current AppImage (we'll create a new one later)
486487 remove_file ( & extract_path) ?;
487488
488489 // In our tempdir we expect 1 directory (should be the <app>.app)
489- let paths = read_dir ( & tmp_dir) . unwrap ( ) ;
490+ let paths = read_dir ( & tmp_dir) ? ;
490491
491492 for path in paths {
492- let found_path = path. expect ( "Unable to extract" ) . path ( ) ;
493+ let found_path = path? . path ( ) ;
493494 // make sure it's our .AppImage
494495 if found_path. extension ( ) == Some ( OsStr :: new ( "AppImage" ) ) {
495496 // Simply overwrite our AppImage (we use the command)
@@ -522,16 +523,15 @@ fn copy_files_and_run(tmp_dir: tempfile::TempDir, extract_path: PathBuf) -> Resu
522523
523524// ## EXE
524525// Update server can provide a custom EXE (installer) who can run any task.
525-
526526#[ cfg( target_os = "windows" ) ]
527527#[ allow( clippy:: unnecessary_wraps) ]
528528fn copy_files_and_run ( tmp_dir : tempfile:: TempDir , _extract_path : PathBuf ) -> Result {
529- let paths = read_dir ( & tmp_dir) . unwrap ( ) ;
529+ let paths = read_dir ( & tmp_dir) ? ;
530530 // This consumes the TempDir without deleting directory on the filesystem,
531531 // meaning that the directory will no longer be automatically deleted.
532532 tmp_dir. into_path ( ) ;
533533 for path in paths {
534- let found_path = path. expect ( "Unable to extract" ) . path ( ) ;
534+ let found_path = path? . path ( ) ;
535535 // we support 2 type of files exe & msi for now
536536 // If it's an `exe` we expect an installer not a runtime.
537537 if found_path. extension ( ) == Some ( OsStr :: new ( "exe" ) ) {
@@ -558,27 +558,57 @@ fn copy_files_and_run(tmp_dir: tempfile::TempDir, _extract_path: PathBuf) -> Res
558558 Ok ( ( ) )
559559}
560560
561- // MacOS
561+ // Get the current app name in the path
562+ // Example; `/Applications/updater-example.app/Contents/MacOS/updater-example`
563+ // Should return; `updater-example.app`
564+ #[ cfg( target_os = "macos" ) ]
565+ fn macos_app_name_in_path ( extract_path : & PathBuf ) -> String {
566+ let components = extract_path. components ( ) ;
567+ let app_name = components. last ( ) . unwrap ( ) ;
568+ let app_name = app_name. as_os_str ( ) . to_str ( ) . unwrap ( ) ;
569+ app_name. to_string ( )
570+ }
562571
572+ // MacOS
563573// ### Expected structure:
564574// ├── [AppName]_[version]_x64.app.tar.gz # GZ generated by tauri-bundler
565575// │ └──[AppName].app # Main application
566576// │ └── Contents # Application contents...
567577// │ └── ...
568578// └── ...
569-
570579#[ cfg( target_os = "macos" ) ]
571580fn copy_files_and_run ( tmp_dir : tempfile:: TempDir , extract_path : PathBuf ) -> Result {
572581 // In our tempdir we expect 1 directory (should be the <app>.app)
573- let paths = read_dir ( & tmp_dir) . unwrap ( ) ;
582+ let paths = read_dir ( & tmp_dir) ?;
583+
584+ // current app name in /Applications/<app>.app
585+ let app_name = macos_app_name_in_path ( & extract_path) ;
574586
575587 for path in paths {
576- let found_path = path. expect ( "Unable to extract" ) . path ( ) ;
588+ let mut found_path = path? . path ( ) ;
577589 // make sure it's our .app
578590 if found_path. extension ( ) == Some ( OsStr :: new ( "app" ) ) {
579- // Walk the temp dir and copy all files by replacing existing files only
580- // and creating directories if needed
581- Move :: from_source ( & found_path) . walk_to_dest ( & extract_path) ?;
591+ let found_app_name = macos_app_name_in_path ( & found_path) ;
592+ // make sure the app name in the archive matche the installed app name on path
593+ if found_app_name != app_name {
594+ // we need to replace the app name in the updater archive to match
595+ // installed app name
596+ let new_path = found_path. parent ( ) . unwrap ( ) . join ( app_name) ;
597+ rename ( & found_path, & new_path) ?;
598+
599+ found_path = new_path;
600+ }
601+
602+ let sandbox_app_path = tempfile:: Builder :: new ( )
603+ . prefix ( "tauri_current_app_sandbox" )
604+ . tempdir ( ) ?;
605+
606+ // Replace the whole application to make sure the
607+ // code signature is following
608+ Move :: from_source ( & found_path)
609+ . replace_using_temp ( sandbox_app_path. path ( ) )
610+ . to_dest ( & extract_path) ?;
611+
582612 // early finish we have everything we need here
583613 return Ok ( ( ) ) ;
584614 }
@@ -619,7 +649,7 @@ pub fn extract_path_from_executable(executable_path: &Path) -> PathBuf {
619649 . expect ( "Can't determine extract path" ) ;
620650
621651 // MacOS example binary is in /Applications/TestApp.app/Contents/MacOS/myApp
622- // We need to get /Applications/TestApp .app
652+ // We need to get /Applications/<app> .app
623653 // todo(lemarier): Need a better way here
624654 // Maybe we could search for <*.app> to get the right path
625655 #[ cfg( target_os = "macos" ) ]
@@ -691,22 +721,16 @@ pub fn verify_signature(
691721 let public_key = PublicKey :: decode ( pub_key_decoded) ?;
692722 let signature_base64_decoded = base64_to_string ( & release_signature) ?;
693723
694- let signature =
695- Signature :: decode ( & signature_base64_decoded) . expect ( "Something wrong with the signature" ) ;
724+ let signature = Signature :: decode ( & signature_base64_decoded) ?;
696725
697726 // We need to open the file and extract the datas to make sure its not corrupted
698- let file_open = OpenOptions :: new ( )
699- . read ( true )
700- . open ( & archive_path)
701- . expect ( "Can't open our archive to validate signature" ) ;
727+ let file_open = OpenOptions :: new ( ) . read ( true ) . open ( & archive_path) ?;
702728
703729 let mut file_buff: BufReader < File > = BufReader :: new ( file_open) ;
704730
705731 // read all bytes since EOF in the buffer
706732 let mut data = vec ! [ ] ;
707- file_buff
708- . read_to_end ( & mut data)
709- . expect ( "Can't read buffer to validate signature" ) ;
733+ file_buff. read_to_end ( & mut data) ?;
710734
711735 // Validate signature or bail out
712736 public_key. verify ( & data, & signature) ?;
@@ -779,6 +803,17 @@ mod test {
779803 }"# . into ( )
780804 }
781805
806+ #[ cfg( target_os = "macos" ) ]
807+ #[ test]
808+ fn test_app_name_in_path ( ) {
809+ let executable = extract_path_from_executable ( Path :: new (
810+ "/Applications/updater-example.app/Contents/MacOS/updater-example" ,
811+ ) ) ;
812+ let app_name = macos_app_name_in_path ( & executable) ;
813+ assert ! ( executable. ends_with( "updater-example.app" ) ) ;
814+ assert_eq ! ( app_name, "updater-example.app" . to_string( ) ) ;
815+ }
816+
782817 #[ test]
783818 fn simple_http_updater ( ) {
784819 let _m = mockito:: mock ( "GET" , "/" )
0 commit comments