-improved cmdline processing

-ignore 'duplicate' events
-added code/UI for whitelist popup
This commit is contained in:
Patrick Wardle 2016-12-20 21:38:26 -10:00
parent 2c1fcc4a72
commit eb635e54d9
10 changed files with 450 additions and 65 deletions

View File

@ -21,7 +21,7 @@ int main(int argc, const char * argv[])
//handle '-install' / '-uninstall'
// ->this performs non-UI logic for easier automated deployment
if( (argc >= 2) &&
(YES != [[NSString stringWithUTF8String:argv[1]] hasPrefix:@"-psn_"]) )
( (0 == strcmp(argv[1], CMD_INSTALL)) || (0 == strcmp(argv[1], CMD_UNINSTALL)) ) )
{
//first check rooot
if(0 != geteuid())
@ -69,56 +69,44 @@ int main(int argc, const char * argv[])
//happy
retVar = 0;
}
//bail
goto bail;
//invalid arg
else
}//args
//check for r00t
// ->then spawn self via auth exec
if(0 != geteuid())
{
//dbg msg
logMsg(LOG_DEBUG, @"non-root installer instance");
//spawn as root
if(YES != spawnAsRoot(argv[0]))
{
//err msg
printf("\nERROR: '%s', is an invalid option\n\n", argv[1]);
logMsg(LOG_ERR, @"failed to spawn self as r00t");
//bail
goto bail;
}
}//args
//happy
retVar = 0;
}
//no args
//otherwise
// ->just kick off app, as we're root now
else
{
//check for r00t
// ->then spawn self via auth exec
if(0 != geteuid())
{
//dbg msg
logMsg(LOG_DEBUG, @"non-root installer instance");
//spawn as root
if(YES != spawnAsRoot(argv[0]))
{
//err msg
logMsg(LOG_ERR, @"failed to spawn self as r00t");
//bail
goto bail;
}
//happy
retVar = 0;
}
//dbg msg
logMsg(LOG_DEBUG, @"root installer instance");
//otherwise
// ->just kick off app, as we're root now
else
{
//dbg msg
logMsg(LOG_DEBUG, @"root installer instance");
//app away
retVar = NSApplicationMain(argc, (const char **)argv);
}
}//no args
//app away
retVar = NSApplicationMain(argc, (const char **)argv);
}
}//pool
//bail

View File

@ -13,20 +13,13 @@
#import <CoreMediaIO/CMIOHardware.h>
#import <AVFoundation/AVFoundation.h>
#import "RemeberWindowController.h"
/* DEFINES */
#define VIDEO_DISABLED 0x0
#define VIDEO_ENABLED 0x1
#define EVENT_SOURCE @"source"
#define EVENT_DEVICE @"device"
#define EVENT_DEVICE_STATUS @"status"
#define EVENT_PROCESS_ID @"processID"
#define SOURCE_AUDIO @0x1
#define SOURCE_VIDEO @0x2
#define DEVICE_INACTIVE @0x0
#define DEVICE_ACTIVE @0x1
@ -53,6 +46,17 @@
//monitor thread
@property(nonatomic, retain)NSThread* videoMonitorThread;
//remember popup/window controller
@property(nonatomic, retain)RememberWindowController* rememberWindowController;
//last event
@property(nonatomic, retain)NSDictionary* lastEvent;
//last notification
@property(nonatomic, retain)NSString* lastNotification;
/* METHODS */
//kicks off thread to monitor

View File

