Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

System profiler privacy and transparency #1690

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions Sparkle/SPUUpdater.h
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,12 @@ SU_EXPORT @interface SPUUpdater : NSObject
*/
- (void)resetUpdateCycle;


/*!
The system profile information that is sent when checking for updates
*/
@property (nonatomic, readonly, copy) NSArray<NSDictionary<NSString *, NSString *> *> *systemProfileArray;

@end

NS_ASSUME_NONNULL_END
22 changes: 19 additions & 3 deletions Sparkle/SPUUpdater.m
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ - (void)startUpdateCycle
}

if (shouldPrompt) {
NSArray<NSDictionary<NSString *, NSString *> *> *profileInfo = [SUSystemProfiler systemProfileArrayForHost:self.host];
NSArray<NSDictionary<NSString *, NSString *> *> *profileInfo = self.systemProfileArray;
// Always say we're sending the system profile here so that the delegate displays the parameters it would send.
if ([self.delegate respondsToSelector:@selector((feedParametersForUpdater:sendingSystemProfile:))]) {
NSArray *feedParameters = [self.delegate feedParametersForUpdater:self sendingSystemProfile:YES];
Expand Down Expand Up @@ -748,15 +748,15 @@ - (NSURL * _Nullable)parameterizedFeedURL
}
if (sendingSystemProfile)
{
parameters = [parameters arrayByAddingObjectsFromArray:[SUSystemProfiler systemProfileArrayForHost:self.host]];
parameters = [parameters arrayByAddingObjectsFromArray:self.systemProfileArray];
[self.host setObject:[NSDate date] forUserDefaultsKey:SULastProfileSubmitDateKey];
}
if ([parameters count] == 0) { return baseFeedURL; }

// Build up the parameterized URL.
NSMutableArray *parameterStrings = [NSMutableArray array];
for (NSDictionary<NSString *, NSString *> *currentProfileInfo in parameters) {
[parameterStrings addObject:[NSString stringWithFormat:@"%@=%@", escapeURLComponent([[currentProfileInfo objectForKey:@"key"] description]), escapeURLComponent([[currentProfileInfo objectForKey:@"value"] description])]];
[parameterStrings addObject:[NSString stringWithFormat:@"%@=%@", escapeURLComponent([currentProfileInfo objectForKey:@"key"]), escapeURLComponent([currentProfileInfo objectForKey:@"value"])]];
}

NSString *separatorCharacter = @"?";
Expand All @@ -773,6 +773,22 @@ - (NSURL * _Nullable)parameterizedFeedURL
return parameterizedFeedURL;
}

- (NSArray<NSDictionary<NSString *, NSString *> *> *)systemProfileArray {
NSArray *systemProfile = [SUSystemProfiler systemProfileArrayForHost:self.host];
if ([self.delegate respondsToSelector:@selector(allowedSystemProfileKeysForUpdater:)]) {
NSArray * allowedKeys = [self.delegate allowedSystemProfileKeysForUpdater:self];
NSMutableArray *filteredProfile = [NSMutableArray array];
for (NSDictionary *profileElement in systemProfile) {
NSString *key = [profileElement objectForKey:@"key"];
if (key && [allowedKeys containsObject:key]) {
[filteredProfile addObject:profileElement];
}
}
systemProfile = [filteredProfile copy];
}
return systemProfile;
}

