Permalink
Browse files

Delegated password prompting to the update driver.

The SUDiskImageUnarchiver shouldn't know about UI, and besides,
it's important that update drivers which should not display UI (like
the automatically-installing and probing drivers) should not display
password prompts.
  • Loading branch information...
1 parent ae52d27 commit d3f975816ea14f3eecd33e5b87b856e72b983c20 @andymatuschak andymatuschak committed Jul 4, 2012
Showing with 57 additions and 31 deletions.
  1. +42 −31 SUDiskImageUnarchiver.m
  2. +14 −0 SUUIBasedUpdateDriver.m
  3. +1 −0 SUUnarchiver.h
View
@@ -11,7 +11,6 @@
#import "NTSynchronousTask.h"
#import "SULog.h"
#import <CoreServices/CoreServices.h>
-#import "SUPasswordPrompt.h"
@implementation SUDiskImageUnarchiver
@@ -20,11 +19,28 @@ + (BOOL)canUnarchivePath:(NSString *)path
return [[path pathExtension] isEqualToString:@"dmg"];
}
+// Called on a non-main thread.
- (void)extractDMG
-{
- // GETS CALLED ON NON-MAIN THREAD!!!
+{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ NSData *result = [NTSynchronousTask task:@"/usr/bin/hdiutil" directory:@"/" withArgs:[NSArray arrayWithObjects: @"isencrypted", archivePath, nil] input:NULL];
+ if([self isEncrypted:result] && [delegate respondsToSelector:@selector(unarchiver:requiresPasswordReturnedViaInvocation:)]) {
+ [self performSelectorOnMainThread:@selector(requestPasswordFromDelegate) withObject:nil waitUntilDone:NO];
+ } else {
+ [self extractDMGWithPassword:nil];
+ }
+
+ [pool release];
+}
+
+// Called on a non-main thread.
+- (void)extractDMGWithPassword:(NSString *)password
+{
+
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
BOOL mountedSuccessfully = NO;
SULog(@"Extracting %@ as a DMG", archivePath);
@@ -49,37 +65,18 @@ - (void)extractDMG
}
while (noErr == FSPathMakeRefWithOptions((UInt8 *)[mountPoint fileSystemRepresentation], kFSPathMakeRefDoNotFollowLeafSymlink, &tmpRef, NULL));
- BOOL isEncrypted = NO;
- NSData *result = [NTSynchronousTask task:@"/usr/bin/hdiutil" directory:@"/" withArgs:[NSArray arrayWithObjects: @"isencrypted", archivePath, nil] input:NULL];
- if([self isEncrypted:result])
- isEncrypted = YES;
-
- NSArray* arguments = [NSArray arrayWithObjects:@"attach", archivePath, @"-mountpoint", mountPoint, /*@"-noverify",*/ @"-nobrowse", @"-noautoopen", nil];
- // set up a pipe and push "yes" (y works too), this will accept any license agreement crap
- // not every .dmg needs this, but this will make sure it works with everyone
-
- NSData* promptData;
- if(isEncrypted) {
- SUPasswordPrompt *prompt = [[SUPasswordPrompt alloc] initWithHost:(SUHost*)[delegate host]];
- if([prompt run])
- {
- NSString *password = [prompt password];
- if(![password length])
- goto reportError;
- NSString *data = [NSString stringWithFormat:@"%@\nyes\n", password];
- const char *bytes = [data cStringUsingEncoding:NSUTF8StringEncoding];
- NSUInteger length = [data lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
- promptData = [NSData dataWithBytes:bytes length:length];
- }
- else
- {
- goto reportError;
- }
- [prompt release];
+ NSData *promptData = nil;
+ if (password) {
+ NSString *data = [NSString stringWithFormat:@"%@\nyes\n", password];
+ const char *bytes = [data cStringUsingEncoding:NSUTF8StringEncoding];
+ NSUInteger length = [data lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
+ promptData = [NSData dataWithBytes:bytes length:length];
}
else
promptData = [NSData dataWithBytes:"yes\n" length:4];
+ NSArray* arguments = [NSArray arrayWithObjects:@"attach", archivePath, @"-mountpoint", mountPoint, /*@"-noverify",*/ @"-nobrowse", @"-noautoopen", nil];
+
NSData *output = nil;
NSInteger taskResult = -1;
@try
@@ -92,7 +89,7 @@ - (void)extractDMG
output = [[[task output] copy] autorelease];
[task release];
}
- @catch (NSException *localException)
+ @catch (NSException *localException)
{
goto reportError;
}
@@ -187,4 +184,18 @@ - (BOOL)isEncrypted:(NSData*)resultData
return result;
}
+- (void)requestPasswordFromDelegate
+{
+ NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[self methodSignatureForSelector:@selector(continueWithPassword:)]];
+ [invocation setSelector:@selector(continueWithPassword:)];
+ [invocation setTarget:self];
+ [invocation retainArguments];
+ [delegate unarchiver:self requiresPasswordReturnedViaInvocation:invocation];
+}
+
+- (void)continueWithPassword:(NSString *)password
+{
+ [NSThread detachNewThreadSelector:@selector(extractDMGWithPassword:) toTarget:self withObject:password];
+}
+
@end
View
@@ -13,6 +13,7 @@
#import "SUHost.h"
#import "SUStatusController.h"
#import "SUConstants.h"
+#import "SUPasswordPrompt.h"
@implementation SUUIBasedUpdateDriver
@@ -160,6 +161,19 @@ - (void)unarchiverDidFinish:(SUUnarchiver *)ua
[NSApp requestUserAttention:NSInformationalRequest];
}
+- (void)unarchiver:(SUUnarchiver *)unarchiver requiresPasswordReturnedViaInvocation:(NSInvocation *)invocation
+{
+ SUPasswordPrompt *prompt = [[SUPasswordPrompt alloc] initWithHost:host];
+ NSString *password = nil;
+ if([prompt run])
+ {
+ password = [prompt password];
+ }
+ [prompt release];
+ [invocation setArgument:&password atIndex:2];
+ [invocation invoke];
+}
+
- (void)installAndRestart: (id)sender
{
[self installWithToolAndRelaunch:YES];
View
@@ -28,6 +28,7 @@
- (void)unarchiver:(SUUnarchiver *)unarchiver extractedLength:(unsigned long)length;
- (void)unarchiverDidFinish:(SUUnarchiver *)unarchiver;
- (void)unarchiverDidFail:(SUUnarchiver *)unarchiver;
+- (void)unarchiver:(SUUnarchiver *)unarchiver requiresPasswordReturnedViaInvocation:(NSInvocation *)invocation;
@end
#endif

0 comments on commit d3f9758

Please sign in to comment.