Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #import "AppDelegate.h" | 5 #import "AppDelegate.h" |
| 6 | 6 |
| 7 #include <Security/Security.h> | 7 #include <Security/Security.h> |
| 8 | 8 |
| 9 #include "chrome/common/chrome_switches.h" | 9 #include "chrome/common/chrome_switches.h" |
| 10 | 10 |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 32 } | 32 } |
| 33 @property(strong) NSWindow* window; | 33 @property(strong) NSWindow* window; |
| 34 - (void)exit; | 34 - (void)exit; |
| 35 @end | 35 @end |
| 36 | 36 |
| 37 @implementation AppDelegate | 37 @implementation AppDelegate |
| 38 @synthesize window = window_; | 38 @synthesize window = window_; |
| 39 | 39 |
| 40 // Sets up the main window and begins the downloading process. | 40 // Sets up the main window and begins the downloading process. |
| 41 - (void)applicationDidFinishLaunching:(NSNotification*)aNotification { | 41 - (void)applicationDidFinishLaunching:(NSNotification*)aNotification { |
| 42 // TODO: fix UI not loading until after asking for authorization. | 42 // TODO: Despite what the code implies -- when the installer is run, the main |
| 43 // window of the application is not visible until the user has taken action on | |
| 44 // the Authorization modal. | |
| 43 window_.delegate = self; | 45 window_.delegate = self; |
| 44 installerWindowController_ = | 46 installerWindowController_ = |
| 45 [[InstallerWindowController alloc] initWithWindow:window_]; | 47 [[InstallerWindowController alloc] initWithWindow:window_]; |
| 46 authorizedInstall_ = [[AuthorizedInstall alloc] init]; | 48 authorizedInstall_ = [[AuthorizedInstall alloc] init]; |
| 49 // TODO: Since the tasks taken care of by the AuthorizedInstall tool are | |
| 50 // relatively simple if we don't need to worry about privilege escalation, we | |
| 51 // can easily create a pure-Objective-C class that takes care of | |
| 52 // AuthorizedInstall's job when the class doesn't load successfully. | |
| 47 if ([authorizedInstall_ loadInstallationTool]) { | 53 if ([authorizedInstall_ loadInstallationTool]) { |
| 48 [self startDownload]; | 54 [self startDownload]; |
| 49 } else { | 55 } else { |
| 50 [self onLoadInstallationToolFailure]; | 56 [self onLoadInstallationToolFailure]; |
| 51 } | 57 } |
| 52 } | 58 } |
| 53 | 59 |
| 54 - (void)applicationWillTerminate:(NSNotification*)aNotification { | 60 - (void)applicationWillTerminate:(NSNotification*)aNotification { |
| 55 } | 61 } |
| 56 | 62 |
| 57 - (NSApplicationTerminateReply)applicationShouldTerminate: | 63 - (NSApplicationTerminateReply)applicationShouldTerminate: |
| 58 (NSApplication*)sender { | 64 (NSApplication*)sender { |
| 59 return preventTermination_ ? NSTerminateCancel : NSTerminateNow; | 65 if (preventTermination_) { |
|
Elly Fong-Jones
2016/08/31 14:25:55
you can use a ternary for this :)
Anna Zeng
2016/08/31 14:31:17
Done.
| |
| 66 return NSTerminateCancel; | |
| 67 } else { | |
| 68 return NSTerminateNow; | |
| 69 } | |
| 60 } | 70 } |
| 61 | 71 |
| 62 // This function effectively takes the place of | 72 // This function effectively takes the place of |
| 63 // applicationShouldTerminateAfterLastWindowClosed: to make sure that the | 73 // applicationShouldTerminateAfterLastWindowClosed: to make sure that the |
| 64 // application does correctly terminate after closing the installer, but does | 74 // application does correctly terminate after closing the installer, but does |
| 65 // not terminate when we call orderOut: to hide the installer during its | 75 // not terminate when we call orderOut: to hide the installer during its |
| 66 // tear-down steps. | 76 // tear-down steps. If the user force-quits the application, the below delegate |
| 77 // method gets called. However, when orderOut is called, the below delegate | |
| 78 // method does not get called. | |
| 67 - (BOOL)windowShouldClose:(id)sender { | 79 - (BOOL)windowShouldClose:(id)sender { |
| 68 [self exit]; | 80 [self exit]; |
| 69 return YES; | 81 return YES; |
| 70 } | 82 } |
| 71 | 83 |
| 72 - (void)exit { | 84 - (void)exit { |
| 73 preventTermination_ = NO; | 85 preventTermination_ = NO; |
| 74 [NSApp terminate:nil]; | 86 [NSApp terminate:nil]; |
| 75 } | 87 } |
| 76 | 88 |
| 77 - (void)startDownload { | 89 - (void)startDownload { |
| 78 [installerWindowController_ updateStatusDescription:@"Initializing..."]; | 90 [installerWindowController_ updateStatusDescription:@"Initializing..."]; |
| 79 | 91 |
| 80 OmahaCommunication* omahaMessenger = [[OmahaCommunication alloc] init]; | 92 OmahaCommunication* omahaMessenger = [[OmahaCommunication alloc] init]; |
| 81 omahaMessenger.delegate = self; | 93 omahaMessenger.delegate = self; |
| 82 [omahaMessenger fetchDownloadURLs]; | 94 [omahaMessenger fetchDownloadURLs]; |
| 83 } | 95 } |
| 84 | 96 |
| 85 - (void)onLoadInstallationToolFailure { | 97 - (void)onLoadInstallationToolFailure { |
| 86 NSError* loadToolError = [NSError | 98 NSError* loadToolError = [NSError |
| 87 errorForAlerts:@"Could not load installion tool" | 99 errorForAlerts:@"Internal Error" |
| 88 withDescription: | 100 withDescription: |
| 89 @"Your Chrome Installer may be corrupted. Download and try again." | 101 @"Your Chrome Installer may be corrupted. Download and try again." |
| 90 isRecoverable:NO]; | 102 isRecoverable:NO]; |
| 91 [self displayError:loadToolError]; | 103 [self displayError:loadToolError]; |
| 92 } | 104 } |
| 93 | 105 |
| 94 - (void)omahaCommunication:(OmahaCommunication*)messenger | 106 - (void)omahaCommunication:(OmahaCommunication*)messenger |
| 95 onSuccess:(NSArray*)URLs { | 107 onSuccess:(NSArray*)URLs { |
| 96 [installerWindowController_ updateStatusDescription:@"Downloading..."]; | 108 [installerWindowController_ updateStatusDescription:@"Downloading..."]; |
| 97 | 109 |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 128 NSError* downloadError = | 140 NSError* downloadError = |
| 129 [NSError errorForAlerts:@"Download Failure" | 141 [NSError errorForAlerts:@"Download Failure" |
| 130 withDescription:@"Unable to download Google Chrome." | 142 withDescription:@"Unable to download Google Chrome." |
| 131 isRecoverable:NO]; | 143 isRecoverable:NO]; |
| 132 [self displayError:downloadError]; | 144 [self displayError:downloadError]; |
| 133 } | 145 } |
| 134 | 146 |
| 135 - (void)unpacker:(Unpacker*)unpacker onMountSuccess:(NSString*)tempAppPath { | 147 - (void)unpacker:(Unpacker*)unpacker onMountSuccess:(NSString*)tempAppPath { |
| 136 SecStaticCodeRef diskStaticCode; | 148 SecStaticCodeRef diskStaticCode; |
| 137 SecRequirementRef diskRequirement; | 149 SecRequirementRef diskRequirement; |
| 138 // TODO: flush out error handling more | 150 // TODO: Include some better error handling below than NSLog |
| 139 OSStatus oserror; | 151 OSStatus oserror; |
| 140 oserror = SecStaticCodeCreateWithPath( | 152 oserror = SecStaticCodeCreateWithPath( |
| 141 (__bridge CFURLRef)[NSURL fileURLWithPath:tempAppPath isDirectory:NO], | 153 (__bridge CFURLRef)[NSURL fileURLWithPath:tempAppPath isDirectory:NO], |
| 142 kSecCSDefaultFlags, &diskStaticCode); | 154 kSecCSDefaultFlags, &diskStaticCode); |
| 143 if (oserror != errSecSuccess) | 155 if (oserror != errSecSuccess) |
| 144 NSLog(@"code %d", oserror); | 156 NSLog(@"code %d", oserror); |
| 145 // TODO: add in a more specific code sign requirement | 157 // TODO: The below requirement is too general as most signed entities have the |
| 158 // below requirement; replace it with something adequately specific. | |
| 146 oserror = | 159 oserror = |
| 147 SecRequirementCreateWithString((CFStringRef) @"anchor apple generic", | 160 SecRequirementCreateWithString((CFStringRef) @"anchor apple generic", |
| 148 kSecCSDefaultFlags, &diskRequirement); | 161 kSecCSDefaultFlags, &diskRequirement); |
| 149 if (oserror != errSecSuccess) | 162 if (oserror != errSecSuccess) |
| 150 NSLog(@"requirement %d", oserror); | 163 NSLog(@"requirement %d", oserror); |
| 151 oserror = SecStaticCodeCheckValidity(diskStaticCode, kSecCSDefaultFlags, | 164 oserror = SecStaticCodeCheckValidity(diskStaticCode, kSecCSDefaultFlags, |
| 152 diskRequirement); | 165 diskRequirement); |
| 153 if (oserror != errSecSuccess) | 166 if (oserror != errSecSuccess) |
| 154 NSLog(@"static code %d", oserror); | 167 NSLog(@"static code %d", oserror); |
| 155 | 168 |
| 156 // Calling this function will change the progress bar into an indeterminate | 169 // Calling this function will change the progress bar into an indeterminate |
| 157 // one. We won't need to update the progress bar any more after this point. | 170 // one. We won't need to update the progress bar any more after this point. |
| 158 [installerWindowController_ updateDownloadProgress:-1.0]; | 171 [installerWindowController_ updateDownloadProgress:-1.0]; |
| 159 // By disabling closing the window or quitting, we can tell the user that | 172 // By disabling closing the window or quitting, we can tell the user that |
| 160 // closing the application at this point is not a good idea. | 173 // closing the application at this point is not a good idea. |
| 161 window_.styleMask &= ~NSClosableWindowMask; | 174 window_.styleMask &= ~NSClosableWindowMask; |
| 162 preventTermination_ = YES; | 175 preventTermination_ = YES; |
| 163 | 176 |
| 164 NSString* chromeInApplicationsFolder = | 177 NSString* chromeInApplicationsFolder = |
| 165 [authorizedInstall_ startInstall:tempAppPath]; | 178 [authorizedInstall_ startInstall:tempAppPath]; |
| 166 | 179 |
| 167 NSMutableArray* installerSettings = [[NSMutableArray alloc] init]; | 180 NSMutableArray* installerSettings = [[NSMutableArray alloc] init]; |
| 168 if ([installerWindowController_ isUserMetricsChecked]) | 181 if ([installerWindowController_ isUserMetricsChecked]) |
| 169 [installerSettings | 182 [installerSettings |
| 170 addObject:[NSString stringWithUTF8String:switches::kEnableUserMetrics]]; | 183 addObject:[NSString stringWithUTF8String:switches::kEnableUserMetrics]]; |
| 171 if ([installerWindowController_ isDefaultBrowserChecked]) | 184 if ([installerWindowController_ isDefaultBrowserChecked]) |
| 172 [installerSettings | 185 [installerSettings |
| 173 addObject:[NSString | 186 addObject:[NSString |
| 187 // NOTE: the |kMakeDefaultBrowser| constant used as a | |
| 188 // command-line switch here only will apply at a user | |
| 189 // level, since the application itself is not running with | |
| 190 // privileges. grt@ suggested this constant should be | |
| 191 // renamed |kMakeDefaultBrowserforUser|. | |
| 174 stringWithUTF8String:switches::kMakeDefaultBrowser]]; | 192 stringWithUTF8String:switches::kMakeDefaultBrowser]]; |
| 175 | 193 |
| 176 NSError* error = nil; | 194 NSError* error = nil; |
| 177 [[NSWorkspace sharedWorkspace] | 195 [[NSWorkspace sharedWorkspace] |
| 178 launchApplicationAtURL:[NSURL fileURLWithPath:chromeInApplicationsFolder | 196 launchApplicationAtURL:[NSURL fileURLWithPath:chromeInApplicationsFolder |
| 179 isDirectory:NO] | 197 isDirectory:NO] |
| 180 options:NSWorkspaceLaunchDefault | 198 options:NSWorkspaceLaunchDefault |
| 181 configuration:@{ | 199 configuration:@{ |
| 182 NSWorkspaceLaunchConfigurationArguments : installerSettings | 200 NSWorkspaceLaunchConfigurationArguments : installerSettings |
| 183 } | 201 } |
| 184 error:&error]; | 202 error:&error]; |
| 185 if (error) { | 203 if (error) { |
| 186 NSLog(@"Chrome failed to launch: %@", error); | 204 NSLog(@"Chrome failed to launch: %@", error); |
| 187 } | 205 } |
| 188 | 206 |
| 189 // Begin teardown stuff! | 207 // Begin teardown step! |
| 190 dispatch_async(dispatch_get_main_queue(), ^{ | 208 dispatch_async(dispatch_get_main_queue(), ^{ |
| 191 [window_ orderOut:nil]; | 209 [window_ orderOut:nil]; |
| 192 }); | 210 }); |
| 193 | 211 |
| 194 [unpacker unmountDMG]; | 212 [unpacker unmountDMG]; |
| 195 } | 213 } |
| 196 | 214 |
| 197 - (void)unpacker:(Unpacker*)unpacker onMountFailure:(NSError*)error { | 215 - (void)unpacker:(Unpacker*)unpacker onMountFailure:(NSError*)error { |
| 198 NSError* extractError = | 216 NSError* extractError = |
| 199 [NSError errorForAlerts:@"Install Failure" | 217 [NSError errorForAlerts:@"Install Error" |
| 200 withDescription:@"Unable to add Google Chrome to Applications." | 218 withDescription:@"Unable to add Google Chrome to Applications." |
| 201 isRecoverable:NO]; | 219 isRecoverable:NO]; |
| 202 [self displayError:extractError]; | 220 [self displayError:extractError]; |
| 203 } | 221 } |
| 204 | 222 |
| 205 - (void)unpacker:(Unpacker*)unpacker onUnmountSuccess:(NSString*)mountpath { | 223 - (void)unpacker:(Unpacker*)unpacker onUnmountSuccess:(NSString*)mountpath { |
| 206 NSLog(@"we're done here!"); | 224 NSLog(@"we're done here!"); |
| 207 [self exit]; | 225 [self exit]; |
| 208 } | 226 } |
| 209 | 227 |
| 210 - (void)unpacker:(Unpacker*)unpacker onUnmountFailure:(NSError*)error { | 228 - (void)unpacker:(Unpacker*)unpacker onUnmountFailure:(NSError*)error { |
| 211 NSLog(@"error unmounting"); | 229 NSLog(@"error unmounting"); |
| 212 // NOTE: since we are not deleting the temporary folder if the unmount fails, | 230 // NOTE: Since we are not deleting the temporary folder if the unmount fails, |
| 213 // we'll just leave it up to the computer to delete the temporary folder on | 231 // we'll just leave it up to the computer to delete the temporary folder on |
| 214 // its own time, and to unmount the disk during a restart at some point. There | 232 // its own time and to unmount the disk during a restart at some point. There |
| 215 // is no other work to be done in the mean time. | 233 // is no other work to be done in the mean time. |
| 216 [self exit]; | 234 [self exit]; |
| 217 } | 235 } |
| 218 | 236 |
| 219 // Displays an alert on the main window using the contents of the passed in | 237 // Displays an alert on the main window using the contents of the passed in |
| 220 // error. | 238 // error. |
| 221 - (void)displayError:(NSError*)error { | 239 - (void)displayError:(NSError*)error { |
| 222 NSAlert* alertForUser = [NSAlert alertWithError:error]; | 240 NSAlert* alertForUser = [NSAlert alertWithError:error]; |
| 223 dispatch_async(dispatch_get_main_queue(), ^{ | 241 dispatch_async(dispatch_get_main_queue(), ^{ |
| 224 [alertForUser beginSheetModalForWindow:window_ | 242 [alertForUser beginSheetModalForWindow:window_ |
| 225 completionHandler:^(NSModalResponse returnCode) { | 243 completionHandler:^(NSModalResponse returnCode) { |
| 226 if (returnCode != [alertForUser quitResponse]) { | 244 if (returnCode != [alertForUser quitResponse]) { |
| 227 [self startDownload]; | 245 [self startDownload]; |
| 228 } else { | 246 } else { |
| 229 [NSApp terminate:nil]; | 247 [NSApp terminate:nil]; |
| 230 } | 248 } |
| 231 }]; | 249 }]; |
| 232 }); | 250 }); |
| 233 } | 251 } |
| 234 | 252 |
| 235 @end | 253 @end |
| OLD | NEW |