- (void)setUpdateCheckInterval:(NSTimeInterval)updateCheckInterval
{
[self.host setObject:@(updateCheckInterval) forUserDefaultsKey:SUScheduledCheckIntervalKey];
Expand Down
31 changes: 31 additions & 0 deletions Sparkle/SPUUpdaterDelegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,22 @@ SU_EXPORT extern NSString *const SUUpdaterAppcastItemNotificationKey;
// Key for the SUAppcast object in the SUUpdaterDidFinishLoadingAppCastNotification userInfo
SU_EXPORT extern NSString *const SUUpdaterAppcastNotificationKey;

// -----------------------------------------------------------------------------
// System Profile Keys
// -----------------------------------------------------------------------------

SU_EXPORT extern NSString *const SUSystemProfilerApplicationNameKey;
SU_EXPORT extern NSString *const SUSystemProfilerApplicationVersionKey;
SU_EXPORT extern NSString *const SUSystemProfilerCPU64bitKey;
SU_EXPORT extern NSString *const SUSystemProfilerCPUCountKey;
SU_EXPORT extern NSString *const SUSystemProfilerCPUFrequencyKey;
SU_EXPORT extern NSString *const SUSystemProfilerCPUTypeKey;
SU_EXPORT extern NSString *const SUSystemProfilerCPUSubtypeKey;
SU_EXPORT extern NSString *const SUSystemProfilerHardwareModelKey;
SU_EXPORT extern NSString *const SUSystemProfilerMemoryKey;
SU_EXPORT extern NSString *const SUSystemProfilerOperatingSystemVersionKey;
SU_EXPORT extern NSString *const SUSystemProfilerPreferredLanguageKey;

// -----------------------------------------------------------------------------
// SPUUpdater Delegate:
// -----------------------------------------------------------------------------
Expand Down Expand Up @@ -99,6 +115,21 @@ typedef NS_ENUM(NSInteger, SPUUpdateCheck)
- (NSArray *)feedParametersForUpdater:(SPUUpdater *)updater sendingSystemProfile:(BOOL)sendingProfile;
#endif

/*!
Returns a list of system profile keys to be appended to the appcast URL's query string.

If this is unimplemented then all keys will be included.

\param updater The updater instance.

\return An array of system profile keys to include in the appcast URL's query string. Elements must be one of the SUSystemProfiler*Key constants
*/
#if __has_feature(objc_generics)
- (NSArray<NSString *> *)allowedSystemProfileKeysForUpdater:(SPUUpdater *)updater;
#else
- (NSArray *)allowedSystemProfileKeysForUpdater:(SPUUpdater *)updater;
#endif

/*!
Returns a custom appcast URL.

Expand Down
40 changes: 23 additions & 17 deletions Sparkle/SUSystemProfiler.m
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,22 @@
#import "SUHost.h"
#import "SUOperatingSystem.h"
#include <sys/sysctl.h>
#import "SPUUpdaterDelegate.h"


#include "AppKitPrevention.h"

static NSString *const SUSystemProfilerApplicationNameKey = @"appName";
static NSString *const SUSystemProfilerApplicationVersionKey = @"appVersion";
static NSString *const SUSystemProfilerCPU64bitKey = @"cpu64bit";
static NSString *const SUSystemProfilerCPUCountKey = @"ncpu";
static NSString *const SUSystemProfilerCPUFrequencyKey = @"cpuFreqMHz";
static NSString *const SUSystemProfilerCPUTypeKey = @"cputype";
static NSString *const SUSystemProfilerCPUSubtypeKey = @"cpusubtype";
static NSString *const SUSystemProfilerHardwareModelKey = @"model";
static NSString *const SUSystemProfilerMemoryKey = @"ramMB";
static NSString *const SUSystemProfilerOperatingSystemVersionKey = @"osVersion";
static NSString *const SUSystemProfilerPreferredLanguageKey = @"lang";
NSString *const SUSystemProfilerApplicationNameKey = @"appName";
NSString *const SUSystemProfilerApplicationVersionKey = @"appVersion";
NSString *const SUSystemProfilerCPU64bitKey = @"cpu64bit";
NSString *const SUSystemProfilerCPUCountKey = @"ncpu";
NSString *const SUSystemProfilerCPUFrequencyKey = @"cpuFreqMHz";
NSString *const SUSystemProfilerCPUTypeKey = @"cputype";
NSString *const SUSystemProfilerCPUSubtypeKey = @"cpusubtype";
NSString *const SUSystemProfilerHardwareModelKey = @"model";
NSString *const SUSystemProfilerMemoryKey = @"ramMB";
NSString *const SUSystemProfilerOperatingSystemVersionKey = @"osVersion";
NSString *const SUSystemProfilerPreferredLanguageKey = @"lang";

@implementation SUSystemProfiler

Expand Down Expand Up @@ -57,6 +58,8 @@ @implementation SUSystemProfiler
error = sysctlbyname("hw.cputype", &value, &length, NULL, 0);
int cpuType = -1;
if (error == 0) {
//hw.cputype is a bitmask that can contain multiple bits of info. We only want the last byte to get the architecture
value = (value & 0x000000ff);
cpuType = value;
NSString *visibleCPUType;
switch (value) {
Expand All @@ -65,7 +68,7 @@ @implementation SUSystemProfiler
case CPU_TYPE_POWERPC: visibleCPUType = @"PowerPC"; break;
default: visibleCPUType = @"Unknown"; break;
}
[profileArray addObject:[NSDictionary dictionaryWithObjects:@[SUSystemProfilerCPUTypeKey, @"CPU Type", @(value), visibleCPUType] forKeys:profileDictKeys]];
[profileArray addObject:[NSDictionary dictionaryWithObjects:@[SUSystemProfilerCPUTypeKey, @"CPU Type", [NSString stringWithFormat:@"%d", value], visibleCPUType] forKeys:profileDictKeys]];
}
error = sysctlbyname("hw.cpu64bit_capable", &value, &length, NULL, 0);
if (error != 0) {
Expand All @@ -79,7 +82,7 @@ @implementation SUSystemProfiler

if (error == 0) {
is64bit = value == 1;
[profileArray addObject:[NSDictionary dictionaryWithObjects:@[SUSystemProfilerCPU64bitKey, @"CPU is 64-Bit?", @(is64bit), is64bit ? @"Yes" : @"No"] forKeys:profileDictKeys]];
[profileArray addObject:[NSDictionary dictionaryWithObjects:@[SUSystemProfilerCPU64bitKey, @"CPU is 64-Bit?", [NSString stringWithFormat:@"%d", is64bit], is64bit ? @"Yes" : @"No"] forKeys:profileDictKeys]];
}
error = sysctlbyname("hw.cpusubtype", &value, &length, NULL, 0);
if (error == 0) {
Expand All @@ -99,7 +102,7 @@ @implementation SUSystemProfiler
} else {
visibleCPUSubType = @"Other";
}
[profileArray addObject:[NSDictionary dictionaryWithObjects:@[SUSystemProfilerCPUSubtypeKey, @"CPU Subtype", @(value), visibleCPUSubType] forKeys:profileDictKeys]];
[profileArray addObject:[NSDictionary dictionaryWithObjects:@[SUSystemProfilerCPUSubtypeKey, @"CPU Subtype", [NSString stringWithFormat:@"%d", value], visibleCPUSubType] forKeys:profileDictKeys]];
}
error = sysctlbyname("hw.model", NULL, &length, NULL, 0);
if (error == 0) {
Expand All @@ -121,7 +124,8 @@ @implementation SUSystemProfiler
// Number of CPUs
error = sysctlbyname("hw.ncpu", &value, &length, NULL, 0);
if (error == 0) {
[profileArray addObject:[NSDictionary dictionaryWithObjects:@[SUSystemProfilerCPUCountKey, @"Number of CPUs", @(value), @(value)] forKeys:profileDictKeys]];
NSString *stringValue = [NSString stringWithFormat:@"%d", value];
[profileArray addObject:[NSDictionary dictionaryWithObjects:@[SUSystemProfilerCPUCountKey, @"Number of CPUs", stringValue, stringValue] forKeys:profileDictKeys]];
}

// User preferred language
Expand All @@ -148,15 +152,17 @@ @implementation SUSystemProfiler
size_t hz_size = sizeof(unsigned long);
if (sysctlbyname("hw.cpufrequency", &hz, &hz_size, NULL, 0) == 0) {
unsigned long mhz = hz / 1000000;
[profileArray addObject:[NSDictionary dictionaryWithObjects:@[SUSystemProfilerCPUFrequencyKey, @"CPU Speed (MHz)", @(mhz), @(mhz / 1000.)] forKeys:profileDictKeys]];
NSString *stringValue = [NSString stringWithFormat:@"%lu", mhz];
[profileArray addObject:[NSDictionary dictionaryWithObjects:@[SUSystemProfilerCPUFrequencyKey, @"CPU Speed (MHz)", stringValue, stringValue] forKeys:profileDictKeys]];
}

// amount of RAM
unsigned long bytes;
size_t bytes_size = sizeof(unsigned long);
if (sysctlbyname("hw.memsize", &bytes, &bytes_size, NULL, 0) == 0) {
double megabytes = bytes / (1024. * 1024.);
[profileArray addObject:[NSDictionary dictionaryWithObjects:@[SUSystemProfilerMemoryKey, @"Memory (MB)", @(megabytes), @(megabytes)] forKeys:profileDictKeys]];
NSString *stringValue = [NSString stringWithFormat:@"%lu", (unsigned long)megabytes];
[profileArray addObject:[NSDictionary dictionaryWithObjects:@[SUSystemProfilerMemoryKey, @"Memory (MB)", stringValue, stringValue] forKeys:profileDictKeys]];
}

return [profileArray copy];
Expand Down