@ -18,9 +18,12 @@
@synthesize mic;
@synthesize camera;
@synthesize lastEvent;
@synthesize audioActive;
@synthesize videoActive;
@synthesize lastNotification;
@synthesize videoMonitorThread;
@synthesize rememberWindowController;
//init
-(id)init
@ -443,6 +446,9 @@ bail:
// ->update menu to show (all) devices & their status
[((AppDelegate*)[[NSApplication sharedApplication] delegate]).statusBarMenuController updateStatusItemMenu:devices];
//add timestamp
event[EVENT_TIMESTAMP] = [NSDate date];
//add device
event[EVENT_DEVICE] = self.camera;
@ -695,6 +701,9 @@ bail:
// ->update menu to show (all) devices & their status
[((AppDelegate*)[[NSApplication sharedApplication] delegate]).statusBarMenuController updateStatusItemMenu:@[@{EVENT_DEVICE:self.mic, EVENT_DEVICE_STATUS:@(self.audioActive)},@{EVENT_DEVICE:self.camera, EVENT_DEVICE_STATUS:@(self.videoActive)}]];
//add timestamp
event[EVENT_TIMESTAMP] = [NSDate date];
//add device
event[EVENT_DEVICE] = self.mic;
@ -860,6 +869,10 @@ bail:
//notification
NSUserNotification* notification = nil;
//device
// ->audio or video
NSNumber* deviceType = nil;
//title
NSMutableString* title = nil;
@ -885,6 +898,32 @@ bail:
//alloc log msg
sysLogMsg = [NSMutableString string];
//check if event is essentially a duplicate (facetime, etc)
if(nil != self.lastEvent)
{
//TODO: remove
//NSLog(@"difference %f", fabs([self.lastEvent[EVENT_TIMESTAMP] timeIntervalSinceDate:event[EVENT_TIMESTAMP]]));
//less than 10 second ago?
if(fabs([self.lastEvent[EVENT_TIMESTAMP] timeIntervalSinceDate:event[EVENT_TIMESTAMP]]) < 10)
{
//same process/device/action
if( (YES == [self.lastEvent[EVENT_PROCESS_ID] isEqual:event[EVENT_PROCESS_ID]]) &&
(YES == [self.lastEvent[EVENT_DEVICE] isEqual:event[EVENT_DEVICE]]) &&
(YES == [self.lastEvent[EVENT_DEVICE_STATUS] isEqual:event[EVENT_DEVICE_STATUS]]) )
{
//update
self.lastEvent = event;
//bail to ignore
goto bail;
}
}
}//'same' event check
//update last event
self.lastEvent = event;
//always (manually) load preferences
preferences = [NSDictionary dictionaryWithContentsOfFile:[APP_PREFERENCES stringByExpandingTildeInPath]];
@ -899,19 +938,24 @@ bail:
goto bail;
}
//set title
// ->audio device
//set device and title for audio
if(YES == [event[EVENT_DEVICE] isKindOfClass:NSClassFromString(@"AVCaptureHALDevice")])
{
//add
[title appendString:@"Audio Device"];
//set device
deviceType = SOURCE_AUDIO;
}
//add source
// ->video device
//set device and title for video
else
{
//add
[title appendString:@"Video Device"];
//set device
deviceType = SOURCE_VIDEO;
}
//add action
@ -953,14 +997,14 @@ bail:
processName = getProcessName([event[EVENT_PROCESS_ID] intValue]);
//set other button title
notification.otherButtonTitle = @"allowz";
notification.otherButtonTitle = @"allow";
//set action title
notification.actionButtonTitle = @"block";
//set pid in user info
// ->allows code to try kill proc (later) if user clicks 'block'
notification.userInfo = @{EVENT_PROCESS_ID:event[EVENT_PROCESS_ID]};
//set pid/name/device into user info
// ->allows code to whitelist proc and/or kill proc (later) if user clicks 'block'
notification.userInfo = @{EVENT_PROCESS_ID:event[EVENT_PROCESS_ID], EVENT_PROCESS_NAME:processName, EVENT_DEVICE:deviceType};
//set details
// ->name of process using it / icon too?
@ -999,6 +1043,9 @@ bail:
//set subtitle
[notification setSubtitle:details];
//set id
notification.identifier = [[NSUUID UUID] UUIDString];
//set notification
[[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:self];
@ -1058,6 +1105,24 @@ bail:
//dbg msg
logMsg(LOG_DEBUG, [NSString stringWithFormat:@"user responded to notification: %@", notification]);
//ignore if this notification was already seen
// ->need this logic, since have to determine if 'allow' was invoke indirectly
if(nil != self.lastNotification)
{
//same?
if(YES == [self.lastNotification isEqualToString:notification.identifier])
{
//update
self.lastNotification = notification.identifier;
//ignore
goto bail;
}
}
//update
self.lastNotification = notification.identifier;
//for alerts without an action
// ->don't need to do anything!
if(YES != notification.hasActionButton)
@ -1092,11 +1157,33 @@ bail:
syslog(LOG_ERR, "%s\n", sysLogMsg.UTF8String);
}
//when user clicks 'allow'
// ->show popup w/ option to whitelist
if(notification.activationType == NSUserNotificationActivationTypeAdditionalActionClicked)
//check if user clicked 'allow' via user info (since OS doesn't directly deliver this)
// ->if allow was clicked, show a popup w/ option to rember ('whitelist') the application
if( (nil != notification.userInfo) &&
(NSUserNotificationActivationTypeAdditionalActionClicked == [notification.userInfo[@"activationType"] integerValue]) )
{
//TODO: show popup
//alloc/init settings window
if(nil == self.rememberWindowController)
{
//alloc/init
rememberWindowController = [[RememberWindowController alloc] initWithWindowNibName:@"RememberPopup"];
}
//center window
[[self.rememberWindowController window] center];
//show it
[self.rememberWindowController showWindow:self];
//manually configure
// ->invoke here as the outlets will be set
[self.rememberWindowController configure:notification];
//make it key window
[self.rememberWindowController.window makeKeyAndOrderFront:self];
//make window front
[NSApp activateIgnoringOtherApps:YES];
//dbg msg
logMsg(LOG_DEBUG, @"user clicked 'allow'");
@ -1104,7 +1191,7 @@ bail:
//when user clicks 'block'
// ->kill the process to block it
else if(notification.activationType == NSUserNotificationActivationTypeActionButtonClicked)
else if(NSUserNotificationActivationTypeActionButtonClicked == notification.activationType)
{
//dbg msg
logMsg(LOG_DEBUG, @"user clicked 'block'");
@ -1140,7 +1227,6 @@ bail:
{
//err msg
logMsg(LOG_ERR, [NSString stringWithFormat:@"failed to kill/block: %@", processID]);
}
//close connection
@ -1158,6 +1244,75 @@ bail:
return;
}
//manually monitor delivered notifications to see if user closes alert
// ->can't detect 'allow' otherwise :/ (see: http://stackoverflow.com/questions/21110714/mac-os-x-nsusernotificationcenter-notification-get-dismiss-event-callback)
-(void)userNotificationCenter:(NSUserNotificationCenter *)center didDeliverNotification:(NSUserNotification *)notification
{
//flag
__block BOOL notificationStillPresent;
//user dictionary
__block NSMutableDictionary* userInfo = nil;
//only process notifications have 'allow' / 'block'
if(YES == notification.hasActionButton)
{
//monitor in background to see if alert was dismissed
// ->invokes normal 'didActivateNotification' callback when alert is dimsissed
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
^{
//monitor all delivered notifications until it goes away
do {
//reset
notificationStillPresent = NO;
//check all delivered notifications
for (NSUserNotification *nox in [[NSUserNotificationCenter defaultUserNotificationCenter] deliveredNotifications])
{
//check
if(YES == [nox.identifier isEqualToString:notification.identifier])
{
//found!
notificationStillPresent = YES;
//exit loop
break;
}
}
//nap if notification is still there
if(YES == notificationStillPresent)
{
//nap
[NSThread sleepForTimeInterval:0.25f];
}
//keep monitoring until its gone
} while(YES == notificationStillPresent);
//alert was dismissed
// ->invoke 'didActivateNotification' to process if it was an 'allow/block' alert
dispatch_async(dispatch_get_main_queue(),
^{
//grab user info dictionary
userInfo = [notification.userInfo mutableCopy];
//add activation type
userInfo[@"activationType"] = [NSNumber numberWithInteger:NSUserNotificationActivationTypeAdditionalActionClicked];
//update
notification.userInfo = userInfo;
//deliver
[self userNotificationCenter:center didActivateNotification:notification];
});
});
}
return;
}
//monitor for new procs (video only at the moment)
// ->runs until video is no longer in use (set elsewhere)
-(void)monitor4Procs
@ -1212,7 +1367,7 @@ bail:
}
//generate notification
[self generateNotification:@{EVENT_DEVICE:self.camera, EVENT_DEVICE_STATUS:DEVICE_ACTIVE, EVENT_PROCESS_ID:processID}];
[self generateNotification:@{EVENT_TIMESTAMP:[NSDate date], EVENT_DEVICE:self.camera, EVENT_DEVICE_STATUS:DEVICE_ACTIVE, EVENT_PROCESS_ID:processID}];
}
//signal sema

