@@ -43,6 +43,9 @@ pub struct RemoteRelease {
4343 pub body : Option < String > ,
4444 /// Optional signature for the current platform
4545 pub signature : Option < String > ,
46+ #[ cfg( target_os = "windows" ) ]
47+ /// Optional: Windows only try to use elevated task
48+ pub with_elevated_task : bool ,
4649}
4750
4851impl RemoteRelease {
@@ -70,10 +73,11 @@ impl RemoteRelease {
7073 } ;
7174
7275 // pub_date is required default is: `N/A` if not provided by the remote JSON
73- let date = match release. get ( "pub_date" ) {
74- Some ( pub_date) => pub_date. as_str ( ) . unwrap_or ( "N/A" ) . to_string ( ) ,
75- None => "N/A" . to_string ( ) ,
76- } ;
76+ let date = release
77+ . get ( "pub_date" )
78+ . and_then ( |v| v. as_str ( ) )
79+ . unwrap_or ( "N/A" )
80+ . to_string ( ) ;
7781
7882 // body is optional to build our update
7983 let body = release
@@ -86,6 +90,8 @@ impl RemoteRelease {
8690 . map ( |signature| signature. as_str ( ) . unwrap_or ( "" ) . to_string ( ) ) ;
8791
8892 let download_url;
93+ #[ cfg( target_os = "windows" ) ]
94+ let mut with_elevated_task = false ;
8995
9096 match release. get ( "platforms" ) {
9197 //
@@ -118,6 +124,13 @@ impl RemoteRelease {
118124 Error :: RemoteMetadata ( "Unable to extract `url` from remote server`" . into ( ) )
119125 } ) ?
120126 . to_string ( ) ;
127+ #[ cfg( target_os = "windows" ) ]
128+ {
129+ with_elevated_task = current_target_data
130+ . get ( "with_elevated_task" )
131+ . and_then ( |v| v. as_bool ( ) )
132+ . unwrap_or_default ( ) ;
133+ }
121134 } else {
122135 // make sure we have an available platform from the static
123136 return Err ( Error :: RemoteMetadata ( "Platform not available" . into ( ) ) ) ;
@@ -134,6 +147,13 @@ impl RemoteRelease {
134147 Error :: RemoteMetadata ( "Unable to extract `url` from remote server`" . into ( ) )
135148 } ) ?
136149 . to_string ( ) ;
150+ #[ cfg( target_os = "windows" ) ]
151+ {
152+ with_elevated_task = match release. get ( "with_elevated_task" ) {
153+ Some ( with_elevated_task) => with_elevated_task. as_bool ( ) . unwrap_or ( false ) ,
154+ None => false ,
155+ } ;
156+ }
137157 }
138158 }
139159 // Return our formatted release
@@ -143,6 +163,8 @@ impl RemoteRelease {
143163 download_url,
144164 body,
145165 signature,
166+ #[ cfg( target_os = "windows" ) ]
167+ with_elevated_task,
146168 } )
147169 }
148170}
@@ -343,6 +365,8 @@ impl<'a> UpdateBuilder<'a> {
343365 download_url : final_release. download_url ,
344366 body : final_release. body ,
345367 signature : final_release. signature ,
368+ #[ cfg( target_os = "windows" ) ]
369+ with_elevated_task : final_release. with_elevated_task ,
346370 } )
347371 }
348372}
@@ -371,6 +395,10 @@ pub struct Update {
371395 download_url : String ,
372396 /// Signature announced
373397 signature : Option < String > ,
398+ #[ cfg( target_os = "windows" ) ]
399+ /// Optional: Windows only try to use elevated task
400+ /// Default to false
401+ with_elevated_task : bool ,
374402}
375403
376404impl Update {
@@ -465,6 +493,9 @@ impl Update {
465493 // we copy the files depending of the operating system
466494 // we run the setup, appimage re-install or overwrite the
467495 // macos .app
496+ #[ cfg( target_os = "windows" ) ]
497+ copy_files_and_run ( tmp_dir, extract_path, self . with_elevated_task ) ?;
498+ #[ cfg( not( target_os = "windows" ) ) ]
468499 copy_files_and_run ( tmp_dir, extract_path) ?;
469500 // We are done!
470501 Ok ( ( ) )
@@ -525,7 +556,11 @@ fn copy_files_and_run(tmp_dir: tempfile::TempDir, extract_path: PathBuf) -> Resu
525556// Update server can provide a custom EXE (installer) who can run any task.
526557#[ cfg( target_os = "windows" ) ]
527558#[ allow( clippy:: unnecessary_wraps) ]
528- fn copy_files_and_run ( tmp_dir : tempfile:: TempDir , _extract_path : PathBuf ) -> Result {
559+ fn copy_files_and_run (
560+ tmp_dir : tempfile:: TempDir ,
561+ _extract_path : PathBuf ,
562+ with_elevated_task : bool ,
563+ ) -> Result {
529564 use crate :: api:: file:: Move ;
530565
531566 let paths = read_dir ( & tmp_dir) ?;
@@ -544,41 +579,42 @@ fn copy_files_and_run(tmp_dir: tempfile::TempDir, _extract_path: PathBuf) -> Res
544579
545580 exit ( 0 ) ;
546581 } else if found_path. extension ( ) == Some ( OsStr :: new ( "msi" ) ) {
547- if let Some ( bin_name) = std:: env:: current_exe ( )
548- . ok ( )
549- . and_then ( |pb| pb. file_name ( ) . map ( |s| s. to_os_string ( ) ) )
550- . and_then ( |s| s. into_string ( ) . ok ( ) )
551- {
552- let product_name = bin_name. replace ( ".exe" , "" ) ;
553-
554- // Check if there is a task that enables the updater to skip the UAC prompt
555- let update_task_name = format ! ( "Update {} - Skip UAC" , product_name) ;
556- if let Ok ( status) = Command :: new ( "schtasks" )
557- . arg ( "/QUERY" )
558- . arg ( "/TN" )
559- . arg ( update_task_name. clone ( ) )
560- . status ( )
582+ if with_elevated_task {
583+ if let Some ( bin_name) = std:: env:: current_exe ( )
584+ . ok ( )
585+ . and_then ( |pb| pb. file_name ( ) . map ( |s| s. to_os_string ( ) ) )
586+ . and_then ( |s| s. into_string ( ) . ok ( ) )
561587 {
562- if status. success ( ) {
563- // Rename the MSI to the match file name the Skip UAC task is expecting it to be
564- let temp_msi = tmp_path. with_file_name ( bin_name) . with_extension ( "msi" ) ;
565- Move :: from_source ( & found_path)
566- . to_dest ( & temp_msi)
567- . expect ( "Unable to move update MSI" ) ;
568- let exit_status = Command :: new ( "schtasks" )
569- . arg ( "/RUN" )
570- . arg ( "/TN" )
571- . arg ( update_task_name)
572- . status ( )
573- . expect ( "failed to start updater task" ) ;
574-
575- if exit_status. success ( ) {
576- // Successfully launched task that skips the UAC prompt
577- exit ( 0 ) ;
588+ let product_name = bin_name. replace ( ".exe" , "" ) ;
589+
590+ // Check if there is a task that enables the updater to skip the UAC prompt
591+ let update_task_name = format ! ( "Update {} - Skip UAC" , product_name) ;
592+ if let Ok ( status) = Command :: new ( "schtasks" )
593+ . arg ( "/QUERY" )
594+ . arg ( "/TN" )
595+ . arg ( update_task_name. clone ( ) )
596+ . status ( )
597+ {
598+ if status. success ( ) {
599+ // Rename the MSI to the match file name the Skip UAC task is expecting it to be
600+ let temp_msi = tmp_path. with_file_name ( bin_name) . with_extension ( "msi" ) ;
601+ Move :: from_source ( & found_path)
602+ . to_dest ( & temp_msi)
603+ . expect ( "Unable to move update MSI" ) ;
604+ let exit_status = Command :: new ( "schtasks" )
605+ . arg ( "/RUN" )
606+ . arg ( "/TN" )
607+ . arg ( update_task_name)
608+ . status ( )
609+ . expect ( "failed to start updater task" ) ;
610+
611+ if exit_status. success ( ) {
612+ // Successfully launched task that skips the UAC prompt
613+ exit ( 0 ) ;
614+ }
578615 }
616+ // Failed to run update task. Following UAC Path
579617 }
580-
581- // Failed to run update task. Following UAC Path
582618 }
583619 }
584620
@@ -834,6 +870,27 @@ mod test {
834870 )
835871 }
836872
873+ fn generate_sample_with_elevated_task_platform_json (
874+ version : & str ,
875+ public_signature : & str ,
876+ download_url : & str ,
877+ with_elevated_task : bool ,
878+ ) -> String {
879+ format ! (
880+ r#"
881+ {{
882+ "name": "v{}",
883+ "notes": "This is the latest version! Once updated you shouldn't see this prompt.",
884+ "pub_date": "2020-06-25T14:14:19Z",
885+ "signature": "{}",
886+ "url": "{}",
887+ "with_elevated_task": "{}"
888+ }}
889+ "# ,
890+ version, public_signature, download_url, with_elevated_task
891+ )
892+ }
893+
837894 fn generate_sample_bad_json ( ) -> String {
838895 r#"{
839896 "version": "v0.0.3",
@@ -963,6 +1020,33 @@ mod test {
9631020 assert ! ( updater. should_update) ;
9641021 }
9651022
1023+ #[ test]
1024+ fn simple_http_updater_with_elevated_task ( ) {
1025+ let _m = mockito:: mock ( "GET" , "/win64/1.0.0" )
1026+ . with_status ( 200 )
1027+ . with_header ( "content-type" , "application/json" )
1028+ . with_body ( generate_sample_with_elevated_task_platform_json (
1029+ "2.0.0" ,
1030+ "SampleTauriKey" ,
1031+ "https://tauri.studio" ,
1032+ true ,
1033+ ) )
1034+ . create ( ) ;
1035+
1036+ let check_update = block ! ( builder( )
1037+ . current_version( "1.0.0" )
1038+ . url( format!(
1039+ "{}/win64/{{{{current_version}}}}" ,
1040+ mockito:: server_url( )
1041+ ) )
1042+ . build( ) ) ;
1043+
1044+ assert ! ( check_update. is_ok( ) ) ;
1045+ let updater = check_update. expect ( "Can't check update" ) ;
1046+
1047+ assert ! ( updater. should_update) ;
1048+ }
1049+
9661050 #[ test]
9671051 fn http_updater_uptodate ( ) {
9681052 let _m = mockito:: mock ( "GET" , "/darwin/10.0.0" )
0 commit comments