Skip to content

Commit

Permalink
Merge branch 'EncryptedDiskImages'
Browse files Browse the repository at this point in the history
  • Loading branch information
andymatuschak committed Jul 6, 2012
2 parents 9662452 + ab74bdc commit 05c51a1
Show file tree
Hide file tree
Showing 11 changed files with 856 additions and 12 deletions.
6 changes: 6 additions & 0 deletions NTSynchronousTask.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@
// returns the result
+(int) task:(NSString*)toolPath directory:(NSString*)currentDirectory withArgs:(NSArray*)args input:(NSData*)input output: (NSData**)outData;

+(NSData*)task:(NSString*)toolPath directory:(NSString*)currentDirectory withArgs:(NSArray*)args input:(NSData*)input;

- (void)run:(NSString*)toolPath directory:(NSString*)currentDirectory withArgs:(NSArray*)args input:(NSData*)input;
- (int)result;
- (NSData *)output;

@end

#endif
1 change: 1 addition & 0 deletions NTSynchronousTask.m
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ - (id)init;

[[self task] setStandardInput:[self inputPipe]];
[[self task] setStandardOutput:[self outputPipe]];
[[self task] setStandardError:[self outputPipe]];
}

return self;
Expand Down
95 changes: 83 additions & 12 deletions SUDiskImageUnarchiver.m
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,35 @@
#import "SULog.h"
#import <CoreServices/CoreServices.h>


@implementation SUDiskImageUnarchiver

+ (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);
Expand All @@ -48,19 +64,46 @@ - (void)extractDMG
}
}
while (noErr == FSPathMakeRefWithOptions((UInt8 *)[mountPoint fileSystemRepresentation], kFSPathMakeRefDoNotFollowLeafSymlink, &tmpRef, NULL));

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];
// 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* yesData = [[[NSData alloc] initWithBytes:"yes\n" length:4] autorelease];
NSArray* arguments = [NSArray arrayWithObjects:@"attach", archivePath, @"-mountpoint", mountPoint, /*@"-noverify",*/ @"-nobrowse", @"-noautoopen", nil];

NSData *output = nil;
NSInteger taskResult = -1;
@try
{
NTSynchronousTask* task = [[NTSynchronousTask alloc] init];

[task run:@"/usr/bin/hdiutil" directory:@"/" withArgs:arguments input:promptData];

taskResult = [task result];
output = [[[task output] copy] autorelease];
[task release];
}
@catch (NSException *localException)
{
goto reportError;
}

NSData *output = nil;
int returnCode = [NTSynchronousTask task:@"/usr/bin/hdiutil" directory:@"/" withArgs:arguments input:yesData output: &output];
if ( returnCode != 0 )
if (taskResult != 0)
{
NSString* resultStr = output ? [[[NSString alloc] initWithData: output encoding: NSUTF8StringEncoding] autorelease] : nil;
SULog( @"hdiutil failed with code: %d data: <<%@>>", returnCode, resultStr );
goto reportError;
if (password != nil && [resultStr rangeOfString:@"Authentication error"].location != NSNotFound && [delegate respondsToSelector:@selector(unarchiver:requiresPasswordReturnedViaInvocation:)]) {
[self performSelectorOnMainThread:@selector(requestPasswordFromDelegate) withObject:nil waitUntilDone:NO];
goto finally;
} else {
SULog( @"hdiutil failed with code: %d data: <<%@>>", taskResult, resultStr );
goto reportError;
}
}
mountedSuccessfully = YES;

Expand Down Expand Up @@ -132,4 +175,32 @@ + (void)load
[self registerImplementation:self];
}

