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 @@
+
@@ -49,10 +53,12 @@
-
+
+
+
@@ -63,10 +69,12 @@
+
+
@@ -85,7 +93,7 @@
-
-
+
+
diff --git a/UI/SearchWindow.xib b/UI/SearchWindow.xib
index dcbc83a..485b1b3 100644
--- a/UI/SearchWindow.xib
+++ b/UI/SearchWindow.xib
@@ -1,10 +1,9 @@
-
+
-
+
-
@@ -24,7 +23,7 @@
-
+
diff --git a/UI/UpdateWindow.xib b/UI/UpdateWindow.xib
new file mode 100644
index 0000000..a76e41c
--- /dev/null
+++ b/UI/UpdateWindow.xib
@@ -0,0 +1,80 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
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 @@
+
+
+
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) )
{