View File

@ -0,0 +1,26 @@
//
// AboutWindowController.h
// OverSight
//
// Created by Patrick Wardle on 7/15/16.
// Copyright (c) 2016 Objective-See. All rights reserved.
//
#import <Cocoa/Cocoa.h>
@interface RememberWindowController : NSWindowController <NSWindowDelegate>
{
}
/* PROPERTIES */
//version label/string
@property (weak) IBOutlet NSTextField *windowText;
/* METHODS */
//configure window w/ dynamic text
-(void)configure:(NSUserNotification*)notification;
@end

View File

@ -0,0 +1,105 @@
//
// RememberWindowController.m
// OverSight
//
// Created by Patrick Wardle on 7/15/16.
// Copyright (c) 2016 Objective-See. All rights reserved.
//
#import "Consts.h"
#import "Utilities.h"
#import "RemeberWindowController.h"
@implementation RememberWindowController
//@synthesize versionLabel;
//automatically called when nib is loaded
// ->center window
-(void)awakeFromNib
{
//center
[self.window center];
}
//automatically invoked when window is loaded
// ->set to white
-(void)windowDidLoad
{
//super
[super windowDidLoad];
//make white
[self.window setBackgroundColor: NSColor.whiteColor];
//set version sting
//[self.versionLabel setStringValue:[NSString stringWithFormat:@"version: %@", getAppVersion()]];
return;
}
/*
//automatically invoked when window is closing
// ->make ourselves unmodal
-(void)windowWillClose:(NSNotification *)notification
{
//make un-modal
[[NSApplication sharedApplication] stopModal];
return;
}
*/
//configure window w/ dynamic text
-(void)configure:(NSUserNotification*)notification
{
//process ID
NSNumber* processID = nil;
//process name
NSString* processName = nil;
//device type
NSString* deviceType = nil;
//grab process id
processID = notification.userInfo[EVENT_PROCESS_ID];
//grab process name
processName = notification.userInfo[EVENT_PROCESS_NAME];
//set device type for audio
if(SOURCE_AUDIO.intValue == [notification.userInfo[EVENT_DEVICE] intValue])
{
//set
deviceType = @"mic";
}
//set device type for mic
else if(SOURCE_VIDEO.intValue == [notification.userInfo[EVENT_DEVICE] intValue])
{
//set
deviceType = @"camera";
}
//set text
[self.windowText setStringValue:[NSString stringWithFormat:@"always allow %@ (%@) to use the %@?", processName, processID, deviceType]];
return;
}
//automatically invoked when user clicks button 'yes' / 'no'
-(IBAction)buttonHandler:(id)sender
{
//handle 'always allow' (whitelist) button
if(BUTTON_ALWAYS_ALLOW == ((NSButton*)sender).tag)
{
//TODO: whitelist
}
//always close
[self.window close];
return;
}
@end