- (BOOL)isEncrypted:(NSData*)resultData
{
BOOL result = NO;
if(resultData)
{
NSString *data = [NSString stringWithCString:(char*)[resultData bytes] encoding:NSUTF8StringEncoding];
if (!NSEqualRanges([data rangeOfString:@"passphrase-count"], NSMakeRange(NSNotFound, 0)))
{
result = YES;
}
}
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
26 changes: 26 additions & 0 deletions SUPasswordPrompt.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//
// SUPasswordPrompt.h
// Sparkle
//
// Created by rudy on 8/18/09.
// Copyright 2009 Ambrosia Software, Inc.. All rights reserved.
//

#import <Cocoa/Cocoa.h>
#import "Sparkle/SUWindowController.h"

@interface SUPasswordPrompt : SUWindowController
{
IBOutlet NSImageView *mIconView;
IBOutlet NSTextField *mTextDescription;
IBOutlet NSSecureTextField *mPasswordField;
NSString *mPassword;
NSString *mName;
NSImage *mIcon;
}

- (id)initWithHost:(SUHost *)aHost;
- (NSInteger)run;
- (NSString *)password;

@end
86 changes: 86 additions & 0 deletions SUPasswordPrompt.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
//
// SUPasswordPrompt.m
// Sparkle
//
// Created by rudy on 8/18/09.
// Copyright 2009 Ambrosia Software, Inc.. All rights reserved.
//

#import "SUPasswordPrompt.h"


@implementation SUPasswordPrompt

- (id)initWithHost:(SUHost *)aHost
{
self = [super initWithHost:aHost windowNibName:@"SUPasswordPrompt"];
if (self)
{
[self setName:[aHost name]];
[self setIcon:[aHost icon]];
mPassword = nil;
[self setShouldCascadeWindows:NO];
}
return self;
}

- (void)awakeFromNib
{
[mIconView setImage:[self icon]];
}

- (void)setName:(NSString*)name
{
[mName release];
mName = [name retain];
}

- (NSString*)name
{
return mName;
}

- (void)setIcon:(NSImage*)icon
{
[mIcon release];
mIcon = [icon retain];
}

- (NSImage*)icon
{
return mIcon;
}

- (NSString *)password
{
return mPassword;
}

- (void)setPassword:(NSString*)password
{
[mPassword release];
mPassword = [password retain];
}

- (NSInteger)run
{
//modally run a password prompt
NSInteger result = [NSApp runModalForWindow:[self window]];
if(result)
[self setPassword:[mPasswordField stringValue]];
return result;
}

- (IBAction)accept:(id)sender
{
[[self window] orderOut:self];
[NSApp stopModalWithCode:1];
}

- (IBAction)cancel:(id)sender
{
[[self window] orderOut:self];
[NSApp stopModalWithCode:0];
}

@end
14 changes: 14 additions & 0 deletions SUUIBasedUpdateDriver.m
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#import "SUHost.h"
#import "SUStatusController.h"
#import "SUConstants.h"
#import "SUPasswordPrompt.h"

@implementation SUUIBasedUpdateDriver

Expand Down Expand Up @@ -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];
Expand Down
1 change: 1 addition & 0 deletions SUUnarchiver.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
2 changes: 2 additions & 0 deletions SUUpdateDriver.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ extern NSString * const SUUpdateDriverFinishedNotification;
- (void)checkForUpdatesAtURL:(NSURL *)URL host:(SUHost *)host;
- (void)abortUpdate;
- (BOOL)finished;
- (SUHost*)host;
- (void)setHost:(SUHost*)newHost;

@end

Expand Down
11 changes: 11 additions & 0 deletions SUUpdateDriver.m
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,15 @@ - (void)dealloc
[super dealloc];
}

- (SUHost*)host
{
return host;
}

- (void)setHost:(SUHost*)newHost
{
[host release];
host = [newHost retain];
}

