mirror of
https://github.com/objective-see/TaskExplorer.git
synced 2026-03-22 07:02:39 +00:00
largely completed virus total logic
began implementing sorting logic (just for top pane)
This commit is contained in:
+11
-7
@@ -31,8 +31,10 @@
|
||||
|
||||
}
|
||||
|
||||
//@property (readonly) NSViewController *currentViewController;
|
||||
//@property(nonatomic, retain)NSViewController *currentViewController;
|
||||
//'filter task' search box
|
||||
// ->top pane
|
||||
@property (weak) IBOutlet NSSearchField *filterTasksBox;
|
||||
|
||||
|
||||
//(current) bottom view controller
|
||||
@property(nonatomic, retain)TaskTableController *bottomViewController;
|
||||
@@ -47,11 +49,6 @@
|
||||
//task table controller object
|
||||
@property (nonatomic, retain)TaskTableController *taskTableController;
|
||||
|
||||
//tree (outline) controller
|
||||
//@property (nonatomic, retain)TreeViewController* treeViewController;
|
||||
|
||||
//array to hold binary objects that are in array
|
||||
//@property (nonatomic, retain)NSMutableArray *tableContents;
|
||||
|
||||
//current task view format
|
||||
// ->flat or tree
|
||||
@@ -72,6 +69,10 @@
|
||||
@property (weak) IBOutlet NSView *bottomPane;
|
||||
|
||||
|
||||
//'filter items' search box
|
||||
// ->bottom pane
|
||||
@property (weak) IBOutlet NSSearchField *filterItemsBox;
|
||||
|
||||
@property (assign) IBOutlet NSWindow *window;
|
||||
|
||||
@property (weak) IBOutlet NSButton *logoButton;
|
||||
@@ -176,5 +177,8 @@
|
||||
// ->either name (flat view) or pid (tree view)
|
||||
-(void)sortTasksForView:(OrderedDictionary*)tasks;
|
||||
|
||||
//filter tasks
|
||||
-(void)filterTasks:(NSString*)filterText;
|
||||
|
||||
|
||||
@end
|
||||
|
||||
+244
-9
@@ -5,6 +5,7 @@
|
||||
|
||||
#import "Consts.h"
|
||||
#import "Binary.h"
|
||||
#import "Connection.h"
|
||||
#import "Exception.h"
|
||||
#import "Utilities.h"
|
||||
#import "AppDelegate.h"
|
||||
@@ -341,6 +342,15 @@
|
||||
}
|
||||
}
|
||||
|
||||
//always unset filter flag
|
||||
self.taskTableController.isFiltered = NO;
|
||||
|
||||
//always reset filter text
|
||||
[self.filterTasksBox setStringValue:@""];
|
||||
|
||||
//set bottom view?
|
||||
self.bottomPaneBtn.selectedSegment = DYLIBS_VIEW;
|
||||
|
||||
//add subview
|
||||
[self.topPane addSubview:[self.taskTableController view]];
|
||||
|
||||
@@ -353,20 +363,42 @@
|
||||
//reload (to re-draw) a specific row in table
|
||||
-(void)reloadRow:(Task*)task item:(ItemBase*)item pane:(NSUInteger)pane
|
||||
{
|
||||
//item's task
|
||||
// ->will use current task if task arg is nil
|
||||
__block Task* itemTask = nil;
|
||||
|
||||
//table view
|
||||
__block NSTableView* tableView = nil;
|
||||
|
||||
//row
|
||||
__block NSUInteger row = 0;
|
||||
|
||||
//segment (for bottom pane
|
||||
__block NSUInteger segmentTag = 0;
|
||||
|
||||
//run everything on main thread
|
||||
// ->ensures table view isn't changed out from under us....
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
|
||||
//get item's task
|
||||
// ->use passed in task if non-nil
|
||||
if(nil != itemTask)
|
||||
{
|
||||
//set
|
||||
itemTask = task;
|
||||
}
|
||||
//passed in task is nil
|
||||
// ->use currently selected one
|
||||
else
|
||||
{
|
||||
//set
|
||||
itemTask = self.currentTask;
|
||||
}
|
||||
|
||||
//top table (pane)
|
||||
if(PANE_TOP == pane)
|
||||
{
|
||||
//get row that task is loaded in
|
||||
//top table view
|
||||
tableView = [((id)self.taskTableController) itemView];
|
||||
|
||||
//reloadItem
|
||||
@@ -375,7 +407,7 @@
|
||||
{
|
||||
//get index where task is
|
||||
// TODO: doesn't account for filtering, etc!!!
|
||||
row = [self.taskEnumerator.tasks indexOfKey:task.pid];
|
||||
row = [self.taskEnumerator.tasks indexOfKey:itemTask.pid];
|
||||
if(NSNotFound == row)
|
||||
{
|
||||
//bail
|
||||
@@ -400,7 +432,7 @@
|
||||
[tableView beginUpdates];
|
||||
|
||||
//reload
|
||||
[(NSOutlineView*)tableView reloadItem:task];
|
||||
[(NSOutlineView*)tableView reloadItem:itemTask];
|
||||
|
||||
//end updates
|
||||
[tableView endUpdates];
|
||||
@@ -408,10 +440,97 @@
|
||||
|
||||
|
||||
}
|
||||
|
||||
//TODO: bottom pane
|
||||
|
||||
|
||||
//bottom pane
|
||||
else
|
||||
{
|
||||
//bottom table view
|
||||
tableView = [((id)self.bottomViewController) itemView];
|
||||
|
||||
//get segment tag
|
||||
segmentTag = [[self.bottomPaneBtn selectedCell] tagForSegment:[self.bottomPaneBtn selectedSegment]];
|
||||
|
||||
//get item
|
||||
// ->will bail if item isn't in (current) view, etc
|
||||
switch(segmentTag)
|
||||
{
|
||||
//dylibs
|
||||
case DYLIBS_VIEW:
|
||||
|
||||
//make sure item class/type matches current view
|
||||
if(YES != [item isKindOfClass:[Binary class]])
|
||||
{
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//sync
|
||||
@synchronized(itemTask.dylibs)
|
||||
{
|
||||
//get row
|
||||
row = [itemTask.dylibs indexOfObject:item];
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
//files
|
||||
case FILES_VIEW:
|
||||
|
||||
//make sure item class/type matches current view
|
||||
if(YES != [item isKindOfClass:[File class]])
|
||||
{
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//sync
|
||||
@synchronized(itemTask.files)
|
||||
{
|
||||
//get row
|
||||
row = [itemTask.files indexOfObject:item];
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
//networking
|
||||
case NETWORKING_VIEW:
|
||||
|
||||
//make sure item class/type matches current view
|
||||
if(YES != [item isKindOfClass:[Connection class]])
|
||||
{
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
//sync
|
||||
@synchronized(itemTask.connections)
|
||||
{
|
||||
//get row
|
||||
row = [itemTask.connections indexOfObject:item];
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
//make sure item was found
|
||||
if(NSNotFound == row)
|
||||
{
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
|
||||
|
||||
//begin updates
|
||||
[tableView beginUpdates];
|
||||
|
||||
//reload row
|
||||
[tableView reloadDataForRowIndexes:[NSIndexSet indexSetWithIndex:(row)] columnIndexes:[NSIndexSet indexSetWithIndex:0]];
|
||||
|
||||
//end updates
|
||||
[tableView endUpdates];
|
||||
}
|
||||
|
||||
//bail
|
||||
bail:
|
||||
;
|
||||
@@ -472,6 +591,7 @@ bail:
|
||||
|
||||
//set table items
|
||||
self.bottomViewController.tableItems = self.currentTask.connections;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -486,7 +606,7 @@ bail:
|
||||
{
|
||||
//reload
|
||||
// ->in main UI thread
|
||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
|
||||
[self finalizeBottomReload];
|
||||
});
|
||||
@@ -500,7 +620,7 @@ bail:
|
||||
|
||||
-(void)finalizeBottomReload
|
||||
{
|
||||
//stop progress indicator
|
||||
//stop progress indicator
|
||||
[self.bottomPaneSpinner stopAnimation:nil];
|
||||
|
||||
//invoke refresh
|
||||
@@ -1299,6 +1419,21 @@ bail:
|
||||
//save selected view
|
||||
self.taskViewFormat = [[sender selectedCell] tag];
|
||||
|
||||
//flat view
|
||||
// ->enable 'filter tasks' search field
|
||||
if(FLAT_VIEW == self.taskViewFormat)
|
||||
{
|
||||
//enable
|
||||
self.filterTasksBox.enabled = YES;
|
||||
}
|
||||
//tree view
|
||||
// ->disable 'filter tasks' search field
|
||||
else
|
||||
{
|
||||
//disable
|
||||
self.filterTasksBox.enabled = NO;
|
||||
}
|
||||
|
||||
//switch (top) view/pane
|
||||
[self changeViewController];
|
||||
|
||||
@@ -1390,4 +1525,104 @@ bail:
|
||||
return;
|
||||
}
|
||||
|
||||
//automatically invoked when user enters text in filter search boxes
|
||||
// ->filter tasks and/or items
|
||||
- (void)controlTextDidChange:(NSNotification *)aNotification
|
||||
{
|
||||
//search text
|
||||
NSTextView* search = nil;
|
||||
|
||||
//extract search (text) view
|
||||
search = aNotification.userInfo[@"NSFieldEditor"];
|
||||
|
||||
//sanity check
|
||||
if(nil == search)
|
||||
{
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//top pane
|
||||
if(YES == [aNotification.object isEqualTo:self.filterTasksBox])
|
||||
{
|
||||
//when text is reset
|
||||
// ->just reset flag
|
||||
if(0 == search.string.length)
|
||||
{
|
||||
//set flag
|
||||
self.taskTableController.isFiltered = NO;
|
||||
}
|
||||
//filter tasks
|
||||
else
|
||||
{
|
||||
//filter
|
||||
[self filterTasks:search.string];
|
||||
|
||||
//set flag
|
||||
self.taskTableController.isFiltered = YES;
|
||||
}
|
||||
|
||||
//always reload task table
|
||||
[self.taskTableController.itemView reloadData];
|
||||
}
|
||||
//bottom pane
|
||||
else if(YES == [aNotification.object isEqualTo:self.filterItemsBox])
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
//NSLog(@"changed!");
|
||||
|
||||
//bail
|
||||
bail:
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
//filter tasks
|
||||
// ->for now, just name & path
|
||||
// TODO filter on everything
|
||||
// TODO: move into task enumerator!?
|
||||
-(void)filterTasks:(NSString*)filterText
|
||||
{
|
||||
//task
|
||||
Task* task = nil;
|
||||
|
||||
//name range
|
||||
NSRange nameRange = {0};
|
||||
|
||||
//path range
|
||||
NSRange pathRange = {0};
|
||||
|
||||
//first reset filter'd items
|
||||
[self.taskTableController.filteredItems removeAllObjects];
|
||||
|
||||
//iterate over all tasks
|
||||
for(NSNumber* taskKey in self.taskEnumerator.tasks)
|
||||
{
|
||||
//extract task
|
||||
task = self.taskEnumerator.tasks[taskKey];
|
||||
|
||||
//init name range
|
||||
nameRange = [task.binary.name rangeOfString:filterText options:NSCaseInsensitiveSearch];
|
||||
|
||||
//init path range
|
||||
pathRange = [task.binary.path rangeOfString:filterText options:NSCaseInsensitiveSearch];
|
||||
|
||||
//check for match
|
||||
if( (NSNotFound != nameRange.location) ||
|
||||
(NSNotFound != pathRange.location) )
|
||||
{
|
||||
//save match
|
||||
[self.taskTableController.filteredItems addObject:task];
|
||||
}
|
||||
|
||||
}//all tasks
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
+5
-1
@@ -36,4 +36,8 @@ void addTrackingArea(NSTableCellView* itemView, NSUInteger subviewTag, id owner)
|
||||
|
||||
//set code signing image
|
||||
// ->either signed, unsigned, or unknown
|
||||
NSImage* getCodeSigningIcon(Binary* binary);
|
||||
NSImage* getCodeSigningIcon(Binary* binary);
|
||||
|
||||
//configure the VT button
|
||||
// ->also set's binary name to red if known malware
|
||||
void configVTButton(NSTableCellView *itemCell, id owner, Binary* binary);
|
||||
+159
@@ -573,6 +573,9 @@ NSTableCellView* createTaskView(NSTableView* tableView, id owner, Task* task)
|
||||
|
||||
//set path
|
||||
[[taskCell viewWithTag:TABLE_ROW_SUB_TEXT_TAG] setStringValue:task.binary.path];
|
||||
|
||||
//config VT button
|
||||
configVTButton(taskCell, owner, task.binary);
|
||||
|
||||
//bail
|
||||
bail:
|
||||
@@ -625,6 +628,9 @@ NSTableCellView* createDylibView(NSTableView* tableView, id owner, Binary* dylib
|
||||
//set path
|
||||
[[dylibCell viewWithTag:TABLE_ROW_SUB_TEXT_TAG] setStringValue:dylib.path];
|
||||
|
||||
//config VT button
|
||||
configVTButton(dylibCell, owner, dylib);
|
||||
|
||||
//bail
|
||||
bail:
|
||||
|
||||
@@ -786,6 +792,159 @@ bail:
|
||||
}
|
||||
|
||||
|
||||
//configure the VT button
|
||||
// ->also set's binary name to red if known malware
|
||||
void configVTButton(NSTableCellView *itemCell, id owner, Binary* binary)
|
||||
{
|
||||
//virus total button
|
||||
// ->for File objects only...
|
||||
VTButton* vtButton;
|
||||
|
||||
//paragraph style
|
||||
NSMutableParagraphStyle *paragraphStyle = nil;
|
||||
|
||||
//attribute dictionary
|
||||
NSMutableDictionary *stringAttributes = nil;
|
||||
|
||||
//VT detection ratio as string
|
||||
NSString* vtDetectionRatio = nil;
|
||||
|
||||
//grab virus total button
|
||||
vtButton = [itemCell viewWithTag:TABLE_ROW_VT_BUTTON];
|
||||
|
||||
|
||||
//[itemCell viewWithTag:TABLE_ROW_VT_BUTTON];
|
||||
|
||||
//configure/show VT info
|
||||
// ->only if 'disable' preference not set
|
||||
//if(YES != ((AppDelegate*)[[NSApplication sharedApplication] delegate]).prefsWindowController.disableVTQueries)
|
||||
//{
|
||||
//set button delegate
|
||||
vtButton.delegate = owner;
|
||||
|
||||
//save file obj
|
||||
vtButton.binary = binary;
|
||||
|
||||
//check if have vt results
|
||||
if(nil != binary.vtInfo)
|
||||
{
|
||||
//set font
|
||||
[vtButton setFont:[NSFont fontWithName:@"Menlo-Bold" size:12]];
|
||||
|
||||
//enable
|
||||
vtButton.enabled = YES;
|
||||
|
||||
//got VT results
|
||||
// ->check 'permalink' to determine if file is known to VT
|
||||
// then, show ratio and set to red if file is flagged
|
||||
if(nil != binary.vtInfo[VT_RESULTS_URL])
|
||||
{
|
||||
//alloc paragraph style
|
||||
paragraphStyle = [[NSMutableParagraphStyle alloc] init];
|
||||
|
||||
//center the text
|
||||
[paragraphStyle setAlignment:NSCenterTextAlignment];
|
||||
|
||||
//alloc attributes dictionary
|
||||
stringAttributes = [NSMutableDictionary dictionary];
|
||||
|
||||
//set underlined attribute
|
||||
stringAttributes[NSUnderlineStyleAttributeName] = @(NSUnderlineStyleSingle);
|
||||
|
||||
//set alignment (center)
|
||||
stringAttributes[NSParagraphStyleAttributeName] = paragraphStyle;
|
||||
|
||||
//set font
|
||||
stringAttributes[NSFontAttributeName] = [NSFont fontWithName:@"Menlo-Bold" size:12];
|
||||
|
||||
//compute detection ratio
|
||||
vtDetectionRatio = [NSString stringWithFormat:@"%lu/%lu", (unsigned long)[binary.vtInfo[VT_RESULTS_POSITIVES] unsignedIntegerValue], (unsigned long)[binary.vtInfo[VT_RESULTS_TOTAL] unsignedIntegerValue]];
|
||||
|
||||
//known 'good' files (0 positivies)
|
||||
if(0 == [binary.vtInfo[VT_RESULTS_POSITIVES] unsignedIntegerValue])
|
||||
{
|
||||
//(re)set title black
|
||||
itemCell.textField.textColor = [NSColor blackColor];
|
||||
|
||||
//set color (black)
|
||||
stringAttributes[NSForegroundColorAttributeName] = [NSColor blackColor];
|
||||
|
||||
//set string (vt ratio), with attributes
|
||||
[vtButton setAttributedTitle:[[NSAttributedString alloc] initWithString:vtDetectionRatio attributes:stringAttributes]];
|
||||
|
||||
//set color (gray)
|
||||
stringAttributes[NSForegroundColorAttributeName] = [NSColor grayColor];
|
||||
|
||||
//set selected text color
|
||||
[vtButton setAttributedAlternateTitle:[[NSAttributedString alloc] initWithString:vtDetectionRatio attributes:stringAttributes]];
|
||||
}
|
||||
//files flagged by VT
|
||||
// ->set name and detection to red
|
||||
else
|
||||
{
|
||||
//set title red
|
||||
itemCell.textField.textColor = [NSColor redColor];
|
||||
|
||||
//set color (red)
|
||||
stringAttributes[NSForegroundColorAttributeName] = [NSColor redColor];
|
||||
|
||||
//set string (vt ratio), with attributes
|
||||
[vtButton setAttributedTitle:[[NSAttributedString alloc] initWithString:vtDetectionRatio attributes:stringAttributes]];
|
||||
|
||||
//set selected text color
|
||||
[vtButton setAttributedAlternateTitle:[[NSAttributedString alloc] initWithString:vtDetectionRatio attributes:stringAttributes]];
|
||||
|
||||
}
|
||||
|
||||
//enable
|
||||
[vtButton setEnabled:YES];
|
||||
}
|
||||
|
||||
//file is not known
|
||||
// ->reset title to '?'
|
||||
else
|
||||
{
|
||||
//set title
|
||||
[vtButton setTitle:@"?"];
|
||||
}
|
||||
}
|
||||
|
||||
//no VT results (e.g. unknown file)
|
||||
else
|
||||
{
|
||||
//set font
|
||||
[vtButton setFont:[NSFont fontWithName:@"Menlo-Bold" size:8]];
|
||||
|
||||
//set title
|
||||
[vtButton setTitle:@"▪ ▪ ▪"];
|
||||
|
||||
//disable
|
||||
vtButton.enabled = NO;
|
||||
}
|
||||
|
||||
//show virus total button
|
||||
vtButton.hidden = NO;
|
||||
|
||||
//show virus total label
|
||||
//[[itemCell viewWithTag:TABLE_ROW_VT_BUTTON+1] setHidden:NO];
|
||||
|
||||
//}//show VT info (pref not disabled)
|
||||
|
||||
/*
|
||||
//hide VT info
|
||||
else
|
||||
{
|
||||
//hide virus total button
|
||||
vtButton.hidden = YES;
|
||||
|
||||
//hide virus total button label
|
||||
[[itemCell viewWithTag:TABLE_ROW_VT_BUTTON+1] setHidden:YES];
|
||||
}
|
||||
*/
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -41,6 +41,10 @@
|
||||
|
||||
/* VIRUS TOTAL INFO */
|
||||
|
||||
//flag saying item is 'last'
|
||||
// ->thus VT items should all be queried
|
||||
@property BOOL lastItem;
|
||||
|
||||
//dictionary returned by VT
|
||||
@property (nonatomic, retain)NSDictionary* vtInfo;
|
||||
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@
|
||||
@synthesize isTaskBinary;
|
||||
|
||||
@synthesize vtInfo;
|
||||
|
||||
@synthesize lastItem;
|
||||
|
||||
//init method
|
||||
-(id)initWithParams:(NSDictionary*)params
|
||||
|
||||
@@ -90,7 +90,6 @@
|
||||
//add item for VT processing
|
||||
[vtObject addItem:binary];
|
||||
|
||||
|
||||
//unlock
|
||||
[self.queueCondition unlock];
|
||||
|
||||
|
||||
@@ -110,22 +110,17 @@
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//indicate that binary is a task (main) executable
|
||||
self.binary.isTaskBinary = YES;
|
||||
|
||||
//add to queue
|
||||
// ->this will processing
|
||||
[((AppDelegate*)[[NSApplication sharedApplication] delegate]).taskEnumerator.binaryQueue enqueue:self.binary];
|
||||
|
||||
//add to VT queue
|
||||
// ->this will trigger background submission to VT
|
||||
[((AppDelegate*)[[NSApplication sharedApplication] delegate]).taskEnumerator.binaryQueue enqueue:self.binary];
|
||||
|
||||
//add it to 'global' list
|
||||
existingBinaries[taskPath] = self.binary;
|
||||
|
||||
}
|
||||
|
||||
//indicate that binary is a task (main) executable
|
||||
//self.binary.isTaskBinary = YES;
|
||||
|
||||
}//init self
|
||||
|
||||
//bail
|
||||
@@ -404,7 +399,7 @@ bail:
|
||||
//add to task's dylibs
|
||||
[self.dylibs addObject:dylib];
|
||||
}
|
||||
}
|
||||
} //all dylibs
|
||||
|
||||
//sync to sort
|
||||
@synchronized(self.dylibs)
|
||||
|
||||
@@ -10,14 +10,14 @@
|
||||
<string>TaskExplorer</string>
|
||||
<key>IDESourceControlProjectOriginsDictionary</key>
|
||||
<dict>
|
||||
<key>A9FFC1B124E25027A0E10FB456DBA9E2803FAE9D</key>
|
||||
<key>61F07AFB33748EF0C810BEEF6126283DAC63A899</key>
|
||||
<string>https://bitbucket.org/objective-see/knockknock.git</string>
|
||||
</dict>
|
||||
<key>IDESourceControlProjectPath</key>
|
||||
<string>TaskExplorer.xcodeproj</string>
|
||||
<key>IDESourceControlProjectRelativeInstallPathDictionary</key>
|
||||
<dict>
|
||||
<key>A9FFC1B124E25027A0E10FB456DBA9E2803FAE9D</key>
|
||||
<key>61F07AFB33748EF0C810BEEF6126283DAC63A899</key>
|
||||
<string>../..</string>
|
||||
</dict>
|
||||
<key>IDESourceControlProjectURL</key>
|
||||
@@ -25,14 +25,14 @@
|
||||
<key>IDESourceControlProjectVersion</key>
|
||||
<integer>111</integer>
|
||||
<key>IDESourceControlProjectWCCIdentifier</key>
|
||||
<string>A9FFC1B124E25027A0E10FB456DBA9E2803FAE9D</string>
|
||||
<string>61F07AFB33748EF0C810BEEF6126283DAC63A899</string>
|
||||
<key>IDESourceControlProjectWCConfigurations</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
|
||||
<string>public.vcs.git</string>
|
||||
<key>IDESourceControlWCCIdentifierKey</key>
|
||||
<string>A9FFC1B124E25027A0E10FB456DBA9E2803FAE9D</string>
|
||||
<string>61F07AFB33748EF0C810BEEF6126283DAC63A899</string>
|
||||
<key>IDESourceControlWCCName</key>
|
||||
<string>TaskExplorer</string>
|
||||
</dict>
|
||||
|
||||
+261
-37
@@ -20,11 +20,11 @@
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "TaskEnumerator.m"
|
||||
timestampString = "456469787.454434"
|
||||
timestampString = "456607885.071145"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "343"
|
||||
endingLineNumber = "343"
|
||||
startingLineNumber = "344"
|
||||
endingLineNumber = "344"
|
||||
landmarkName = "-removeTask:"
|
||||
landmarkType = "5">
|
||||
</BreakpointContent>
|
||||
@@ -36,11 +36,11 @@
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "AppDelegate.m"
|
||||
timestampString = "456541711.785304"
|
||||
timestampString = "456648442.982284"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "661"
|
||||
endingLineNumber = "661"
|
||||
startingLineNumber = "775"
|
||||
endingLineNumber = "775"
|
||||
landmarkName = "-reloadTaskTable"
|
||||
landmarkType = "5">
|
||||
</BreakpointContent>
|
||||
@@ -52,27 +52,11 @@
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "TaskTableController.m"
|
||||
timestampString = "456474649.232255"
|
||||
timestampString = "456648442.982284"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "711"
|
||||
endingLineNumber = "711"
|
||||
landmarkName = "-refresh"
|
||||
landmarkType = "5">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "TaskTableController.m"
|
||||
timestampString = "456474649.232255"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "1122"
|
||||
endingLineNumber = "1122"
|
||||
startingLineNumber = "1174"
|
||||
endingLineNumber = "1174"
|
||||
landmarkName = "-outlineView:rowViewForItem:"
|
||||
landmarkType = "5">
|
||||
</BreakpointContent>
|
||||
@@ -84,11 +68,11 @@
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "TaskTableController.m"
|
||||
timestampString = "456474649.232255"
|
||||
timestampString = "456648442.982284"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "1115"
|
||||
endingLineNumber = "1115"
|
||||
startingLineNumber = "1167"
|
||||
endingLineNumber = "1167"
|
||||
landmarkName = "-outlineView:viewForTableColumn:item:"
|
||||
landmarkType = "5">
|
||||
</BreakpointContent>
|
||||
@@ -100,11 +84,11 @@
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "TaskTableController.m"
|
||||
timestampString = "456474649.232255"
|
||||
timestampString = "456648442.982284"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "1105"
|
||||
endingLineNumber = "1105"
|
||||
startingLineNumber = "1157"
|
||||
endingLineNumber = "1157"
|
||||
landmarkName = "-outlineViewSelectionDidChange:"
|
||||
landmarkType = "5">
|
||||
</BreakpointContent>
|
||||
@@ -132,11 +116,11 @@
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "TaskTableController.m"
|
||||
timestampString = "456521744.657881"
|
||||
timestampString = "456648442.982284"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "934"
|
||||
endingLineNumber = "934"
|
||||
startingLineNumber = "1000"
|
||||
endingLineNumber = "1000"
|
||||
landmarkName = "-showInfo:"
|
||||
landmarkType = "5">
|
||||
</BreakpointContent>
|
||||
@@ -148,11 +132,11 @@
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "AppDelegate.m"
|
||||
timestampString = "456521776.780775"
|
||||
timestampString = "456621956.395811"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "317"
|
||||
endingLineNumber = "317"
|
||||
startingLineNumber = "318"
|
||||
endingLineNumber = "318"
|
||||
landmarkName = "-changeViewController"
|
||||
landmarkType = "5">
|
||||
</BreakpointContent>
|
||||
@@ -167,5 +151,245 @@
|
||||
moduleName = "">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "VirusTotal.m"
|
||||
timestampString = "456607881.829588"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "35"
|
||||
endingLineNumber = "35"
|
||||
landmarkName = "-addItem:"
|
||||
landmarkType = "5">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "VirusTotal.m"
|
||||
timestampString = "456638843.665835"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "55"
|
||||
endingLineNumber = "55"
|
||||
landmarkName = "-addItem:"
|
||||
landmarkType = "5">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "VirusTotal.m"
|
||||
timestampString = "456638843.665835"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "654"
|
||||
endingLineNumber = "654"
|
||||
landmarkName = "-processResults:results:"
|
||||
landmarkType = "5">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "AppDelegate.m"
|
||||
timestampString = "456648442.982284"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "545"
|
||||
endingLineNumber = "545"
|
||||
landmarkName = "-reloadBottomPane:itemView:"
|
||||
landmarkType = "5">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "AppDelegate.m"
|
||||
timestampString = "456648442.982284"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "563"
|
||||
endingLineNumber = "563"
|
||||
landmarkName = "-reloadBottomPane:itemView:"
|
||||
landmarkType = "5">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "Task.m"
|
||||
timestampString = "456638843.665835"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "344"
|
||||
endingLineNumber = "344"
|
||||
landmarkName = "-enumerateDylibs:allDylibs:"
|
||||
landmarkType = "5">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "Task.m"
|
||||
timestampString = "456638843.665835"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "320"
|
||||
endingLineNumber = "320"
|
||||
landmarkName = "-enumerateDylibs:allDylibs:"
|
||||
landmarkType = "5">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "TaskTableController.m"
|
||||
timestampString = "456648442.982284"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "1203"
|
||||
endingLineNumber = "1203"
|
||||
landmarkName = "-handleRowSelection"
|
||||
landmarkType = "5">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "TaskTableController.m"
|
||||
timestampString = "456648442.982284"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "731"
|
||||
endingLineNumber = "731"
|
||||
landmarkName = "-refresh"
|
||||
landmarkType = "5">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "TaskTableController.m"
|
||||
timestampString = "456648442.982284"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "86"
|
||||
endingLineNumber = "86"
|
||||
landmarkName = "-numberOfRowsInTableView:"
|
||||
landmarkType = "5">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "TaskTableController.m"
|
||||
timestampString = "456648442.982284"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "1003"
|
||||
endingLineNumber = "1003"
|
||||
landmarkName = "-showInfo:"
|
||||
landmarkType = "5">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "TaskTableController.m"
|
||||
timestampString = "456648442.982284"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "783"
|
||||
endingLineNumber = "783"
|
||||
landmarkName = "-refresh"
|
||||
landmarkType = "5">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "Task.m"
|
||||
timestampString = "456638843.665835"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "433"
|
||||
endingLineNumber = "433"
|
||||
landmarkName = "-enumerateDylibs:allDylibs:"
|
||||
landmarkType = "5">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "AppDelegate.m"
|
||||
timestampString = "456648442.982284"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "1589"
|
||||
endingLineNumber = "1589"
|
||||
landmarkName = "-filterTasks:"
|
||||
landmarkType = "5">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "TaskTableController.m"
|
||||
timestampString = "456648442.982284"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "130"
|
||||
endingLineNumber = "130"
|
||||
landmarkName = "-tableViewSelectionDidChange:"
|
||||
landmarkType = "5">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
</Breakpoints>
|
||||
</Bucket>
|
||||
|
||||
@@ -23,12 +23,18 @@
|
||||
//flag for first time init's
|
||||
@property BOOL didInit;
|
||||
|
||||
//tasks
|
||||
// ->updated by task enumerator
|
||||
//@property(nonatomic, retain)OrderedDictionary* tasks;
|
||||
//flag for ignoring automated row selections
|
||||
@property BOOL ignoreSelection;
|
||||
|
||||
//flag for filtering
|
||||
@property BOOL isFiltered;
|
||||
|
||||
//all table items
|
||||
@property(nonatomic, retain)NSMutableArray* tableItems;
|
||||
|
||||
//filtered table items
|
||||
@property(nonatomic, retain)NSMutableArray* filteredItems;
|
||||
|
||||
//category table view
|
||||
@property(weak) IBOutlet NSTableView *itemView;
|
||||
|
||||
|
||||
+165
-111
@@ -6,7 +6,7 @@
|
||||
// Copyright (c) 2015 Objective-See. All rights reserved.
|
||||
//
|
||||
|
||||
//TODO: list of what's running on my Mac!!!!
|
||||
//TODO: list of what's running on my Mac on website!!!!
|
||||
|
||||
#import "Binary.h"
|
||||
#import "Consts.h"
|
||||
@@ -30,59 +30,39 @@
|
||||
@implementation TaskTableController
|
||||
|
||||
@synthesize itemView;
|
||||
@synthesize isFiltered;
|
||||
@synthesize tableItems;
|
||||
@synthesize selectedRow;
|
||||
@synthesize isBottomPane;
|
||||
@synthesize filteredItems;
|
||||
@synthesize ignoreSelection;
|
||||
@synthesize vtWindowController;
|
||||
@synthesize infoWindowController;
|
||||
|
||||
@synthesize didInit;
|
||||
|
||||
//@synthesize tasks;
|
||||
|
||||
//TODO: called many timesss
|
||||
-(void)awakeFromNib
|
||||
{
|
||||
|
||||
//single time init
|
||||
if(YES != didInit)
|
||||
{
|
||||
//init selected row
|
||||
self.selectedRow = -1;
|
||||
|
||||
//for outline (tree) view
|
||||
// ->expand
|
||||
if(YES == [self.itemView isKindOfClass:[NSOutlineView class]])
|
||||
{
|
||||
[(NSOutlineView*)self.itemView expandItem:nil expandChildren:YES];
|
||||
}
|
||||
//alloc array for filtered items
|
||||
filteredItems = [NSMutableArray array];
|
||||
|
||||
//extand tree view
|
||||
if(YES == [self.itemView isKindOfClass:[NSOutlineView class]])
|
||||
{
|
||||
//expand
|
||||
[(NSOutlineView*)self.itemView expandItem:nil expandChildren:YES];
|
||||
}
|
||||
|
||||
//set flag
|
||||
self.didInit = YES;
|
||||
|
||||
}
|
||||
|
||||
//self.selectedRow = -1;
|
||||
|
||||
/*
|
||||
//for outline (tree) view
|
||||
// ->expand
|
||||
if(YES == [self.itemView isKindOfClass:[NSOutlineView class]])
|
||||
{
|
||||
[(NSOutlineView*)self.itemView expandItem:nil expandChildren:YES];
|
||||
|
||||
//TODO: do this in IB?
|
||||
//[itemView setTarget:self];
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
NSString *title = @"[ all tasks ]";
|
||||
NSTableColumn *yourColumn = self.itemView.tableColumns.lastObject;
|
||||
[yourColumn.headerCell setStringValue:title];
|
||||
|
||||
[self.itemView setIndicatorImage:[NSImage imageNamed:@"NSDescendingSortIndicator"] inTableColumn:self.itemView.tableColumns.lastObject];
|
||||
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
@@ -115,13 +95,26 @@
|
||||
// ->use tasks from enumerator
|
||||
if(YES != self.isBottomPane)
|
||||
{
|
||||
//grab tasks
|
||||
tasks = ((AppDelegate*)[[NSApplication sharedApplication] delegate]).taskEnumerator.tasks;
|
||||
//when not filtered
|
||||
// ->use tasks
|
||||
if(YES != isFiltered)
|
||||
{
|
||||
//get tasks
|
||||
tasks = ((AppDelegate*)[[NSApplication sharedApplication] delegate]).taskEnumerator.tasks;
|
||||
|
||||
//set row count
|
||||
rows = tasks.count;
|
||||
//set count
|
||||
rows = tasks.count;
|
||||
}
|
||||
//when filtered
|
||||
// ->use filtered items
|
||||
else
|
||||
{
|
||||
//set count
|
||||
rows = self.filteredItems.count;
|
||||
}
|
||||
}
|
||||
//bottom pane uses table items
|
||||
//bottom pane uses 'tableItems' iVar
|
||||
//TODO: filter support
|
||||
else
|
||||
{
|
||||
//set row count
|
||||
@@ -130,14 +123,19 @@
|
||||
|
||||
return rows;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//automatically invoked when user selects row
|
||||
// ->only care about for top pane, trigger load bottom view
|
||||
-(void)tableViewSelectionDidChange:(NSNotification *)notification
|
||||
{
|
||||
//handle selection
|
||||
[self handleRowSelection];
|
||||
//only handle user selections
|
||||
// ->not those from 'reloadData'
|
||||
if(YES != self.ignoreSelection)
|
||||
{
|
||||
//handle selection
|
||||
[self handleRowSelection];
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -157,23 +155,45 @@
|
||||
NSView* rowView = nil;
|
||||
|
||||
//for TOP PANE
|
||||
// ->use tasks from enumerator
|
||||
// ->use tasks from enumerator or filtered items
|
||||
if(YES != self.isBottomPane)
|
||||
{
|
||||
//grab tasks
|
||||
tasks = ((AppDelegate*)[[NSApplication sharedApplication] delegate]).taskEnumerator.tasks;
|
||||
|
||||
//sanity check
|
||||
// ->make sure there is table item for row
|
||||
if(tasks.count <= row)
|
||||
//when not filtered
|
||||
// ->use tasks
|
||||
if(YES != isFiltered)
|
||||
{
|
||||
//bail
|
||||
goto bail;
|
||||
//grab tasks
|
||||
tasks = ((AppDelegate*)[[NSApplication sharedApplication] delegate]).taskEnumerator.tasks;
|
||||
|
||||
//sanity check
|
||||
// ->make sure there is table item for row
|
||||
if(tasks.count <= row)
|
||||
{
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//get task object
|
||||
// ->by index to get key, then by key
|
||||
item = tasks[[tasks keyAtIndex:row]];
|
||||
|
||||
}
|
||||
|
||||
//get task object
|
||||
// ->by index to get key, then by key
|
||||
item = tasks[[tasks keyAtIndex:row]];
|
||||
//when filtered
|
||||
// ->use filtered items
|
||||
else
|
||||
{
|
||||
//sanity check
|
||||
// ->make sure there is table item for row
|
||||
if(self.filteredItems.count <= row)
|
||||
{
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//get task object
|
||||
item = self.filteredItems[row];
|
||||
}
|
||||
}
|
||||
|
||||
//for BOTTOM PANE
|
||||
@@ -725,9 +745,15 @@ bail:
|
||||
//get task
|
||||
selectedTask = [self taskForRow:nil];
|
||||
|
||||
//ignore selection change though
|
||||
self.ignoreSelection = YES;
|
||||
|
||||
//always reload
|
||||
[self.itemView reloadData];
|
||||
|
||||
//don't ignore selection
|
||||
self.ignoreSelection = NO;
|
||||
|
||||
//when an item was selected
|
||||
// ->get its index and make sure that's still selected
|
||||
if(nil != selectedTask)
|
||||
@@ -749,6 +775,40 @@ bail:
|
||||
[self.itemView endUpdates];
|
||||
}
|
||||
}
|
||||
/*
|
||||
//otherwise select first row
|
||||
else
|
||||
{
|
||||
//selected row cell
|
||||
NSTableCellView* rowView = nil;
|
||||
|
||||
//default to first row
|
||||
self.selectedRow = 0;
|
||||
|
||||
//sanity check
|
||||
if(0 == [self numberOfRowsInTableView:self.itemView])
|
||||
{
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//get first row
|
||||
rowView = [self.itemView viewAtColumn:0 row:0 makeIfNecessary:YES];
|
||||
|
||||
//extract task
|
||||
// ->pid of task is view's id :)
|
||||
Task* task = tasks[[NSNumber numberWithInteger:(rowView.tag - PID_TAG_DELTA)]];
|
||||
|
||||
//save task
|
||||
((AppDelegate*)[[NSApplication sharedApplication] delegate]).currentTask = task;
|
||||
|
||||
//reload bottom pane
|
||||
[((AppDelegate*)[[NSApplication sharedApplication] delegate]) selectBottomPaneContent:nil];
|
||||
}
|
||||
*/
|
||||
|
||||
//bail
|
||||
bail:
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -784,28 +844,34 @@ bail:
|
||||
{
|
||||
//grab row
|
||||
taskRow = [self.itemView selectedRow];
|
||||
|
||||
}
|
||||
|
||||
//TODO: add check for filterItems.count
|
||||
//sanity check(s)
|
||||
// ->make sure row has item
|
||||
// ->make sure row is decent
|
||||
if( (-1 == taskRow) ||
|
||||
(tasks.count < taskRow) )
|
||||
((YES != self.isFiltered) && (tasks.count < taskRow)) ||
|
||||
((YES == self.isFiltered) && (self.filteredItems.count < taskRow)) )
|
||||
{
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//get task object
|
||||
// ->by index to get key, then by key
|
||||
//task = tasks[[tasks keyAtIndex:taskRow]];
|
||||
|
||||
//get row that's about to be selected
|
||||
rowView = [self.itemView viewAtColumn:0 row:taskRow makeIfNecessary:YES];
|
||||
|
||||
//extract task
|
||||
// ->pid of task is view's id :)
|
||||
task = tasks[[NSNumber numberWithInteger:(rowView.tag - PID_TAG_DELTA)]];
|
||||
//when not filtered, use all tasks
|
||||
//if(YES != isFiltered)
|
||||
//{
|
||||
//extract task
|
||||
// ->pid of task is view's id :)
|
||||
task = tasks[[NSNumber numberWithInteger:(rowView.tag - PID_TAG_DELTA)]];
|
||||
//}
|
||||
//when filtered, use filtered items
|
||||
//else
|
||||
//{
|
||||
// task = self.filteredItems[
|
||||
//}
|
||||
|
||||
//bail
|
||||
bail:
|
||||
@@ -966,54 +1032,40 @@ bail:
|
||||
|
||||
//invoked when the user clicks 'virus total' icon
|
||||
// ->launch browser and browse to virus total's page
|
||||
-(void)showVTInfo:(NSView*)button
|
||||
-(void)showVTInfo:(id)sender
|
||||
{
|
||||
//array backing table
|
||||
NSArray* tableItems = nil;
|
||||
//item
|
||||
// ->task, dylib, file, etc
|
||||
Binary* item = nil;
|
||||
|
||||
//selected item
|
||||
File* selectedItem = nil;
|
||||
//for top pane
|
||||
// ->get task
|
||||
if(YES != self.isBottomPane)
|
||||
{
|
||||
//get task
|
||||
item = [(Task*)[self taskForRow:sender] binary];
|
||||
}
|
||||
|
||||
//bottom pane
|
||||
else
|
||||
{
|
||||
//get item
|
||||
item = (Binary*)[self itemForRow:sender];
|
||||
}
|
||||
|
||||
//row that button was clicked on
|
||||
NSUInteger rowIndex = -1;
|
||||
|
||||
//get row index
|
||||
rowIndex = [self.itemView rowForView:button];
|
||||
|
||||
//grab item table items
|
||||
tableItems = [self getTableItems];
|
||||
|
||||
//sanity check
|
||||
// ->make sure row has item
|
||||
if(tableItems.count < rowIndex)
|
||||
//bail on nil items
|
||||
if(nil == item)
|
||||
{
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//sanity check
|
||||
if(-1 != rowIndex)
|
||||
{
|
||||
//extract selected item
|
||||
// ->invoke helper function to get array backing table
|
||||
selectedItem = tableItems[rowIndex];
|
||||
|
||||
//alloc/init info window
|
||||
vtWindowController = [[VTInfoWindowController alloc] initWithItem:selectedItem rowIndex:rowIndex];
|
||||
|
||||
//show it
|
||||
[self.vtWindowController.windowController showWindow:self];
|
||||
|
||||
/*
|
||||
//make it modal
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
|
||||
//modal!
|
||||
[[NSApplication sharedApplication] runModalForWindow:vtWindowController.windowController.window];
|
||||
|
||||
});
|
||||
*/
|
||||
}
|
||||
|
||||
//alloc/init info window
|
||||
vtWindowController = [[VTInfoWindowController alloc] initWithItem:item];
|
||||
|
||||
//show it
|
||||
[self.vtWindowController.windowController showWindow:self];
|
||||
|
||||
|
||||
//bail
|
||||
bail:
|
||||
@@ -1177,7 +1229,8 @@ bail:
|
||||
|
||||
//sanity check
|
||||
if( (-1 == newlySelectedRow) ||
|
||||
(newlySelectedRow >= tasks.count) )
|
||||
((YES != self.isFiltered) && (newlySelectedRow >= tasks.count)) ||
|
||||
((YES == self.isFiltered) && (newlySelectedRow >= self.filteredItems.count)) )
|
||||
{
|
||||
//bail
|
||||
goto bail;
|
||||
@@ -1241,9 +1294,9 @@ bail:
|
||||
|
||||
}
|
||||
|
||||
|
||||
//ignore if row selection didn't change
|
||||
if([self.itemView selectedRow] == self.selectedRow)
|
||||
//ignore if row selection and task didn't change
|
||||
if( ([self.itemView selectedRow] == self.selectedRow) &&
|
||||
(((AppDelegate*)[[NSApplication sharedApplication] delegate]).currentTask == task) )
|
||||
{
|
||||
//ignore
|
||||
goto bail;
|
||||
@@ -1262,7 +1315,8 @@ bail:
|
||||
//bail
|
||||
bail:
|
||||
|
||||
;
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@
|
||||
@property(assign)TaskTableController *delegate;
|
||||
|
||||
//File object
|
||||
@property(nonatomic, retain)Binary* fileObj;
|
||||
@property(nonatomic, retain)Binary* binary;
|
||||
|
||||
//button's row index
|
||||
|
||||
|
||||
+11
-11
@@ -13,7 +13,7 @@
|
||||
|
||||
@implementation VTButton
|
||||
|
||||
@synthesize fileObj;
|
||||
@synthesize binary;
|
||||
@synthesize delegate;
|
||||
@synthesize mouseDown;
|
||||
@synthesize mouseExit;
|
||||
@@ -53,8 +53,8 @@
|
||||
|
||||
//flagged files
|
||||
// ->make em red!
|
||||
if( (nil != self.fileObj.vtInfo) &&
|
||||
(0 != [self.fileObj.vtInfo[VT_RESULTS_POSITIVES] unsignedIntegerValue]) )
|
||||
if( (nil != self.binary.vtInfo) &&
|
||||
(0 != [self.binary.vtInfo[VT_RESULTS_POSITIVES] unsignedIntegerValue]) )
|
||||
{
|
||||
//set color (light red)
|
||||
color = [NSColor colorWithCalibratedRed:(255/255.0f) green:(1.0/255.0f) blue:(1.0/255.0f) alpha:0.5];
|
||||
@@ -94,8 +94,8 @@
|
||||
|
||||
//flagged files
|
||||
// ->make em red!
|
||||
if( (nil != self.fileObj.vtInfo) &&
|
||||
(0 != [self.fileObj.vtInfo[VT_RESULTS_POSITIVES] unsignedIntegerValue]) )
|
||||
if( (nil != self.binary.vtInfo) &&
|
||||
(0 != [self.binary.vtInfo[VT_RESULTS_POSITIVES] unsignedIntegerValue]) )
|
||||
{
|
||||
//set color (light red)
|
||||
color = [NSColor redColor];
|
||||
@@ -126,8 +126,8 @@
|
||||
|
||||
//flagged files
|
||||
// ->make em red!
|
||||
if( (nil != self.fileObj.vtInfo) &&
|
||||
(0 != [self.fileObj.vtInfo[VT_RESULTS_POSITIVES] unsignedIntegerValue]) )
|
||||
if( (nil != self.binary.vtInfo) &&
|
||||
(0 != [self.binary.vtInfo[VT_RESULTS_POSITIVES] unsignedIntegerValue]) )
|
||||
{
|
||||
//set color (lightish red)
|
||||
color = [NSColor colorWithCalibratedRed:(255/255.0f) green:(1.0/255.0f) blue:(1.0/255.0f) alpha:0.66];
|
||||
@@ -162,8 +162,8 @@
|
||||
{
|
||||
//flagged files
|
||||
// ->make em red!
|
||||
if( (nil != self.fileObj.vtInfo) &&
|
||||
(0 != [self.fileObj.vtInfo[VT_RESULTS_POSITIVES] unsignedIntegerValue]) )
|
||||
if( (nil != self.binary.vtInfo) &&
|
||||
(0 != [self.binary.vtInfo[VT_RESULTS_POSITIVES] unsignedIntegerValue]) )
|
||||
{
|
||||
//set color (lightish red)
|
||||
color = [NSColor colorWithCalibratedRed:(255/255.0f) green:(1.0/255.0f) blue:(1.0/255.0f) alpha:0.66];
|
||||
@@ -182,8 +182,8 @@
|
||||
{
|
||||
//flagged files
|
||||
// ->make em red!
|
||||
if( (nil != self.fileObj.vtInfo) &&
|
||||
(0 != [self.fileObj.vtInfo[VT_RESULTS_POSITIVES] unsignedIntegerValue]) )
|
||||
if( (nil != self.binary.vtInfo) &&
|
||||
(0 != [self.binary.vtInfo[VT_RESULTS_POSITIVES] unsignedIntegerValue]) )
|
||||
{
|
||||
//set color (light red)
|
||||
color = [NSColor redColor];
|
||||
|
||||
@@ -22,10 +22,10 @@
|
||||
@property(nonatomic, strong)VTInfoWindowController *windowController;
|
||||
|
||||
//file object
|
||||
@property(nonatomic, retain)Binary* fileObj;
|
||||
@property(nonatomic, retain)Binary* item;
|
||||
|
||||
//row index
|
||||
@property NSUInteger rowIndex;
|
||||
//@property NSUInteger rowIndex;
|
||||
|
||||
//properties in window
|
||||
@property (weak) IBOutlet NSTextField *unknownFile;
|
||||
@@ -50,7 +50,7 @@
|
||||
|
||||
//init method
|
||||
// ->save item and load nib
|
||||
-(id)initWithItem:(File*)selectedItem rowIndex:(NSUInteger)itemRowIndex;
|
||||
-(id)initWithItem:(Binary*)binary;
|
||||
|
||||
//'submit' button handler
|
||||
-(IBAction)vtButtonHandler:(id)sender;
|
||||
|
||||
+25
-44
@@ -23,13 +23,13 @@
|
||||
|
||||
@implementation VTInfoWindowController
|
||||
|
||||
@synthesize rowIndex;
|
||||
@synthesize item;
|
||||
@synthesize windowController;
|
||||
|
||||
|
||||
//init method
|
||||
// ->save item and load nib
|
||||
-(id)initWithItem:(File*)selectedItem rowIndex:(NSUInteger)itemRowIndex
|
||||
-(id)initWithItem:(Binary*)binary
|
||||
{
|
||||
self = [super init];
|
||||
if(nil != self)
|
||||
@@ -38,10 +38,10 @@
|
||||
self.windowController = [[VTInfoWindowController alloc] initWithWindowNibName:@"VTInfoWindow"];
|
||||
|
||||
//save item
|
||||
self.windowController.fileObj = selectedItem;
|
||||
self.windowController.item = binary;
|
||||
|
||||
//save row index
|
||||
self.windowController.rowIndex = itemRowIndex;
|
||||
//self.windowController.rowIndex = itemRowIndex;
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -92,7 +92,7 @@
|
||||
NSColor* textColor = nil;
|
||||
|
||||
//get status
|
||||
if(nil != self.fileObj.vtInfo[VT_RESULTS_URL])
|
||||
if(nil != self.item.vtInfo[VT_RESULTS_URL])
|
||||
{
|
||||
//known
|
||||
isKnown = YES;
|
||||
@@ -105,17 +105,17 @@
|
||||
textColor = [NSColor blackColor];
|
||||
|
||||
//set color to red if its flagged
|
||||
if(0 != [self.fileObj.vtInfo[VT_RESULTS_POSITIVES] unsignedIntegerValue])
|
||||
if(0 != [self.item.vtInfo[VT_RESULTS_POSITIVES] unsignedIntegerValue])
|
||||
{
|
||||
//red
|
||||
textColor = [NSColor redColor];
|
||||
}
|
||||
|
||||
//generate detection ratio
|
||||
vtDetectionRatio = [NSString stringWithFormat:@"%lu/%lu", (unsigned long)[self.fileObj.vtInfo[VT_RESULTS_POSITIVES] unsignedIntegerValue], (unsigned long)[self.fileObj.vtInfo[VT_RESULTS_TOTAL] unsignedIntegerValue]];
|
||||
vtDetectionRatio = [NSString stringWithFormat:@"%lu/%lu", (unsigned long)[self.item.vtInfo[VT_RESULTS_POSITIVES] unsignedIntegerValue], (unsigned long)[self.item.vtInfo[VT_RESULTS_TOTAL] unsignedIntegerValue]];
|
||||
|
||||
//set name
|
||||
[self.fileName setStringValue:self.fileObj.name];
|
||||
[self.fileName setStringValue:self.item.name];
|
||||
|
||||
//set color
|
||||
self.fileName.textColor = textColor;
|
||||
@@ -130,7 +130,7 @@
|
||||
[self.analysisURL setStringValue:@"VirusTotal report"];
|
||||
|
||||
//make analyis url a hyperlink
|
||||
makeTextViewHyperlink(self.analysisURL, [NSURL URLWithString:self.fileObj.vtInfo[VT_RESULTS_URL]]);
|
||||
makeTextViewHyperlink(self.analysisURL, [NSURL URLWithString:self.item.vtInfo[VT_RESULTS_URL]]);
|
||||
|
||||
//set 'submit' button text to 'rescan'
|
||||
self.submitButton.title = @"rescan?";
|
||||
@@ -157,7 +157,7 @@
|
||||
self.analysisURL.hidden = YES;
|
||||
|
||||
//set unknown file msg
|
||||
[self.unknownFile setStringValue:[NSString stringWithFormat:@"no results found for '%@'", self.fileObj.name]];
|
||||
[self.unknownFile setStringValue:[NSString stringWithFormat:@"no results found for '%@'", self.item.name]];
|
||||
|
||||
//show 'unknown file' msg
|
||||
self.unknownFile.hidden = NO;
|
||||
@@ -253,7 +253,7 @@
|
||||
if(YES == [((NSButton*)sender).title isEqualToString:@"rescan?"])
|
||||
{
|
||||
//set status msg
|
||||
[self.statusMsg setStringValue:[NSString stringWithFormat:@"submitting re-scan request for %@", self.fileObj.name]];
|
||||
[self.statusMsg setStringValue:[NSString stringWithFormat:@"submitting re-scan request for %@", self.item.name]];
|
||||
|
||||
//show status msg
|
||||
self.statusMsg.hidden = NO;
|
||||
@@ -262,8 +262,8 @@
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
|
||||
//make request to VT
|
||||
//TODO: re-enable
|
||||
//result = [vtObj reScan:self.fileObj];
|
||||
// ->will also update UI to show '...'
|
||||
result = [vtObj reScan:self.item];
|
||||
|
||||
//got result
|
||||
// ->update UI and launch browswer to show report
|
||||
@@ -273,6 +273,9 @@
|
||||
// ->need this for (re)queries
|
||||
scanID = result[VT_RESULTS_SCANID];
|
||||
|
||||
//TODO: do something w/ prev flagged files!?
|
||||
// ...i don't think we'll keep a list~
|
||||
|
||||
/*
|
||||
|
||||
//if file was flagged
|
||||
@@ -290,29 +293,18 @@
|
||||
|
||||
*/
|
||||
|
||||
//remove file's VT info (since it'd now out of date)
|
||||
self.fileObj.vtInfo = nil;
|
||||
|
||||
//with a scan id can re-query VT
|
||||
// ->will update VT button in UI once results are retrieved
|
||||
if(nil != scanID)
|
||||
{
|
||||
////TODO: re-enable
|
||||
|
||||
/*
|
||||
//kick off task to re-query VT
|
||||
// ->wait 60 seconds though to give VT servers some time to process
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 60 * NSEC_PER_SEC), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
[vtObj getInfoForItem:self.fileObj scanID:scanID rowIndex:self.rowIndex];
|
||||
[vtObj getInfoForItem:self.item scanID:scanID];
|
||||
});
|
||||
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
//ask app delegate to update item in table
|
||||
// ->will change the item's VT status to ... (pending)
|
||||
[((AppDelegate*)[[NSApplication sharedApplication] delegate]) itemProcessed:self.fileObj rowIndex:self.rowIndex];
|
||||
|
||||
//nap so user can see msg 'submitting' msg
|
||||
[NSThread sleepForTimeInterval:0.5];
|
||||
|
||||
@@ -340,7 +332,6 @@
|
||||
[self.window close];
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
//error
|
||||
@@ -359,13 +350,13 @@
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
} //rescan file
|
||||
|
||||
//submit file
|
||||
else
|
||||
{
|
||||
//set status msg
|
||||
[self.statusMsg setStringValue:[NSString stringWithFormat:@"submitting %@", self.fileObj.name]];
|
||||
[self.statusMsg setStringValue:[NSString stringWithFormat:@"submitting %@", self.item.name]];
|
||||
|
||||
//show status msg
|
||||
self.statusMsg.hidden = NO;
|
||||
@@ -374,36 +365,26 @@
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
|
||||
//submit file to VT
|
||||
//TODO: re-enable
|
||||
//result = [vtObj submit:self.fileObj];
|
||||
// ->will also update UI to show '...'
|
||||
result = [vtObj submit:self.item];
|
||||
|
||||
// ->need this for (re)queries
|
||||
scanID = result[VT_RESULTS_SCANID];
|
||||
|
||||
//reset file's VT info
|
||||
self.fileObj.vtInfo = nil;
|
||||
|
||||
//with a scan id can query VT
|
||||
// ->will update VT button in UI once results are retrieved
|
||||
if(nil != scanID)
|
||||
{
|
||||
//TODO: re-enable
|
||||
/*
|
||||
//kick off task to re-query VT
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 60 * NSEC_PER_SEC), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
[vtObj getInfoForItem:self.fileObj scanID:scanID rowIndex:self.rowIndex];
|
||||
[vtObj getInfoForItem:self.item scanID:scanID];
|
||||
});
|
||||
*/
|
||||
}
|
||||
|
||||
//got response
|
||||
// ->update UI and launch browswer to show report
|
||||
// ->launch browswer to show report
|
||||
if(nil != result)
|
||||
{
|
||||
//ask app delegate to update item in table
|
||||
// ->will change the item's VT status to ... (pending)
|
||||
[((AppDelegate*)[[NSApplication sharedApplication] delegate]) itemProcessed:self.fileObj rowIndex:self.rowIndex];
|
||||
|
||||
//update status msg
|
||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||
|
||||
@@ -447,7 +428,7 @@
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
} //submit file
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
+8
-4
@@ -34,17 +34,21 @@
|
||||
-(NSDictionary*)postRequest:(NSURL*)url parameters:(id)params;
|
||||
|
||||
//submit a file to VT
|
||||
//-(NSDictionary*)submit:(File*)fileObj;
|
||||
-(NSDictionary*)submit:(Binary*)item;
|
||||
|
||||
//submit a rescan request
|
||||
//-(NSDictionary*)reScan:(File*)fileObj;
|
||||
-(NSDictionary*)reScan:(Binary*)item;
|
||||
|
||||
//process results
|
||||
// ->updates items (found, detection ratio, etc)
|
||||
-(void)processResults:(NSMutableDictionary*)queriedItems results:(NSDictionary*)results;
|
||||
|
||||
//get info for a single item
|
||||
// ->will callback into AppDelegate to reload plugin
|
||||
//-(void)getInfoForItem:(File*)fileObj scanID:(NSString*)scanID rowIndex:(NSUInteger)rowIndex;
|
||||
// ->will callback into AppDelegate to reload item
|
||||
-(void)getInfoForItem:(Binary*)item scanID:(NSString*)scanID;
|
||||
|
||||
//call back up to update item in UI
|
||||
// ->will either reload task table (top), or just row in item (bottom) table
|
||||
-(void)updateUI:(Binary*)item;
|
||||
|
||||
@end
|
||||
|
||||
+93
-40
@@ -30,6 +30,7 @@
|
||||
return self;
|
||||
}
|
||||
|
||||
//TODO: move this in Queue?
|
||||
//add item
|
||||
// ->will query VT when 25 items are hit
|
||||
-(void)addItem:(Binary*)binary
|
||||
@@ -42,22 +43,26 @@
|
||||
}
|
||||
|
||||
//query VT once 25 items have been gathered
|
||||
if(VT_MAX_QUERY_COUNT == self.items.count)
|
||||
// ->or this is a 'last' item
|
||||
if( (VT_MAX_QUERY_COUNT == self.items.count) ||
|
||||
(YES == binary.lastItem) )
|
||||
{
|
||||
//process
|
||||
[self queryVT];
|
||||
//kick of thread to make a query to VT
|
||||
[NSThread detachNewThreadSelector:@selector(queryVT) toTarget:self withObject:nil];
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//make query to VT
|
||||
-(void)queryVT
|
||||
{
|
||||
//VT query URL
|
||||
NSURL* queryURL = nil;
|
||||
|
||||
//item data
|
||||
NSMutableDictionary* itemData = nil;
|
||||
|
||||
//VT query URL
|
||||
NSURL* queryURL = nil;
|
||||
|
||||
//array of queried items
|
||||
// ->needed so can save VT results back into binaries
|
||||
NSMutableDictionary* queriedItems = nil;
|
||||
@@ -67,9 +72,6 @@
|
||||
|
||||
//results
|
||||
NSDictionary* results = nil;
|
||||
|
||||
//init query URL
|
||||
queryURL = [NSURL URLWithString:[NSString stringWithFormat:@"%@%@", VT_QUERY_URL, VT_API_KEY]];
|
||||
|
||||
//alloc list for items
|
||||
parameters = [NSMutableArray array];
|
||||
@@ -77,6 +79,9 @@
|
||||
//alloc dictionary for queried items
|
||||
queriedItems = [NSMutableDictionary dictionary];
|
||||
|
||||
//init query URL
|
||||
queryURL = [NSURL URLWithString:[NSString stringWithFormat:@"%@%@", VT_QUERY_URL, VT_API_KEY]];
|
||||
|
||||
//sync
|
||||
@synchronized(self.items)
|
||||
{
|
||||
@@ -84,6 +89,14 @@
|
||||
//add all binaries to VT query
|
||||
for(Binary* item in self.items)
|
||||
{
|
||||
//skip items with blank hashes
|
||||
// ->TODO not sure why this would happen
|
||||
if(nil == item.hashes[KEY_HASH_SHA1])
|
||||
{
|
||||
//skip
|
||||
continue;
|
||||
}
|
||||
|
||||
//alloc item data
|
||||
itemData = [NSMutableDictionary dictionary];
|
||||
|
||||
@@ -115,6 +128,7 @@
|
||||
|
||||
}//sync
|
||||
|
||||
|
||||
//make query to VT
|
||||
results = [self postRequest:queryURL parameters:parameters];
|
||||
if(nil != results)
|
||||
@@ -122,6 +136,7 @@
|
||||
//process results
|
||||
[self processResults:queriedItems results:results];
|
||||
}
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -272,9 +287,10 @@
|
||||
return;
|
||||
}
|
||||
*/
|
||||
|
||||
//get VT info for a single item
|
||||
// ->will then callback into AppDelegate to reload item in UI
|
||||
-(void)getInfoForItem:(Binary*)fileObj scanID:(NSString*)scanID rowIndex:(NSUInteger)rowIndex
|
||||
-(void)getInfoForItem:(Binary*)item scanID:(NSString*)scanID
|
||||
{
|
||||
//VT query URL
|
||||
NSURL* queryURL = nil;
|
||||
@@ -296,8 +312,9 @@
|
||||
(1 == [results[VT_RESULTS_RESPONSE] integerValue]) )
|
||||
{
|
||||
//save result
|
||||
fileObj.vtInfo = results;
|
||||
item.vtInfo = results;
|
||||
|
||||
//TODO: do something if it's flagged!
|
||||
//if its flagged save in File's plugin
|
||||
if(0 != [results[VT_RESULTS_POSITIVES] unsignedIntegerValue])
|
||||
{
|
||||
@@ -310,10 +327,12 @@
|
||||
[fileObj.plugin.flaggedItems addObject:fileObj];
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
//callback up into UI to reload item
|
||||
[((AppDelegate*)[[NSApplication sharedApplication] delegate]) itemProcessed:fileObj rowIndex:rowIndex];
|
||||
//update UI
|
||||
// ->will make item in task or dylib table have updated VT results
|
||||
[self updateUI:item];
|
||||
|
||||
//exit loop
|
||||
break;
|
||||
@@ -326,6 +345,7 @@
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//make the (POST)query to VT
|
||||
-(NSDictionary*)postRequest:(NSURL*)url parameters:(id)params
|
||||
{
|
||||
@@ -347,7 +367,7 @@
|
||||
|
||||
//response (HTTP) from VT
|
||||
NSURLResponse* httpResponse = nil;
|
||||
|
||||
|
||||
//alloc/init request
|
||||
request = [[NSMutableURLRequest alloc] initWithURL:url];
|
||||
|
||||
@@ -399,8 +419,8 @@
|
||||
|
||||
//sanity check(s)
|
||||
if( (nil == vtData) ||
|
||||
(nil != error) ||
|
||||
(200 != (long)[(NSHTTPURLResponse *)httpResponse statusCode]) )
|
||||
(nil != error) ||
|
||||
(200 != (long)[(NSHTTPURLResponse *)httpResponse statusCode]) )
|
||||
{
|
||||
//err msg
|
||||
NSLog(@"OBJECTIVE-SEE ERROR: failed to query VirusTotal (%@, %@)", error, httpResponse);
|
||||
@@ -443,7 +463,7 @@ bail:
|
||||
}
|
||||
|
||||
//submit a file to VT
|
||||
-(NSDictionary*)submit:(File*)fileObj
|
||||
-(NSDictionary*)submit:(Binary*)item
|
||||
{
|
||||
//results
|
||||
NSDictionary* results = nil;
|
||||
@@ -468,15 +488,23 @@ bail:
|
||||
|
||||
//response (HTTP) from VT
|
||||
NSURLResponse* httpResponse = nil;
|
||||
|
||||
//remove item's vt info
|
||||
// ->as its about to be outdates
|
||||
item.vtInfo = nil;
|
||||
|
||||
//reload UI
|
||||
// ->will change item's VT button back to ...
|
||||
[self updateUI:item];
|
||||
|
||||
//init submit URL
|
||||
submitURL = [NSURL URLWithString:[NSString stringWithFormat:@"%@?apikey=%@&resource=%@", VT_SUBMIT_URL, VT_API_KEY, fileObj.hashes[KEY_HASH_MD5]]];
|
||||
submitURL = [NSURL URLWithString:[NSString stringWithFormat:@"%@?apikey=%@&resource=%@", VT_SUBMIT_URL, VT_API_KEY, item.hashes[KEY_HASH_MD5]]];
|
||||
|
||||
//init request
|
||||
request = [[NSMutableURLRequest alloc] initWithURL:submitURL];
|
||||
|
||||
//set boundary string
|
||||
NSString *boundary = @"qqqq___knockknock___qqqq";
|
||||
NSString *boundary = @"qqqq___taskexplorer___qqqq";
|
||||
|
||||
//set HTTP method (POST)
|
||||
[request setHTTPMethod:@"POST"];
|
||||
@@ -491,13 +519,13 @@ bail:
|
||||
body = [NSMutableData data];
|
||||
|
||||
//load file into memory
|
||||
fileContents = [NSData dataWithContentsOfFile:fileObj.pathForFinder];
|
||||
fileContents = [NSData dataWithContentsOfFile:item.pathForFinder];
|
||||
|
||||
//sanity check
|
||||
if(nil == fileContents)
|
||||
{
|
||||
//err msg
|
||||
NSLog(@"OBJECTIVE-SEE ERROR: failed to load %@ into memory for submission", fileObj.path);
|
||||
NSLog(@"OBJECTIVE-SEE ERROR: failed to load %@ into memory for submission", item.path);
|
||||
|
||||
//bail
|
||||
goto bail;
|
||||
@@ -507,7 +535,7 @@ bail:
|
||||
[body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
|
||||
|
||||
//append 'Content-Disposition' file name, etc
|
||||
[body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"file\"; filename=\"%@\"\r\n", fileObj.name] dataUsingEncoding:NSUTF8StringEncoding]];
|
||||
[body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"file\"; filename=\"%@\"\r\n", item.name] dataUsingEncoding:NSUTF8StringEncoding]];
|
||||
|
||||
//append 'Content-Type'
|
||||
[body appendData:[@"Content-Type: application/octet-stream\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
|
||||
@@ -576,8 +604,9 @@ bail:
|
||||
return results;
|
||||
}
|
||||
|
||||
|
||||
//submit a rescan request
|
||||
-(NSDictionary*)reScan:(File*)fileObj
|
||||
-(NSDictionary*)reScan:(Binary*)item
|
||||
{
|
||||
//result data
|
||||
NSDictionary* result = nil;
|
||||
@@ -585,19 +614,28 @@ bail:
|
||||
//scan url
|
||||
NSURL* reScanURL = nil;
|
||||
|
||||
//remove item's vt info
|
||||
// ->as its about to be outdates
|
||||
item.vtInfo = nil;
|
||||
|
||||
//reload UI
|
||||
// ->will change item's VT button back to ...
|
||||
[self updateUI:item];
|
||||
|
||||
//init scan url
|
||||
reScanURL = [NSURL URLWithString:[NSString stringWithFormat:@"%@?apikey=%@&resource=%@", VT_RESCAN_URL, VT_API_KEY, fileObj.hashes[KEY_HASH_MD5]]];
|
||||
reScanURL = [NSURL URLWithString:[NSString stringWithFormat:@"%@?apikey=%@&resource=%@", VT_RESCAN_URL, VT_API_KEY, item.hashes[KEY_HASH_MD5]]];
|
||||
|
||||
//make request to VT
|
||||
result = [self postRequest:reScanURL parameters:nil];
|
||||
if(nil == result)
|
||||
{
|
||||
//err msg
|
||||
NSLog(@"OBJECTIVE-SEE ERROR: failed to re-scan %@", fileObj.name);
|
||||
NSLog(@"OBJECTIVE-SEE ERROR: failed to re-scan %@", item.name);
|
||||
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
|
||||
|
||||
//bail
|
||||
bail:
|
||||
@@ -606,7 +644,7 @@ bail:
|
||||
}
|
||||
|
||||
//process results
|
||||
// ->save VT info into
|
||||
// ->save VT info into Binary object & reload relevant pane
|
||||
-(void)processResults:(NSMutableDictionary*)queriedItems results:(NSDictionary*)results
|
||||
{
|
||||
//queried binary obj
|
||||
@@ -616,10 +654,6 @@ bail:
|
||||
// ->will be set if any of the queried binaries are a task executable
|
||||
BOOL reloadTopPane = NO;
|
||||
|
||||
//flag for bottom pane reload
|
||||
// ->will be set if any of the queried binaries are a dylib
|
||||
BOOL reloadBottomPane = NO;
|
||||
|
||||
//process all results
|
||||
// ->save VT result dictionary into File obj
|
||||
for(NSDictionary* result in results[VT_RESULTS])
|
||||
@@ -646,10 +680,11 @@ bail:
|
||||
reloadTopPane = YES;
|
||||
}
|
||||
//for dylibs
|
||||
// ->set flag to reload bottom
|
||||
// ->no dups, update each via row reload
|
||||
else
|
||||
{
|
||||
reloadBottomPane = YES;
|
||||
//update
|
||||
[self updateUI:queriedItem];
|
||||
}
|
||||
|
||||
//TODO: do something with detections!?
|
||||
@@ -657,20 +692,38 @@ bail:
|
||||
}
|
||||
|
||||
//reload top pane
|
||||
// ->do full since there might be dups (e.g. Chrome Helper)
|
||||
if(YES == reloadTopPane)
|
||||
{
|
||||
//reload
|
||||
[((AppDelegate*)[[NSApplication sharedApplication] delegate]) reloadTaskTable];
|
||||
}
|
||||
|
||||
//reload bottom pane
|
||||
if(YES == reloadBottomPane)
|
||||
{
|
||||
//reload
|
||||
[((AppDelegate*)[[NSApplication sharedApplication] delegate]) reloadBottomPane:nil itemView:DYLIBS_VIEW];
|
||||
[self updateUI:nil];
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//call back up to update item in UI
|
||||
// ->will either reload task table (top), or just row in item (bottom) table
|
||||
-(void)updateUI:(Binary*)item
|
||||
{
|
||||
//handle case where item is a task (top)
|
||||
// ->fully reload task table (since there can be dups)
|
||||
if( (nil == item) ||
|
||||
(YES == item.isTaskBinary) )
|
||||
{
|
||||
//reload
|
||||
[((AppDelegate*)[[NSApplication sharedApplication] delegate]) reloadTaskTable];
|
||||
}
|
||||
//handle case where item is a dylib (bottom)
|
||||
// ->just reload row
|
||||
else
|
||||
{
|
||||
//reload row
|
||||
[((AppDelegate*)[[NSApplication sharedApplication] delegate]) reloadRow:nil item:item pane:PANE_BOTTOM];
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="7706" systemVersion="14D136" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
|
||||
<dependencies>
|
||||
<deployment identifier="macosx"/>
|
||||
<development version="5000" identifier="xcode"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="7706"/>
|
||||
</dependencies>
|
||||
@@ -99,6 +98,9 @@
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</searchFieldCell>
|
||||
<connections>
|
||||
<outlet property="delegate" destination="494" id="4ig-0K-Oup"/>
|
||||
</connections>
|
||||
</searchField>
|
||||
<button fixedFrame="YES" tag="1001" translatesAutoresizingMaskIntoConstraints="NO" id="gSG-Nq-plb">
|
||||
<rect key="frame" x="9" y="4" width="35" height="32"/>
|
||||
@@ -180,6 +182,9 @@
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</searchFieldCell>
|
||||
<connections>
|
||||
<outlet property="delegate" destination="494" id="B1g-Qz-f4r"/>
|
||||
</connections>
|
||||
</searchField>
|
||||
</toolbarItem>
|
||||
<toolbarItem implicitItemIdentifier="A5784C30-D7FC-4958-875B-487768A4E610" label="" paletteLabel="" id="O1y-1z-g0u">
|
||||
@@ -223,6 +228,8 @@
|
||||
<outlet property="bottomPane" destination="E4M-PF-VD0" id="Au5-EH-OKZ"/>
|
||||
<outlet property="bottomPaneBtn" destination="gtq-gn-VPL" id="Uxg-Ab-QzA"/>
|
||||
<outlet property="bottomPaneSpinner" destination="LMT-Bu-FAk" id="a1H-Ag-GT8"/>
|
||||
<outlet property="filterItemsBox" destination="bNA-gy-9Ta" id="hAw-Ja-am4"/>
|
||||
<outlet property="filterTasksBox" destination="4Kr-b9-X6j" id="CB1-Rb-dew"/>
|
||||
<outlet property="logoButton" destination="HoI-FQ-vTI" id="bzc-wu-4Hv"/>
|
||||
<outlet property="noItemsLabel" destination="kIC-ZZ-ldy" id="nOm-8E-tZA"/>
|
||||
<outlet property="progressIndicator" destination="839" id="870"/>
|
||||
|
||||
@@ -282,6 +282,10 @@ bail:
|
||||
mach_vm_deallocate(mach_task_self(), (vm_offset_t)allImageInfo, aifBytesRead);
|
||||
}
|
||||
|
||||
//remove dups
|
||||
//TODO: this isn't mutable - which is ok, but maybe change reply method def?
|
||||
[dylibPaths setArray:[[NSSet setWithArray:dylibPaths] allObjects]];
|
||||
|
||||
//invoke reply block
|
||||
reply(dylibPaths);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user