View File

@ -0,0 +1,77 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="11542" systemVersion="16B2555" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="11542"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="RememberWindowController">
<connections>
<outlet property="window" destination="F0z-JX-Cv5" id="gIp-Ho-8D9"/>
<outlet property="windowText" destination="OSm-xS-Dmd" id="Hi5-F0-gUp"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<window allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" releasedWhenClosed="NO" showsToolbarButton="NO" animationBehavior="default" id="F0z-JX-Cv5">
<windowStyleMask key="styleMask" titled="YES" closable="YES" texturedBackground="YES" unifiedTitleAndToolbar="YES"/>
<rect key="contentRect" x="196" y="240" width="422" height="123"/>
<rect key="screenRect" x="0.0" y="0.0" width="1920" height="1058"/>
<view key="contentView" id="se5-gp-TjO">
<rect key="frame" x="0.0" y="0.0" width="422" height="123"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="lEv-Wj-6S5">
<rect key="frame" x="10" y="36" width="104" height="82"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="icon" id="xKf-GK-m0k"/>
</imageView>
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Eaf-yA-bbe">
<rect key="frame" x="20" y="6" width="94" height="22"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="overSight" id="Ws8-bD-j2R"/>
</imageView>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="OSm-xS-Dmd">
<rect key="frame" x="120" y="47" width="290" height="56"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" truncatesLastVisibleLine="YES" sendsActionOnEndEditing="YES" id="bBK-v0-ypq">
<font key="font" size="13" name="Menlo-Regular"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<button verticalHuggingPriority="750" fixedFrame="YES" tag="101" translatesAutoresizingMaskIntoConstraints="NO" id="HZZ-Es-mpy">
<rect key="frame" x="352" y="11" width="56" height="32"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="push" title="no" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="J9x-sM-h9S">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" size="13" name="Menlo-Regular"/>
</buttonCell>
<connections>
<action selector="buttonHandler:" target="-2" id="yBL-R5-DDG"/>
</connections>
</button>
<button verticalHuggingPriority="750" fixedFrame="YES" tag="100" translatesAutoresizingMaskIntoConstraints="NO" id="RKg-ba-EQ4">
<rect key="frame" x="202" y="11" width="127" height="32"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="push" title="yes, always" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="0OU-M1-ErX">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" size="13" name="Menlo-Regular"/>
</buttonCell>
<connections>
<action selector="buttonHandler:" target="-2" id="LNd-1i-TBg"/>
</connections>
</button>
</subviews>
</view>
<connections>
<outlet property="delegate" destination="-2" id="0bl-1N-AYu"/>
</connections>
<point key="canvasLocation" x="318" y="246.5"/>
</window>
</objects>
<resources>
<image name="icon" width="512" height="512"/>
<image name="overSight" width="1396" height="286"/>
</resources>
</document>

