@@ -43,6 +43,9 @@ pub struct RemoteRelease {
43
43
pub body : Option < String > ,
44
44
/// Optional signature for the current platform
45
45
pub signature : Option < String > ,
46
+ #[ cfg( target_os = "windows" ) ]
47
+ /// Optional: Windows only try to use elevated task
48
+ pub with_elevated_task : bool ,
46
49
}
47
50
48
51
impl RemoteRelease {
@@ -70,10 +73,11 @@ impl RemoteRelease {
70
73
} ;
71
74
72
75
// 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 ( ) ;
77
81
78
82
// body is optional to build our update
79
83
let body = release
@@ -86,6 +90,8 @@ impl RemoteRelease {
86
90
. map ( |signature| signature. as_str ( ) . unwrap_or ( "" ) . to_string ( ) ) ;
87
91
88
92
let download_url;
93
+ #[ cfg( target_os = "windows" ) ]
94
+ let mut with_elevated_task = false ;
89
95
90
96
match release. get ( "platforms" ) {
91
97
//
@@ -118,6 +124,13 @@ impl RemoteRelease {
118
124
Error :: RemoteMetadata ( "Unable to extract `url` from remote server`" . into ( ) )
119
125
} ) ?
120
126
. 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
+ }
121
134
} else {
122
135
// make sure we have an available platform from the static
123
136
return Err ( Error :: RemoteMetadata ( "Platform not available" . into ( ) ) ) ;
@@ -134,6 +147,13 @@ impl RemoteRelease {
134
147
Error :: RemoteMetadata ( "Unable to extract `url` from remote server`" . into ( ) )
135
148
} ) ?
136
149
. 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
+ }
137
157
}
138
158
}
139
159
// Return our formatted release
@@ -143,6 +163,8 @@ impl RemoteRelease {
143
163
download_url,
144
164
body,
145
165
signature,
166
+ #[ cfg( target_os = "windows" ) ]
167
+ with_elevated_task,
146
168
} )
147
169
}
148
170
}
@@ -343,6 +365,8 @@ impl<'a> UpdateBuilder<'a> {
343
365
download_url : final_release. download_url ,
344
366
body : final_release. body ,
345
367
signature : final_release. signature ,
368
+ #[ cfg( target_os = "windows" ) ]
369
+ with_elevated_task : final_release. with_elevated_task ,
346
370
} )
347
371
}
348
372
}
@@ -371,6 +395,10 @@ pub struct Update {
371
395
download_url : String ,
372
396
/// Signature announced
373
397
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 ,
374
402
}
375
403
376
404
impl Update {
@@ -465,6 +493,9 @@ impl Update {
465
493
// we copy the files depending of the operating system
466
494
// we run the setup, appimage re-install or overwrite the
467
495
// 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" ) ) ]
468
499
copy_files_and_run ( tmp_dir, extract_path) ?;
469
500
// We are done!
470
501
Ok ( ( ) )
@@ -525,7 +556,11 @@ fn copy_files_and_run(tmp_dir: tempfile::TempDir, extract_path: PathBuf) -> Resu
525
556
// Update server can provide a custom EXE (installer) who can run any task.
526
557
#[ cfg( target_os = "windows" ) ]
527
558
#[ 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 {
529
564
use crate :: api:: file:: Move ;
530
565
531
566
let paths = read_dir ( & tmp_dir) ?;
@@ -544,41 +579,42 @@ fn copy_files_and_run(tmp_dir: tempfile::TempDir, _extract_path: PathBuf) -> Res
544
579
545
580
exit ( 0 ) ;
546
581
} 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 ( ) )
561
587
{
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
+ }
578
615
}
616
+ // Failed to run update task. Following UAC Path
579
617
}
580
-
581
- // Failed to run update task. Following UAC Path
582
618
}
583
619
}
584
620
@@ -834,6 +870,27 @@ mod test {
834
870
)
835
871
}
836
872
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
+
837
894
fn generate_sample_bad_json ( ) -> String {
838
895
r#"{
839
896
"version": "v0.0.3",
@@ -963,6 +1020,33 @@ mod test {
963
1020
assert ! ( updater. should_update) ;
964
1021
}
965
1022
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
+
966
1050
#[ test]
967
1051
fn http_updater_uptodate ( ) {
968
1052
let _m = mockito:: mock ( "GET" , "/darwin/10.0.0" )
0 commit comments