forked from sparkle-project/Sparkle
-
Notifications
You must be signed in to change notification settings - Fork 0
/
SUPlainInstaller.m
86 lines (74 loc) · 3.76 KB
/
SUPlainInstaller.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
//
// SUPlainInstaller.m
// Sparkle
//
// Created by Andy Matuschak on 4/10/08.
// Copyright 2008 Andy Matuschak. All rights reserved.
//
#import "SUPlainInstaller.h"
#import "SUPlainInstallerInternals.h"
#import "SUConstants.h"
#import "SUHost.h"
static NSString * const SUInstallerPathKey = @"SUInstallerPath";
static NSString * const SUInstallerTargetPathKey = @"SUInstallerTargetPath";
static NSString * const SUInstallerTempNameKey = @"SUInstallerTempName";
static NSString * const SUInstallerHostKey = @"SUInstallerHost";
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 finishInstallationToPath:info[SUInstallerInstallationPathKey] withResult:[info[SUInstallerResultKey] boolValue] host:info[SUInstallerHostKey] error:info[SUInstallerErrorKey] delegate:info[SUInstallerDelegateKey]];
}
+ (void)performInstallationWithInfo:(NSDictionary *)info
{
// *** GETS CALLED ON NON-MAIN THREAD!
@autoreleasepool {
NSError *error = nil;
NSString * oldPath = [info[SUInstallerHostKey] bundlePath];
NSString * installationPath = info[SUInstallerInstallationPathKey];
BOOL result = [self copyPathWithAuthentication:info[SUInstallerPathKey] overPath: installationPath temporaryName:info[SUInstallerTempNameKey] error:&error];
if( result )
{
BOOL haveOld = [[NSFileManager defaultManager] fileExistsAtPath: oldPath];
BOOL differentFromNew = ![oldPath isEqualToString: installationPath];
if( haveOld && differentFromNew )
[self _movePathToTrash: oldPath]; // On success, trash old copy if there's still one due to renaming.
}
NSMutableDictionary *mutableInfo = [[info mutableCopy] autorelease];
mutableInfo[SUInstallerResultKey] = @(result);
mutableInfo[SUInstallerInstallationPathKey] = installationPath;
if (!result && error)
mutableInfo[SUInstallerErrorKey] = error;
dispatch_async(dispatch_get_main_queue(), ^{
[self finishInstallationWithInfo:mutableInfo];
});
}
}
+ (void)performInstallationToPath:(NSString *)installationPath fromPath:(NSString *)path host:(SUHost *)host delegate:(id<SUInstallerDelegate>)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:@{NSLocalizedDescriptionKey: errorMessage}];
[self finishInstallationToPath:installationPath withResult:NO host:host error:error delegate:delegate];
return;
}
#endif
NSString *targetPath = [host installationPath];
NSString *tempName = [self temporaryNameForPath:targetPath];
NSDictionary *info = @{SUInstallerPathKey: path, SUInstallerTargetPathKey: targetPath, SUInstallerTempNameKey: tempName, SUInstallerHostKey: host, SUInstallerDelegateKey: delegate, SUInstallerInstallationPathKey: installationPath};
if (synchronously)
[self performInstallationWithInfo:info];
else {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
[self performInstallationWithInfo:info];
});
}
}
@end