View File

@ -18,6 +18,8 @@
7D17CFE51D8133840017B475 /* AVMonitor.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D17CFE11D81121E0017B475 /* AVMonitor.m */; };
7D17D0101D8136C60017B475 /* OverSightXPC.xpc in Embed XPC Services */ = {isa = PBXBuildFile; fileRef = 7DC9C8121D641A350017D143 /* OverSightXPC.xpc */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
7D3B524C1D9B3A74006568D9 /* libbsm.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 7D9A7DED1D8CACE30091C1AF /* libbsm.tbd */; };
7D6216731E078D65002C1774 /* RemeberWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D6216701E078C09002C1774 /* RemeberWindowController.m */; };
7D6216741E07BB27002C1774 /* RememberPopup.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7D62166E1E078BDD002C1774 /* RememberPopup.xib */; };
7D62457C1D84FB8900870565 /* Enumerator.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D62457B1D84FB8900870565 /* Enumerator.m */; };
7D6245801D85348E00870565 /* Utilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D62457F1D85348E00870565 /* Utilities.m */; };
7D6245851D87C43900870565 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 7D6245841D87C43900870565 /* Images.xcassets */; };
@ -108,6 +110,9 @@
7D17CFE11D81121E0017B475 /* AVMonitor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AVMonitor.m; sourceTree = "<group>"; };
7D17CFE21D81121E0017B475 /* AVMonitor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AVMonitor.h; sourceTree = "<group>"; };
7D32457A1DA59A3700AE0711 /* main.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = main.h; sourceTree = "<group>"; };
7D62166E1E078BDD002C1774 /* RememberPopup.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = RememberPopup.xib; sourceTree = "<group>"; };
7D6216701E078C09002C1774 /* RemeberWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RemeberWindowController.m; sourceTree = "<group>"; };
7D6216721E078C13002C1774 /* RemeberWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RemeberWindowController.h; sourceTree = "<group>"; };
7D62457A1D84FB8900870565 /* Enumerator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Enumerator.h; sourceTree = "<group>"; };
7D62457B1D84FB8900870565 /* Enumerator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Enumerator.m; sourceTree = "<group>"; };
7D62457E1D85348E00870565 /* Utilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Utilities.h; sourceTree = "<group>"; };
@ -277,6 +282,9 @@
8B5755C319DA3F9300799E6B /* LoginItem */ = {
isa = PBXGroup;
children = (
7D6216721E078C13002C1774 /* RemeberWindowController.h */,
7D6216701E078C09002C1774 /* RemeberWindowController.m */,
7D62166E1E078BDD002C1774 /* RememberPopup.xib */,
7D17C5131D658FE20066232A /* Images */,
8B5755C919DA3F9300799E6B /* AppDelegate.m */,
7D17CFE21D81121E0017B475 /* AVMonitor.h */,
@ -363,7 +371,7 @@
8B57559319DA3E9500799E6B /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0800;
LastUpgradeCheck = 0810;
ORGANIZATIONNAME = "Cory Bohon";
TargetAttributes = {
7DC9C8111D641A350017D143 = {
@ -435,6 +443,7 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
7D6216741E07BB27002C1774 /* RememberPopup.xib in Resources */,
7D9A7DE81D893E4F0091C1AF /* InfoWindow.xib in Resources */,
7D6245951D87E14800870565 /* MainMenu.xib in Resources */,
7D6245931D87E13200870565 /* icon.png in Resources */,
@ -479,6 +488,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
7D6216731E078D65002C1774 /* RemeberWindowController.m in Sources */,
7D6245881D87C57600870565 /* Logging.m in Sources */,
7D6245801D85348E00870565 /* Utilities.m in Sources */,
7D17CFE51D8133840017B475 /* AVMonitor.m in Sources */,

View File

@ -21,7 +21,7 @@
/* METHODS */
//invoked when user clicks 'more info' button
// ->open KK's webpage
// ->open OverSights webpage
- (IBAction)moreInfo:(id)sender;
@end

View File

@ -107,6 +107,26 @@
//path to facetime
#define FACE_TIME @"/Applications/FaceTime.app/Contents/MacOS/FaceTime"
//event keys
//#define EVENT_SOURCE @"source"
#define EVENT_DEVICE @"device"
#define EVENT_TIMESTAMP @"timestamp"
#define EVENT_DEVICE_STATUS @"status"
#define EVENT_PROCESS_ID @"processID"
#define EVENT_PROCESS_NAME @"processName"
//source audio
#define SOURCE_AUDIO @0x1
//source video
#define SOURCE_VIDEO @0x2
//always allow button
#define BUTTON_ALWAYS_ALLOW 100
//no/close button
#define BUTTON_NO 101

View File

@ -1,6 +1,6 @@
//
// PrefsWindowController.m
// KnockKnock
// OverSight
//
// Created by Patrick Wardle on 2/6/15.
// Copyright (c) 2015 Objective-See, LLC. All rights reserved.