@end
20 changes: 20 additions & 0 deletions Sparkle.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,9 @@
61F83F720DBFE140006FDD30 /* SUBasicUpdateDriver.m in Sources */ = {isa = PBXBuildFile; fileRef = 61F83F700DBFE137006FDD30 /* SUBasicUpdateDriver.m */; };
61F83F740DBFE141006FDD30 /* SUBasicUpdateDriver.h in Headers */ = {isa = PBXBuildFile; fileRef = 61F83F6F0DBFE137006FDD30 /* SUBasicUpdateDriver.h */; settings = {ATTRIBUTES = (); }; };
61FA52880E2D9EA400EF58AD /* Sparkle.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8DC2EF5B0486A6940098B216 /* Sparkle.framework */; settings = {ATTRIBUTES = (Required, ); }; };
93FB277A156BD80D001937C7 /* SUPasswordPrompt.h in Headers */ = {isa = PBXBuildFile; fileRef = 93FB2778156BD80D001937C7 /* SUPasswordPrompt.h */; };
93FB277B156BD80D001937C7 /* SUPasswordPrompt.m in Sources */ = {isa = PBXBuildFile; fileRef = 93FB2779156BD80D001937C7 /* SUPasswordPrompt.m */; };
93FB277F156BD826001937C7 /* SUPasswordPrompt.xib in Resources */ = {isa = PBXBuildFile; fileRef = 93FB277D156BD826001937C7 /* SUPasswordPrompt.xib */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -381,6 +384,9 @@
61F83F700DBFE137006FDD30 /* SUBasicUpdateDriver.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SUBasicUpdateDriver.m; sourceTree = "<group>"; };
8DC2EF5A0486A6940098B216 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
8DC2EF5B0486A6940098B216 /* Sparkle.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Sparkle.framework; sourceTree = BUILT_PRODUCTS_DIR; };
93FB2778156BD80D001937C7 /* SUPasswordPrompt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SUPasswordPrompt.h; sourceTree = "<group>"; };
93FB2779156BD80D001937C7 /* SUPasswordPrompt.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SUPasswordPrompt.m; sourceTree = "<group>"; };
93FB277E156BD826001937C7 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/SUPasswordPrompt.xib; sourceTree = "<group>"; };
FA1941CA0D94A70100DD942E /* ConfigFrameworkDebug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = ConfigFrameworkDebug.xcconfig; sourceTree = "<group>"; };
FA1941CB0D94A70100DD942E /* ConfigTestAppDebug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = ConfigTestAppDebug.xcconfig; sourceTree = "<group>"; };
FA1941CC0D94A70100DD942E /* ConfigCommonRelease.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = ConfigCommonRelease.xcconfig; sourceTree = "<group>"; };
Expand Down Expand Up @@ -518,6 +524,7 @@
55C14BF0136EF26100649790 /* SUUpdateAlert.xib */,
55C14BDA136EF20D00649790 /* SUAutomaticUpdateAlert.xib */,
55C14BD8136EF00C00649790 /* SUStatus.xib */,
93FB277D156BD826001937C7 /* SUPasswordPrompt.xib */,
);
name = "Framework Resources";
sourceTree = "<group>";
Expand Down Expand Up @@ -608,6 +615,8 @@
612DCBAE0D488BC60015DBEA /* SUUpdatePermissionPrompt.m */,
61180BC80D64138900B4E0D1 /* SUWindowController.h */,
61180BC90D64138900B4E0D1 /* SUWindowController.m */,
93FB2778156BD80D001937C7 /* SUPasswordPrompt.h */,
93FB2779156BD80D001937C7 /* SUPasswordPrompt.m */,
);
name = "User Interface";
sourceTree = "<group>";
Expand Down Expand Up @@ -772,6 +781,7 @@
55C14F06136EF6DB00649790 /* SULog.h in Headers */,
55C14F0F136EF73600649790 /* finish_installation.pch in Headers */,
6158A1C5137904B300487EC1 /* SUUpdater_Private.h in Headers */,
93FB277A156BD80D001937C7 /* SUPasswordPrompt.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -981,6 +991,7 @@
55C14C04136EF26100649790 /* SUUpdateAlert.xib in Resources */,
55C14C19136EF2C700649790 /* SUUpdatePermissionPrompt.xib in Resources */,
55C14F3B136EFCB300649790 /* finish_installation.app in Resources */,
93FB277F156BD826001937C7 /* SUPasswordPrompt.xib in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -1144,6 +1155,7 @@
5D06E8ED0FD68CE4005AE3F6 /* SUBinaryDeltaCommon.m in Sources */,
5D06E93A0FD69271005AE3F6 /* SUBinaryDeltaUnarchiver.m in Sources */,
55C14F07136EF6DB00649790 /* SULog.m in Sources */,
93FB277B156BD80D001937C7 /* SUPasswordPrompt.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -1307,6 +1319,14 @@
name = MainMenu.nib;
sourceTree = "<group>";
};
93FB277D156BD826001937C7 /* SUPasswordPrompt.xib */ = {
isa = PBXVariantGroup;
children = (
93FB277E156BD826001937C7 /* en */,
);
name = SUPasswordPrompt.xib;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */

/* Begin XCBuildConfiguration section */
Expand Down
Loading

0 comments on commit 05c51a1

Please sign in to comment.