v2.1.6
macOS 13.3 compatibility improved relaunching app when it's already running
This commit is contained in:
parent
9aa7aec8ad
commit
8c833cde89
|
@ -30,7 +30,6 @@
|
|||
CD8FD5F823C05AD900EFE0FB /* RulesWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = CD8FD5F323C05AD800EFE0FB /* RulesWindowController.m */; };
|
||||
CD8FD5FA23C05AD900EFE0FB /* Rules.xib in Resources */ = {isa = PBXBuildFile; fileRef = CD8FD5F523C05AD900EFE0FB /* Rules.xib */; };
|
||||
CDA88A792537CE2400C469BF /* Sentry.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = CD21501B20AD2EE000CEF17B /* Sentry.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
CDB009A429483A4300945F07 /* OverSight Installer.app in Resources */ = {isa = PBXBuildFile; fileRef = CDB009A329483A4300945F07 /* OverSight Installer.app */; };
|
||||
CDC6098E263CB7EB006D1332 /* LogMonitor.m in Sources */ = {isa = PBXBuildFile; fileRef = CDC6098D263CB7EB006D1332 /* LogMonitor.m */; };
|
||||
CDC60991263CBD36006D1332 /* AVMonitor.m in Sources */ = {isa = PBXBuildFile; fileRef = CDC60990263CBD36006D1332 /* AVMonitor.m */; };
|
||||
CDC60994263CBEE7006D1332 /* Client.m in Sources */ = {isa = PBXBuildFile; fileRef = CDC60993263CBEE7006D1332 /* Client.m */; };
|
||||
|
@ -90,7 +89,6 @@
|
|||
CD8FD5F223C05AD800EFE0FB /* RuleRowCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RuleRowCell.m; sourceTree = "<group>"; };
|
||||
CD8FD5F323C05AD800EFE0FB /* RulesWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RulesWindowController.m; sourceTree = "<group>"; };
|
||||
CD8FD5F523C05AD900EFE0FB /* Rules.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = Rules.xib; sourceTree = "<group>"; };
|
||||
CDB009A329483A4300945F07 /* OverSight Installer.app */ = {isa = PBXFileReference; lastKnownFileType = wrapper.application; path = "OverSight Installer.app"; sourceTree = "<group>"; };
|
||||
CDC6098C263CB7EB006D1332 /* LogMonitor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LogMonitor.h; sourceTree = "<group>"; };
|
||||
CDC6098D263CB7EB006D1332 /* LogMonitor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LogMonitor.m; sourceTree = "<group>"; };
|
||||
CDC6098F263CBD36006D1332 /* AVMonitor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AVMonitor.h; sourceTree = "<group>"; };
|
||||
|
@ -218,7 +216,6 @@
|
|||
CDE09AF12919829000561CFF /* Uninstaller */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
CDB009A329483A4300945F07 /* OverSight Installer.app */,
|
||||
);
|
||||
path = Uninstaller;
|
||||
sourceTree = "<group>";
|
||||
|
@ -296,7 +293,6 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
CD8FD5D523BAE2D200EFE0FB /* Preferences.xib in Resources */,
|
||||
CDB009A429483A4300945F07 /* OverSight Installer.app in Resources */,
|
||||
CD6836682391DB6F00CF19C1 /* security.plist in Resources */,
|
||||
CD2F800C24455333009C3D77 /* AboutWindow.xib in Resources */,
|
||||
7D16D6951F64E43300DB3161 /* UpdateWindow.xib in Resources */,
|
||||
|
@ -469,7 +465,7 @@
|
|||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = NO;
|
||||
CODE_SIGN_IDENTITY = "Developer ID Application";
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 2.1.5;
|
||||
CURRENT_PROJECT_VERSION = 2.1.6;
|
||||
DEVELOPMENT_TEAM = VBG97UB4TA;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/../Carthage/Build/Mac";
|
||||
|
@ -480,7 +476,7 @@
|
|||
LD_RUNPATH_SEARCH_PATHS = "$(LD_RUNPATH_SEARCH_PATHS_$(IS_MACCATALYST)) @executable_path/../Frameworks";
|
||||
LIBRARY_SEARCH_PATHS = "";
|
||||
MACOSX_DEPLOYMENT_TARGET = 12.0;
|
||||
MARKETING_VERSION = 2.1.5;
|
||||
MARKETING_VERSION = 2.1.6;
|
||||
ONLY_ACTIVE_ARCH = NO;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.objective-see.oversight";
|
||||
PRODUCT_NAME = OverSight;
|
||||
|
@ -495,7 +491,7 @@
|
|||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = NO;
|
||||
CODE_SIGN_IDENTITY = "Developer ID Application";
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 2.1.5;
|
||||
CURRENT_PROJECT_VERSION = 2.1.6;
|
||||
DEVELOPMENT_TEAM = VBG97UB4TA;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/../Carthage/Build/Mac";
|
||||
|
@ -506,7 +502,7 @@
|
|||
LD_RUNPATH_SEARCH_PATHS = "$(LD_RUNPATH_SEARCH_PATHS_$(IS_MACCATALYST)) @executable_path/../Frameworks";
|
||||
LIBRARY_SEARCH_PATHS = "";
|
||||
MACOSX_DEPLOYMENT_TARGET = 12.0;
|
||||
MARKETING_VERSION = 2.1.5;
|
||||
MARKETING_VERSION = 2.1.6;
|
||||
ONLY_ACTIVE_ARCH = NO;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.objective-see.oversight";
|
||||
PRODUCT_NAME = OverSight;
|
||||
|
|
|
@ -43,6 +43,9 @@
|
|||
//initial camera state
|
||||
@property NSControlStateValue initialCameraState;
|
||||
|
||||
//last (camera) pid
|
||||
@property NSInteger lastCameraClient;
|
||||
|
||||
//last mic off
|
||||
@property(nonatomic, retain)AVCaptureDevice* lastMicOff;
|
||||
|
||||
|
|
|
@ -153,179 +153,248 @@ extern os_log_t logHandle;
|
|||
{
|
||||
//dbg msg
|
||||
os_log_debug(logHandle, "starting log monitor for AV events via w/ 'com.apple.SystemStatus'");
|
||||
|
||||
//start logging
|
||||
[self.logMonitor start:[NSPredicate predicateWithFormat:@"subsystem=='com.apple.SystemStatus'"] level:Log_Level_Default callback:^(OSLogEvent* logEvent) {
|
||||
|
||||
//dbg msg
|
||||
os_log_debug(logHandle, "received log message from 'com.apple.SystemStatus': %{public}@", logEvent.composedMessage);
|
||||
//macOS 13.3
|
||||
// use predicate: "subsystem=='com.apple.cmio'" looking for 'CMIOExtensionPropertyDeviceControlPID'
|
||||
if (@available(macOS 13.3, *)) {
|
||||
|
||||
//regex
|
||||
NSRegularExpression* regex = nil;
|
||||
|
||||
//sync to process
|
||||
@synchronized (self) {
|
||||
|
||||
//flags
|
||||
BOOL audioAttributionsList = NO;
|
||||
BOOL cameraAttributionsList = NO;
|
||||
|
||||
//new audio attributions
|
||||
NSMutableArray* newAudioAttributions = nil;
|
||||
|
||||
//new camera attributions
|
||||
NSMutableArray* newCameraAttributions = nil;
|
||||
|
||||
//only interested on "Server data changed..." msgs
|
||||
if(YES != [logEvent.composedMessage containsString:@"Server data changed for media domain"])
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//split on newlines
|
||||
// ...and then parse out audio/camera attributions
|
||||
for(NSString* __strong line in [logEvent.composedMessage componentsSeparatedByString:@"\n"])
|
||||
{
|
||||
//pid
|
||||
NSNumber* pid = 0;
|
||||
|
||||
//trim
|
||||
line = [line stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
|
||||
|
||||
//'audioAttributions' list?
|
||||
if( (YES == [line hasPrefix:@"audioAttributions = "]) ||
|
||||
(YES == [line hasPrefix:@"audioRecordingAttributions = "]) )
|
||||
{
|
||||
//dbg msg
|
||||
os_log_debug(logHandle, "found 'audio attributions'");
|
||||
|
||||
//set flag
|
||||
audioAttributionsList = YES;
|
||||
|
||||
//init
|
||||
newAudioAttributions = [NSMutableArray array];
|
||||
|
||||
//unset (other) list
|
||||
cameraAttributionsList = NO;
|
||||
|
||||
//next
|
||||
continue;
|
||||
}
|
||||
|
||||
//'cameraAttributions' list?
|
||||
if( (YES == [line hasPrefix:@"cameraAttributions = "]) ||
|
||||
(YES == [line hasPrefix:@"cameraCaptureAttributions = "]) )
|
||||
{
|
||||
//dbg msg
|
||||
os_log_debug(logHandle, "found 'camera attributions'");
|
||||
|
||||
//set flag
|
||||
cameraAttributionsList = YES;
|
||||
|
||||
//init
|
||||
newCameraAttributions = [NSMutableArray array];
|
||||
|
||||
//unset (other) list
|
||||
audioAttributionsList = NO;
|
||||
|
||||
//next
|
||||
continue;
|
||||
}
|
||||
|
||||
//audit token of item?
|
||||
if(YES == [line containsString:@"<BSAuditToken:"])
|
||||
{
|
||||
//dbg msg
|
||||
os_log_debug(logHandle, "line has audit token...");
|
||||
|
||||
//pid extraction regex
|
||||
NSRegularExpression* regex = nil;
|
||||
|
||||
//match
|
||||
NSTextCheckingResult* match = nil;
|
||||
|
||||
//init regex
|
||||
regex = [NSRegularExpression regularExpressionWithPattern:@"(?<=PID: )[0-9]*" options:0 error:nil];
|
||||
|
||||
//match/extract pid
|
||||
match = [regex firstMatchInString:line options:0 range:NSMakeRange(0, line.length)];
|
||||
if( (nil == match) ||
|
||||
(NSNotFound == match.range.location))
|
||||
{
|
||||
//dbg msg
|
||||
os_log_debug(logHandle, "no match on regex");
|
||||
|
||||
//ignore
|
||||
continue;
|
||||
}
|
||||
|
||||
//extract pid
|
||||
pid = @([[line substringWithRange:[match rangeAtIndex:0]] intValue]);
|
||||
|
||||
//dbg msg
|
||||
os_log_debug(logHandle, "pid: %@", pid);
|
||||
|
||||
//in audio list?
|
||||
if(YES == audioAttributionsList)
|
||||
{
|
||||
//dbg msg
|
||||
os_log_debug(logHandle, "...for audio");
|
||||
|
||||
//add
|
||||
[newAudioAttributions addObject:[NSNumber numberWithInt:[pid intValue]]];
|
||||
}
|
||||
//in camera list?
|
||||
else if(YES == cameraAttributionsList)
|
||||
{
|
||||
//dbg msg
|
||||
os_log_debug(logHandle, "...for camera");
|
||||
|
||||
//add
|
||||
[newCameraAttributions addObject:[NSNumber numberWithInt:[pid intValue]]];
|
||||
}
|
||||
|
||||
//next
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
//macOS 12: off events trigger the removal of the list
|
||||
// so then we'll just pass in an empty list in that case
|
||||
if(12 == NSProcessInfo.processInfo.operatingSystemVersion.majorVersion)
|
||||
{
|
||||
//nil?
|
||||
if(nil == newAudioAttributions)
|
||||
{
|
||||
//init blank
|
||||
newAudioAttributions = [NSMutableArray array];
|
||||
}
|
||||
|
||||
//nil?
|
||||
if(nil == newCameraAttributions)
|
||||
{
|
||||
//init blank
|
||||
newCameraAttributions = [NSMutableArray array];
|
||||
}
|
||||
}
|
||||
|
||||
//process attibutions
|
||||
[self processAttributions:newAudioAttributions newCameraAttributions:newCameraAttributions];
|
||||
|
||||
}//sync
|
||||
//init regex
|
||||
regex = [NSRegularExpression regularExpressionWithPattern:@"=\\s*(\\d+)\\s*;" options:0 error:nil];
|
||||
|
||||
//(re)enumerate active devices
|
||||
// delayed need as device deactiavation
|
||||
// then update status menu (on main thread)
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^
|
||||
{
|
||||
//update on on main thread
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
//start logging
|
||||
[self.logMonitor start:[NSPredicate predicateWithFormat:@"subsystem=='com.apple.cmio'"] level:Log_Level_Debug callback:^(OSLogEvent* logEvent) {
|
||||
|
||||
//match
|
||||
NSTextCheckingResult* match = nil;
|
||||
|
||||
//update status menu
|
||||
[((AppDelegate*)[[NSApplication sharedApplication] delegate]).statusBarItemController setActiveDevices:[self enumerateActiveDevices]];
|
||||
//pid
|
||||
NSInteger pid = 0;
|
||||
|
||||
//sync to process
|
||||
@synchronized (self) {
|
||||
|
||||
});
|
||||
//only interested on "CMIOExtensionPropertyDeviceControlPID = <pid>;" msgs
|
||||
if(YES != [logEvent.composedMessage containsString:@"CMIOExtensionPropertyDeviceControlPID = "])
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//match on pid
|
||||
match = [regex firstMatchInString:logEvent.composedMessage options:0 range:NSMakeRange(0, logEvent.composedMessage.length)];
|
||||
if( (nil == match) ||
|
||||
(NSNotFound == match.range.location) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//extract/convert pid
|
||||
pid = [[logEvent.composedMessage substringWithRange:[match rangeAtIndex:1]] integerValue];
|
||||
if( (0 == pid) ||
|
||||
(-1 == pid) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//save
|
||||
self.lastCameraClient = pid;
|
||||
|
||||
//(re)enumerate active devices
|
||||
// delayed need as device deactiavation
|
||||
// then update status menu (on main thread)
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^
|
||||
{
|
||||
//update on on main thread
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
|
||||
//update status menu
|
||||
[((AppDelegate*)[[NSApplication sharedApplication] delegate]).statusBarItemController setActiveDevices:[self enumerateActiveDevices]];
|
||||
|
||||
});
|
||||
|
||||
}); //dispatch for delay
|
||||
}
|
||||
|
||||
}); //dispatch for delay
|
||||
}];
|
||||
|
||||
}];
|
||||
|
||||
}
|
||||
|
||||
//previous versions of macoS
|
||||
// use predicate: "subsystem=='com.apple.SystemStatus'"
|
||||
else
|
||||
{
|
||||
//start logging
|
||||
[self.logMonitor start:[NSPredicate predicateWithFormat:@"subsystem=='com.apple.SystemStatus'"] level:Log_Level_Default callback:^(OSLogEvent* logEvent) {
|
||||
|
||||
//sync to process
|
||||
@synchronized (self) {
|
||||
|
||||
//flags
|
||||
BOOL audioAttributionsList = NO;
|
||||
BOOL cameraAttributionsList = NO;
|
||||
|
||||
//new audio attributions
|
||||
NSMutableArray* newAudioAttributions = nil;
|
||||
|
||||
//new camera attributions
|
||||
NSMutableArray* newCameraAttributions = nil;
|
||||
|
||||
//only interested on "Server data changed..." msgs
|
||||
if(YES != [logEvent.composedMessage containsString:@"Server data changed for media domain"])
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//split on newlines
|
||||
// ...and then parse out audio/camera attributions
|
||||
for(NSString* __strong line in [logEvent.composedMessage componentsSeparatedByString:@"\n"])
|
||||
{
|
||||
//pid
|
||||
NSNumber* pid = 0;
|
||||
|
||||
//trim
|
||||
line = [line stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
|
||||
|
||||
//'audioAttributions' list?
|
||||
if( (YES == [line hasPrefix:@"audioAttributions = "]) ||
|
||||
(YES == [line hasPrefix:@"audioRecordingAttributions = "]) )
|
||||
{
|
||||
//dbg msg
|
||||
os_log_debug(logHandle, "found 'audio attributions'");
|
||||
|
||||
//set flag
|
||||
audioAttributionsList = YES;
|
||||
|
||||
//init
|
||||
newAudioAttributions = [NSMutableArray array];
|
||||
|
||||
//unset (other) list
|
||||
cameraAttributionsList = NO;
|
||||
|
||||
//next
|
||||
continue;
|
||||
}
|
||||
|
||||
//'cameraAttributions' list?
|
||||
if( (YES == [line hasPrefix:@"cameraAttributions = "]) ||
|
||||
(YES == [line hasPrefix:@"cameraCaptureAttributions = "]) )
|
||||
{
|
||||
//dbg msg
|
||||
os_log_debug(logHandle, "found 'camera attributions'");
|
||||
|
||||
//set flag
|
||||
cameraAttributionsList = YES;
|
||||
|
||||
//init
|
||||
newCameraAttributions = [NSMutableArray array];
|
||||
|
||||
//unset (other) list
|
||||
audioAttributionsList = NO;
|
||||
|
||||
//next
|
||||
continue;
|
||||
}
|
||||
|
||||
//audit token of item?
|
||||
if(YES == [line containsString:@"<BSAuditToken:"])
|
||||
{
|
||||
//dbg msg
|
||||
os_log_debug(logHandle, "line has audit token...");
|
||||
|
||||
//pid extraction regex
|
||||
NSRegularExpression* regex = nil;
|
||||
|
||||
//match
|
||||
NSTextCheckingResult* match = nil;
|
||||
|
||||
//init regex
|
||||
regex = [NSRegularExpression regularExpressionWithPattern:@"(?<=PID: )[0-9]*" options:0 error:nil];
|
||||
|
||||
//match/extract pid
|
||||
match = [regex firstMatchInString:line options:0 range:NSMakeRange(0, line.length)];
|
||||
if( (nil == match) ||
|
||||
(NSNotFound == match.range.location))
|
||||
{
|
||||
//dbg msg
|
||||
os_log_debug(logHandle, "no match on regex");
|
||||
|
||||
//ignore
|
||||
continue;
|
||||
}
|
||||
|
||||
//extract pid
|
||||
pid = @([[line substringWithRange:[match rangeAtIndex:0]] intValue]);
|
||||
|
||||
//dbg msg
|
||||
os_log_debug(logHandle, "pid: %@", pid);
|
||||
|
||||
//in audio list?
|
||||
if(YES == audioAttributionsList)
|
||||
{
|
||||
//dbg msg
|
||||
os_log_debug(logHandle, "...for audio");
|
||||
|
||||
//add
|
||||
[newAudioAttributions addObject:[NSNumber numberWithInt:[pid intValue]]];
|
||||
}
|
||||
//in camera list?
|
||||
else if(YES == cameraAttributionsList)
|
||||
{
|
||||
//dbg msg
|
||||
os_log_debug(logHandle, "...for camera");
|
||||
|
||||
//add
|
||||
[newCameraAttributions addObject:[NSNumber numberWithInt:[pid intValue]]];
|
||||
}
|
||||
|
||||
//next
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
//macOS 12: off events trigger the removal of the list
|
||||
// so then we'll just pass in an empty list in that case
|
||||
if(12 == NSProcessInfo.processInfo.operatingSystemVersion.majorVersion)
|
||||
{
|
||||
//nil?
|
||||
if(nil == newAudioAttributions)
|
||||
{
|
||||
//init blank
|
||||
newAudioAttributions = [NSMutableArray array];
|
||||
}
|
||||
|
||||
//nil?
|
||||
if(nil == newCameraAttributions)
|
||||
{
|
||||
//init blank
|
||||
newCameraAttributions = [NSMutableArray array];
|
||||
}
|
||||
}
|
||||
|
||||
//process attibutions
|
||||
[self processAttributions:newAudioAttributions newCameraAttributions:newCameraAttributions];
|
||||
|
||||
}//sync
|
||||
|
||||
//(re)enumerate active devices
|
||||
// delayed need as device deactiavation
|
||||
// then update status menu (on main thread)
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^
|
||||
{
|
||||
//update on on main thread
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
|
||||
//update status menu
|
||||
[((AppDelegate*)[[NSApplication sharedApplication] delegate]).statusBarItemController setActiveDevices:[self enumerateActiveDevices]];
|
||||
|
||||
});
|
||||
|
||||
}); //dispatch for delay
|
||||
}];
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -502,7 +571,7 @@ extern os_log_t logHandle;
|
|||
self.cameraEventTimer = nil;
|
||||
|
||||
//camera off?
|
||||
// sent event
|
||||
// send event
|
||||
if(0 == cameraDifferences.insertions.count)
|
||||
{
|
||||
//dbg msg
|
||||
|
@ -626,6 +695,9 @@ extern os_log_t logHandle;
|
|||
{
|
||||
//state
|
||||
NSInteger state = -1;
|
||||
|
||||
//event
|
||||
__block Event* event = nil;
|
||||
|
||||
//get state
|
||||
state = [self getMicState:device];
|
||||
|
@ -639,6 +711,69 @@ extern os_log_t logHandle;
|
|||
//save
|
||||
self.lastMicOff = device;
|
||||
}
|
||||
|
||||
//macOS 13.3
|
||||
// use this as trigger
|
||||
if (@available(macOS 13.3, *)) {
|
||||
|
||||
//dbg msg
|
||||
os_log_debug(logHandle, "new audio event");
|
||||
|
||||
//cancel prev timer
|
||||
if(nil != self.audioEventTimer)
|
||||
{
|
||||
//cancel
|
||||
dispatch_cancel(self.audioEventTimer);
|
||||
self.audioEventTimer = nil;
|
||||
}
|
||||
|
||||
//re-init timer
|
||||
self.audioEventTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, self.audioEventQueue);
|
||||
dispatch_source_set_timer(self.audioEventTimer, dispatch_walltime(NULL, 0.5 * NSEC_PER_SEC), DISPATCH_TIME_FOREVER, 0.1 * NSEC_PER_SEC);
|
||||
|
||||
//set handler
|
||||
dispatch_source_set_event_handler(self.audioEventTimer, ^{
|
||||
|
||||
//canel timer
|
||||
dispatch_cancel(self.audioEventTimer);
|
||||
self.audioEventTimer = nil;
|
||||
|
||||
//audio off?
|
||||
// send event
|
||||
if(NSControlStateValueOff == state)
|
||||
{
|
||||
//dbg msg
|
||||
os_log_debug(logHandle, "audio event: off");
|
||||
|
||||
//init event
|
||||
// process (client) and device are nil
|
||||
event = [[Event alloc] init:nil device:nil deviceType:Device_Microphone state:NSControlStateValueOff];
|
||||
|
||||
//handle event
|
||||
[self handleEvent:event];
|
||||
}
|
||||
|
||||
//audio on?
|
||||
// send event
|
||||
else if(NSControlStateValueOn == state)
|
||||
{
|
||||
//dbg msg
|
||||
os_log_debug(logHandle, "audio event: on");
|
||||
|
||||
//init event
|
||||
// devivce is nil
|
||||
event = [[Event alloc] init:nil device:nil deviceType:Device_Microphone state:NSControlStateValueOn];
|
||||
|
||||
//handle event
|
||||
[self handleEvent:event];
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
//start audio event timer
|
||||
dispatch_resume(self.audioEventTimer);
|
||||
|
||||
} //macOS 13.3
|
||||
};
|
||||
|
||||
//add property listener for audio changes
|
||||
|
@ -712,6 +847,79 @@ bail:
|
|||
//save
|
||||
self.lastCameraOff = device;
|
||||
}
|
||||
|
||||
//camera on?
|
||||
// macOS 13.3, use this as trigger
|
||||
if (@available(macOS 13.3, *)) {
|
||||
|
||||
//event
|
||||
__block Event* event = nil;
|
||||
|
||||
//dbg msg
|
||||
os_log_debug(logHandle, "new camera event");
|
||||
|
||||
//camera: on
|
||||
if(NSControlStateValueOn == state)
|
||||
{
|
||||
//dbg msg
|
||||
os_log_debug(logHandle, "camera event: on");
|
||||
|
||||
//cancel prev timer
|
||||
if(nil != self.cameraEventTimer)
|
||||
{
|
||||
//cancel
|
||||
dispatch_cancel(self.cameraEventTimer);
|
||||
self.cameraEventTimer = nil;
|
||||
}
|
||||
|
||||
//re-init timer
|
||||
self.cameraEventTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, self.cameraEventQueue);
|
||||
dispatch_source_set_timer(self.cameraEventTimer, dispatch_walltime(NULL, 1.0 * NSEC_PER_SEC), DISPATCH_TIME_FOREVER, 0.1 * NSEC_PER_SEC);
|
||||
|
||||
//set handler
|
||||
dispatch_source_set_event_handler(self.cameraEventTimer, ^{
|
||||
|
||||
//client
|
||||
Client* client = nil;
|
||||
|
||||
//init client from attribution
|
||||
client = [[Client alloc] init];
|
||||
client.pid = [NSNumber numberWithInteger:self.lastCameraClient];
|
||||
client.path = valueForStringItem(getProcessPath(client.pid.intValue));
|
||||
client.name = valueForStringItem(getProcessName(client.path));
|
||||
|
||||
//canel timer
|
||||
dispatch_cancel(self.cameraEventTimer);
|
||||
self.cameraEventTimer = nil;
|
||||
|
||||
//init event
|
||||
// with client and (active) camera
|
||||
event = [[Event alloc] init:client device:device deviceType:Device_Camera state:NSControlStateValueOn];
|
||||
|
||||
//handle event
|
||||
[self handleEvent:event];
|
||||
|
||||
});
|
||||
|
||||
//start camera timer
|
||||
dispatch_resume(self.cameraEventTimer);
|
||||
}
|
||||
|
||||
//camera: off
|
||||
else if(NSControlStateValueOff == state)
|
||||
{
|
||||
//dbg msg
|
||||
os_log_debug(logHandle, "camera event: off");
|
||||
|
||||
//init event
|
||||
// process (client) and device are nil
|
||||
event = [[Event alloc] init:nil device:nil deviceType:Device_Camera state:NSControlStateValueOff];
|
||||
|
||||
//handle event
|
||||
[self handleEvent:event];
|
||||
}
|
||||
|
||||
} //macOS 13.3
|
||||
};
|
||||
|
||||
//register (add) property block listener
|
||||
|
@ -897,7 +1105,6 @@ bail:
|
|||
return objectID;
|
||||
}
|
||||
|
||||
|
||||
//determine if audio device is active
|
||||
-(UInt32)getMicState:(AVCaptureDevice*)device;
|
||||
{
|
||||
|
@ -1086,37 +1293,39 @@ bail:
|
|||
|
||||
} //PREF_NO_EXTERNAL_DEVICES_MODE
|
||||
|
||||
//(new) mic event?
|
||||
// need extra logic, since macOS sometimes toggles / delivers 2x events :/
|
||||
if(Device_Microphone == event.deviceType)
|
||||
//macOS sometimes toggles / delivers 2x events for same device
|
||||
if(deviceLastEvent.deviceType == event.deviceType)
|
||||
{
|
||||
//ignore if mic's last event was <0.5
|
||||
//ignore if last event was < 0.5 ago
|
||||
if([event.timestamp timeIntervalSinceDate:deviceLastEvent.timestamp] < 0.5f)
|
||||
{
|
||||
//set result
|
||||
result = NOTIFICATION_SPURIOUS;
|
||||
|
||||
//dbg msg
|
||||
os_log_debug(logHandle, "ignoring mic event, as it happened <0.5s ago");
|
||||
os_log_debug(logHandle, "ignoring event, as it happened <0.5s ago");
|
||||
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//ignore if mic's last event was same state
|
||||
//ignore if last event was same state
|
||||
if( (deviceLastEvent.state == event.state) &&
|
||||
([event.timestamp timeIntervalSinceDate:deviceLastEvent.timestamp] < 2.0f) )
|
||||
{
|
||||
|
||||
//set result
|
||||
result = NOTIFICATION_SPURIOUS;
|
||||
|
||||
//dbg msg
|
||||
os_log_debug(logHandle, "ignoring mic event as it was same state as last (%ld), and happened <2.0s ago", (long)event.state);
|
||||
os_log_debug(logHandle, "ignoring event as it was same state as last (%ld), and happened <2.0s ago", (long)event.state);
|
||||
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
}
|
||||
|
||||
} //same device
|
||||
|
||||
|
||||
//client provided?
|
||||
// check if its allowed
|
||||
|
|
|
@ -184,17 +184,30 @@ bail:
|
|||
{
|
||||
//dbg msg
|
||||
os_log_debug(logHandle, "method '%s' invoked from (hasVisibleWindows: %d)", __PRETTY_FUNCTION__, hasVisibleWindows);
|
||||
|
||||
//no visible window(s)
|
||||
// and not invoked via notification
|
||||
// default to show preferences window
|
||||
if( (YES != hasVisibleWindows) &&
|
||||
(nil != avMonitor.lastNotificationDefaultAction) &&
|
||||
(fabs([avMonitor.lastNotificationDefaultAction timeIntervalSinceNow]) > 1) )
|
||||
|
||||
//already shown?
|
||||
// nothing to do, bail
|
||||
if(YES == hasVisibleWindows)
|
||||
{
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//no notifications
|
||||
// show preferences window
|
||||
if(nil == avMonitor.lastNotificationDefaultAction)
|
||||
{
|
||||
//show prefs
|
||||
[self showPreferences:nil];
|
||||
}
|
||||
//had notifications
|
||||
// if more than one second, show preferences window
|
||||
else if(fabs([avMonitor.lastNotificationDefaultAction timeIntervalSinceNow]) > 1)
|
||||
{
|
||||
//show prefs
|
||||
[self showPreferences:nil];
|
||||
}
|
||||
|
||||
bail:
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
|
2
Cartfile
2
Cartfile
|
@ -1 +1 @@
|
|||
github "getsentry/sentry-cocoa" "6.0.10"
|
||||
github "getsentry/sentry-cocoa" "8.3.3"
|
||||
|
|
|
@ -1 +1 @@
|
|||
github "getsentry/sentry-cocoa" "6.0.0"
|
||||
github "getsentry/sentry-cocoa" "8.3.3"
|
||||
|
|
|
@ -333,7 +333,7 @@
|
|||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "#Note: To build uninstaller for app (menu)\n# 1. Delete this script and build installer\n# 2. *Copy* into App \"Uninstaller\" folder\n# 3. Re-add script, and archive for deployment\n\n#archive\n# copy in main application \nif [[ $BUILT_PRODUCTS_DIR = *\"ArchiveIntermediates\"* ]]; then\n cp -R -f \"$PROJECT_TEMP_ROOT/UninstalledProducts/macosx/OverSight.app\" \"$BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Resources\"\n \n#normal build\n# delete and copy in main application \nelse\n\nrm -rf \"$BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Resources/OverSight.app\"\ncp -R -f \"$BUILT_PRODUCTS_DIR/OverSight.app\" \"$BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Resources\"\n\nfi\n\n\n";
|
||||
shellScript = "#Note: To build uninstaller for app (menu)\n# 0. Delete this script and Installer.app from App's project\n# 1. Build installer\n# 2. *Copy* into App \"Uninstaller\" folder\n# 3. Re-add script, and archive for deployment\n\n#archive\n# copy in main application \nif [[ $BUILT_PRODUCTS_DIR = *\"ArchiveIntermediates\"* ]]; then\n cp -R -f \"$PROJECT_TEMP_ROOT/UninstalledProducts/macosx/OverSight.app\" \"$BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Resources\"\n \n#normal build\n# delete and copy in main application \nelse\n\nrm -rf \"$BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Resources/OverSight.app\"\ncp -R -f \"$BUILT_PRODUCTS_DIR/OverSight.app\" \"$BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Resources\"\n\nfi\n\n\n\n\n";
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
|
@ -384,14 +384,14 @@
|
|||
CODE_SIGN_ENTITLEMENTS = "";
|
||||
CODE_SIGN_IDENTITY = "Developer ID Application";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CURRENT_PROJECT_VERSION = 2.1.5;
|
||||
CURRENT_PROJECT_VERSION = 2.1.6;
|
||||
DEVELOPMENT_TEAM = VBG97UB4TA;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/../Carthage/Build/Mac";
|
||||
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = NO;
|
||||
INFOPLIST_FILE = Helper/Info.plist;
|
||||
MACOSX_DEPLOYMENT_TARGET = 12.0;
|
||||
MARKETING_VERSION = 2.1.5;
|
||||
MARKETING_VERSION = 2.1.6;
|
||||
ONLY_ACTIVE_ARCH = NO;
|
||||
OTHER_CODE_SIGN_FLAGS = "";
|
||||
OTHER_LDFLAGS = (
|
||||
|
@ -419,14 +419,14 @@
|
|||
CODE_SIGN_ENTITLEMENTS = "";
|
||||
CODE_SIGN_IDENTITY = "Developer ID Application";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CURRENT_PROJECT_VERSION = 2.1.5;
|
||||
CURRENT_PROJECT_VERSION = 2.1.6;
|
||||
DEVELOPMENT_TEAM = VBG97UB4TA;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/../Carthage/Build/Mac";
|
||||
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = NO;
|
||||
INFOPLIST_FILE = Helper/Info.plist;
|
||||
MACOSX_DEPLOYMENT_TARGET = 12.0;
|
||||
MARKETING_VERSION = 2.1.5;
|
||||
MARKETING_VERSION = 2.1.6;
|
||||
ONLY_ACTIVE_ARCH = NO;
|
||||
OTHER_CODE_SIGN_FLAGS = "";
|
||||
OTHER_LDFLAGS = (
|
||||
|
@ -455,7 +455,7 @@
|
|||
CODE_SIGN_IDENTITY = "Developer ID Application";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 2.1.5;
|
||||
CURRENT_PROJECT_VERSION = 2.1.6;
|
||||
DEVELOPMENT_TEAM = VBG97UB4TA;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/../Carthage/Build/Mac";
|
||||
|
@ -467,7 +467,7 @@
|
|||
);
|
||||
LIBRARY_SEARCH_PATHS = "";
|
||||
MACOSX_DEPLOYMENT_TARGET = 12.0;
|
||||
MARKETING_VERSION = 2.1.5;
|
||||
MARKETING_VERSION = 2.1.6;
|
||||
OTHER_CODE_SIGN_FLAGS = "";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.objective-see.oversight.installer";
|
||||
PRODUCT_NAME = "OverSight Installer";
|
||||
|
@ -484,7 +484,7 @@
|
|||
CODE_SIGN_IDENTITY = "Developer ID Application";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 2.1.5;
|
||||
CURRENT_PROJECT_VERSION = 2.1.6;
|
||||
DEVELOPMENT_TEAM = VBG97UB4TA;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/../Carthage/Build/Mac";
|
||||
|
@ -496,7 +496,7 @@
|
|||
);
|
||||
LIBRARY_SEARCH_PATHS = "";
|
||||
MACOSX_DEPLOYMENT_TARGET = 12.0;
|
||||
MARKETING_VERSION = 2.1.5;
|
||||
MARKETING_VERSION = 2.1.6;
|
||||
OTHER_CODE_SIGN_FLAGS = "";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.objective-see.oversight.installer";
|
||||
PRODUCT_NAME = "OverSight Installer";
|
||||
|
|
|
@ -1,105 +0,0 @@
|
|||
//
|
||||
// file: UserClientShared.h
|
||||
// project: lulu (shared)
|
||||
// description: dispatch selectors and data structs shared between user and kernel mode
|
||||
//
|
||||
// created by Patrick Wardle
|
||||
// copyright (c) 2017 Objective-See. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef userClientShared_h
|
||||
#define userClientShared_h
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined (KERNEL)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <sys/proc.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
#if defined (KERNEL)
|
||||
}
|
||||
#endif
|
||||
|
||||
//user client method dispatch selectors.
|
||||
enum dispatchSelectors {
|
||||
|
||||
kTestUserClientEnable,
|
||||
kTestUserClientDisable,
|
||||
kTestUserClientAddRule,
|
||||
kTestUserClientRemoveRule,
|
||||
kTestUserClientMethodCount
|
||||
};
|
||||
|
||||
//type
|
||||
struct genericEvent_s
|
||||
{
|
||||
//type
|
||||
UInt32 type;
|
||||
};
|
||||
|
||||
//network out event struct
|
||||
struct networkOutEvent_s {
|
||||
|
||||
//type
|
||||
UInt32 type;
|
||||
|
||||
//process pid
|
||||
UInt32 pid;
|
||||
|
||||
//socket type
|
||||
int socketType;
|
||||
|
||||
//local socket address
|
||||
struct sockaddr_in6 localAddress;
|
||||
|
||||
//remote socket address
|
||||
struct sockaddr_in6 remoteAddress;
|
||||
};
|
||||
|
||||
//dns response out event struct
|
||||
struct dnsResponseEvent_s {
|
||||
|
||||
//type
|
||||
UInt32 type;
|
||||
|
||||
//response
|
||||
unsigned char response[512];
|
||||
};
|
||||
|
||||
//firewall event union
|
||||
// holds various structs, but max size will be 'padding'
|
||||
typedef union
|
||||
{
|
||||
//generic event
|
||||
struct genericEvent_s genericEvent;
|
||||
|
||||
//network out event
|
||||
struct networkOutEvent_s networkOutEvent;
|
||||
|
||||
//dns response event
|
||||
struct dnsResponseEvent_s dnsResponseEvent;
|
||||
|
||||
//padding
|
||||
unsigned char padding[sizeof(UInt32) + 512];
|
||||
|
||||
} firewallEvent;
|
||||
|
||||
//dns header struct
|
||||
// from: http://www.nersc.gov/~scottc/software/snort/dns_head.html
|
||||
#pragma pack(push,1)
|
||||
struct dnsHeader {
|
||||
unsigned short id;
|
||||
unsigned short flags;
|
||||
unsigned short qdcount;
|
||||
unsigned short ancount;
|
||||
unsigned short nscount;
|
||||
unsigned short arcount;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue