diff --git a/AboutWindow.xib b/AboutWindow.xib deleted file mode 100644 index b3718bd..0000000 --- a/AboutWindow.xib +++ /dev/null @@ -1,122 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/AboutWindowController.h b/AboutWindowController.h index b5a4279..e04d687 100644 --- a/AboutWindowController.h +++ b/AboutWindowController.h @@ -1,12 +1,13 @@ // -// AboutWindowController.h -// TaskExplorer +// file: AboutWindowController.h +// project: lulu (config) +// description: about window display/controller (header) // -// Created by Patrick Wardle on 7/15/16. -// Copyright (c) 2016 Objective-See. All rights reserved. +// created by Patrick Wardle +// copyright (c) 2018 Objective-See. All rights reserved. // -#import +@import Cocoa; @interface AboutWindowController : NSWindowController { @@ -16,13 +17,13 @@ /* PROPERTIES */ //version label/string -@property (weak) IBOutlet NSTextField *versionLabel; +@property (weak, atomic) IBOutlet NSTextField *versionLabel; //patrons -@property (unsafe_unretained) IBOutlet NSTextView *patrons; +@property (unsafe_unretained, atomic) IBOutlet NSTextView *patrons; - -/* METHODS */ +//'support us' button +@property (weak, atomic) IBOutlet NSButton *supportUs; @end diff --git a/AboutWindowController.m b/AboutWindowController.m index 26e3a94..aa4bcda 100644 --- a/AboutWindowController.m +++ b/AboutWindowController.m @@ -1,9 +1,10 @@ // -// AboutWindowController.m -// TaskExplorer +// file: AboutWindowController.m +// project: lulu (config) +// description: about window display/controller // -// Created by Patrick Wardle on 7/15/16. -// Copyright (c) 2016 Objective-See. All rights reserved. +// created by Patrick Wardle +// copyright (c) 2018 Objective-See. All rights reserved. // #import "Consts.h" @@ -13,10 +14,11 @@ @implementation AboutWindowController @synthesize patrons; +@synthesize supportUs; @synthesize versionLabel; //automatically called when nib is loaded -// ->center window +// center window -(void)awakeFromNib { //center @@ -24,28 +26,47 @@ } //automatically invoked when window is loaded -// ->set to white +// set to white -(void)windowDidLoad { //super [super windowDidLoad]; - //make white - [self.window setBackgroundColor: NSColor.whiteColor]; + //not in dark mode? + // make window white + if(YES != isDarkMode()) + { + //make white + self.window.backgroundColor = NSColor.whiteColor; + } //set version sting self.versionLabel.stringValue = [NSString stringWithFormat:@"Version: %@", getAppVersion()]; //load patrons self.patrons.string = [NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"patrons" ofType:@"txt"] encoding:NSUTF8StringEncoding error:NULL]; - + + //make 'support us' default + [self.supportUs setKeyEquivalent:@"\r"]; + + //make first responder + // calling this without a timeout sometimes fails :/ + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (100 * NSEC_PER_MSEC)), dispatch_get_main_queue(), ^{ + + //and make it first responder + [self.window makeFirstResponder:self.supportUs]; + + }); + return; } //automatically invoked when window is closing -// ->make ourselves unmodal +// make ourselves unmodal -(void)windowWillClose:(NSNotification *)notification { + #pragma unused(notification) + //make un-modal [[NSApplication sharedApplication] stopModal]; @@ -53,14 +74,14 @@ } //automatically invoked when user clicks any of the buttons -// ->load patreon or products webpage in user's default browser +// load patreon or products webpage in user's default browser -(IBAction)buttonHandler:(id)sender { //support us button if(((NSButton*)sender).tag == BUTTON_SUPPORT_US) { //open URL - // ->invokes user's default browser + // invokes user's default browser [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:PATREON_URL]]; } @@ -68,7 +89,7 @@ else if(((NSButton*)sender).tag == BUTTON_MORE_INFO) { //open URL - // ->invokes user's default browser + // invokes user's default browser [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:PRODUCT_URL]]; } diff --git a/AppDelegate.h b/AppDelegate.h index 492715c..c7cf856 100755 --- a/AppDelegate.h +++ b/AppDelegate.h @@ -19,6 +19,7 @@ #import "AboutWindowController.h" #import "PrefsWindowController.h" #import "SearchWindowController.h" +#import "UpdateWindowController.h" #import "ResultsWindowController.h" #import "FlaggedItemWindowController.h" #import "RequestRootWindowController.h" @@ -29,6 +30,9 @@ } +//friends +@property (weak) IBOutlet NSWindow *friends; + //start time @property NSTimeInterval startTime; @@ -172,6 +176,9 @@ //message for filtering @property (weak) IBOutlet NSTextField *filteringMessage; +//update window controller +@property(nonatomic, retain)UpdateWindowController* updateWindowController; + /* METHODS */ //complete a few inits diff --git a/AppDelegate.m b/AppDelegate.m index f0ad680..0fd3e00 100755 --- a/AppDelegate.m +++ b/AppDelegate.m @@ -3,19 +3,20 @@ // TaskExplorer // + +#import + +#import "Task.h" #import "Consts.h" #import "Binary.h" +#import "Update.h" #import "Connection.h" -#import "Exception.h" #import "Utilities.h" #import "AppDelegate.h" #import "serviceInterface.h" - #import "TaskTableController.h" #import "RequestRootWindowController.h" -#import "Task.h" - //TODO: filter out dup'd networks (airportd 0:0..) -not sure want to do this //TODO: autolayout vertically @@ -48,34 +49,14 @@ @synthesize bottomViewController; @synthesize aboutWindowController; @synthesize searchWindowController; +@synthesize updateWindowController; @synthesize resultsWindowController; @synthesize flagItemsWindowController; @synthesize requestRootWindowController; -//center window -// ->also make front --(void)awakeFromNib +//kick off main window/logic +-(void)taskExplore { - //center - [self.window center]; - - //make it key window - [self.window makeKeyAndOrderFront:self]; - - //make window front - [NSApp activateIgnoringOtherApps:YES]; - - return; -} - -//automatically invoked by OS -// ->main entry point --(void)applicationDidFinishLaunching:(NSNotification *)notification -{ - //first thing... - // ->install exception handlers! - installExceptionHandlers(); - //for autolayout [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"NSConstraintBasedLayoutVisualizeMutuallyExclusiveConstraints"]; @@ -131,6 +112,11 @@ exit(0); } + //check + [self check4Update:nil]; + + return; + //register for hotkey presses [self registerKeypressHandler]; @@ -162,7 +148,7 @@ //set flag self.bottomViewController.isBottomPane = YES; - + //disable autosize translations self.bottomViewController.view.translatesAutoresizingMaskIntoConstraints = NO; @@ -177,10 +163,47 @@ //add 'items' not found msg [self.bottomViewController.view addSubview:self.noItemsLabel]; - + //set delegate // ->ensures our 'windowWillClose' method, which has logic to fully exit app self.window.delegate = self; +} + +//automatically invoked by OS +// ->main entry point +-(void)applicationDidFinishLaunching:(NSNotification *)notification +{ + //init crash reporting + initCrashReporting(); + + //first time run? + // show thanks to friends window! + // note: on close invokes method to show main window + if(YES != [[NSUserDefaults standardUserDefaults] boolForKey:NOT_FIRST_TIME]) + { + //set key + [[NSUserDefaults standardUserDefaults] setBool:YES forKey:NOT_FIRST_TIME]; + + //front + [self.friends makeKeyAndOrderFront:self]; + + //front + [NSApp activateIgnoringOtherApps:YES]; + + //close after 3 seconds + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ + + //hide + [self hideFriends:nil]; + + }); + } + //start task exploring + else + { + //show + [self taskExplore]; + } return; } @@ -202,6 +225,7 @@ return; } + //invoked for any (but only) key-down events -(NSEvent*)handleKeypress:(NSEvent*)event { @@ -291,8 +315,26 @@ bail: // the event from being dispatched, nil return event; +} +//hide friends view +// also shows/kicks off main window +- (IBAction)hideFriends:(id)sender +{ + //once + static dispatch_once_t onceToken; + + //close and launch main window + dispatch_once (&onceToken, ^{ + + //close + [self.friends close]; + + //start task exploring + [self taskExplore]; + }); + return; } //complete a few inits @@ -583,13 +625,31 @@ bail: -(void)reloadBottomPane:(Task*)task itemView:(NSUInteger)itemView { //tag - NSUInteger segmentTag = 0; + __block NSUInteger segmentTag = 0; //not found msg NSString* noItemsMsg = nil; - //get segment tag - segmentTag = [[self.bottomPaneBtn selectedCell] tagForSegment:[self.bottomPaneBtn selectedSegment]]; + //main thread + // get segment tag + if(YES == [NSThread isMainThread]) + { + //get segment tag + segmentTag = [[self.bottomPaneBtn selectedCell] tagForSegment:[self.bottomPaneBtn selectedSegment]]; + } + //background thread + // get segment tag on main thread + else + { + //on main thread + // get segment tag + dispatch_sync(dispatch_get_main_queue(), ^{ + + //get segment tag + segmentTag = [[self.bottomPaneBtn selectedCell] tagForSegment:[self.bottomPaneBtn selectedSegment]]; + + }); + } //ignore reloads for unselected tasks // ->note: when no task is passed in, always reload though @@ -1753,8 +1813,8 @@ bail: //maks self.filteringOverlay.layer.masksToBounds = YES; - //set overlay's view color to black - self.filteringOverlay.layer.backgroundColor = [NSColor grayColor].CGColor; + //set overlay's view color to gray + self.filteringOverlay.layer.backgroundColor = NSColor.grayColor.CGColor; //make it semi-transparent self.filteringOverlay.alphaValue = 0.95; @@ -2335,4 +2395,103 @@ bail: return fieldEditor; } + + +//call into Update obj +// check to see if there an update? +- (IBAction)check4Update:(id)sender +{ + //update obj + Update* update = nil; + + //init update obj + update = [[Update alloc] init]; + + //check for update + // ->'updateResponse newVersion:' method will be called when check is done + [update checkForUpdate:^(NSUInteger result, NSString* newVersion) { + + //process response + // when invoked from menu show full results + [self updateResponse:result newVersion:newVersion alwaysShow:(nil != sender)]; + + }]; + + return; +} + +//process update response +// error, no update, update/new version +-(void)updateResponse:(NSInteger)result newVersion:(NSString*)newVersion alwaysShow:(BOOL)alwaysShow +{ + //details + NSString* details = nil; + + //action + NSString* action = nil; + + //handle response + // new version, show popup + switch (result) + { + //error + case -1: + + //set details + details = @"error, failed to check for an update."; + + //set action + action = @"Close"; + + break; + + //no updates + case 0: + + //set details + details = [NSString stringWithFormat:@"you're all up to date! (v. %@)", getAppVersion()]; + + //set action + action = @"Close"; + + break; + + //new version + case 1: + + //set details + details = [NSString stringWithFormat:@"a new version (%@) is available!", newVersion]; + + //set action + action = @"Update"; + + break; + } + + //always show results? + if(YES == alwaysShow) + { + //alloc update window + updateWindowController = [[UpdateWindowController alloc] initWithWindowNibName:@"UpdateWindow"]; + + //configure + [self.updateWindowController configure:details buttonTitle:action]; + + //center window + [[self.updateWindowController window] center]; + + //show it + [self.updateWindowController showWindow:self]; + + //invoke function in background that will make window modal + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + + //make modal + makeModal(self.updateWindowController); + + }); + } + + return; +} @end diff --git a/Assets.xcassets/AppIcon.appiconset/Contents.json b/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..7cd4f8e --- /dev/null +++ b/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "icon_16x16.png", + "scale" : "1x" + }, + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "icon_16x16@2x.png", + "scale" : "2x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "icon_32x32.png", + "scale" : "1x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "icon_32x32@2x.png", + "scale" : "2x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "icon_128x128.png", + "scale" : "1x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "icon_128x128@2x.png", + "scale" : "2x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "icon_256x256.png", + "scale" : "1x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "icon_256x256@2x.png", + "scale" : "2x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "icon_512x512.png", + "scale" : "1x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "icon_512x512@2x.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/images/icon.iconset/icon_128x128.png b/Assets.xcassets/AppIcon.appiconset/icon_128x128.png similarity index 100% rename from images/icon.iconset/icon_128x128.png rename to Assets.xcassets/AppIcon.appiconset/icon_128x128.png diff --git a/images/icon.iconset/icon_128x128@2x.png b/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png similarity index 100% rename from images/icon.iconset/icon_128x128@2x.png rename to Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png diff --git a/images/icon.iconset/icon_16x16.png b/Assets.xcassets/AppIcon.appiconset/icon_16x16.png similarity index 100% rename from images/icon.iconset/icon_16x16.png rename to Assets.xcassets/AppIcon.appiconset/icon_16x16.png diff --git a/images/icon.iconset/icon_16x16@2x.png b/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png similarity index 100% rename from images/icon.iconset/icon_16x16@2x.png rename to Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png diff --git a/images/icon.iconset/icon_256x256.png b/Assets.xcassets/AppIcon.appiconset/icon_256x256.png similarity index 100% rename from images/icon.iconset/icon_256x256.png rename to Assets.xcassets/AppIcon.appiconset/icon_256x256.png diff --git a/images/icon.iconset/icon_256x256@2x.png b/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png similarity index 100% rename from images/icon.iconset/icon_256x256@2x.png rename to Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png diff --git a/images/icon.iconset/icon_32x32.png b/Assets.xcassets/AppIcon.appiconset/icon_32x32.png similarity index 100% rename from images/icon.iconset/icon_32x32.png rename to Assets.xcassets/AppIcon.appiconset/icon_32x32.png diff --git a/images/icon.iconset/icon_32x32@2x.png b/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png similarity index 100% rename from images/icon.iconset/icon_32x32@2x.png rename to Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png diff --git a/images/icon.iconset/icon_512x512.png b/Assets.xcassets/AppIcon.appiconset/icon_512x512.png similarity index 100% rename from images/icon.iconset/icon_512x512.png rename to Assets.xcassets/AppIcon.appiconset/icon_512x512.png diff --git a/images/icon.iconset/icon_512x512@2x.png b/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png similarity index 100% rename from images/icon.iconset/icon_512x512@2x.png rename to Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png diff --git a/Assets.xcassets/Contents.json b/Assets.xcassets/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Assets.xcassets/FriendsDigita.imageset/Contents.json b/Assets.xcassets/FriendsDigita.imageset/Contents.json new file mode 100644 index 0000000..d54931d --- /dev/null +++ b/Assets.xcassets/FriendsDigita.imageset/Contents.json @@ -0,0 +1,35 @@ +{ + "images" : [ + { + "idiom" : "mac", + "filename" : "digita.pdf" + }, + { + "idiom" : "mac", + "filename" : "digitaLight.pdf", + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "light" + } + ] + }, + { + "idiom" : "mac", + "filename" : "digitaDark.pdf", + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ] + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + }, + "properties" : { + "preserves-vector-representation" : true + } +} \ No newline at end of file diff --git a/Assets.xcassets/FriendsDigita.imageset/digita.pdf b/Assets.xcassets/FriendsDigita.imageset/digita.pdf new file mode 100644 index 0000000..fcae0fc Binary files /dev/null and b/Assets.xcassets/FriendsDigita.imageset/digita.pdf differ diff --git a/Assets.xcassets/FriendsDigita.imageset/digitaDark.pdf b/Assets.xcassets/FriendsDigita.imageset/digitaDark.pdf new file mode 100644 index 0000000..fcae0fc Binary files /dev/null and b/Assets.xcassets/FriendsDigita.imageset/digitaDark.pdf differ diff --git a/Assets.xcassets/FriendsDigita.imageset/digitaLight.pdf b/Assets.xcassets/FriendsDigita.imageset/digitaLight.pdf new file mode 100644 index 0000000..fcae0fc Binary files /dev/null and b/Assets.xcassets/FriendsDigita.imageset/digitaLight.pdf differ diff --git a/Assets.xcassets/FriendsMalwarebytes.imageset/Contents.json b/Assets.xcassets/FriendsMalwarebytes.imageset/Contents.json new file mode 100644 index 0000000..f3c6d2f --- /dev/null +++ b/Assets.xcassets/FriendsMalwarebytes.imageset/Contents.json @@ -0,0 +1,35 @@ +{ + "images" : [ + { + "idiom" : "mac", + "filename" : "malwarebytes.pdf" + }, + { + "idiom" : "mac", + "filename" : "malwarebytesLight.pdf", + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "light" + } + ] + }, + { + "idiom" : "mac", + "filename" : "malwarebytesDark.pdf", + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ] + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + }, + "properties" : { + "preserves-vector-representation" : true + } +} \ No newline at end of file diff --git a/Assets.xcassets/FriendsMalwarebytes.imageset/malwarebytes.pdf b/Assets.xcassets/FriendsMalwarebytes.imageset/malwarebytes.pdf new file mode 100644 index 0000000..943c2de Binary files /dev/null and b/Assets.xcassets/FriendsMalwarebytes.imageset/malwarebytes.pdf differ diff --git a/Assets.xcassets/FriendsMalwarebytes.imageset/malwarebytesDark.pdf b/Assets.xcassets/FriendsMalwarebytes.imageset/malwarebytesDark.pdf new file mode 100644 index 0000000..943c2de Binary files /dev/null and b/Assets.xcassets/FriendsMalwarebytes.imageset/malwarebytesDark.pdf differ diff --git a/Assets.xcassets/FriendsMalwarebytes.imageset/malwarebytesLight.pdf b/Assets.xcassets/FriendsMalwarebytes.imageset/malwarebytesLight.pdf new file mode 100644 index 0000000..943c2de Binary files /dev/null and b/Assets.xcassets/FriendsMalwarebytes.imageset/malwarebytesLight.pdf differ diff --git a/Assets.xcassets/FriendsSophos.imageset/Contents.json b/Assets.xcassets/FriendsSophos.imageset/Contents.json new file mode 100644 index 0000000..3221459 --- /dev/null +++ b/Assets.xcassets/FriendsSophos.imageset/Contents.json @@ -0,0 +1,35 @@ +{ + "images" : [ + { + "idiom" : "mac", + "filename" : "sophos.png" + }, + { + "idiom" : "mac", + "filename" : "sophosLight.png", + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "light" + } + ] + }, + { + "idiom" : "mac", + "filename" : "sophosDark.png", + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ] + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + }, + "properties" : { + "preserves-vector-representation" : true + } +} \ No newline at end of file diff --git a/Assets.xcassets/FriendsSophos.imageset/sophos.png b/Assets.xcassets/FriendsSophos.imageset/sophos.png new file mode 100644 index 0000000..a5da643 Binary files /dev/null and b/Assets.xcassets/FriendsSophos.imageset/sophos.png differ diff --git a/Assets.xcassets/FriendsSophos.imageset/sophosDark.png b/Assets.xcassets/FriendsSophos.imageset/sophosDark.png new file mode 100644 index 0000000..a5da643 Binary files /dev/null and b/Assets.xcassets/FriendsSophos.imageset/sophosDark.png differ diff --git a/Assets.xcassets/FriendsSophos.imageset/sophosLight.png b/Assets.xcassets/FriendsSophos.imageset/sophosLight.png new file mode 100644 index 0000000..a5da643 Binary files /dev/null and b/Assets.xcassets/FriendsSophos.imageset/sophosLight.png differ diff --git a/Cartfile b/Cartfile new file mode 100644 index 0000000..36d649c --- /dev/null +++ b/Cartfile @@ -0,0 +1 @@ +github "getsentry/sentry-cocoa" "4.1.0" diff --git a/Cartfile.resolved b/Cartfile.resolved new file mode 100644 index 0000000..36d649c --- /dev/null +++ b/Cartfile.resolved @@ -0,0 +1 @@ +github "getsentry/sentry-cocoa" "4.1.0" diff --git a/Consts.h b/Consts.h index 6f074fe..f6dfae8 100644 --- a/Consts.h +++ b/Consts.h @@ -1,13 +1,16 @@ // // Consts.h -// DHS +// TaskExplorer // // Created by Patrick Wardle on 2/4/15. // Copyright (c) 2015 Objective-See. All rights reserved. // -#ifndef KK_Consts_h -#define KK_Consts_h +#ifndef TE_Consts_h +#define TE_Consts_h + +//not first run +#define NOT_FIRST_TIME @"notFirstTime" //button text, start scan #define START_SCAN @"Start Scan" @@ -75,6 +78,15 @@ //path to open #define OPEN @"/usr/bin/open" +//key for stdout output +#define STDOUT @"stdOutput" + +//key for stderr output +#define STDERR @"stdError" + +//key for exit code +#define EXIT_CODE @"exitCode" + //hash key, SHA1 #define KEY_HASH_SHA1 @"sha1" @@ -374,4 +386,14 @@ //product url #define PRODUCT_URL @"https://objective-see.com/products/taskexplorer.html" +//crash reporting URL +#define CRASH_REPORTING_URL @"https://c48b6be026d34bf5938a9167d5d5ee77@sentry.io/1337533" + +//product name +// ...for version check +#define PRODUCT_NAME @"TaskExplorer" + +//product version url +#define PRODUCT_VERSIONS_URL @"https://objective-see.com/products.json" + #endif diff --git a/Exception.h b/Exception.h deleted file mode 100755 index 641fe85..0000000 --- a/Exception.h +++ /dev/null @@ -1,24 +0,0 @@ -// Created by Patrick Wardle on 2/6/15. -// Copyright (c) 2015 Objective-See, LLC. All rights reserved. - -#import -#import -#import - -//install exception/signal handlers -void installExceptionHandlers(); - -//exception handler for Obj-C exceptions -void exceptionHandler(NSException *exception); - -//signal handler for *nix style exceptions -void signalHandler(int signal, siginfo_t *info, void *context); - -//display an alert -void showAlert(); - -//given an error reason (e.g. '*** Collection <__NSArrayM: 0x7fdb36a72b80> was mutated while being enumerated' -// ->extract and grab objective-c object's description; 0x7fdb36a72b80 (NSArray*) -void displayObject(NSException* exception); - - diff --git a/Exception.m b/Exception.m deleted file mode 100755 index ea54d0e..0000000 --- a/Exception.m +++ /dev/null @@ -1,222 +0,0 @@ -// Created by Patrick Wardle on 2/6/15. -// Copyright (c) 2015 Objective-See, LLC. All rights reserved. - -#import "Consts.h" -#import "Exception.h" -#import "Utilities.h" - - -//install exception/signal handlers -void installExceptionHandlers() -{ - //sigaction struct - struct sigaction sa = {0}; - - //init struct - sigemptyset (&sa.sa_mask); - sa.sa_flags = SA_SIGINFO; - sa.sa_sigaction = signalHandler; - - //exception handler - NSSetUncaughtExceptionHandler(&exceptionHandler); - - //install signal handlers - sigaction(SIGILL, &sa, NULL); - sigaction(SIGSEGV, &sa, NULL); - sigaction(SIGBUS, &sa, NULL); - sigaction(SIGABRT, &sa, NULL); - sigaction(SIGTRAP, &sa, NULL); - sigaction(SIGFPE, &sa, NULL); - - return; -} - -//display error alert -void showAlert() -{ - //response - // ->index of button click - NSModalResponse response = 0; - - //alert box - NSAlert* fullScanAlert = nil; - - //alloc/init alert - fullScanAlert = [NSAlert alertWithMessageText:@"ERROR: detected unrecoverable fault" defaultButton:@"Exit" alternateButton:@"Info" otherButton:nil informativeTextWithFormat:@"click 'Info' to help fix the issue!"]; - - //and show it - response = [fullScanAlert runModal]; - - //handle case where user clicks 'Info' - // ->take 'em to error page - if(0 == response) - { - //open page in browser - [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"https://objective-see.com/errors.html"]]; - } - - //kill app - exit(0); - - return; -} - -//exception handler -// will be invoked for Obj-C exceptions -void exceptionHandler(NSException *exception) -{ - //error msg - NSString* errMsg = nil; - - //err msg - syslog(LOG_ERR, "OBJECTIVE-SEE ERROR: OS version: %s /App version: %s", [[[NSProcessInfo processInfo] operatingSystemVersionString] UTF8String], [getAppVersion() UTF8String]); - - //create error msg - errMsg = [NSString stringWithFormat:@"unhandled obj-c exception caught [name: %@ / reason: %@]", [exception name], [exception reason]]; - - //err msg - syslog(LOG_ERR, "OBJECTIVE-SEE ERROR: %s", [errMsg UTF8String]); - - //err msg - syslog(LOG_ERR, "OBJECTIVE-SEE ERROR: %s/%s", [[exception.callStackSymbols description] UTF8String], [[exception.callStackReturnAddresses description] UTF8String]); - - //try print any objective-c objects in exception's 'reason' - displayObject(exception); - - //main thread - // ->just show UI alert - if(YES == [NSThread isMainThread]) - { - //show - showAlert(); - } - //back thread - // ->have to show it on main thread - else - { - //show alert - // ->in main UI thread - dispatch_sync(dispatch_get_main_queue(), ^{ - - //show - showAlert(); - - }); - } - - return; -} - -//handler for signals -// will be invoked for BSD/*nix signals -void signalHandler(int signal, siginfo_t *info, void *context) -{ - //error msg - NSString* errMsg = nil; - - //context - ucontext_t *uContext = NULL; - - //err msg - syslog(LOG_ERR, "OBJECTIVE-SEE ERROR: OS version: %s /App version: %s", [[[NSProcessInfo processInfo] operatingSystemVersionString] UTF8String], [getAppVersion() UTF8String]); - - //typecast context - uContext = (ucontext_t *)context; - - //create error msg - errMsg = [NSString stringWithFormat:@"unhandled exception caught, si_signo: %d /si_code: %s /si_addr: %p /rip: %p", - info->si_signo, (info->si_code == SEGV_MAPERR) ? "SEGV_MAPERR" : "SEGV_ACCERR", info->si_addr, (unsigned long*)uContext->uc_mcontext->__ss.__rip]; - - //err msg - syslog(LOG_ERR, "OBJECTIVE-SEE ERROR: %s", [errMsg UTF8String]); - - //err msg - syslog(LOG_ERR, "OBJECTIVE-SEE ERROR: %s", [[[NSThread callStackSymbols] description] UTF8String]); - - //main thread - // ->just show UI alert - if(YES == [NSThread isMainThread]) - { - //show - showAlert(); - } - //back thread - // ->have to show it on main thread - else - { - //show alert - // ->in main UI thread - dispatch_sync(dispatch_get_main_queue(), ^{ - - //show - showAlert(); - - }); - } - - return; -} - -//given an error reason (e.g. '*** Collection <__NSArrayM: 0x7fdb36a72b80> was mutated while being enumerated' -// ->extract and grab objective-c object's description; 0x7fdb36a72b80 (NSArray*) -void displayObject(NSException* exception) -{ - //object description - NSString* objectDescription = nil; - - //start - NSRange start = {0}; - - //end - NSRange end = {0}; - - //extracted addr - NSString* extractedAddr = nil; - - //scanner - // ->used to convert hex string to pointer - NSScanner* scanner = nil; - - //address - unsigned long long objAddress = 0; - - //find start - // ->find '0x' in something like: *** Collection <__NSArrayM: 0x7fdb36a72b80> - start = [exception.reason rangeOfString:@"0x"]; - if(NSNotFound == start.location) - { - //bail - goto bail; - } - - //find end - // ->find '>' in something like: *** Collection <__NSArrayM: 0x7fdb36a72b80> - end = [exception.reason rangeOfString:@">"]; - if(NSNotFound == end.location) - { - //bail - goto bail; - } - - //extract address - // ->will still be a (hex) string, but will be converted below - extractedAddr = [exception.reason substringWithRange:NSMakeRange(start.location + start.length, end.location - start.location- start.length)]; - - //init scanner - scanner = [NSScanner scannerWithString:extractedAddr]; - - //convert extracted address from hex string to pointer - [scanner scanHexLongLong:&objAddress]; - - //cast to obj-c object - // ->then get description - objectDescription = [(__bridge_transfer NSArray*)((void*)objAddress) description]; - - //err msg - syslog(LOG_ERR, "OBJECTIVE-SEE ERROR: object: %s", [objectDescription UTF8String]); - -//bail -bail: - - return; -} diff --git a/InfoWindowController.m b/InfoWindowController.m index b711938..447b315 100644 --- a/InfoWindowController.m +++ b/InfoWindowController.m @@ -29,8 +29,13 @@ //super [super windowDidLoad]; - //make white - [self.window setBackgroundColor: NSColor.whiteColor]; + //no dark mode? + // make window white + if(YES != isDarkMode()) + { + //make white + self.window.backgroundColor = NSColor.whiteColor; + } return; } diff --git a/ItemView.m b/ItemView.m index bd4e2fd..146f3d1 100644 --- a/ItemView.m +++ b/ItemView.m @@ -214,8 +214,8 @@ NSTableCellView* createLoadedItemView(NSTableView* tableView, id owner, id item) } //default - // ->(re)set main textfield's color to black - loadedItemCell.textField.textColor = [NSColor blackColor]; + // ->(re)set main textfield's color + loadedItemCell.textField.textColor = NSColor.controlTextColor; //set main text loadedItemCell.textField.attributedStringValue = initLoadedInString(item); @@ -297,9 +297,8 @@ NSAttributedString* initBinaryString(id item, BOOL isSearchWindow) //add name [taskString appendAttributedString:[[NSMutableAttributedString alloc] initWithString:binary.name]]; - //init color for pid - // ->light gray - attributes = [NSDictionary dictionaryWithObject:[NSColor lightGrayColor] forKey:NSForegroundColorAttributeName]; + //init gray color for pid + attributes = [NSDictionary dictionaryWithObject:NSColor.grayColor forKey:NSForegroundColorAttributeName]; //search window // ->only for tasks, since dylibs in search window are handled elsewhere ('loaded in') @@ -327,7 +326,7 @@ NSAttributedString* initBinaryString(id item, BOOL isSearchWindow) { //init color for comma, etc // ->light gray - attributes = [NSDictionary dictionaryWithObject:[NSColor lightGrayColor] forKey:NSForegroundColorAttributeName]; + attributes = [NSDictionary dictionaryWithObject:NSColor.grayColor forKey:NSForegroundColorAttributeName]; //tasks //add comma string @@ -368,7 +367,7 @@ NSAttributedString* initBinaryString(id item, BOOL isSearchWindow) (YES != binary.notFound)) { //init color for closing - attributes = [NSDictionary dictionaryWithObject:[NSColor lightGrayColor] forKey:NSForegroundColorAttributeName]; + attributes = [NSDictionary dictionaryWithObject:NSColor.grayColor forKey:NSForegroundColorAttributeName]; //close string [taskString appendAttributedString:[[NSMutableAttributedString alloc] initWithString:@")" attributes:attributes]]; @@ -385,7 +384,7 @@ NSAttributedString* initBinaryString(id item, BOOL isSearchWindow) { //init color for comma, // ->light gray - attributes = [NSDictionary dictionaryWithObject:[NSColor lightGrayColor] forKey:NSForegroundColorAttributeName]; + attributes = [NSDictionary dictionaryWithObject:NSColor.grayColor forKey:NSForegroundColorAttributeName]; //add [taskString appendAttributedString:[[NSAttributedString alloc] initWithString:@", " attributes:attributes]]; @@ -395,7 +394,7 @@ NSAttributedString* initBinaryString(id item, BOOL isSearchWindow) { //init color for comma, etc // ->light gray - attributes = [NSDictionary dictionaryWithObject:[NSColor lightGrayColor] forKey:NSForegroundColorAttributeName]; + attributes = [NSDictionary dictionaryWithObject:NSColor.grayColor forKey:NSForegroundColorAttributeName]; //tasks //add comma string @@ -426,7 +425,7 @@ NSAttributedString* initBinaryString(id item, BOOL isSearchWindow) if(YES != [item isKindOfClass:[Task class]]) { //init color for closing - attributes = [NSDictionary dictionaryWithObject:[NSColor lightGrayColor] forKey:NSForegroundColorAttributeName]; + attributes = [NSDictionary dictionaryWithObject:NSColor.grayColor forKey:NSForegroundColorAttributeName]; //close string [taskString appendAttributedString:[[NSMutableAttributedString alloc] initWithString:@")" attributes:attributes]]; @@ -441,7 +440,7 @@ NSAttributedString* initBinaryString(id item, BOOL isSearchWindow) { //init color for closing // ->light gray - attributes = [NSDictionary dictionaryWithObject:[NSColor lightGrayColor] forKey:NSForegroundColorAttributeName]; + attributes = [NSDictionary dictionaryWithObject:NSColor.grayColor forKey:NSForegroundColorAttributeName]; //close string [taskString appendAttributedString:[[NSMutableAttributedString alloc] initWithString:@")" attributes:attributes]]; @@ -490,7 +489,7 @@ NSAttributedString* initLoadedInString(id item) //init color for 'loaded in...' // ->light gray - attributes = [NSDictionary dictionaryWithObject:[NSColor lightGrayColor] forKey:NSForegroundColorAttributeName]; + attributes = [NSDictionary dictionaryWithObject:NSColor.grayColor forKey:NSForegroundColorAttributeName]; //add dylib indicator //-> '(dylib, loaded in: ... ' @@ -583,8 +582,8 @@ NSTableCellView* createTaskView(NSTableView* tableView, id owner, Task* task) ((NSImageView*)[taskCell viewWithTag:TABLE_ROW_SIGNATURE_ICON]).image = getCodeSigningIcon(task.binary); //default - // ->(re)set main textfield's color to black - taskCell.textField.textColor = [NSColor blackColor]; + // ->(re)set main textfield's color + taskCell.textField.textColor = NSColor.controlTextColor; //set main text taskCell.textField.attributedStringValue = initBinaryString(task, [owner isKindOfClass:[SearchWindowController class]]); @@ -636,8 +635,8 @@ NSTableCellView* createDylibView(NSTableView* tableView, id owner, Binary* dylib ((NSImageView*)[dylibCell viewWithTag:TABLE_ROW_SIGNATURE_ICON]).image = getCodeSigningIcon(dylib); //default - // ->(re)set main textfield's color to black - dylibCell.textField.textColor = [NSColor blackColor]; + // ->(re)set main textfield's color + dylibCell.textField.textColor = NSColor.controlTextColor; //set main text // ->final arg is flag indicating normal or search window @@ -691,8 +690,8 @@ NSTableCellView* createFileView(NSTableView* tableView, id owner, File* file) } //default - // ->(re)set main textfield's color to black - fileCell.textField.textColor = [NSColor blackColor]; + // ->(re)set main textfield's color + fileCell.textField.textColor = NSColor.controlTextColor; //set main text // ->name @@ -731,8 +730,8 @@ NSTableCellView* createNetworkView(NSTableView* tableView, id owner, Connection* connectionCell.imageView.image = connection.icon; //default - // ->(re)set main textfield's color to black - connectionCell.textField.textColor = [NSColor blackColor]; + // ->(re)set main textfield's color + connectionCell.textField.textColor = NSColor.controlTextColor; //set main text // ->connection endpoints @@ -834,17 +833,17 @@ void configVTButton(NSTableCellView *itemCell, id owner, Binary* binary) //known 'good' files (0 positivies) if(0 == [binary.vtInfo[VT_RESULTS_POSITIVES] unsignedIntegerValue]) { - //(re)set title black - itemCell.textField.textColor = [NSColor blackColor]; + //(re)set title + itemCell.textField.textColor = NSColor.controlTextColor; - //set color (black) - stringAttributes[NSForegroundColorAttributeName] = [NSColor blackColor]; + //set color + stringAttributes[NSForegroundColorAttributeName] = NSColor.controlTextColor; //set string (vt ratio), with attributes [vtButton setAttributedTitle:[[NSAttributedString alloc] initWithString:vtDetectionRatio attributes:stringAttributes]]; //set color (gray) - stringAttributes[NSForegroundColorAttributeName] = [NSColor grayColor]; + stringAttributes[NSForegroundColorAttributeName] = NSColor.grayColor; //set selected text color [vtButton setAttributedAlternateTitle:[[NSAttributedString alloc] initWithString:vtDetectionRatio attributes:stringAttributes]]; diff --git a/Items/File.m b/Items/File.m index 7cbbda8..756752c 100644 --- a/Items/File.m +++ b/Items/File.m @@ -46,22 +46,29 @@ bail: -(void)setFileType { //results from 'file' cmd - NSString* results = nil; + NSMutableDictionary* results = nil; + + //output + NSString* output = nil; //array of parsed results NSArray* parsedResults = nil; //exec 'file' to get file type - results = [[NSString alloc] initWithData:execTask(FILE, @[self.path], YES) encoding:NSUTF8StringEncoding]; - if(nil == results) + results = execTask(FILE, @[self.path], YES); + if( (nil == results[EXIT_CODE]) || + (0 != [results[EXIT_CODE] integerValue]) ) { //bail goto bail; } + //convert stdout data to string + output = [[NSString alloc] initWithData:results[STDOUT] encoding:NSUTF8StringEncoding]; + //parse results // ->format: : - parsedResults = [results componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@":\n"]]; + parsedResults = [output componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]]; //sanity check // ->should be two items in array, and diff --git a/KKRow.m b/KKRow.m index 9902368..6e6ef6c 100644 --- a/KKRow.m +++ b/KKRow.m @@ -7,6 +7,7 @@ // #import "KKRow.h" +#import "Utilities.h" @implementation KKRow @@ -25,14 +26,27 @@ //make selection rect selectionRect = NSInsetRect(self.bounds, 2.5, 2.5); - //set stroke - [[NSColor colorWithCalibratedWhite:.65 alpha:1.0] setStroke]; - - //set fill - [[NSColor colorWithCalibratedWhite:.82 alpha:1.0] setFill]; + //dark mode highlight + if(YES == isDarkMode()) + { + //set stroke + [[NSColor colorWithCalibratedWhite:1.0 alpha:1.0] setStroke]; + + //set fill + [[NSColor colorWithCalibratedWhite:.65 alpha:1.0] setFill]; + } + //light mode highlight + else + { + //set stroke + [[NSColor colorWithCalibratedWhite:.65 alpha:1.0] setStroke]; + + //set fill + [[NSColor colorWithCalibratedWhite:.82 alpha:1.0] setFill]; + } //create selection path - // ->with rounded corners + // ...with rounded corners selectionPath = [NSBezierPath bezierPathWithRoundedRect:selectionRect xRadius:5 yRadius:5]; //fill diff --git a/PrefsWindowController.m b/PrefsWindowController.m index c9a79ed..f5af828 100644 --- a/PrefsWindowController.m +++ b/PrefsWindowController.m @@ -7,6 +7,7 @@ // +#import "Utilities.h" #import "AppDelegate.h" #import "PrefsWindowController.h" @@ -30,20 +31,24 @@ //automatically invoked when window is loaded -// ->set to white -(void)windowDidLoad { //super [super windowDidLoad]; - //make white - [self.window setBackgroundColor: NSColor.whiteColor]; + //no dark mode? + // make window white + if(YES != isDarkMode()) + { + //make white + self.window.backgroundColor = NSColor.whiteColor; + } //make button selected [self.window makeFirstResponder:self.okButton]; //capture existing prefs - // ->needed to trigger re-saves + // needed to trigger re-saves [self captureExistingPrefs]; return; diff --git a/RequestRootWindowController.m b/RequestRootWindowController.m index 8a6088d..4c42722 100644 --- a/RequestRootWindowController.m +++ b/RequestRootWindowController.m @@ -45,8 +45,13 @@ //super [super windowDidLoad]; - //make white - [self.window setBackgroundColor: NSColor.whiteColor]; + //no dark mode? + // make window white + if(YES != isDarkMode()) + { + //make white + self.window.backgroundColor = NSColor.whiteColor; + } //set version sting //[self.versionLabel setStringValue:[NSString stringWithFormat:@"version: %@", getAppVersion()]]; @@ -118,7 +123,7 @@ installArgs[3] = NULL; //reset text color - self.statusMsg.textColor = [NSColor blackColor]; + self.statusMsg.textColor = NSColor.controlTextColor; //create authorization ref osStatus = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &authorizationRef); diff --git a/ResultsWindowController.m b/ResultsWindowController.m index faee940..13f6efd 100644 --- a/ResultsWindowController.m +++ b/ResultsWindowController.m @@ -33,8 +33,13 @@ //super [super windowDidLoad]; - //make white - [self.window setBackgroundColor: NSColor.whiteColor]; + //no dark mode? + // make window white + if(YES != isDarkMode()) + { + //make white + self.window.backgroundColor = NSColor.whiteColor; + } //set details self.detailsLabel.stringValue = self.details; diff --git a/SearchWindowController.m b/SearchWindowController.m index 69fdd75..5fe5da9 100644 --- a/SearchWindowController.m +++ b/SearchWindowController.m @@ -532,8 +532,8 @@ bail: //maks self.overlay.layer.masksToBounds = YES; - //set overlay's view color to black - self.overlay.layer.backgroundColor = [NSColor grayColor].CGColor; + //set overlay's view color to gray + self.overlay.layer.backgroundColor = NSColor.grayColor.CGColor; //make it semi-transparent self.overlay.alphaValue = 0.95; diff --git a/Task.m b/Task.m index 43d0ad2..f323754 100644 --- a/Task.m +++ b/Task.m @@ -374,7 +374,7 @@ bail: }] mutableCopy]; //reload bottom pane now - // ->this will only reload if new task is the currently selected one, etc + // note: this will only reload if new task is the currently selected one, etc [((AppDelegate*)[[NSApplication sharedApplication] delegate]) reloadBottomPane:self itemView:DYLIBS_VIEW]; }//sync diff --git a/TaskExplorer.xcodeproj/project.pbxproj b/TaskExplorer.xcodeproj/project.pbxproj index 0ba6e20..b1f2030 100755 --- a/TaskExplorer.xcodeproj/project.pbxproj +++ b/TaskExplorer.xcodeproj/project.pbxproj @@ -18,10 +18,8 @@ 7D7348111BCB82C900CD7235 /* flaggedRedOver.png in Resources */ = {isa = PBXBuildFile; fileRef = 7D73480E1BCB82C900CD7235 /* flaggedRedOver.png */; }; 7DA5CA0F1C7AA8CB00627DD7 /* MachO.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DA5CA0E1C7AA8CB00627DD7 /* MachO.m */; }; 7DAA78091B903BF1004840B9 /* CustomTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DAA78081B903BF1004840B9 /* CustomTextField.m */; }; - 7DB0FCA21C7AECB300D2CE0D /* Exception.m in Sources */ = {isa = PBXBuildFile; fileRef = CD7B9F4F1ACB9A8400DF3C71 /* Exception.m */; }; CD001B381AB903040089014A /* logo.png in Resources */ = {isa = PBXBuildFile; fileRef = CD001B351AB903040089014A /* logo.png */; }; CD001B391AB903040089014A /* logoApple.png in Resources */ = {isa = PBXBuildFile; fileRef = CD001B361AB903040089014A /* logoApple.png */; }; - CD02194F1AD34D8B005148A2 /* AboutWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = CD02194D1AD34D8B005148A2 /* AboutWindow.xib */; }; CD0219501AD34D8B005148A2 /* PrefsWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = CD02194E1AD34D8B005148A2 /* PrefsWindow.xib */; }; CD0219531AD34D9A005148A2 /* AboutWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = CD0219521AD34D9A005148A2 /* AboutWindowController.m */; }; CD0219581AD37748005148A2 /* signed2.png in Resources */ = {isa = PBXBuildFile; fileRef = CD0219561AD37748005148A2 /* signed2.png */; }; @@ -29,6 +27,15 @@ CD02195C1AD38823005148A2 /* kkRowCell.m in Sources */ = {isa = PBXBuildFile; fileRef = CD02195B1AD38823005148A2 /* kkRowCell.m */; }; CD02195E1AD39A74005148A2 /* ResultsWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = CD02195D1AD39A74005148A2 /* ResultsWindow.xib */; }; CD0219611AD39A83005148A2 /* ResultsWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = CD0219601AD39A83005148A2 /* ResultsWindowController.m */; }; + CD1508D221BA4A190081F1AF /* patrons.txt in Resources */ = {isa = PBXBuildFile; fileRef = CD1508D121BA4A190081F1AF /* patrons.txt */; }; + CD1508D421BA4A8A0081F1AF /* AboutWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = CD1508D321BA4A890081F1AF /* AboutWindow.xib */; }; + CD1508D921BA4B9D0081F1AF /* UpdateWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = CD1508D521BA4B9C0081F1AF /* UpdateWindowController.m */; }; + CD1508DA21BA4B9D0081F1AF /* Update.m in Sources */ = {isa = PBXBuildFile; fileRef = CD1508D821BA4B9D0081F1AF /* Update.m */; }; + CD1508DC21BA4BAC0081F1AF /* UpdateWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = CD1508DB21BA4BAC0081F1AF /* UpdateWindow.xib */; }; + CD1D14EF21B7A67600FF7F4B /* Sentry.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = CD1D14EB21B7A5DB00FF7F4B /* Sentry.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + CD1D14F121B7A69300FF7F4B /* Sentry.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = CD1D14EB21B7A5DB00FF7F4B /* Sentry.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + CD1D14F321B8F2FC00FF7F4B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CD1D14F221B8F2FC00FF7F4B /* Assets.xcassets */; }; + CD1D14F421B8F2FC00FF7F4B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CD1D14F221B8F2FC00FF7F4B /* Assets.xcassets */; }; CD3F4CE81AF5CF68002A2647 /* TaskEnumerator.m in Sources */ = {isa = PBXBuildFile; fileRef = CD3F4CE61AF5CF68002A2647 /* TaskEnumerator.m */; }; CD3F4CEB1AF6D948002A2647 /* OrderedDictionary.m in Sources */ = {isa = PBXBuildFile; fileRef = CD3F4CEA1AF6D948002A2647 /* OrderedDictionary.m */; }; CD3F4CFA1AF71B58002A2647 /* Binary.m in Sources */ = {isa = PBXBuildFile; fileRef = CD3F4CF31AF71B58002A2647 /* Binary.m */; }; @@ -48,7 +55,7 @@ CD4D54281B2EAC7800008030 /* NetworkInfoWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = CD4D54271B2EAC7800008030 /* NetworkInfoWindow.xib */; }; CD4D543F1B2FF32C00008030 /* signedAppleIcon.png in Resources */ = {isa = PBXBuildFile; fileRef = CD4D543E1B2FF32C00008030 /* signedAppleIcon.png */; }; CD6095731A87067D00E091CD /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD6095721A87067D00E091CD /* Security.framework */; }; - CD6AFB7F1B4736DF00D42C34 /* flatIcon.png in Resources */ = {isa = PBXBuildFile; fileRef = CD6AFB7E1B4736DF00D42C34 /* flatIcon.png */; }; + CD6AFB7F1B4736DF00D42C34 /* teIcon.png in Resources */ = {isa = PBXBuildFile; fileRef = CD6AFB7E1B4736DF00D42C34 /* teIcon.png */; }; CD6AFB811B4737AC00D42C34 /* arrow.png in Resources */ = {isa = PBXBuildFile; fileRef = CD6AFB801B4737AC00D42C34 /* arrow.png */; }; CD6AFB831B4BAA2100D42C34 /* refreshIcon.png in Resources */ = {isa = PBXBuildFile; fileRef = CD6AFB821B4BAA2100D42C34 /* refreshIcon.png */; }; CD6AFB861B4BABB200D42C34 /* refreshIconBG.png in Resources */ = {isa = PBXBuildFile; fileRef = CD6AFB841B4BABB200D42C34 /* refreshIconBG.png */; }; @@ -59,7 +66,6 @@ CD74A07B1B7F170B00A8AAD3 /* FlaggedItemWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = CD74A0791B7F170B00A8AAD3 /* FlaggedItemWindowController.m */; }; CD74A07E1B81B5D400A8AAD3 /* FlaggedItems.xib in Resources */ = {isa = PBXBuildFile; fileRef = CD74A07D1B81B5D400A8AAD3 /* FlaggedItems.xib */; }; CD7B9F4D1ACB959200DF3C71 /* logoAppleOver.png in Resources */ = {isa = PBXBuildFile; fileRef = CD7B9F4C1ACB959200DF3C71 /* logoAppleOver.png */; }; - CD7B9F501ACB9A8400DF3C71 /* Exception.m in Sources */ = {isa = PBXBuildFile; fileRef = CD7B9F4F1ACB9A8400DF3C71 /* Exception.m */; }; CD7B9FA41ACBCFAD00DF3C71 /* spotlightIcon.png in Resources */ = {isa = PBXBuildFile; fileRef = CD7B9FA31ACBCFAD00DF3C71 /* spotlightIcon.png */; }; CD7B9FA71ACCAE5E00DF3C71 /* startScanOver.png in Resources */ = {isa = PBXBuildFile; fileRef = CD7B9FA51ACCAE5E00DF3C71 /* startScanOver.png */; }; CD7B9FA81ACCAE5E00DF3C71 /* stopScanOver.png in Resources */ = {isa = PBXBuildFile; fileRef = CD7B9FA61ACCAE5E00DF3C71 /* stopScanOver.png */; }; @@ -85,7 +91,6 @@ CDA81D701A95B4E9009790E2 /* stopScan.png in Resources */ = {isa = PBXBuildFile; fileRef = CDA81D661A95B4E9009790E2 /* stopScan.png */; }; CDA81D711A95B4E9009790E2 /* stopScanBG.png in Resources */ = {isa = PBXBuildFile; fileRef = CDA81D671A95B4E9009790E2 /* stopScanBG.png */; }; CDA81D721A95B4E9009790E2 /* virus.png in Resources */ = {isa = PBXBuildFile; fileRef = CDA81D681A95B4E9009790E2 /* virus.png */; }; - CDA81D741A95B4FB009790E2 /* icon.iconset in Resources */ = {isa = PBXBuildFile; fileRef = CDA81D731A95B4FB009790E2 /* icon.iconset */; }; CDA81D7B1A95D29B009790E2 /* TaskTableController.m in Sources */ = {isa = PBXBuildFile; fileRef = CDA81D7A1A95D29B009790E2 /* TaskTableController.m */; }; CDA81DC91A9960A3009790E2 /* info.png in Resources */ = {isa = PBXBuildFile; fileRef = CDA81DC51A9960A3009790E2 /* info.png */; }; CDA81DCA1A9960A3009790E2 /* infoBG.png in Resources */ = {isa = PBXBuildFile; fileRef = CDA81DC61A9960A3009790E2 /* infoBG.png */; }; @@ -140,6 +145,28 @@ /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ + CD1D14EE21B7A65B00FF7F4B /* Copy Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + CD1D14EF21B7A67600FF7F4B /* Sentry.framework in Copy Frameworks */, + ); + name = "Copy Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; + CD1D14F021B7A68900FF7F4B /* Copy Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + CD1D14F121B7A69300FF7F4B /* Sentry.framework in Copy Frameworks */, + ); + name = "Copy Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; CDA5F6B91B16D805003CE340 /* Embed XPC Services */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; @@ -173,7 +200,6 @@ 7DAA78081B903BF1004840B9 /* CustomTextField.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CustomTextField.m; sourceTree = ""; }; CD001B351AB903040089014A /* logo.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = logo.png; path = images/logo.png; sourceTree = SOURCE_ROOT; }; CD001B361AB903040089014A /* logoApple.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = logoApple.png; path = images/logoApple.png; sourceTree = SOURCE_ROOT; }; - CD02194D1AD34D8B005148A2 /* AboutWindow.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = AboutWindow.xib; path = UI/AboutWindow.xib; sourceTree = ""; }; CD02194E1AD34D8B005148A2 /* PrefsWindow.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = PrefsWindow.xib; path = UI/PrefsWindow.xib; sourceTree = ""; }; CD0219511AD34D9A005148A2 /* AboutWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AboutWindowController.h; sourceTree = ""; }; CD0219521AD34D9A005148A2 /* AboutWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AboutWindowController.m; sourceTree = ""; }; @@ -184,6 +210,15 @@ CD02195D1AD39A74005148A2 /* ResultsWindow.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = ResultsWindow.xib; path = UI/ResultsWindow.xib; sourceTree = ""; }; CD02195F1AD39A83005148A2 /* ResultsWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ResultsWindowController.h; sourceTree = ""; }; CD0219601AD39A83005148A2 /* ResultsWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ResultsWindowController.m; sourceTree = ""; }; + CD1508D121BA4A190081F1AF /* patrons.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = patrons.txt; sourceTree = SOURCE_ROOT; }; + CD1508D321BA4A890081F1AF /* AboutWindow.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = AboutWindow.xib; path = UI/AboutWindow.xib; sourceTree = ""; }; + CD1508D521BA4B9C0081F1AF /* UpdateWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UpdateWindowController.m; sourceTree = SOURCE_ROOT; }; + CD1508D621BA4B9C0081F1AF /* Update.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Update.h; sourceTree = SOURCE_ROOT; }; + CD1508D721BA4B9D0081F1AF /* UpdateWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UpdateWindowController.h; sourceTree = SOURCE_ROOT; }; + CD1508D821BA4B9D0081F1AF /* Update.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Update.m; sourceTree = SOURCE_ROOT; }; + CD1508DB21BA4BAC0081F1AF /* UpdateWindow.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = UpdateWindow.xib; path = UI/UpdateWindow.xib; sourceTree = ""; }; + CD1D14EB21B7A5DB00FF7F4B /* Sentry.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Sentry.framework; path = Carthage/Build/Mac/Sentry.framework; sourceTree = ""; }; + CD1D14F221B8F2FC00FF7F4B /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = SOURCE_ROOT; }; CD3F4CE61AF5CF68002A2647 /* TaskEnumerator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TaskEnumerator.m; sourceTree = SOURCE_ROOT; }; CD3F4CE71AF5CF68002A2647 /* TaskEnumerator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TaskEnumerator.h; sourceTree = SOURCE_ROOT; }; CD3F4CE91AF6D948002A2647 /* OrderedDictionary.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OrderedDictionary.h; path = 3rdParty/OrderedDictionary.h; sourceTree = ""; }; @@ -211,7 +246,7 @@ CD4D54271B2EAC7800008030 /* NetworkInfoWindow.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = NetworkInfoWindow.xib; path = UI/NetworkInfoWindow.xib; sourceTree = ""; }; CD4D543E1B2FF32C00008030 /* signedAppleIcon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = signedAppleIcon.png; path = images/signedAppleIcon.png; sourceTree = SOURCE_ROOT; }; CD6095721A87067D00E091CD /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; - CD6AFB7E1B4736DF00D42C34 /* flatIcon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = flatIcon.png; path = images/flatIcon.png; sourceTree = SOURCE_ROOT; }; + CD6AFB7E1B4736DF00D42C34 /* teIcon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = teIcon.png; path = images/teIcon.png; sourceTree = SOURCE_ROOT; }; CD6AFB801B4737AC00D42C34 /* arrow.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = arrow.png; path = images/arrow.png; sourceTree = SOURCE_ROOT; }; CD6AFB821B4BAA2100D42C34 /* refreshIcon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = refreshIcon.png; path = images/refreshIcon.png; sourceTree = SOURCE_ROOT; }; CD6AFB841B4BABB200D42C34 /* refreshIconBG.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = refreshIconBG.png; path = images/refreshIconBG.png; sourceTree = SOURCE_ROOT; }; @@ -224,8 +259,6 @@ CD74A0791B7F170B00A8AAD3 /* FlaggedItemWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FlaggedItemWindowController.m; sourceTree = ""; }; CD74A07D1B81B5D400A8AAD3 /* FlaggedItems.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = FlaggedItems.xib; path = UI/FlaggedItems.xib; sourceTree = ""; }; CD7B9F4C1ACB959200DF3C71 /* logoAppleOver.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = logoAppleOver.png; path = images/logoAppleOver.png; sourceTree = SOURCE_ROOT; }; - CD7B9F4E1ACB9A8400DF3C71 /* Exception.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Exception.h; sourceTree = SOURCE_ROOT; }; - CD7B9F4F1ACB9A8400DF3C71 /* Exception.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Exception.m; sourceTree = SOURCE_ROOT; }; CD7B9FA31ACBCFAD00DF3C71 /* spotlightIcon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = spotlightIcon.png; path = images/spotlightIcon.png; sourceTree = SOURCE_ROOT; }; CD7B9FA51ACCAE5E00DF3C71 /* startScanOver.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = startScanOver.png; path = images/startScanOver.png; sourceTree = SOURCE_ROOT; }; CD7B9FA61ACCAE5E00DF3C71 /* stopScanOver.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = stopScanOver.png; path = images/stopScanOver.png; sourceTree = SOURCE_ROOT; }; @@ -262,7 +295,6 @@ CDA81D661A95B4E9009790E2 /* stopScan.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = stopScan.png; path = images/stopScan.png; sourceTree = SOURCE_ROOT; }; CDA81D671A95B4E9009790E2 /* stopScanBG.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = stopScanBG.png; path = images/stopScanBG.png; sourceTree = SOURCE_ROOT; }; CDA81D681A95B4E9009790E2 /* virus.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = virus.png; path = images/virus.png; sourceTree = SOURCE_ROOT; }; - CDA81D731A95B4FB009790E2 /* icon.iconset */ = {isa = PBXFileReference; lastKnownFileType = folder.iconset; name = icon.iconset; path = images/icon.iconset; sourceTree = SOURCE_ROOT; }; CDA81D791A95D29B009790E2 /* TaskTableController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TaskTableController.h; sourceTree = ""; }; CDA81D7A1A95D29B009790E2 /* TaskTableController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TaskTableController.m; sourceTree = ""; }; CDA81DC51A9960A3009790E2 /* info.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = info.png; path = images/info.png; sourceTree = SOURCE_ROOT; }; @@ -385,6 +417,7 @@ 1D21BC4D172AF43D009D1CFD /* Frameworks */ = { isa = PBXGroup; children = ( + CD1D14EB21B7A5DB00FF7F4B /* Sentry.framework */, CD7FBF241B6EDAC000578C5D /* SystemConfiguration.framework */, CDF08CE91AC8D97B009B3423 /* Quartz.framework */, CD6095721A87067D00E091CD /* Security.framework */, @@ -407,15 +440,17 @@ 1D21BC54172AF43D009D1CFD /* TaskExplorer */ = { isa = PBXGroup; children = ( + CD1D14F221B8F2FC00FF7F4B /* Assets.xcassets */, CD3F4CE61AF5CF68002A2647 /* TaskEnumerator.m */, + CD1508D621BA4B9C0081F1AF /* Update.h */, + CD1508D821BA4B9D0081F1AF /* Update.m */, + CD1508D721BA4B9D0081F1AF /* UpdateWindowController.h */, + CD1508D521BA4B9C0081F1AF /* UpdateWindowController.m */, CD3F4CE71AF5CF68002A2647 /* TaskEnumerator.h */, CDD248391AF5CC4D00232422 /* Task.h */, CDD2483A1AF5CC4D00232422 /* Task.m */, - CD7B9F4E1ACB9A8400DF3C71 /* Exception.h */, - CD7B9F4F1ACB9A8400DF3C71 /* Exception.m */, CDF08CC71AC4C678009B3423 /* PrefsWindowController.h */, CDF08CC81AC4C678009B3423 /* PrefsWindowController.m */, - CDA81D731A95B4FB009790E2 /* icon.iconset */, CDA81D561A95B4B4009790E2 /* MainMenu.xib */, CDF08CC41AC46E75009B3423 /* VTButton.h */, CDF08CC51AC46E75009B3423 /* VTButton.m */, @@ -434,6 +469,7 @@ 1D21BC55172AF43D009D1CFD /* Supporting Files */ = { isa = PBXGroup; children = ( + CD1508D121BA4A190081F1AF /* patrons.txt */, CDA81D541A95B4B4009790E2 /* InfoPlist.strings */, CDA81D581A95B4B4009790E2 /* TaskExplorer-Info.plist */, CDA81D591A95B4B4009790E2 /* TaskExplorer-Prefix.pch */, @@ -466,7 +502,7 @@ CD6AFB851B4BABB200D42C34 /* refreshIconOver.png */, CD6AFB821B4BAA2100D42C34 /* refreshIcon.png */, CD6AFB801B4737AC00D42C34 /* arrow.png */, - CD6AFB7E1B4736DF00D42C34 /* flatIcon.png */, + CD6AFB7E1B4736DF00D42C34 /* teIcon.png */, CDEE77031B41220300763826 /* search.png */, CDEE77041B41220300763826 /* searchBG.png */, CDEE77051B41220300763826 /* searchOver.png */, @@ -587,6 +623,8 @@ CDA81E621AA020E8009790E2 /* UI */ = { isa = PBXGroup; children = ( + CD1508DB21BA4BAC0081F1AF /* UpdateWindow.xib */, + CD1508D321BA4A890081F1AF /* AboutWindow.xib */, 7D2F567B1B81BEAB00C7D85E /* SearchWindow.xib */, CD74A07D1B81B5D400A8AAD3 /* FlaggedItems.xib */, CD4D54271B2EAC7800008030 /* NetworkInfoWindow.xib */, @@ -596,7 +634,6 @@ CD3F4D131AF85088002A2647 /* FlatView.xib */, CD3F4CFE1AF72BC4002A2647 /* TaskInfoWindow.xib */, CD02195D1AD39A74005148A2 /* ResultsWindow.xib */, - CD02194D1AD34D8B005148A2 /* AboutWindow.xib */, CD02194E1AD34D8B005148A2 /* PrefsWindow.xib */, CDF08CE11AC88E0F009B3423 /* VTInfoWindow.xib */, CDA81E641AA020FD009790E2 /* FileInfoWindow.xib */, @@ -630,6 +667,7 @@ 1D21BC48172AF43D009D1CFD /* Frameworks */, 1D21BC49172AF43D009D1CFD /* Resources */, CDA5F6B91B16D805003CE340 /* Embed XPC Services */, + CD1D14EE21B7A65B00FF7F4B /* Copy Frameworks */, ); buildRules = ( ); @@ -648,6 +686,7 @@ CDA5F6A91B16D805003CE340 /* Sources */, CDA5F6AA1B16D805003CE340 /* Frameworks */, CDA5F6AB1B16D805003CE340 /* Resources */, + CD1D14F021B7A68900FF7F4B /* Copy Frameworks */, ); buildRules = ( ); @@ -713,6 +752,7 @@ CDEE77081B41220300763826 /* searchOver.png in Resources */, CD74A07E1B81B5D400A8AAD3 /* FlaggedItems.xib in Resources */, CDA81D6B1A95B4E9009790E2 /* show.png in Resources */, + CD1508D221BA4A190081F1AF /* patrons.txt in Resources */, CD74A06D1B7DA71200A8AAD3 /* flaggedBG.png in Resources */, CDF08CF31ACA6864009B3423 /* browserIcon.png in Resources */, CDEE77061B41220300763826 /* search.png in Resources */, @@ -741,10 +781,13 @@ CD7B9FA71ACCAE5E00DF3C71 /* startScanOver.png in Resources */, CDF08CC11AC3E8B0009B3423 /* showOver.png in Resources */, CD4D54241B2D082300008030 /* DylibInfoWindow.xib in Resources */, - CD6AFB7F1B4736DF00D42C34 /* flatIcon.png in Resources */, + CD6AFB7F1B4736DF00D42C34 /* teIcon.png in Resources */, + CD1508DC21BA4BAC0081F1AF /* UpdateWindow.xib in Resources */, CD6AFB811B4737AC00D42C34 /* arrow.png in Resources */, CDA81DCC1A9960A3009790E2 /* virusTotalBG.png in Resources */, CD74A06E1B7DA71200A8AAD3 /* flaggedOver.png in Resources */, + CD1508D421BA4A8A0081F1AF /* AboutWindow.xib in Resources */, + CD1D14F321B8F2FC00FF7F4B /* Assets.xcassets in Resources */, CD001B381AB903040089014A /* logo.png in Resources */, CDF08CCF1AC4C6E8009B3423 /* settingsOver.png in Resources */, CDAB98A31AEB413C00C75B4B /* dylibIcon.png in Resources */, @@ -767,9 +810,7 @@ CDA81D721A95B4E9009790E2 /* virus.png in Resources */, CD6AFB831B4BAA2100D42C34 /* refreshIcon.png in Resources */, CDA81DC91A9960A3009790E2 /* info.png in Resources */, - CDA81D741A95B4FB009790E2 /* icon.iconset in Resources */, CDA81D6E1A95B4E9009790E2 /* startScan.png in Resources */, - CD02194F1AD34D8B005148A2 /* AboutWindow.xib in Resources */, CDA81DCA1A9960A3009790E2 /* infoBG.png in Resources */, CDF08CD11AC4C6E8009B3423 /* settings.png in Resources */, CDA81DD31A9970A0009790E2 /* signed.png in Resources */, @@ -783,6 +824,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + CD1D14F421B8F2FC00FF7F4B /* Assets.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -793,6 +835,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + CD1508DA21BA4B9D0081F1AF /* Update.m in Sources */, CD3F4CE81AF5CF68002A2647 /* TaskEnumerator.m in Sources */, CD4D54221B2CE6F200008030 /* NSMutableArray+QueueAdditions.m in Sources */, 7DA5CA0F1C7AA8CB00627DD7 /* MachO.m in Sources */, @@ -817,9 +860,9 @@ CD3F4CFA1AF71B58002A2647 /* Binary.m in Sources */, CD3F4CFC1AF71B58002A2647 /* File.m in Sources */, CDA81D5E1A95B4B4009790E2 /* main.m in Sources */, - CD7B9F501ACB9A8400DF3C71 /* Exception.m in Sources */, CDD248341AF5947300232422 /* TAAdaptiveSpaceItem.m in Sources */, CD0219531AD34D9A005148A2 /* AboutWindowController.m in Sources */, + CD1508D921BA4B9D0081F1AF /* UpdateWindowController.m in Sources */, CDF08CC61AC46E75009B3423 /* VTButton.m in Sources */, CD3F4CFB1AF71B58002A2647 /* Connection.m in Sources */, CDD248351AF5947300232422 /* TAAdaptiveSpaceItemView.m in Sources */, @@ -834,7 +877,6 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 7DB0FCA21C7AECB300D2CE0D /* Exception.m in Sources */, CDA5F6B61B16D805003CE340 /* main.m in Sources */, CDA5F6B41B16D805003CE340 /* remoteTaskService.m in Sources */, 7D2A4C6C1BC789070029A284 /* Utilities.m in Sources */, @@ -953,12 +995,19 @@ 1D21BC69172AF43D009D1CFD /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = "Developer ID Application: Objective-See, LLC (VBG97UB4TA)"; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Developer ID Application: Objective-See, LLC (VBG97UB4TA)"; COMBINE_HIDPI_IMAGES = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Carthage/Build/Mac", + ); GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "TaskExplorer-Prefix.pch"; INFOPLIST_FILE = "TaskExplorer-Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "@executable_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.objective-see.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = TaskExplorer; PROVISIONING_PROFILE = ""; @@ -969,12 +1018,19 @@ 1D21BC6A172AF43D009D1CFD /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = "Developer ID Application: Objective-See, LLC (VBG97UB4TA)"; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Developer ID Application: Objective-See, LLC (VBG97UB4TA)"; COMBINE_HIDPI_IMAGES = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Carthage/Build/Mac", + ); GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "TaskExplorer-Prefix.pch"; INFOPLIST_FILE = "TaskExplorer-Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "@executable_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.objective-see.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = TaskExplorer; PROVISIONING_PROFILE = ""; @@ -994,6 +1050,10 @@ COMBINE_HIDPI_IMAGES = YES; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Carthage/Build/Mac", + ); GCC_NO_COMMON_BLOCKS = YES; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", @@ -1004,6 +1064,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; INFOPLIST_FILE = remoteTaskService/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ""; MACOSX_DEPLOYMENT_TARGET = 10.10; MTL_ENABLE_DEBUG_INFO = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.objective-see.$(PRODUCT_NAME:rfc1034identifier)"; @@ -1025,12 +1086,17 @@ COPY_PHASE_STRIP = NO; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Carthage/Build/Mac", + ); GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; INFOPLIST_FILE = remoteTaskService/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ""; MACOSX_DEPLOYMENT_TARGET = 10.10; MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_BUNDLE_IDENTIFIER = "com.objective-see.$(PRODUCT_NAME:rfc1034identifier)"; diff --git a/TaskExplorer.xcodeproj/project.xcworkspace/xcuserdata/patrick.xcuserdatad/UserInterfaceState.xcuserstate b/TaskExplorer.xcodeproj/project.xcworkspace/xcuserdata/patrick.xcuserdatad/UserInterfaceState.xcuserstate index cf288de..793d3ed 100644 Binary files a/TaskExplorer.xcodeproj/project.xcworkspace/xcuserdata/patrick.xcuserdatad/UserInterfaceState.xcuserstate and b/TaskExplorer.xcodeproj/project.xcworkspace/xcuserdata/patrick.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/TaskExplorer.xcodeproj/xcuserdata/patrick.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/TaskExplorer.xcodeproj/xcuserdata/patrick.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist deleted file mode 100644 index 897e481..0000000 --- a/TaskExplorer.xcodeproj/xcuserdata/patrick.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +++ /dev/null @@ -1,395 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/TaskExplorer.xcodeproj/xcuserdata/patrick.xcuserdatad/xcschemes/TaskExplorer.xcscheme b/TaskExplorer.xcodeproj/xcuserdata/patrick.xcuserdatad/xcschemes/TaskExplorer.xcscheme index ebcae91..8389691 100644 --- a/TaskExplorer.xcodeproj/xcuserdata/patrick.xcuserdatad/xcschemes/TaskExplorer.xcscheme +++ b/TaskExplorer.xcodeproj/xcuserdata/patrick.xcuserdatad/xcschemes/TaskExplorer.xcscheme @@ -7,10 +7,10 @@ buildImplicitDependencies = "YES"> + shouldUseLaunchSchemeArgsEnv = "YES"> @@ -22,15 +22,19 @@ ReferencedContainer = "container:TaskExplorer.xcodeproj"> + + @@ -53,10 +57,10 @@ diff --git a/TaskExplorer.xcodeproj/xcuserdata/patrick.xcuserdatad/xcschemes/remoteTaskService.xcscheme b/TaskExplorer.xcodeproj/xcuserdata/patrick.xcuserdatad/xcschemes/remoteTaskService.xcscheme index 68fb558..51895e0 100644 --- a/TaskExplorer.xcodeproj/xcuserdata/patrick.xcuserdatad/xcschemes/remoteTaskService.xcscheme +++ b/TaskExplorer.xcodeproj/xcuserdata/patrick.xcuserdatad/xcschemes/remoteTaskService.xcscheme @@ -1,7 +1,7 @@ + version = "2.0"> @@ -23,10 +23,10 @@ + shouldUseLaunchSchemeArgsEnv = "YES"> @@ -38,34 +38,42 @@ ReferencedContainer = "container:TaskExplorer.xcodeproj"> + + - + debugServiceExtension = "internal" + allowLocationSimulation = "YES" + launchAutomaticallySubstyle = "2"> + + + - + - + + - + + + + - - - - + + + + - + - - + + + - + + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -52,11 +115,11 @@ - + - - + + diff --git a/UI/RequestRootWindow.xib b/UI/RequestRootWindow.xib index 152955e..443baa2 100644 --- a/UI/RequestRootWindow.xib +++ b/UI/RequestRootWindow.xib @@ -1,8 +1,9 @@ - - + + - + + @@ -17,20 +18,22 @@ - - + + - + - + + + @@ -39,6 +42,7 @@ - + + + + + + + + + + + + + + + + + diff --git a/Update.h b/Update.h new file mode 100644 index 0000000..d4c7633 --- /dev/null +++ b/Update.h @@ -0,0 +1,26 @@ +// +// file: Update.h +// project: lulu (shared) +// description: checks for new versions of LuLu (header) +// +// created by Patrick Wardle +// copyright (c) 2017 Objective-See. All rights reserved. +// + + +#ifndef Update_h +#define Update_h + +@import Cocoa; +@import Foundation; + +@interface Update : NSObject + +//check for an update +// will invoke app delegate method to update UI when check completes +-(void)checkForUpdate:(void (^)(NSUInteger result, NSString* latestVersion))completionHandler; + +@end + + +#endif /* Update_h */ diff --git a/Update.m b/Update.m new file mode 100644 index 0000000..3b77e1a --- /dev/null +++ b/Update.m @@ -0,0 +1,97 @@ +// +// file: Update.m +// project: lulu (shared) +// description: checks for new versions of LuLu +// +// created by Patrick Wardle +// copyright (c) 2017 Objective-See. All rights reserved. +// + +#import "Consts.h" +#import "Update.h" +#import "Utilities.h" +#import "AppDelegate.h" + + +@implementation Update + +//check for an update +// ->will invoke app delegate method to update UI when check completes +-(void)checkForUpdate:(void (^)(NSUInteger result, NSString* latestVersion))completionHandler +{ + //latest version + __block NSString* latestVersion = nil; + + //result + __block NSInteger result = -1; + + //get latest version in background + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + + //grab latest version + latestVersion = [self getLatestVersion]; + if(nil != latestVersion) + { + //check + result = (NSOrderedAscending == [getAppVersion() compare:latestVersion options:NSNumericSearch]); + } + + //invoke app delegate method + // ->will update UI/show popup if necessart + dispatch_async(dispatch_get_main_queue(), + ^{ + completionHandler(result, latestVersion); + }); + + }); + + return; +} + +//query interwebz to get latest version +-(NSString*)getLatestVersion +{ + //product version(s) data + NSData* productsVersionData = nil; + + //version dictionary + NSDictionary* productsVersionDictionary = nil; + + //latest version + NSString* latestVersion = nil; + + //get version from remote URL + productsVersionData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:PRODUCT_VERSIONS_URL]]; + if(nil == productsVersionData) + { + //bail + goto bail; + } + + //convert JSON to dictionary + // ->wrap as may throw exception + @try + { + //convert + productsVersionDictionary = [NSJSONSerialization JSONObjectWithData:productsVersionData options:0 error:nil]; + if(nil == productsVersionDictionary) + { + //bail + goto bail; + } + } + @catch(NSException* exception) + { + //bail + goto bail; + } + + //extract latest version + latestVersion = [[productsVersionDictionary objectForKey:PRODUCT_NAME] objectForKey:@"version"]; + +bail: + + return latestVersion; +} + +@end diff --git a/UpdateWindowController.h b/UpdateWindowController.h new file mode 100644 index 0000000..390ae87 --- /dev/null +++ b/UpdateWindowController.h @@ -0,0 +1,49 @@ +// +// file: UpdateWindowController.m +// project: KnockKnock +// description: window handler for update window/popup (header) +// +// created by Patrick Wardle +// copyright (c) 2017 Objective-See. All rights reserved. +// + +@import Cocoa; + +@interface UpdateWindowController : NSWindowController +{ + +} + +/* PROPERTIES */ + +//version label/string +@property(weak)IBOutlet NSTextField *infoLabel; + +//action button +@property(weak)IBOutlet NSButton *actionButton; + +//label string +@property(nonatomic, retain)NSString* infoLabelString; + +//first button ('update check') +@property(weak)IBOutlet NSView *firstButton; + +//button title +@property(nonatomic, retain)NSString* actionButtonTitle; + +//overlay view +@property(weak)IBOutlet NSView *overlayView; + +//spinner +@property(weak)IBOutlet NSProgressIndicator *progressIndicator; + +/* METHODS */ + +//save the main label's & button title's text +-(void)configure:(NSString*)label buttonTitle:(NSString*)buttonTitle; + +//invoked when user clicks button +// ->trigger action such as opening product website, updating, etc +-(IBAction)buttonHandler:(id)sender; + +@end diff --git a/UpdateWindowController.m b/UpdateWindowController.m new file mode 100644 index 0000000..8bfd55b --- /dev/null +++ b/UpdateWindowController.m @@ -0,0 +1,121 @@ +// +// file: UpdateWindowController.m +// project: KnockKnock +// description: window handler for update window/popup +// +// created by Patrick Wardle +// copyright (c) 2017 Objective-See. All rights reserved. +// + +#import "Consts.h" +#import "Utilities.h" +#import "AppDelegate.h" +#import "UpdateWindowController.h" + + +@implementation UpdateWindowController + +@synthesize infoLabel; +@synthesize overlayView; +@synthesize firstButton; +@synthesize actionButton; +@synthesize infoLabelString; +@synthesize actionButtonTitle; +@synthesize progressIndicator; + +//automatically called when nib is loaded +// ->center window +-(void)awakeFromNib +{ + //center + [self.window center]; + + return; +} + +//automatically invoked when window is loaded +// ->set to white +-(void)windowDidLoad +{ + //super + [super windowDidLoad]; + + //not in dark mode? + // make window white + if(YES != isDarkMode()) + { + //make white + self.window.backgroundColor = NSColor.whiteColor; + } + + //indicated title bar is tranparent (too) + self.window.titlebarAppearsTransparent = YES; + + //set main label + [self.infoLabel setStringValue:self.infoLabelString]; + + //set button text + self.actionButton.title = self.actionButtonTitle; + + //hide first button when action is 'update' + // ->don't need update check button ;) + if(YES == [self.actionButton.title isEqualToString:@"Update"]) + { + //hide + self.firstButton.hidden = YES; + + //then make action button first responder + [self.window makeFirstResponder:self.actionButton]; + } + + //make it key window + [self.window makeKeyAndOrderFront:self]; + + //make window front + [NSApp activateIgnoringOtherApps:YES]; + + return; +} + +//automatically invoked when window is closing +// ->make ourselves unmodal +-(void)windowWillClose:(NSNotification *)notification +{ + //make un-modal + [[NSApplication sharedApplication] stopModal]; + + return; +} + +//save the main label's & button title's text +// ->invoked before window is loaded (and thus buttons, etc are nil) +-(void)configure:(NSString*)label buttonTitle:(NSString*)buttonTitle +{ + //save label's string + self.infoLabelString = label; + + //save button's title + self.actionButtonTitle = buttonTitle; + + return; +} + +//invoked when user clicks button +// trigger action such as opening product website, updating, etc +-(IBAction)buttonHandler:(id)sender +{ + //handle 'update' / 'more info', etc + // ->open LuLu's webpage, if they *didn't* click 'Close' + if(YES != [((NSButton*)sender).title isEqualToString:@"Close"]) + { + //open URL + // ->invokes user's default browser + [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:PRODUCT_URL]]; + } + + //always close window + [[self window] close]; + + return; +} +@end diff --git a/Utilities.h b/Utilities.h index e01e190..df37f2a 100644 --- a/Utilities.h +++ b/Utilities.h @@ -17,10 +17,17 @@ NSDictionary* extractSigningInfo(NSString* path); -/* METHODS */ +/* FUNCTIONS */ + +//loads a framework +// note: assumes it is in 'Framework' dir +NSBundle* loadFramework(NSString* name); + +//init crash reporting +void initCrashReporting(void); //check if OS is supported -BOOL isSupportedOS(); +BOOL isSupportedOS(void); //get OS's major or minor version SInt32 getVersion(OSType selector); @@ -53,7 +60,7 @@ BOOL isApple(NSString* path); NSMutableAttributedString* setStringColor(NSAttributedString* string, NSColor* color); //exec a process and grab it's output -NSData* execTask(NSString* binaryPath, NSArray* arguments, BOOL shouldWait); +NSMutableDictionary* execTask(NSString* binaryPath, NSArray* arguments, BOOL shouldWait); //wait until a window is non nil // ->then make it modal @@ -84,4 +91,8 @@ BOOL Is32Bit(pid_t targetPID); // ->based on http://lapcatsoftware.com/articles/detect-app-translocation.html NSURL* getUnTranslocatedURL(); +//check if (full) dark mode +// meaning, Mojave+ and dark mode enabled +BOOL isDarkMode(); + #endif diff --git a/Utilities.m b/Utilities.m index cdfe0d1..42ca2ed 100644 --- a/Utilities.m +++ b/Utilities.m @@ -6,6 +6,8 @@ // Copyright (c) 2015 Objective-See. All rights reserved. // +@import Sentry; + #import "Consts.h" #import "Utilities.h" @@ -20,6 +22,92 @@ #import #import +//init crash reporting +void initCrashReporting() +{ + //sentry + NSBundle *sentry = nil; + + //error + NSError* error = nil; + + //class + Class SentryClient = nil; + + //load senty + sentry = loadFramework(@"Sentry.framework"); + if(nil == sentry) + { + //bail + goto bail; + } + + //get client class + SentryClient = NSClassFromString(@"SentryClient"); + if(nil == SentryClient) + { + //bail + goto bail; + } + + //set shared client + [SentryClient setSharedClient:[[SentryClient alloc] initWithDsn:CRASH_REPORTING_URL didFailWithError:&error]]; + if(nil != error) + { + //bail + goto bail; + } + + //start crash handler + [[SentryClient sharedClient] startCrashHandlerWithError:&error]; + if(nil != error) + { + //bail + goto bail; + } + +bail: + + return; +} + +//loads a framework +// note: assumes it is in 'Framework' dir +NSBundle* loadFramework(NSString* name) +{ + //handle + NSBundle* framework = nil; + + //framework path + NSString* path = nil; + + //init path + path = [NSString stringWithFormat:@"%@/../Frameworks/%@", [NSProcessInfo.processInfo.arguments[0] stringByDeletingLastPathComponent], name]; + + //standardize path + path = [path stringByStandardizingPath]; + + //init framework (bundle) + framework = [NSBundle bundleWithPath:path]; + if(NULL == framework) + { + //bail + goto bail; + } + + //load framework + if(YES != [framework loadAndReturnError:nil]) + { + //bail + goto bail; + } + +bail: + + return framework; +} + + //check if OS is supported // ->Lion and newer BOOL isSupportedOS() @@ -508,71 +596,141 @@ NSMutableAttributedString* setStringColor(NSAttributedString* string, NSColor* c return coloredString; } -//exec a process and grab it's output -NSData* execTask(NSString* binaryPath, NSArray* arguments, BOOL shouldWait) +//exec a process with args +// if 'shouldWait' is set, wait and return stdout/in and termination status +NSMutableDictionary* execTask(NSString* binaryPath, NSArray* arguments, BOOL shouldWait) { //task - NSTask *task = nil; + NSTask* task = nil; - //output pipe - NSPipe *outPipe = nil; + //output pipe for stdout + NSPipe* stdOutPipe = nil; - //output - NSData *output = nil; + //output pipe for stderr + NSPipe* stdErrPipe = nil; + + //read handle for stdout + NSFileHandle* stdOutReadHandle = nil; + + //read handle for stderr + NSFileHandle* stdErrReadHandle = nil; + + //results dictionary + NSMutableDictionary* results = nil; + + //output for stdout + NSMutableData *stdOutData = nil; + + //output for stderr + NSMutableData *stdErrData = nil; + + //init dictionary for results + results = [NSMutableDictionary dictionary]; //init task task = [NSTask new]; - //init pipe - outPipe = [NSPipe pipe]; + //TODO: + NSLog(@"calling %@ / %@", binaryPath, arguments); + printf("calling %s / %s\n", binaryPath.UTF8String, arguments.description.UTF8String); + + //only setup pipes if wait flag is set + if(YES == shouldWait) + { + //init stdout pipe + stdOutPipe = [NSPipe pipe]; + + //init stderr pipe + stdErrPipe = [NSPipe pipe]; + + //init stdout read handle + stdOutReadHandle = [stdOutPipe fileHandleForReading]; + + //init stderr read handle + stdErrReadHandle = [stdErrPipe fileHandleForReading]; + + //init stdout output buffer + stdOutData = [NSMutableData data]; + + //init stderr output buffer + stdErrData = [NSMutableData data]; + + //set task's stdout + task.standardOutput = stdOutPipe; + + //set task's stderr + task.standardError = stdErrPipe; + } //set task's path task.launchPath = binaryPath; //set task's args - task.arguments = arguments; - - //set task's output to pipe - // ->but only if we're waiting for exit - if(YES == shouldWait) + if(nil != arguments) { - //redirect - task.standardOutput = outPipe; + //set + task.arguments = arguments; } - + //wrap task launch @try { //launch [task launch]; } - @catch(NSException* exception) + @catch(NSException *exception) { //bail goto bail; } - //when waiting - // ->grab data - if(YES == shouldWait) + //no need to wait + // can just bail w/ no output + if(YES != shouldWait) { - //read until file is closed - output = [outPipe.fileHandleForReading readDataToEndOfFile]; + //bail + goto bail; + } + + //read in stdout/stderr + while(YES == [task isRunning]) + { + //accumulate stdout + [stdOutData appendData:[stdOutReadHandle readDataToEndOfFile]]; - //wait till exit - [task waitUntilExit]; - - //really kill - kill(task.processIdentifier, SIGKILL); - - }//wait + //accumulate stderr + [stdErrData appendData:[stdErrReadHandle readDataToEndOfFile]]; + } + + //grab any leftover stdout + [stdOutData appendData:[stdOutReadHandle readDataToEndOfFile]]; + + //grab any leftover stderr + [stdErrData appendData:[stdErrReadHandle readDataToEndOfFile]]; + + //add stdout + if(0 != stdOutData.length) + { + //add + results[STDOUT] = stdOutData; + } + + //add stderr + if(0 != stdErrData.length) + { + //add + results[STDERR] = stdErrData; + } + + //add exit code + results[EXIT_CODE] = [NSNumber numberWithInteger:task.terminationStatus]; -//bail bail: - return output; + return results; } + //wait until a window is non nil // ->then make it modal void makeModal(NSWindowController* windowController) @@ -1029,6 +1187,36 @@ bail: } +//check if (full) dark mode +// meaning, Mojave+ and dark mode enabled +BOOL isDarkMode() +{ + //flag + BOOL darkMode = NO; + + //not mojave? + // bail, since not true dark mode + if(YES != [[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion:(NSOperatingSystemVersion){10, 14, 0}]) + { + //bail + goto bail; + } + + //not dark mode? + if(YES != [[[NSUserDefaults standardUserDefaults] stringForKey:@"AppleInterfaceStyle"] isEqualToString:@"Dark"]) + { + //bail + goto bail; + } + + //ok, mojave dark mode it is! + darkMode = YES; + +bail: + + return darkMode; +} + diff --git a/VTButton.m b/VTButton.m index 768e93c..0a78e2a 100644 --- a/VTButton.m +++ b/VTButton.m @@ -60,11 +60,11 @@ color = [NSColor colorWithCalibratedRed:(255/255.0f) green:(1.0/255.0f) blue:(1.0/255.0f) alpha:0.5]; } //non-flagged files - // ->just gray + //gray else { //gray - color = [NSColor lightGrayColor]; + color = NSColor.grayColor; } //set string @@ -101,11 +101,10 @@ color = [NSColor redColor]; } //non-flagged files - // ->just black + // set (back) to default else { - //gray - color = [NSColor blackColor]; + color = NSColor.controlTextColor; } //set string @@ -133,11 +132,11 @@ color = [NSColor colorWithCalibratedRed:(255/255.0f) green:(1.0/255.0f) blue:(1.0/255.0f) alpha:0.66]; } //non-flagged files - // ->just black + // set (back) to default else { //gray - color = [NSColor grayColor]; + color = NSColor.grayColor; } //set string @@ -173,7 +172,7 @@ else { //gray - color = [NSColor grayColor]; + color = NSColor.grayColor; } } //mouse is up @@ -189,11 +188,11 @@ color = [NSColor redColor]; } //non-flagged files - // ->just black + // set (back) to default else { //gray - color = [NSColor blackColor]; + color = NSColor.controlTextColor; } } diff --git a/VTInfoWindowController.m b/VTInfoWindowController.m index 28f957a..ef522e6 100644 --- a/VTInfoWindowController.m +++ b/VTInfoWindowController.m @@ -55,11 +55,13 @@ //super [super windowDidLoad]; - //make it modal - //[[NSApplication sharedApplication] runModalForWindow:self.window]; - - //make white - [self.window setBackgroundColor: NSColor.whiteColor]; + //no dark mode? + // make window white + if(YES != isDarkMode()) + { + //make white + self.window.backgroundColor = NSColor.whiteColor; + } //make close button selected [self.window makeFirstResponder:self.closeButton]; @@ -101,8 +103,8 @@ //file status (known/unknown) if(YES == isKnown) { - //default color to black - textColor = [NSColor blackColor]; + //default color + textColor = NSColor.controlTextColor; //set color to red if its flagged if(0 != [self.item.vtInfo[VT_RESULTS_POSITIVES] unsignedIntegerValue]) @@ -234,7 +236,7 @@ //pre-req [self.overlayView setWantsLayer:YES]; - //set overlay's view color to black + //set overlay's view color to white self.overlayView.layer.backgroundColor = [NSColor whiteColor].CGColor; //make it semi-transparent diff --git a/en.lproj/MainMenu.xib b/en.lproj/MainMenu.xib index bddd564..7d7b4b7 100755 --- a/en.lproj/MainMenu.xib +++ b/en.lproj/MainMenu.xib @@ -1,9 +1,8 @@ - + - - + @@ -19,12 +18,18 @@ - + + + + + + + @@ -39,15 +44,15 @@ - - + + - + - + + + + diff --git a/images/flatIcon.png b/images/teIcon.png similarity index 100% rename from images/flatIcon.png rename to images/teIcon.png diff --git a/kkRowCell.m b/kkRowCell.m index da46e13..4991d75 100644 --- a/kkRowCell.m +++ b/kkRowCell.m @@ -12,7 +12,6 @@ @synthesize tag; - //draw method - (void)drawRect:(NSRect)dirtyRect { diff --git a/patrons.txt b/patrons.txt new file mode 100644 index 0000000..e576b0c --- /dev/null +++ b/patrons.txt @@ -0,0 +1,5 @@ +Patrons: +Halo Privacy, Ash Morgan, Nando Mendonca, Geoffrey Weber, Randy Wong, Aaron Kiemele, Beau Galbraith, Gamer_Bot + +Friends of Objective-See: +Digita Security, Sophos, Malwarebytes, SmugMug, Guardian Mobile Firewall, SecureMac diff --git a/remoteTaskService/main.m b/remoteTaskService/main.m index ec0c199..224129b 100644 --- a/remoteTaskService/main.m +++ b/remoteTaskService/main.m @@ -6,9 +6,10 @@ // Copyright (c) 2015 Objective-See, LLC. All rights reserved. // +#import "../Utilities.h" #import "serviceInterface.h" #import "remoteTaskService.h" -#import "../Exception.h" + #import #import @@ -125,9 +126,8 @@ int main(int argc, const char *argv[]) //listener NSXPCListener* listener = nil; - //first thing... - // ->install exception handlers! - installExceptionHandlers(); + //init crash reporting + initCrashReporting(); //make really r00t // ->needed for exec'ing vmmap, etc diff --git a/remoteTaskService/remoteTaskService.m b/remoteTaskService/remoteTaskService.m index 3e394c5..38bdf7a 100644 --- a/remoteTaskService/remoteTaskService.m +++ b/remoteTaskService/remoteTaskService.m @@ -239,15 +239,15 @@ bail: versionMinor = getVersion(gestaltSystemVersionMinor); //when OS version is older then el capitan - // ->read memory directly + // read memory directly to get list of loaded dylibs if(versionMinor < OS_MINOR_VERSION_EL_CAPITAN) { //enum dylibs dylibPaths = [self enumerateDylibsOld:(NSNumber*)taskPID]; } - //OS version is el capitan - // ->have to use vmmap, since we don't com.apple.system-task-ports entitlement + //OS version is el capitan+ + // have to use vmmap, since we don't com.apple.system-task-ports entitlement else { //enum dylibs @@ -455,14 +455,17 @@ bail: } //enumerate dylibs via vmmap -// ->OS version is el capitan, and we don't have the com.apple.system-task-ports entitlement :/ +// ->OS version is el capitan+, and we don't have the com.apple.system-task-ports entitlement :/ -(NSMutableArray*)enumerateDylibsNew:(NSNumber*)pid { //dylibs NSMutableArray* dylibs = nil; //results from 'file' cmd - NSString* results = nil; + NSMutableDictionary* results = nil; + + //output (stdout) from 'file' cmd + NSString* output = nil; //path offset NSRange pathOffset = {0}; @@ -473,6 +476,22 @@ bail: //alloc array for dylibs dylibs = [NSMutableArray array]; + //skip launchd + // mojave has a bug + if(1 == pid.integerValue) + { + //skip + goto bail; + } + + //skip self + // mojave call's suspend on process + if(getpid() == pid.integerValue) + { + //skip + goto bail; + } + //vmmap can't directly handle 32bit procs // ->so either exec 'vmmap32' or on older OSs, exec via 'arch -i386 vmmap <32bit pid>' if(YES == Is32Bit(pid.unsignedIntValue)) @@ -482,14 +501,14 @@ bail: if(YES == [[NSFileManager defaultManager] fileExistsAtPath:VMMAP_32]) { //exec vmmap32 - results = [[NSString alloc] initWithData:execTask(VMMAP_32, @[@"-w", [pid stringValue]], YES) encoding:NSUTF8StringEncoding]; + results = execTask(VMMAP_32, @[@"-w", [pid stringValue]], YES); } //otherwise // ->assume vmmap is 'fat', and exec 32bit version (pre El Capitan) else { //exec vmmap, but it's i386 version - results = [[NSString alloc] initWithData:execTask(ARCH, @[@"-i386", VMMAP, [pid stringValue]], YES) encoding:NSUTF8StringEncoding]; + results = execTask(ARCH, @[@"-i386", VMMAP, [pid stringValue]], YES); } } //for 64bit procs @@ -497,20 +516,23 @@ bail: else { //exec vmmap - results = [[NSString alloc] initWithData:execTask(VMMAP, @[@"-w", [pid stringValue]], YES) encoding:NSUTF8StringEncoding]; + results = execTask(VMMAP, @[@"-w", [pid stringValue]], YES); } //sanity check - if( (nil == results) || - (0 == results.length)) + if( (nil == results[EXIT_CODE]) || + (0 != [results[EXIT_CODE] integerValue]) ) { //bail goto bail; } + //convert stdout data to string + output = [[NSString alloc] initWithData:results[STDOUT] encoding:NSUTF8StringEncoding]; + //iterate over all results // ->line by line, looking for '__TEXT' - for(NSString* line in [results componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"\n"]]) + for(NSString* line in [output componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]]) { //ignore any line that doesn't start with '__TEXT' if(YES != [line hasPrefix:@"__TEXT"]) @@ -561,7 +583,7 @@ bail: -(void)enumerateFiles:(NSNumber*)taskPID withReply:(void (^)(NSMutableArray *))reply { //results - NSData* results = nil; + NSMutableDictionary* results = nil; //results split on '\n' NSArray* splitResults = nil; @@ -587,19 +609,15 @@ bail: //exec 'file' to get file type results = execTask(LSOF, @[@"-Fn", @"-p", taskPID.stringValue], YES); - - //sanity check(s) - if( (nil == results) || - (0 == results.length) ) + if( (nil == results[EXIT_CODE]) || + (0 != [results[EXIT_CODE] integerValue]) ) { //bail goto bail; } //split results into array - splitResults = [[[NSString alloc] initWithData:results encoding:NSUTF8StringEncoding] componentsSeparatedByString:@"\n"]; - - //sanity check(s) + splitResults = [[[NSString alloc] initWithData:results[STDOUT] encoding:NSUTF8StringEncoding] componentsSeparatedByString:@"\n"]; if( (nil == splitResults) || (0 == splitResults.count) ) {