Permalink
Browse files

Fixes #133: Sparkle deleting/replacing the wrong executable when it u…

…npacks

-[SUHost installationPath] can return different values before and after
the installation is performed, because it may attempt to normalize the
installation path--but only if the normalized version of the path isn't
already present. Which it would be after the installation had completed.

Now we only compute the installation path once for the whole installation
process.
  • Loading branch information...
1 parent c1510a5 commit 7a283bfaebc3e0b7f72a88dd727f0b009a5854b4 @andymatuschak andymatuschak committed Aug 16, 2012
Showing with 28 additions and 20 deletions.
  1. +2 −2 SUInstaller.h
  2. +7 −7 SUInstaller.m
  3. +5 −4 SUPackageInstaller.m
  4. +1 −1 SUPlainInstaller.h
  5. +7 −5 SUPlainInstaller.m
  6. +6 −1 finish_installation.m
View
4 SUInstaller.h
@@ -14,8 +14,8 @@
@class SUHost;
@interface SUInstaller : NSObject { }
-+ (void) installFromUpdateFolder:(NSString *)updateFolder overHost:(SUHost *)host delegate:delegate synchronously:(BOOL)synchronously versionComparator:(id <SUVersionComparison>)comparator;
-+ (void) finishInstallationWithResult:(BOOL)result host:(SUHost *)host error:(NSError *)error delegate:delegate;
++ (void) installFromUpdateFolder:(NSString *)updateFolder overHost:(SUHost *)host installationPath:(NSString *)installationPath delegate:delegate synchronously:(BOOL)synchronously versionComparator:(id <SUVersionComparison>)comparator;
++ (void) finishInstallationToPath:(NSString *)installationPath withResult:(BOOL)result host:(SUHost *)host error:(NSError *)error delegate:delegate;
+ (NSString*) updateFolder;
+ (void) notifyDelegateOfFailure: (NSDictionary*)dict;
@end
View
14 SUInstaller.m
@@ -43,7 +43,7 @@ + (BOOL)isAliasFolderAtPath:(NSString *)path
}
-+ (void)installFromUpdateFolder:(NSString *)inUpdateFolder overHost:(SUHost *)host delegate:delegate synchronously:(BOOL)synchronously versionComparator:(id <SUVersionComparison>)comparator
++ (void)installFromUpdateFolder:(NSString *)inUpdateFolder overHost:(SUHost *)host installationPath:(NSString *)installationPath delegate:delegate synchronously:(BOOL)synchronously versionComparator:(id <SUVersionComparison>)comparator
{
// Search subdirectories for the application
NSString *currentFile,
@@ -109,23 +109,23 @@ + (void)installFromUpdateFolder:(NSString *)inUpdateFolder overHost:(SUHost *)ho
if (newAppDownloadPath == nil)
{
- [self finishInstallationWithResult:NO host:host error:[NSError errorWithDomain:SUSparkleErrorDomain code:SUMissingUpdateError userInfo:[NSDictionary dictionaryWithObject:@"Couldn't find an appropriate update in the downloaded package." forKey:NSLocalizedDescriptionKey]] delegate:delegate];
+ [self finishInstallationToPath:installationPath withResult:NO host:host error:[NSError errorWithDomain:SUSparkleErrorDomain code:SUMissingUpdateError userInfo:[NSDictionary dictionaryWithObject:@"Couldn't find an appropriate update in the downloaded package." forKey:NSLocalizedDescriptionKey]] delegate:delegate];
}
else
{
- [(isPackage ? [SUPackageInstaller class] : [SUPlainInstaller class]) performInstallationWithPath:newAppDownloadPath host:host delegate:delegate synchronously:synchronously versionComparator:comparator];
+ [(isPackage ? [SUPackageInstaller class] : [SUPlainInstaller class]) performInstallationToPath:installationPath fromPath:newAppDownloadPath host:host delegate:delegate synchronously:synchronously versionComparator:comparator];
}
}
-+ (void)mdimportHost:(SUHost *)host
++ (void)mdimportInstallationPath:(NSString *)installationPath
{
// *** GETS CALLED ON NON-MAIN THREAD!
SULog( @"mdimporting" );
NSTask *mdimport = [[[NSTask alloc] init] autorelease];
[mdimport setLaunchPath:@"/usr/bin/mdimport"];
- [mdimport setArguments:[NSArray arrayWithObject:[host installationPath]]];
+ [mdimport setArguments:[NSArray arrayWithObject:installationPath]];
@try
{
[mdimport launch];
@@ -143,11 +143,11 @@ + (void)mdimportHost:(SUHost *)host
#define SUNotifyDictErrorKey @"SUNotifyDictError"
#define SUNotifyDictDelegateKey @"SUNotifyDictDelegate"
-+ (void)finishInstallationWithResult:(BOOL)result host:(SUHost *)host error:(NSError *)error delegate:delegate
++ (void)finishInstallationToPath:(NSString *)installationPath withResult:(BOOL)result host:(SUHost *)host error:(NSError *)error delegate:delegate
{
if (result)
{
- [self mdimportHost:host];
+ [self mdimportInstallationPath:installationPath];
if ([delegate respondsToSelector:@selector(installerFinishedForHost:)])
[delegate performSelectorOnMainThread: @selector(installerFinishedForHost:) withObject: host waitUntilDone: NO];
}
View
9 SUPackageInstaller.m
@@ -14,12 +14,13 @@
NSString *SUPackageInstallerArgumentsKey = @"SUPackageInstallerArguments";
NSString *SUPackageInstallerHostKey = @"SUPackageInstallerHost";
NSString *SUPackageInstallerDelegateKey = @"SUPackageInstallerDelegate";
+NSString *SUPackageInstallerInstallationPathKey = @"SUPackageInstallerInstallationPathKey";
@implementation SUPackageInstaller
+ (void)finishInstallationWithInfo:(NSDictionary *)info
{
- [self finishInstallationWithResult:YES host:[info objectForKey:SUPackageInstallerHostKey] error:nil delegate:[info objectForKey:SUPackageInstallerDelegateKey]];
+ [self finishInstallationToPath:[info objectForKey:SUPackageInstallerInstallationPathKey] withResult:YES host:[info objectForKey:SUPackageInstallerHostKey] error:nil delegate:[info objectForKey:SUPackageInstallerDelegateKey]];
}
+ (void)performInstallationWithInfo:(NSDictionary *)info
@@ -35,7 +36,7 @@ + (void)performInstallationWithInfo:(NSDictionary *)info
[pool drain];
}
-+ (void)performInstallationWithPath:(NSString *)path host:(SUHost *)host delegate:delegate synchronously:(BOOL)synchronously versionComparator:(id <SUVersionComparison>)comparator
++ (void)performInstallationToPath:(NSString *)installationPath fromPath:(NSString *)path host:(SUHost *)host delegate:delegate synchronously:(BOOL)synchronously versionComparator:(id <SUVersionComparison>)comparator
{
NSString *command;
NSArray *args;
@@ -56,11 +57,11 @@ + (void)performInstallationWithPath:(NSString *)path host:(SUHost *)host delegat
if (![[NSFileManager defaultManager] fileExistsAtPath:command])
{
NSError *error = [NSError errorWithDomain:SUSparkleErrorDomain code:SUMissingInstallerToolError userInfo:[NSDictionary dictionaryWithObject:@"Couldn't find Apple's installer tool!" forKey:NSLocalizedDescriptionKey]];
- [self finishInstallationWithResult:NO host:host error:error delegate:delegate];
+ [self finishInstallationToPath:installationPath withResult:NO host:host error:error delegate:delegate];
}
else
{
- NSDictionary *info = [NSDictionary dictionaryWithObjectsAndKeys:command, SUPackageInstallerCommandKey, args, SUPackageInstallerArgumentsKey, host, SUPackageInstallerHostKey, delegate, SUPackageInstallerDelegateKey, nil];
+ NSDictionary *info = [NSDictionary dictionaryWithObjectsAndKeys:command, SUPackageInstallerCommandKey, args, SUPackageInstallerArgumentsKey, host, SUPackageInstallerHostKey, delegate, SUPackageInstallerDelegateKey, installationPath, SUPackageInstallerInstallationPathKey, nil];
if (synchronously)
[self performInstallationWithInfo:info];
else
View
2 SUPlainInstaller.h
@@ -20,7 +20,7 @@
@class SUHost;
@interface SUPlainInstaller : SUInstaller { }
-+ (void)performInstallationWithPath:(NSString *)path host:(SUHost *)host delegate:delegate synchronously:(BOOL)synchronously versionComparator:(id <SUVersionComparison>)comparator;
++ (void)performInstallationToPath:(NSString *)installationPath fromPath:(NSString *)path host:(SUHost *)host delegate:delegate synchronously:(BOOL)synchronously versionComparator:(id <SUVersionComparison>)comparator;
@end
#endif
View
12 SUPlainInstaller.m
@@ -18,14 +18,15 @@
static NSString * const SUInstallerDelegateKey = @"SUInstallerDelegate";
static NSString * const SUInstallerResultKey = @"SUInstallerResult";
static NSString * const SUInstallerErrorKey = @"SUInstallerError";
+static NSString * const SUInstallerInstallationPathKey = @"SUInstallerInstallationPath";
@implementation SUPlainInstaller
+ (void)finishInstallationWithInfo:(NSDictionary *)info
{
// *** GETS CALLED ON NON-MAIN THREAD!
- [self finishInstallationWithResult:[[info objectForKey:SUInstallerResultKey] boolValue] host:[info objectForKey:SUInstallerHostKey] error:[info objectForKey:SUInstallerErrorKey] delegate:[info objectForKey:SUInstallerDelegateKey]];
+ [self finishInstallationToPath:[info objectForKey:SUInstallerInstallationPathKey] withResult:[[info objectForKey:SUInstallerResultKey] boolValue] host:[info objectForKey:SUInstallerHostKey] error:[info objectForKey:SUInstallerErrorKey] delegate:[info objectForKey:SUInstallerDelegateKey]];
}
+ (void)performInstallationWithInfo:(NSDictionary *)info
@@ -37,7 +38,7 @@ + (void)performInstallationWithInfo:(NSDictionary *)info
NSError *error = nil;
NSString * oldPath = [[info objectForKey:SUInstallerHostKey] bundlePath];
- NSString * installationPath = [[info objectForKey:SUInstallerHostKey] installationPath];
+ NSString * installationPath = [info objectForKey:SUInstallerInstallationPathKey];
BOOL result = [self copyPathWithAuthentication:[info objectForKey:SUInstallerPathKey] overPath: installationPath temporaryName:[info objectForKey:SUInstallerTempNameKey] error:&error];
if( result )
@@ -49,29 +50,30 @@ + (void)performInstallationWithInfo:(NSDictionary *)info
}
NSMutableDictionary *mutableInfo = [[info mutableCopy] autorelease];
[mutableInfo setObject:[NSNumber numberWithBool:result] forKey:SUInstallerResultKey];
+ [mutableInfo setObject:installationPath forKey:SUInstallerInstallationPathKey];
if (!result && error)
[mutableInfo setObject:error forKey:SUInstallerErrorKey];
[self performSelectorOnMainThread:@selector(finishInstallationWithInfo:) withObject:mutableInfo waitUntilDone:NO];
[pool drain];
}
-+ (void)performInstallationWithPath:(NSString *)path host:(SUHost *)host delegate:delegate synchronously:(BOOL)synchronously versionComparator:(id <SUVersionComparison>)comparator
++ (void)performInstallationToPath:(NSString *)installationPath fromPath:(NSString *)path host:(SUHost *)host delegate:delegate synchronously:(BOOL)synchronously versionComparator:(id <SUVersionComparison>)comparator
{
// Prevent malicious downgrades:
#if !PERMIT_AUTOMATED_DOWNGRADES
if ([comparator compareVersion:[host version] toVersion:[[NSBundle bundleWithPath:path] objectForInfoDictionaryKey:@"CFBundleVersion"]] == NSOrderedDescending)
{
NSString * errorMessage = [NSString stringWithFormat:@"Sparkle Updater: Possible attack in progress! Attempting to \"upgrade\" from %@ to %@. Aborting update.", [host version], [[NSBundle bundleWithPath:path] objectForInfoDictionaryKey:@"CFBundleVersion"]];
NSError *error = [NSError errorWithDomain:SUSparkleErrorDomain code:SUDowngradeError userInfo:[NSDictionary dictionaryWithObject:errorMessage forKey:NSLocalizedDescriptionKey]];
- [self finishInstallationWithResult:NO host:host error:error delegate:delegate];
+ [self finishInstallationToPath:installationPath withResult:NO host:host error:error delegate:delegate];
return;
}
#endif
NSString *targetPath = [host installationPath];
NSString *tempName = [self temporaryNameForPath:targetPath];
- NSDictionary *info = [NSDictionary dictionaryWithObjectsAndKeys:path, SUInstallerPathKey, targetPath, SUInstallerTargetPathKey, tempName, SUInstallerTempNameKey, host, SUInstallerHostKey, delegate, SUInstallerDelegateKey, nil];
+ NSDictionary *info = [NSDictionary dictionaryWithObjectsAndKeys:path, SUInstallerPathKey, targetPath, SUInstallerTargetPathKey, tempName, SUInstallerTempNameKey, host, SUInstallerHostKey, delegate, SUInstallerDelegateKey, installationPath, SUInstallerInstallationPathKey, nil];
if (synchronously)
[self performInstallationWithInfo:info];
else
View
7 finish_installation.m
@@ -19,6 +19,7 @@ @interface TerminationListener : NSObject
pid_t parentprocessid;
const char *folderpath;
NSString *selfPath;
+ NSString *installationPath;
NSTimer *watchdogTimer;
NSTimer *longInstallationTimer;
SUHost *host;
@@ -69,6 +70,8 @@ -(void) dealloc
[selfPath release];
selfPath = nil;
+
+ [installationPath release];
[watchdogTimer release];
watchdogTimer = nil;
@@ -115,7 +118,7 @@ - (void) relaunch
if( !folderpath || strcmp(executablepath, hostpath) != 0 )
appPath = [[NSFileManager defaultManager] stringWithFileSystemRepresentation:executablepath length:strlen(executablepath)];
else
- appPath = [host installationPath];
+ appPath = installationPath;
[[NSWorkspace sharedWorkspace] openFile: appPath];
}
@@ -139,6 +142,7 @@ - (void) install
{
NSBundle *theBundle = [NSBundle bundleWithPath: [[NSFileManager defaultManager] stringWithFileSystemRepresentation: hostpath length:strlen(hostpath)]];
host = [[SUHost alloc] initWithBundle: theBundle];
+ installationPath = [[host installationPath] copy];
// Perhaps a poor assumption but: if we're not relaunching, we assume we shouldn't be showing any UI either. Because non-relaunching installations are kicked off without any user interaction, we shouldn't be interrupting them.
if (shouldRelaunch) {
@@ -151,6 +155,7 @@ - (void) install
[SUInstaller installFromUpdateFolder: [[NSFileManager defaultManager] stringWithFileSystemRepresentation: folderpath length: strlen(folderpath)]
overHost: host
+ installationPath: installationPath
delegate: self synchronously: NO
versionComparator: [SUStandardVersionComparator defaultComparator]];
}

0 comments on commit 7a283bf

Please sign in to comment.