mirror of
https://github.com/objective-see/KnockKnock.git
synced 2026-03-22 06:52:25 +00:00
improvements to commandline scan, VT integration, and welcome window(s)
This commit is contained in:
+1
-4
@@ -102,12 +102,9 @@ extern Filter* itemFilter;
|
||||
//non-UI thread that performs actual scan
|
||||
@property(nonatomic, strong)NSThread *scannerThread;
|
||||
|
||||
//virus total object
|
||||
//VT object
|
||||
@property(nonatomic, retain)VirusTotal* virusTotalObj;
|
||||
|
||||
//array for all virus total threads
|
||||
@property(nonatomic, retain)NSMutableArray* vtThreads;
|
||||
|
||||
//differences window controller
|
||||
@property (strong) DiffWindowController* diffWindowController;
|
||||
|
||||
|
||||
+36
-106
@@ -17,7 +17,6 @@
|
||||
|
||||
@synthesize friends;
|
||||
@synthesize plugins;
|
||||
@synthesize vtThreads;
|
||||
@synthesize scanButton;
|
||||
@synthesize isConnected;
|
||||
@synthesize scannerThread;
|
||||
@@ -123,9 +122,6 @@ void uncaughtExceptionHandler(NSException* exception) {
|
||||
//init virus total object
|
||||
virusTotalObj = [[VirusTotal alloc] init];
|
||||
|
||||
//init array for virus total threads
|
||||
vtThreads = [NSMutableArray array];
|
||||
|
||||
//alloc shared item enumerator
|
||||
sharedItemEnumerator = [[ItemEnumerator alloc] init];
|
||||
|
||||
@@ -449,12 +445,22 @@ void uncaughtExceptionHandler(NSException* exception) {
|
||||
// ->runs in the background to execute each plugin
|
||||
-(void)scan
|
||||
{
|
||||
//flag indicating an active VT thread
|
||||
BOOL activeThread = NO;
|
||||
//query VT?
|
||||
BOOL queryVT = NO;
|
||||
|
||||
//set scan flag
|
||||
self.isConnected = isNetworkConnected();
|
||||
|
||||
//load VT API key
|
||||
NSString* vtAPIKey = loadAPIKeyFromKeychain();
|
||||
|
||||
//skip VT scanning if
|
||||
// not connected, user disabled queries, or no API key
|
||||
queryVT = (vtAPIKey.length) && self.isConnected && (!self.prefsWindowController.disableVTQueries);
|
||||
|
||||
//create dispatch group for VT queries
|
||||
dispatch_group_t vtGroup = dispatch_group_create();
|
||||
|
||||
//iterate over all plugins
|
||||
// ->invoke's each scan message
|
||||
for(PluginBase* plugin in self.plugins)
|
||||
@@ -490,26 +496,32 @@ void uncaughtExceptionHandler(NSException* exception) {
|
||||
//scan
|
||||
// will invoke callback as items are found
|
||||
[plugin scan];
|
||||
|
||||
//when 'disable VT' prefs not selected and network is reachable
|
||||
// ->kick of thread to perform VT query in background
|
||||
if( (YES != self.prefsWindowController.disableVTQueries) &&
|
||||
(YES == self.isConnected) )
|
||||
{
|
||||
//do query
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
[self->virusTotalObj checkFiles:plugin];
|
||||
});
|
||||
|
||||
//should query VT?
|
||||
// if so, do it in background
|
||||
if(queryVT)
|
||||
{
|
||||
//enter group
|
||||
dispatch_group_enter(vtGroup);
|
||||
|
||||
//VT query in BG
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
|
||||
//check all plugin's files
|
||||
[self->virusTotalObj checkFiles:plugin apiKey:vtAPIKey uiMode:YES completion:^{
|
||||
//done
|
||||
dispatch_group_leave(vtGroup);
|
||||
}];
|
||||
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
}//pool
|
||||
}
|
||||
|
||||
//if VT querying is enabled (default) and network is available
|
||||
// ->wait till all VT threads are done
|
||||
if( (YES != self.prefsWindowController.disableVTQueries) &&
|
||||
(YES == self.isConnected) )
|
||||
//wait till all VT threads are done
|
||||
if(queryVT)
|
||||
{
|
||||
//update scanner msg
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
@@ -521,53 +533,10 @@ void uncaughtExceptionHandler(NSException* exception) {
|
||||
|
||||
//nap
|
||||
// ->VT threads take some time to spawn/process
|
||||
[NSThread sleepForTimeInterval:3.0f];
|
||||
[NSThread sleepForTimeInterval:1.0f];
|
||||
|
||||
//wait for all VT threads to exit
|
||||
while(YES)
|
||||
{
|
||||
//reset flag
|
||||
activeThread = NO;
|
||||
|
||||
//sync
|
||||
@synchronized(self.vtThreads)
|
||||
{
|
||||
//check all threads
|
||||
for(NSThread* vtThread in self.vtThreads)
|
||||
{
|
||||
//check if still running
|
||||
// ->set flag & break out of loop
|
||||
if(YES == [vtThread isExecuting])
|
||||
{
|
||||
//set flag
|
||||
activeThread = YES;
|
||||
|
||||
//bail
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}//sync
|
||||
|
||||
//check flag
|
||||
if(YES != activeThread)
|
||||
{
|
||||
//finally no active threads
|
||||
// ->bail
|
||||
break;
|
||||
}
|
||||
|
||||
//exit if scanner (self) thread was cancelled
|
||||
if(YES == [[NSThread currentThread] isCancelled])
|
||||
{
|
||||
//exit
|
||||
[NSThread exit];
|
||||
}
|
||||
|
||||
//nap
|
||||
[NSThread sleepForTimeInterval:0.5];
|
||||
|
||||
}//active thread
|
||||
//wait for all VT queries to complete
|
||||
dispatch_group_wait(vtGroup, DISPATCH_TIME_FOREVER);
|
||||
|
||||
}//VT scanning enabled
|
||||
|
||||
@@ -588,7 +557,7 @@ void uncaughtExceptionHandler(NSException* exception) {
|
||||
|
||||
});
|
||||
|
||||
}//scan not stopped by user
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -751,7 +720,6 @@ void uncaughtExceptionHandler(NSException* exception) {
|
||||
}
|
||||
|
||||
//callback when user has updated prefs
|
||||
// ->reload table, etc
|
||||
-(void)applyPreferences
|
||||
{
|
||||
//currently selected category
|
||||
@@ -770,26 +738,6 @@ void uncaughtExceptionHandler(NSException* exception) {
|
||||
//reload item table
|
||||
[self.itemTableController.itemTableView reloadData];
|
||||
|
||||
//(re)check network connectivity
|
||||
// ->set iVar
|
||||
self.isConnected = isNetworkConnected();
|
||||
|
||||
//if VT query was never done (e.g. scan was started w/ pref disabled) and network is available
|
||||
// ->kick off VT queries now
|
||||
if( (0 == self.vtThreads.count) &&
|
||||
(YES != self.prefsWindowController.disableVTQueries) &&
|
||||
(YES == self.isConnected) )
|
||||
{
|
||||
//iterate over all plugins
|
||||
// ->do VT query for each
|
||||
for(PluginBase* plugin in self.plugins)
|
||||
{
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
[self->virusTotalObj checkFiles:plugin];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -863,24 +811,6 @@ void uncaughtExceptionHandler(NSException* exception) {
|
||||
[sharedItemEnumerator.enumeratorThread cancel];
|
||||
}
|
||||
|
||||
//sync to cancel all VT threads
|
||||
@synchronized(self.vtThreads)
|
||||
{
|
||||
//tell all VT threads to bail
|
||||
for(NSThread* vtThread in self.vtThreads)
|
||||
{
|
||||
//cancel running threads
|
||||
if(YES == [vtThread isExecuting])
|
||||
{
|
||||
//cancel
|
||||
[vtThread cancel];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//remove all VT threads
|
||||
[self.vtThreads removeAllObjects];
|
||||
|
||||
//when invoked from the UI (e.g. 'Stop Scan' was clicked)
|
||||
// ->cancel scanner thread
|
||||
if([NSThread currentThread] != self.scannerThread)
|
||||
|
||||
+150
-138
@@ -28,23 +28,23 @@
|
||||
</customObject>
|
||||
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
|
||||
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
|
||||
<window title="KnockKnock" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" id="F0z-JX-Cv5">
|
||||
<window title="Welcome to KnockKnock" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" restorable="NO" releasedWhenClosed="NO" frameAutosaveName="" animationBehavior="default" id="F0z-JX-Cv5">
|
||||
<windowStyleMask key="styleMask" titled="YES"/>
|
||||
<rect key="contentRect" x="196" y="240" width="700" height="350"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="1280" height="769"/>
|
||||
<value key="minSize" type="size" width="700" height="350"/>
|
||||
<value key="maxSize" type="size" width="700" height="350"/>
|
||||
<rect key="contentRect" x="196" y="240" width="700" height="400"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="3440" height="1409"/>
|
||||
<value key="minSize" type="size" width="700" height="400"/>
|
||||
<value key="maxSize" type="size" width="700" height="400"/>
|
||||
<view key="contentView" wantsLayer="YES" id="se5-gp-TjO">
|
||||
<rect key="frame" x="0.0" y="0.0" width="700" height="350"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="700" height="400"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</view>
|
||||
<connections>
|
||||
<outlet property="delegate" destination="-2" id="0bl-1N-AYu"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="-39" y="-409"/>
|
||||
<point key="canvasLocation" x="-42" y="-508"/>
|
||||
</window>
|
||||
<customView id="97j-sp-rBE" userLabel="Welcome">
|
||||
<rect key="frame" x="0.0" y="0.0" width="700" height="350"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="700" height="400"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<subviews>
|
||||
<box fixedFrame="YES" boxType="custom" borderType="none" titlePosition="noTitle" translatesAutoresizingMaskIntoConstraints="NO" id="JYh-c0-q0Z">
|
||||
@@ -57,7 +57,7 @@
|
||||
<color key="fillColor" red="0.57793885469999995" green="0.75859862570000003" blue="0.2368842065" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</box>
|
||||
<textField focusRingType="none" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" preferredMaxLayoutWidth="660" translatesAutoresizingMaskIntoConstraints="NO" id="NEo-Sr-1a0">
|
||||
<rect key="frame" x="149" y="290" width="338" height="54"/>
|
||||
<rect key="frame" x="149" y="340" width="338" height="54"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="left" title="Welcome to" id="Qyh-uK-Afv">
|
||||
<font key="font" size="41" name="AvenirNextCondensed-Regular"/>
|
||||
@@ -77,17 +77,17 @@
|
||||
</connections>
|
||||
</button>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="rNc-Xa-Jqh">
|
||||
<rect key="frame" x="151" y="196" width="371" height="101"/>
|
||||
<rect key="frame" x="151" y="246" width="371" height="101"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyUpOrDown" image="kkText" id="zfH-MI-2vJ"/>
|
||||
</imageView>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="14w-0v-UJ5">
|
||||
<rect key="frame" x="15" y="217" width="128" height="128"/>
|
||||
<rect key="frame" x="15" y="267" width="128" height="128"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="kkIcon" id="vEL-Yw-xip"/>
|
||||
</imageView>
|
||||
<textField focusRingType="none" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" preferredMaxLayoutWidth="660" translatesAutoresizingMaskIntoConstraints="NO" id="cpq-67-lQt">
|
||||
<rect key="frame" x="18" y="86" width="664" height="87"/>
|
||||
<rect key="frame" x="18" y="171" width="664" height="52"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="center" id="eic-lg-Ln7">
|
||||
<font key="font" size="19" name="AvenirNextCondensed-Regular"/>
|
||||
@@ -97,15 +97,24 @@ KnockKnock checks “who’s there” by scanning all persistent software to rev
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField focusRingType="none" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" preferredMaxLayoutWidth="660" translatesAutoresizingMaskIntoConstraints="NO" id="LWe-j3-zJp">
|
||||
<rect key="frame" x="18" y="90" width="664" height="31"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="center" title="Now let’s set up how you want KnockKnock to run. " id="JKZ-vA-I78">
|
||||
<font key="font" size="19" name="AvenirNextCondensed-Regular"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
</subviews>
|
||||
<point key="canvasLocation" x="-296" y="504"/>
|
||||
</customView>
|
||||
<customView id="R7i-MV-IAu" userLabel="Disk Access">
|
||||
<rect key="frame" x="0.0" y="0.0" width="966" height="403"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="966" height="400"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<button tag="1" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Rrc-n2-rAG">
|
||||
<rect key="frame" x="80" y="272" width="197" height="32"/>
|
||||
<rect key="frame" x="80" y="273" width="197" height="32"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="push" title="Open 'System Settings'" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="aCh-Th-bAz">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
@@ -128,7 +137,7 @@ KnockKnock checks “who’s there” by scanning all persistent software to rev
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="OQh-jg-YAn">
|
||||
<rect key="frame" x="78" y="255" width="330" height="14"/>
|
||||
<rect key="frame" x="78" y="254" width="330" height="14"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" title="This is where you manage privacy permissions." id="y5g-ZT-ugG">
|
||||
<font key="font" size="12" name="Menlo-Regular"/>
|
||||
@@ -137,7 +146,7 @@ KnockKnock checks “who’s there” by scanning all persistent software to rev
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="VM6-h0-eYz">
|
||||
<rect key="frame" x="78" y="196" width="179" height="21"/>
|
||||
<rect key="frame" x="78" y="195" width="179" height="21"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<textFieldCell key="cell" alignment="left" title="Turn on KnockKnock
" id="zaJ-jI-pg9">
|
||||
<font key="font" size="15" name="Menlo-Regular"/>
|
||||
@@ -164,7 +173,7 @@ KnockKnock checks “who’s there” by scanning all persistent software to rev
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField focusRingType="none" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" preferredMaxLayoutWidth="660" translatesAutoresizingMaskIntoConstraints="NO" id="mRa-dq-CpM">
|
||||
<rect key="frame" x="38" y="345" width="664" height="54"/>
|
||||
<rect key="frame" x="38" y="361" width="664" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="left" title="Grant KnockKnock Full Disk Access" id="np6-Pk-2uu">
|
||||
<font key="font" size="32" name="AvenirNextCondensed-Medium"/>
|
||||
@@ -173,7 +182,7 @@ KnockKnock checks “who’s there” by scanning all persistent software to rev
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField focusRingType="none" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" preferredMaxLayoutWidth="445" translatesAutoresizingMaskIntoConstraints="NO" id="5bH-jb-blZ">
|
||||
<rect key="frame" x="41" y="343" width="739" height="14"/>
|
||||
<rect key="frame" x="41" y="334" width="739" height="28"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" sendsActionOnEndEditing="YES" title="Full Disk Access lets KnockKnock scan your entire system for potential threats." id="tSA-vA-bDC">
|
||||
<font key="font" size="12" name="Menlo-Regular"/>
|
||||
@@ -182,7 +191,7 @@ KnockKnock checks “who’s there” by scanning all persistent software to rev
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<box fixedFrame="YES" boxType="custom" borderType="none" titlePosition="noTitle" translatesAutoresizingMaskIntoConstraints="NO" id="yDJ-oc-cE9">
|
||||
<rect key="frame" x="0.0" y="0.0" width="966" height="48"/>
|
||||
<rect key="frame" x="0.0" y="-3" width="966" height="48"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<view key="contentView" id="SJT-x5-8f3">
|
||||
<rect key="frame" x="0.0" y="0.0" width="966" height="48"/>
|
||||
@@ -217,7 +226,7 @@ KnockKnock checks “who’s there” by scanning all persistent software to rev
|
||||
<color key="fillColor" red="0.57793885469999995" green="0.75859862570000003" blue="0.2368842065" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</box>
|
||||
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="jZB-fa-4Xa">
|
||||
<rect key="frame" x="78" y="161" width="330" height="34"/>
|
||||
<rect key="frame" x="78" y="159" width="330" height="34"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" title="Allow KnockKnock to access all files." id="gDa-9D-yHk">
|
||||
<font key="font" size="12" name="Menlo-Regular"/>
|
||||
@@ -226,7 +235,7 @@ KnockKnock checks “who’s there” by scanning all persistent software to rev
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="QYO-Jw-YPQ">
|
||||
<rect key="frame" x="440" y="90" width="494" height="216"/>
|
||||
<rect key="frame" x="440" y="87" width="494" height="216"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" animates="YES" imageScaling="proportionallyDown" imageFrameStyle="grayBezel" image="SystemPrefs" id="Bef-Qy-itv"/>
|
||||
</imageView>
|
||||
@@ -234,18 +243,18 @@ KnockKnock checks “who’s there” by scanning all persistent software to rev
|
||||
<point key="canvasLocation" x="143" y="-15"/>
|
||||
</customView>
|
||||
<customView id="kOW-Us-kgD" userLabel="Configure">
|
||||
<rect key="frame" x="0.0" y="0.0" width="637" height="302"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="700" height="400"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<subviews>
|
||||
<box fixedFrame="YES" boxType="custom" borderType="none" titlePosition="noTitle" translatesAutoresizingMaskIntoConstraints="NO" id="f2W-Nn-YWU">
|
||||
<rect key="frame" x="0.0" y="0.0" width="637" height="48"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="700" height="48"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<view key="contentView" id="jcK-yh-GlV">
|
||||
<rect key="frame" x="0.0" y="0.0" width="637" height="48"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="700" height="48"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<button tag="3" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Syw-cO-leg">
|
||||
<rect key="frame" x="536" y="8" width="81" height="32"/>
|
||||
<rect key="frame" x="599" y="8" width="81" height="32"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="push" title="Next" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="xbU-XH-hYT">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
@@ -260,7 +269,7 @@ KnockKnock checks “who’s there” by scanning all persistent software to rev
|
||||
<color key="fillColor" red="0.57793885469999995" green="0.75859862570000003" blue="0.2368842065" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</box>
|
||||
<textField focusRingType="none" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" preferredMaxLayoutWidth="660" translatesAutoresizingMaskIntoConstraints="NO" id="ikd-wz-01Q">
|
||||
<rect key="frame" x="30" y="263" width="664" height="44"/>
|
||||
<rect key="frame" x="38" y="361" width="664" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="left" title="Configure KnockKnock:" id="XHD-XH-wR0">
|
||||
<font key="font" size="32" name="AvenirNextCondensed-Medium"/>
|
||||
@@ -269,7 +278,7 @@ KnockKnock checks “who’s there” by scanning all persistent software to rev
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField focusRingType="none" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" preferredMaxLayoutWidth="445" translatesAutoresizingMaskIntoConstraints="NO" id="qME-7o-m8l">
|
||||
<rect key="frame" x="31" y="247" width="433" height="18"/>
|
||||
<rect key="frame" x="38" y="334" width="433" height="28"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" sendsActionOnEndEditing="YES" title="Note: These can later be changed via KnockKnock's Settings" id="E65-cF-gfk">
|
||||
<font key="font" size="12" name="Menlo-Regular"/>
|
||||
@@ -278,41 +287,24 @@ KnockKnock checks “who’s there” by scanning all persistent software to rev
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="b0q-yl-6sv">
|
||||
<rect key="frame" x="32" y="182" width="22" height="44"/>
|
||||
<rect key="frame" x="40" y="275" width="22" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="check" bezelStyle="regularSquare" imagePosition="left" inset="2" id="6UN-fn-MkZ">
|
||||
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||
<font key="font" size="18" name="Menlo-Bold"/>
|
||||
</buttonCell>
|
||||
</button>
|
||||
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="LHE-lc-cEL">
|
||||
<rect key="frame" x="32" y="114" width="22" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="check" bezelStyle="regularSquare" imagePosition="left" inset="2" id="aZp-4P-816">
|
||||
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||
<font key="font" metaFont="system" size="20"/>
|
||||
</buttonCell>
|
||||
</button>
|
||||
<textField focusRingType="none" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" preferredMaxLayoutWidth="445" translatesAutoresizingMaskIntoConstraints="NO" id="AhJ-ov-jbx">
|
||||
<rect key="frame" x="57" y="176" width="459" height="15"/>
|
||||
<rect key="frame" x="63" y="255" width="602" height="28"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" sendsActionOnEndEditing="YES" title="Shows persistent macOS and Apple-installed components." id="r1b-Nl-Ii7">
|
||||
<font key="font" size="12" name="Menlo-Regular"/>
|
||||
<color key="textColor" name="secondaryLabelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField focusRingType="none" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" preferredMaxLayoutWidth="445" translatesAutoresizingMaskIntoConstraints="NO" id="KHZ-VJ-JkQ">
|
||||
<rect key="frame" x="55" y="98" width="482" height="21"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" sendsActionOnEndEditing="YES" title="Prevents the app from checking for updates automatically." id="3aO-AI-YtY">
|
||||
<textFieldCell key="cell" sendsActionOnEndEditing="YES" title="Enable this otion to show persistent macOS and Apple-installed components." id="r1b-Nl-Ii7">
|
||||
<font key="font" size="12" name="Menlo-Regular"/>
|
||||
<color key="textColor" name="secondaryLabelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Udh-qU-3t3">
|
||||
<rect key="frame" x="55" y="187" width="310" height="28"/>
|
||||
<rect key="frame" x="63" y="279" width="310" height="28"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Include macOS components" id="zo1-a0-tPg">
|
||||
<font key="font" size="17" name="Menlo-Bold"/>
|
||||
@@ -320,8 +312,25 @@ KnockKnock checks “who’s there” by scanning all persistent software to rev
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="LHE-lc-cEL">
|
||||
<rect key="frame" x="40" y="192" width="22" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="check" bezelStyle="regularSquare" imagePosition="left" inset="2" id="aZp-4P-816">
|
||||
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||
<font key="font" metaFont="system" size="20"/>
|
||||
</buttonCell>
|
||||
</button>
|
||||
<textField focusRingType="none" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" preferredMaxLayoutWidth="445" translatesAutoresizingMaskIntoConstraints="NO" id="KHZ-VJ-JkQ">
|
||||
<rect key="frame" x="63" y="184" width="608" height="14"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" sendsActionOnEndEditing="YES" title="Enable this optoion to prevent the app from checking for updates automatically." id="3aO-AI-YtY">
|
||||
<font key="font" size="12" name="Menlo-Regular"/>
|
||||
<color key="textColor" name="secondaryLabelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Gf8-do-3hb">
|
||||
<rect key="frame" x="55" y="117" width="399" height="28"/>
|
||||
<rect key="frame" x="63" y="196" width="399" height="28"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Disable automatic update check" id="ymJ-tB-qiA">
|
||||
<font key="font" size="17" name="Menlo-Bold"/>
|
||||
@@ -330,28 +339,30 @@ KnockKnock checks “who’s there” by scanning all persistent software to rev
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
</subviews>
|
||||
<point key="canvasLocation" x="431.5" y="502"/>
|
||||
<point key="canvasLocation" x="431" y="502"/>
|
||||
</customView>
|
||||
<customView id="2qR-UH-6qk" userLabel="Support">
|
||||
<rect key="frame" x="0.0" y="0.0" width="812" height="454"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="812" height="400"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<subviews>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="0L0-vQ-k5x">
|
||||
<rect key="frame" x="23" y="245" width="128" height="128"/>
|
||||
<rect key="frame" x="20" y="227" width="128" height="128"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="Heart" id="NdE-ks-tao"/>
|
||||
</imageView>
|
||||
<textField focusRingType="none" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" preferredMaxLayoutWidth="660" translatesAutoresizingMaskIntoConstraints="NO" id="NuI-gL-I9N">
|
||||
<rect key="frame" x="153" y="257" width="636" height="110"/>
|
||||
<rect key="frame" x="150" y="235" width="636" height="110"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="center" title="It's free, open-source, and written by a single (Mac-loving) coder!" id="Uzd-7P-dzG">
|
||||
<font key="font" size="40" name="AvenirNextCondensed-Regular"/>
|
||||
<textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="center" id="Uzd-7P-dzG">
|
||||
<font key="font" size="32" name="AvenirNextCondensed-Regular"/>
|
||||
<string key="title">It's free, open-source, and written by a single
|
||||
(Mac-loving) coder!</string>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<box fixedFrame="YES" boxType="custom" borderType="none" titlePosition="noTitle" translatesAutoresizingMaskIntoConstraints="NO" id="3oj-Go-OSg">
|
||||
<rect key="frame" x="0.0" y="1" width="812" height="48"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="812" height="48"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<view key="contentView" id="kck-xf-IsF">
|
||||
<rect key="frame" x="0.0" y="0.0" width="812" height="48"/>
|
||||
@@ -383,8 +394,71 @@ KnockKnock checks “who’s there” by scanning all persistent software to rev
|
||||
</view>
|
||||
<color key="fillColor" red="0.57793885469999995" green="0.75859862570000003" blue="0.2368842065" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</box>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" alphaValue="0.90000000000000002" id="AM3-9J-hwR">
|
||||
<rect key="frame" x="258" y="60" width="138" height="31"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="FriendsMacPaw" id="Ylq-Y7-0yI"/>
|
||||
</imageView>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" alphaValue="0.80000000000000004" id="mxQ-16-QkH">
|
||||
<rect key="frame" x="573" y="58" width="142" height="31"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="FriendsHuntress" id="5gc-uV-gX6"/>
|
||||
</imageView>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" alphaValue="0.80000000000000004" id="KQq-D5-uls">
|
||||
<rect key="frame" x="100" y="58" width="142" height="31"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" animates="YES" imageScaling="proportionallyDown" image="FriendsMalwarebytes" id="0Du-KM-jmM"/>
|
||||
</imageView>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" alphaValue="0.80000000000000004" id="2M2-4t-B3w">
|
||||
<rect key="frame" x="724" y="62" width="73" height="25"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="FriendsiVerify" id="Qy2-wU-bbf"/>
|
||||
</imageView>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" alphaValue="0.80000000000000004" id="7sb-Zs-q5d">
|
||||
<rect key="frame" x="234" y="95" width="102" height="37"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="FriendsKandji" id="W0a-k0-8a1"/>
|
||||
</imageView>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" alphaValue="0.90000000000000002" id="CsL-Yj-dhy">
|
||||
<rect key="frame" x="362" y="106" width="89" height="31"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" animates="YES" imageScaling="proportionallyDown" image="FriendsFleet" id="jTn-RV-2Tp"/>
|
||||
</imageView>
|
||||
<textField focusRingType="none" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" preferredMaxLayoutWidth="660" translatesAutoresizingMaskIntoConstraints="NO" id="JBN-MO-km3">
|
||||
<rect key="frame" x="38" y="361" width="664" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="left" title="Support KnockKnock?" id="qNj-Zh-8FW">
|
||||
<font key="font" size="32" name="AvenirNextCondensed-Medium"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField focusRingType="none" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" preferredMaxLayoutWidth="660" translatesAutoresizingMaskIntoConstraints="NO" id="NeU-Pi-VDr">
|
||||
<rect key="frame" x="287" y="179" width="499" height="57"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="right" title="Show some love? " id="XBE-gW-YkK">
|
||||
<font key="font" size="32" name="AvenirNextCondensed-Regular"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" alphaValue="0.90000000000000002" id="a5u-a9-9Hv">
|
||||
<rect key="frame" x="13" y="62" width="77" height="23"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="FriendsJamf" id="2Ll-Bq-g75"/>
|
||||
</imageView>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" alphaValue="0.80000000000000004" id="wYW-XY-DPT">
|
||||
<rect key="frame" x="416" y="55" width="148" height="36"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" animates="YES" imageScaling="proportionallyDown" image="FriendsSophos" id="ZqJ-o4-Joj"/>
|
||||
</imageView>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" alphaValue="0.90000000000000002" id="fcd-Wp-myp">
|
||||
<rect key="frame" x="476" y="101" width="126" height="29"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="FriendsPANW" id="Dio-uY-kZm"/>
|
||||
</imageView>
|
||||
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" alphaValue="0.59999999999999998" id="SzT-r7-Ma4">
|
||||
<rect key="frame" x="290" y="137" width="233" height="29"/>
|
||||
<rect key="frame" x="299" y="139" width="233" height="29"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" alignment="center" title="Mahalo to the "Friends Objective-See"" id="7pD-BH-c8i">
|
||||
<font key="font" size="15" name="AvenirNextCondensed-Regular"/>
|
||||
@@ -392,85 +466,22 @@ KnockKnock checks “who’s there” by scanning all persistent software to rev
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" alphaValue="0.90000000000000002" id="AM3-9J-hwR">
|
||||
<rect key="frame" x="258" y="59" width="138" height="31"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="FriendsMacPaw" id="Ylq-Y7-0yI"/>
|
||||
</imageView>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" alphaValue="0.80000000000000004" id="mxQ-16-QkH">
|
||||
<rect key="frame" x="573" y="57" width="142" height="31"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="FriendsHuntress" id="5gc-uV-gX6"/>
|
||||
</imageView>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" alphaValue="0.80000000000000004" id="KQq-D5-uls">
|
||||
<rect key="frame" x="100" y="57" width="142" height="31"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" animates="YES" imageScaling="proportionallyDown" image="FriendsMalwarebytes" id="0Du-KM-jmM"/>
|
||||
</imageView>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" alphaValue="0.80000000000000004" id="2M2-4t-B3w">
|
||||
<rect key="frame" x="724" y="61" width="73" height="25"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="FriendsiVerify" id="Qy2-wU-bbf"/>
|
||||
</imageView>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" alphaValue="0.80000000000000004" id="7sb-Zs-q5d">
|
||||
<rect key="frame" x="234" y="94" width="102" height="37"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="FriendsKandji" id="W0a-k0-8a1"/>
|
||||
</imageView>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" alphaValue="0.90000000000000002" id="CsL-Yj-dhy">
|
||||
<rect key="frame" x="362" y="105" width="89" height="31"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" animates="YES" imageScaling="proportionallyDown" image="FriendsFleet" id="jTn-RV-2Tp"/>
|
||||
</imageView>
|
||||
<textField focusRingType="none" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" preferredMaxLayoutWidth="660" translatesAutoresizingMaskIntoConstraints="NO" id="JBN-MO-km3">
|
||||
<rect key="frame" x="38" y="380" width="664" height="55"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="left" title="Support KnockKnock?" id="qNj-Zh-8FW">
|
||||
<font key="font" size="40" name="AvenirNextCondensed-Regular"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField focusRingType="none" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" preferredMaxLayoutWidth="660" translatesAutoresizingMaskIntoConstraints="NO" id="NeU-Pi-VDr">
|
||||
<rect key="frame" x="290" y="192" width="499" height="57"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="right" title="Show some love? " id="XBE-gW-YkK">
|
||||
<font key="font" size="40" name="AvenirNextCondensed-Regular"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" alphaValue="0.90000000000000002" id="a5u-a9-9Hv">
|
||||
<rect key="frame" x="13" y="61" width="77" height="23"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="FriendsJamf" id="2Ll-Bq-g75"/>
|
||||
</imageView>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" alphaValue="0.80000000000000004" id="wYW-XY-DPT">
|
||||
<rect key="frame" x="416" y="54" width="148" height="36"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" animates="YES" imageScaling="proportionallyDown" image="FriendsSophos" id="ZqJ-o4-Joj"/>
|
||||
</imageView>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" alphaValue="0.90000000000000002" id="fcd-Wp-myp">
|
||||
<rect key="frame" x="476" y="100" width="126" height="29"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="FriendsPANW" id="Dio-uY-kZm"/>
|
||||
</imageView>
|
||||
</subviews>
|
||||
<point key="canvasLocation" x="685" y="1355"/>
|
||||
</customView>
|
||||
<customView id="afB-QN-4Zp" userLabel="Configure">
|
||||
<rect key="frame" x="0.0" y="0.0" width="699" height="290"/>
|
||||
<customView id="afB-QN-4Zp" userLabel="VT Integration">
|
||||
<rect key="frame" x="0.0" y="0.0" width="700" height="400"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<subviews>
|
||||
<box fixedFrame="YES" boxType="custom" borderType="none" titlePosition="noTitle" translatesAutoresizingMaskIntoConstraints="NO" id="b9g-lW-n01">
|
||||
<rect key="frame" x="0.0" y="0.0" width="699" height="48"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="700" height="48"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<view key="contentView" id="ofA-lY-dxh">
|
||||
<rect key="frame" x="0.0" y="0.0" width="699" height="48"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="700" height="48"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<button tag="4" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="ahC-4V-9UW">
|
||||
<rect key="frame" x="598" y="8" width="81" height="32"/>
|
||||
<rect key="frame" x="599" y="8" width="81" height="32"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="push" title="Next" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="wgk-Ma-GMi">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
@@ -485,16 +496,16 @@ KnockKnock checks “who’s there” by scanning all persistent software to rev
|
||||
<color key="fillColor" red="0.57793885469999995" green="0.75859862570000003" blue="0.2368842065" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</box>
|
||||
<textField focusRingType="none" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" preferredMaxLayoutWidth="660" translatesAutoresizingMaskIntoConstraints="NO" id="Fub-o3-w3r">
|
||||
<rect key="frame" x="30" y="251" width="664" height="44"/>
|
||||
<rect key="frame" x="38" y="361" width="664" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="left" title="VirusTotal Integration:" id="1Hq-3Y-qbJ">
|
||||
<textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="left" title="(Optional) VirusTotal Integration:" id="1Hq-3Y-qbJ">
|
||||
<font key="font" size="32" name="AvenirNextCondensed-Medium"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="NOF-lL-dnS">
|
||||
<rect key="frame" x="30" y="193" width="86" height="20"/>
|
||||
<rect key="frame" x="38" y="276" width="86" height="20"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" title="API Key:" id="7SG-o8-mRZ">
|
||||
<font key="font" size="17" name="Menlo-Bold"/>
|
||||
@@ -503,7 +514,7 @@ KnockKnock checks “who’s there” by scanning all persistent software to rev
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField focusRingType="none" verticalHuggingPriority="750" fixedFrame="YES" textCompletion="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Msu-yL-eqA">
|
||||
<rect key="frame" x="125" y="188" width="503" height="24"/>
|
||||
<rect key="frame" x="133" y="273" width="503" height="24"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" placeholderString="Your VirusTotal API Key" drawsBackground="YES" id="Og2-Lo-pbi">
|
||||
<font key="font" size="13" name="Menlo-Regular"/>
|
||||
@@ -512,7 +523,7 @@ KnockKnock checks “who’s there” by scanning all persistent software to rev
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField focusRingType="none" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Ucj-y5-V2I">
|
||||
<rect key="frame" x="31" y="159" width="447" height="21"/>
|
||||
<rect key="frame" x="39" y="244" width="447" height="21"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" selectable="YES" title="Obtain a key (for free!) here:" id="GXa-el-UVP">
|
||||
<font key="font" size="11" name="Menlo-Regular"/>
|
||||
@@ -521,7 +532,7 @@ KnockKnock checks “who’s there” by scanning all persistent software to rev
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="fi7-v7-obV" customClass="HyperlinkTextField">
|
||||
<rect key="frame" x="241" y="167" width="389" height="13"/>
|
||||
<rect key="frame" x="249" y="252" width="389" height="13"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" title="https://docs.virustotal.com/docs/please-give-me-an-api-key" id="6xX-Qx-lt6">
|
||||
<font key="font" size="11" name="Menlo-Regular"/>
|
||||
@@ -530,16 +541,17 @@ KnockKnock checks “who’s there” by scanning all persistent software to rev
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField focusRingType="none" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" preferredMaxLayoutWidth="445" translatesAutoresizingMaskIntoConstraints="NO" id="uQb-VS-DuG">
|
||||
<rect key="frame" x="30" y="224" width="639" height="28"/>
|
||||
<rect key="frame" x="38" y="334" width="639" height="28"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" sendsActionOnEndEditing="YES" title="Check persistent items with VirusTotal’s threat database to identify known malware." id="7ox-4I-TfC">
|
||||
<textFieldCell key="cell" sendsActionOnEndEditing="YES" id="7ox-4I-TfC">
|
||||
<font key="font" size="12" name="Menlo-Regular"/>
|
||||
<string key="title">Check persistent items with VirusTotal’s threat database to identify known malware. You can add an API key now or anytime later in KnockKnock’s Settings.</string>
|
||||
<color key="textColor" name="secondaryLabelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="GdO-mh-Ufm">
|
||||
<rect key="frame" x="32" y="100" width="22" height="44"/>
|
||||
<rect key="frame" x="40" y="183" width="22" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="check" bezelStyle="regularSquare" imagePosition="left" inset="2" id="5gm-6I-Af8">
|
||||
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||
@@ -547,16 +559,16 @@ KnockKnock checks “who’s there” by scanning all persistent software to rev
|
||||
</buttonCell>
|
||||
</button>
|
||||
<textField focusRingType="none" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" preferredMaxLayoutWidth="445" translatesAutoresizingMaskIntoConstraints="NO" id="0O9-FJ-fB9">
|
||||
<rect key="frame" x="55" y="93" width="503" height="14"/>
|
||||
<rect key="frame" x="63" y="173" width="647" height="18"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" sendsActionOnEndEditing="YES" title="Prevents the app from querying VirusTotal for known malware." id="TDp-uQ-UJx">
|
||||
<textFieldCell key="cell" sendsActionOnEndEditing="YES" title="Enable this option to prevent the app from querying VirusTotal for known malware." id="TDp-uQ-UJx">
|
||||
<font key="font" size="12" name="Menlo-Regular"/>
|
||||
<color key="textColor" name="secondaryLabelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="W2v-5l-YaL">
|
||||
<rect key="frame" x="55" y="103" width="399" height="28"/>
|
||||
<rect key="frame" x="63" y="186" width="399" height="28"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Disable VirusTotal Integration " id="9lZ-zf-ok2">
|
||||
<font key="font" size="17" name="Menlo-Bold"/>
|
||||
@@ -565,7 +577,7 @@ KnockKnock checks “who’s there” by scanning all persistent software to rev
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
</subviews>
|
||||
<point key="canvasLocation" x="309.5" y="881"/>
|
||||
<point key="canvasLocation" x="309" y="881"/>
|
||||
</customView>
|
||||
</objects>
|
||||
<resources>
|
||||
|
||||
@@ -717,7 +717,6 @@ bail:
|
||||
//dbg msg
|
||||
//NSLog(@"%s's entropy: %f", ((struct segment_command *)loadCommand)->segname, segmentEntropy);
|
||||
|
||||
//TODO: test more!
|
||||
if(segmentEntropy > 7.2f)
|
||||
{
|
||||
//inc total
|
||||
|
||||
+2
-1
@@ -378,7 +378,8 @@ bail:
|
||||
//init json
|
||||
json = [NSString stringWithFormat:@"\"name\": \"%@\", \"path\": \"%@\", \"plist\": \"%@\", \"hashes\": %@, \"signature(s)\": %@", self.name, self.path, filePlist, fileHashes, fileSigs];
|
||||
|
||||
//include VT
|
||||
//include VT?
|
||||
// append detection
|
||||
if(![NSProcessInfo.processInfo.arguments containsObject:@"-skipVT"])
|
||||
{
|
||||
//append VT detection
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
<window title="KnockKnock Settings" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="F0z-JX-Cv5">
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES" texturedBackground="YES"/>
|
||||
<rect key="contentRect" x="196" y="240" width="565" height="310"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="1280" height="769"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="3440" height="1409"/>
|
||||
<view key="contentView" id="se5-gp-TjO">
|
||||
<rect key="frame" x="0.0" y="0.0" width="565" height="310"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
@@ -126,7 +126,7 @@
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" selectable="YES" id="Nua-Eb-VTm">
|
||||
<font key="font" size="11" name="Menlo-Regular"/>
|
||||
<string key="title">Enter your personal VirusTotal API.
|
||||
<string key="title">Enter your personal VirusTotal API key.
|
||||
You can learn more about getting such a key (for free!) here:</string>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<window title="Unknown Items" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" frameAutosaveName="" animationBehavior="default" id="pvW-8N-g8T">
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
|
||||
<rect key="contentRect" x="403" y="305" width="643" height="339"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="1280" height="769"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="3440" height="1409"/>
|
||||
<value key="minSize" type="size" width="643" height="339"/>
|
||||
<view key="contentView" id="XBF-k3-Nqu">
|
||||
<rect key="frame" x="0.0" y="0.0" width="643" height="339"/>
|
||||
|
||||
@@ -98,13 +98,13 @@
|
||||
}
|
||||
},
|
||||
"Nua-Eb-VTm.title" : {
|
||||
"comment" : "Class = \"NSTextFieldCell\"; title = \"Enter your personal VirusTotal API. \\nYou can learn more about getting such a key (for free!) here:\"; ObjectID = \"Nua-Eb-VTm\";",
|
||||
"comment" : "Class = \"NSTextFieldCell\"; title = \"Enter your personal VirusTotal API key. \\nYou can learn more about getting such a key (for free!) here:\"; ObjectID = \"Nua-Eb-VTm\";",
|
||||
"extractionState" : "extracted_with_value",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"value" : "Enter your personal VirusTotal API. \nYou can learn more about getting such a key (for free!) here:"
|
||||
"value" : "Enter your personal VirusTotal API key. \nYou can learn more about getting such a key (for free!) here:"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -310,6 +310,7 @@
|
||||
}
|
||||
else {
|
||||
|
||||
//err msg
|
||||
NSLog(@"ERROR: %@", result[VT_ERROR]);
|
||||
|
||||
//show error msg
|
||||
|
||||
+4
-3
@@ -16,9 +16,10 @@
|
||||
|
||||
/* METHODS */
|
||||
|
||||
-(void)checkFiles:(PluginBase*)plugin;
|
||||
|
||||
- (void)submitFile:(NSString *)filePath completion:(void (^)(NSDictionary *result))completion;
|
||||
//check (all plugin's) files
|
||||
-(void)checkFiles:(PluginBase*)plugin apiKey:(NSString*)apiKey uiMode:(BOOL)uiMode completion:(void(^)(void))completion;
|
||||
|
||||
//submit a file for scanning
|
||||
-(void)submitFile:(NSString *)filePath completion:(void (^)(NSDictionary *result))completion;
|
||||
|
||||
@end
|
||||
|
||||
+66
-57
@@ -20,12 +20,16 @@ extern BOOL cmdlineMode;
|
||||
|
||||
@implementation VirusTotal
|
||||
|
||||
|
||||
//ask VT about all files for a given plugin
|
||||
// note: skips Apple binaries
|
||||
-(void)checkFiles:(PluginBase*)plugin {
|
||||
// note: always skips Apple binaries, as these won't be malware, and API keys usually rate limited
|
||||
-(void)checkFiles:(PluginBase*)plugin apiKey:(NSString*)apiKey uiMode:(BOOL)uiMode completion:(void(^)(void))completion {
|
||||
|
||||
//load key
|
||||
NSString* vtAPIKey = loadAPIKeyFromKeychain();
|
||||
//sanity check
|
||||
if(!plugin.allItems.count) {
|
||||
if(completion) completion();
|
||||
return;
|
||||
}
|
||||
|
||||
//all items in the plugin
|
||||
for(ItemBase* item in plugin.allItems) {
|
||||
@@ -49,81 +53,83 @@ extern BOOL cmdlineMode;
|
||||
continue;
|
||||
}
|
||||
|
||||
//semaphore for synchronous request
|
||||
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
|
||||
|
||||
//build the API URL
|
||||
NSURL* url = [NSURL URLWithString:[NSString stringWithFormat:@"https://www.virustotal.com/api/v3/files/%@", sha1]];
|
||||
|
||||
//create the request
|
||||
NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:url];
|
||||
[request setHTTPMethod:@"GET"];
|
||||
[request setValue:vtAPIKey forHTTPHeaderField:@"x-apikey"];
|
||||
[request setValue:apiKey forHTTPHeaderField:@"x-apikey"];
|
||||
|
||||
//kick off request
|
||||
NSURLSessionDataTask* task = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
|
||||
|
||||
if (error) {
|
||||
NSLog(@"VirusTotal error: %@", error.localizedDescription);
|
||||
NSLog(@"VirusTotal ERROR: %@", error.localizedDescription);
|
||||
|
||||
//signal
|
||||
dispatch_semaphore_signal(sema);
|
||||
return;
|
||||
}
|
||||
|
||||
//grab HTTP status
|
||||
NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse *)response;
|
||||
|
||||
//401 is API key issue :|
|
||||
//401 is API key issue
|
||||
if (httpResponse.statusCode == 401) {
|
||||
|
||||
//dbg msg
|
||||
NSLog(@"VT ERROR: API key %@ is not valid", vtAPIKey);
|
||||
|
||||
//show alert
|
||||
// just once though
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
|
||||
//alert
|
||||
NSAlert* alert = nil;
|
||||
|
||||
//alloc/init alert
|
||||
alert = [NSAlert alertWithMessageText:@"ERROR: VirusTotal Responded with HTTP 401"
|
||||
defaultButton:@"OK"
|
||||
alternateButton:nil
|
||||
otherButton:nil
|
||||
informativeTextWithFormat:@"%@", [NSString stringWithFormat:@"API key: '%@', likely invalid.", vtAPIKey]];
|
||||
|
||||
//show it
|
||||
[alert runModal];
|
||||
NSLog(@"VirusTotal ERROR: API key %@ is not valid", apiKey);
|
||||
|
||||
if(uiMode) {
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
NSAlert* alert = [NSAlert alertWithMessageText:@"ERROR: VirusTotal Responded with HTTP 401"
|
||||
defaultButton:@"OK"
|
||||
alternateButton:nil
|
||||
otherButton:nil
|
||||
informativeTextWithFormat:@"%@", [NSString stringWithFormat:@"API key: '%@', likely invalid.", apiKey]];
|
||||
[alert runModal];
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
//signal
|
||||
dispatch_semaphore_signal(sema);
|
||||
return;
|
||||
}
|
||||
|
||||
//404 is (unknown) file not found
|
||||
//404 is file not found
|
||||
if (httpResponse.statusCode == 404) {
|
||||
|
||||
//dbg msg
|
||||
NSLog(@"%@ is unknown to VirusTotal (hash: %@)", file.name, sha1);
|
||||
|
||||
//add to unknown items
|
||||
@synchronized(item.plugin.unknownItems) {
|
||||
[item.plugin.unknownItems addObject:item];
|
||||
}
|
||||
|
||||
//save
|
||||
// blank to indicate not found
|
||||
file.vtInfo = @{};
|
||||
|
||||
//notify UI on main thread
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[((AppDelegate*)NSApplication.sharedApplication.delegate) itemProcessed:file];
|
||||
});
|
||||
if(uiMode) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[((AppDelegate*)NSApplication.sharedApplication.delegate) itemProcessed:file];
|
||||
});
|
||||
}
|
||||
|
||||
//signal
|
||||
dispatch_semaphore_signal(sema);
|
||||
return;
|
||||
}
|
||||
|
||||
//all other error(s)
|
||||
if (httpResponse.statusCode != 200) {
|
||||
NSLog(@"VirusTotal HTTP error: %ld", (long)httpResponse.statusCode);
|
||||
|
||||
//signal
|
||||
dispatch_semaphore_signal(sema);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -132,13 +138,15 @@ extern BOOL cmdlineMode;
|
||||
NSDictionary* json = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonError];
|
||||
if (jsonError) {
|
||||
NSLog(@"VirusTotal JSON error: %@", jsonError.localizedDescription);
|
||||
|
||||
//signal
|
||||
dispatch_semaphore_signal(sema);
|
||||
return;
|
||||
}
|
||||
|
||||
//extract
|
||||
NSDictionary* attributes = json[@"data"][@"attributes"];
|
||||
NSDictionary* stats = attributes[@"last_analysis_stats"];
|
||||
|
||||
NSString* itemID = json[@"data"][@"id"];
|
||||
|
||||
NSInteger malicious = [stats[@"malicious"] integerValue];
|
||||
@@ -146,15 +154,11 @@ extern BOOL cmdlineMode;
|
||||
NSInteger undetected = [stats[@"undetected"] integerValue];
|
||||
NSInteger harmless = [stats[@"harmless"] integerValue];
|
||||
|
||||
//(browser) report
|
||||
NSString* link = [NSString stringWithFormat:@"https://www.virustotal.com/gui/file/%@", itemID];
|
||||
|
||||
//calculate total
|
||||
//TODO: double check this
|
||||
NSInteger total = malicious + suspicious + undetected + harmless;
|
||||
|
||||
//create result dictionary
|
||||
NSDictionary *result = @{
|
||||
//save results
|
||||
file.vtInfo = @{
|
||||
VT_RESULTS_POSITIVES : @(malicious),
|
||||
@"suspicious": @(suspicious),
|
||||
@"undetected": @(undetected),
|
||||
@@ -164,29 +168,34 @@ extern BOOL cmdlineMode;
|
||||
VT_RESULTS_URL: link
|
||||
};
|
||||
|
||||
//save
|
||||
file.vtInfo = result;
|
||||
|
||||
//dbg msg
|
||||
NSLog(@"File: %@ - Detection ratio: %ld/%ld", file.name, (long)malicious, (long)total);
|
||||
|
||||
//malicious?
|
||||
// add to flagged items
|
||||
if (malicious > 0) {
|
||||
@synchronized(item.plugin.flaggedItems) {
|
||||
[item.plugin.flaggedItems addObject:item];
|
||||
}
|
||||
}
|
||||
|
||||
//notify UI on main thread
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[((AppDelegate*)NSApplication.sharedApplication.delegate) itemProcessed:file];
|
||||
});
|
||||
//notify UI
|
||||
if(uiMode) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[((AppDelegate*)NSApplication.sharedApplication.delegate) itemProcessed:file];
|
||||
});
|
||||
}
|
||||
|
||||
//signal
|
||||
dispatch_semaphore_signal(sema);
|
||||
}];
|
||||
|
||||
//query
|
||||
[task resume];
|
||||
|
||||
//wait for this request to finish
|
||||
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
|
||||
}
|
||||
|
||||
//all files done
|
||||
if(completion) completion();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//submit a file to VT
|
||||
|
||||
+13
-33
@@ -57,7 +57,7 @@ extern os_log_t logHandle;
|
||||
|
||||
//no FDA?
|
||||
// next view should be 'request FDA'
|
||||
if(!hasFDA()) {
|
||||
if(hasFDA()) {
|
||||
self.nextButton.tag = REQUEST_FDA;
|
||||
}
|
||||
//otherwise
|
||||
@@ -69,24 +69,14 @@ extern os_log_t logHandle;
|
||||
//show view
|
||||
[self showView:self.welcomeView firstResponder:self.nextButton];
|
||||
|
||||
//center (before showing)
|
||||
[self.window center];
|
||||
|
||||
//make key and front
|
||||
[self.window makeKeyAndOrderFront:self];
|
||||
|
||||
//TODO:
|
||||
//center
|
||||
[self.window center];
|
||||
|
||||
//activate
|
||||
if(@available(macOS 14.0, *)) {
|
||||
[NSApp activate];
|
||||
}
|
||||
else
|
||||
{
|
||||
[NSApp activateIgnoringOtherApps:YES];
|
||||
}
|
||||
|
||||
//(re)make front
|
||||
[[NSRunningApplication currentApplication] activateWithOptions:(NSApplicationActivateAllWindows | NSApplicationActivateIgnoringOtherApps)];
|
||||
[NSApp activateIgnoringOtherApps:YES];
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -241,12 +231,6 @@ extern os_log_t logHandle;
|
||||
// note: replaces old view and highlights specified responder
|
||||
-(void)showView:(NSView*)view firstResponder:(NSView*)firstResponder
|
||||
{
|
||||
//x position
|
||||
CGFloat xPos = 0;
|
||||
|
||||
//y position
|
||||
CGFloat yPos = 0;
|
||||
|
||||
//not in dark mode?
|
||||
// make window white
|
||||
if(YES != isDarkMode())
|
||||
@@ -261,15 +245,6 @@ extern os_log_t logHandle;
|
||||
//update config view
|
||||
self.window.contentView = view;
|
||||
|
||||
//center x
|
||||
xPos = NSWidth(self.window.screen.frame)/2 - NSWidth(self.window.frame)/2;
|
||||
|
||||
//center y
|
||||
yPos = NSHeight(self.window.screen.frame)/2 - NSHeight(self.window.frame)/2;
|
||||
|
||||
//center window
|
||||
[self.window setFrame:NSMakeRect(xPos, yPos, NSWidth(self.window.frame), NSHeight(self.window.frame)) display:YES];
|
||||
|
||||
//make 'next' button first responder
|
||||
// calling this without a timeout, sometimes fails :/
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (100 * NSEC_PER_MSEC)), dispatch_get_main_queue(), ^{
|
||||
@@ -285,10 +260,15 @@ extern os_log_t logHandle;
|
||||
|
||||
return;
|
||||
}
|
||||
- (IBAction)openSystemSettings:(id)sender {
|
||||
|
||||
|
||||
//open system settings to FDA
|
||||
-(IBAction)openSystemSettings:(id)sender {
|
||||
|
||||
//open `System Preferences`
|
||||
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"x-apple.systempreferences:com.apple.preference.security?Privacy_AllFiles"]];
|
||||
//show FDA view
|
||||
[NSWorkspace.sharedWorkspace openURL:[NSURL URLWithString:@"x-apple.systempreferences:com.apple.preference.security?Privacy_AllFiles"]];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -32,6 +32,9 @@ BOOL cmdlineMode = NO;
|
||||
//cmdline flag
|
||||
BOOL isVerbose = NO;
|
||||
|
||||
//(VT) API key for cmdline scan
|
||||
NSString* vtAPIKey = nil;
|
||||
|
||||
/* FUNCTIONS */
|
||||
|
||||
//print usage
|
||||
@@ -41,7 +44,7 @@ void usage(void);
|
||||
void version(void);
|
||||
|
||||
//perform a cmdline scan
|
||||
void cmdlineScan(void);
|
||||
void cmdlineScan(NSArray* args);
|
||||
|
||||
//pretty print JSON
|
||||
void prettyPrintJSON(NSString* output);
|
||||
|
||||
@@ -13,11 +13,13 @@ int main(int argc, char *argv[])
|
||||
//status
|
||||
int status = -1;
|
||||
|
||||
NSArray* args = NSProcessInfo.processInfo.arguments;
|
||||
|
||||
@autoreleasepool
|
||||
{
|
||||
//handle '-h' or '-help'
|
||||
if( (YES == [NSProcessInfo.processInfo.arguments containsObject:@"-h"]) ||
|
||||
(YES == [NSProcessInfo.processInfo.arguments containsObject:@"-help"]) )
|
||||
if( (YES == [args containsObject:@"-h"]) ||
|
||||
(YES == [args containsObject:@"-help"]) )
|
||||
{
|
||||
//print usage
|
||||
usage();
|
||||
@@ -26,7 +28,8 @@ int main(int argc, char *argv[])
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if(YES == [NSProcessInfo.processInfo.arguments containsObject:@"-version"])
|
||||
//print version
|
||||
if(YES == [args containsObject:@"-version"])
|
||||
{
|
||||
//print usage
|
||||
version();
|
||||
@@ -36,19 +39,54 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
|
||||
|
||||
//handle '-scan'
|
||||
// cmdline scan without UI
|
||||
if(YES == [NSProcessInfo.processInfo.arguments containsObject:@"-whosthere"])
|
||||
if(YES == [args containsObject:@"-whosthere"])
|
||||
{
|
||||
//api key
|
||||
NSUInteger keyIndex = NSNotFound;
|
||||
|
||||
//set flag
|
||||
cmdlineMode = YES;
|
||||
|
||||
//set flag
|
||||
isVerbose = [NSProcessInfo.processInfo.arguments containsObject:@"-verbose"];
|
||||
isVerbose = [args containsObject:@"-verbose"];
|
||||
|
||||
//extract VT API key
|
||||
keyIndex = [args indexOfObject:@"-key"];
|
||||
if(keyIndex != NSNotFound)
|
||||
{
|
||||
//sanity check
|
||||
if(keyIndex + 1 < args.count)
|
||||
{
|
||||
//grab
|
||||
vtAPIKey = args[keyIndex + 1];
|
||||
}
|
||||
|
||||
//validate
|
||||
if(vtAPIKey.length == 0)
|
||||
{
|
||||
//usage
|
||||
usage();
|
||||
|
||||
//done
|
||||
goto bail;
|
||||
}
|
||||
}
|
||||
|
||||
//need FDA
|
||||
if(!hasFDA()) {
|
||||
|
||||
//err msg
|
||||
printf("ERROR: KnockKnock requires Full Disk Access...\n\n");
|
||||
|
||||
//done
|
||||
goto bail;
|
||||
|
||||
}
|
||||
|
||||
//scan
|
||||
cmdlineScan();
|
||||
cmdlineScan(args);
|
||||
|
||||
//happy
|
||||
status = 0;
|
||||
@@ -83,9 +121,9 @@ void version(void) {
|
||||
NSDictionary* info = NSBundle.mainBundle.infoDictionary;
|
||||
NSString* version = info[@"CFBundleVersion"];
|
||||
if (version) {
|
||||
printf("%s\n", version.UTF8String);
|
||||
printf("KnockKnock Version: %s\n", version.UTF8String);
|
||||
} else {
|
||||
printf("unknown\n");
|
||||
printf("KnockKnock Version: unknown\n");
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -96,19 +134,20 @@ void usage(void)
|
||||
{
|
||||
//usage
|
||||
printf("\nKNOCKNOCK USAGE:\n");
|
||||
printf(" -h or -help display this usage info\n");
|
||||
printf(" -whosthere perform command line scan\n");
|
||||
printf(" -version display current version of\n");
|
||||
printf(" -verbose display detailed output\n");
|
||||
printf(" -pretty final output is 'pretty-printed'\n");
|
||||
printf(" -apple include apple/system items\n");
|
||||
printf(" -skipVT do not query VirusTotal with item hashes\n\n");
|
||||
printf(" -h or -help display this usage info\n");
|
||||
printf(" -whosthere perform command line scan\n");
|
||||
printf(" -version display current version of\n");
|
||||
printf(" -verbose display detailed output\n");
|
||||
printf(" -pretty final output is 'pretty-printed'\n");
|
||||
printf(" -apple include Apple/System items\n");
|
||||
printf(" -key <API key> your VirusTotal API key\n");
|
||||
printf(" -skipVT do not query VirusTotal with item hashes\n\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//perform a cmdline scan
|
||||
void cmdlineScan(void)
|
||||
void cmdlineScan(NSArray* args)
|
||||
{
|
||||
//virus total obj
|
||||
VirusTotal* virusTotal = nil;
|
||||
@@ -131,6 +170,9 @@ void cmdlineScan(void)
|
||||
//flag
|
||||
BOOL prettyPrint = NO;
|
||||
|
||||
//flag
|
||||
BOOL queryVT = NO;
|
||||
|
||||
//output
|
||||
NSMutableString* output = nil;
|
||||
|
||||
@@ -143,9 +185,6 @@ void cmdlineScan(void)
|
||||
//init filter object
|
||||
itemFilter = [[Filter alloc] init];
|
||||
|
||||
//init virus total object
|
||||
virusTotal = [[VirusTotal alloc] init];
|
||||
|
||||
//alloc shared item enumerator
|
||||
sharedItemEnumerator = [[ItemEnumerator alloc] init];
|
||||
|
||||
@@ -156,20 +195,29 @@ void cmdlineScan(void)
|
||||
if(YES == isVerbose)
|
||||
{
|
||||
//msg
|
||||
printf("starting scan...\n");
|
||||
printf("Starting KnockKnock scan...\n");
|
||||
}
|
||||
|
||||
|
||||
//set flag
|
||||
// include apple items?
|
||||
includeApple = [NSProcessInfo.processInfo.arguments containsObject:@"-apple"];
|
||||
includeApple = [args containsObject:@"-apple"];
|
||||
|
||||
//set flag
|
||||
// skip virus total?
|
||||
skipVirusTotal = [NSProcessInfo.processInfo.arguments containsObject:@"-skipVT"];
|
||||
skipVirusTotal = [args containsObject:@"-skipVT"];
|
||||
|
||||
//set flag
|
||||
// pretty print json?
|
||||
prettyPrint = [NSProcessInfo.processInfo.arguments containsObject:@"-pretty"];
|
||||
prettyPrint = [args containsObject:@"-pretty"];
|
||||
|
||||
//skip VT scanning if
|
||||
// user disabled queries, or no API key
|
||||
queryVT = (vtAPIKey.length) && !skipVirusTotal;
|
||||
if(queryVT)
|
||||
{
|
||||
//init virus total object
|
||||
virusTotal = [[VirusTotal alloc] init];
|
||||
}
|
||||
|
||||
//init output string
|
||||
output = [NSMutableString string];
|
||||
@@ -215,20 +263,19 @@ void cmdlineScan(void)
|
||||
printf(" found %lu %s\n", (unsigned long)plugin.allItems.count, plugin.name.UTF8String);
|
||||
}
|
||||
|
||||
//query VT
|
||||
// unless no items or user explicity says otherwise
|
||||
if( (YES != skipVirusTotal) &&
|
||||
(0 != plugin.allItems.count) )
|
||||
//query VT?
|
||||
if(queryVT)
|
||||
{
|
||||
//dbg msg
|
||||
if(YES == isVerbose)
|
||||
{
|
||||
//msg
|
||||
printf(" scanning via Virus Total\n");
|
||||
printf(" querying VirusTotal...\n");
|
||||
}
|
||||
|
||||
//TODO: need API key
|
||||
// and then scan
|
||||
//check all plugin's files
|
||||
[virusTotal checkFiles:plugin apiKey:vtAPIKey uiMode:NO completion:NULL];
|
||||
|
||||
}
|
||||
|
||||
//append plugin name to output
|
||||
@@ -281,8 +328,8 @@ void cmdlineScan(void)
|
||||
int seconds = (int)(timeInterval - (minutes * 60));
|
||||
|
||||
//msg
|
||||
printf("\nscan completed in %02d minutes, %02d seconds\n\n", minutes, seconds);
|
||||
printf("RESULTS:\n %lu persistent items\n %lu flagged items\n\n", (unsigned long)items, (unsigned long)flaggedItems);
|
||||
printf("\nScan completed in %02d minutes, %02d seconds\n\n", minutes, seconds);
|
||||
printf("RESULTS:\n %lu persistent items\n %lu (VT) flagged items\n\n", (unsigned long)items, (unsigned long)flaggedItems);
|
||||
}
|
||||
|
||||
//pretty print?
|
||||
|
||||
Reference in New Issue
Block a user