Hi,
I’m required to identify file content type (e.g. - tell you that a file is in PDF format, even if the user forced its name to end with .docX, .txt, or even removed it altogether. In other words - identify file type by its real contents. I need to do this fast, for lots of files.
I searched in vain through the MacOS different APIs/Frameworks, from LaunchServices, via MDLS, NSWorkspace, NSURL, and NSFileManager — to no avail. These all provide wonderful APIs for identifying file types - but miserably report the file type as “Microsoft Word” if its filename extension has been set to “.doc” or “.docx”, no matter the content.
I then found the ‘file’ command-line in Terminal which does EXACTLY what I want, and reports the correct type every time (well maybe it fails somethings, but I haven’t seen it fail once so far.)
Reading ‘man file’ I leaned that it examines a file in 3 stages. stat(2) to start with (identifying Unix things like pipes, sockets, symbolic links etc.) then, it works using some 'unix style' thing called “magic number” mechanism, that employs a “compiled magic file” /usr/share/file/magic.mgc containing “binary signatures” or special “magic numbers” at known offsets that allow quick identification of file formats.
Tiny hacking into this file using ’strings’ command I found a rather huge list of formats identifiable by MacOS out of the box - plus - according to man page of file , you should be able to add more “magic” files yourself!
However, I wouldn't want to spawn a 'file' command process every time I need to identify a file. I'd rather call some code, or framework from within my process. (This process is of high sensitivity - it is an "Endpoint Security Client" and has lots of restrictions.
Is there any public API (Cocoa, Unix, Posix, Core-Foundation, anything!) that will use this "Magic" mechanism to tell me the type of a file?
Thank you very much.
Post not yet marked as solved
Hi, I have a LaunchAgent (whose .plist is in /Library/LaunchAgents/ as expected)
It is build as a single un-bundled binary, and installed away from regular user access at /Library/MyCompany/executables/
When I try to init a reference to UNUserNotificationCenter:
UNUserNotificationCenter *unc = [UNUserNotificationCenter currentNotificationCenter];
I immediately have an exception, like thus:
2021-05-02 19:57:39.297823+0300 agent[12504:225879] *** Assertion failure in +[UNUserNotificationCenter currentNotificationCenter], /AppleInternal/BuildRoot/Library/Caches/com.apple.xbs/Sources/UserNotifications/UserNotifications-281.6/UNUserNotificationCenter.m:44
2021-05-02 19:57:39.299464+0300 agent[12504:225879] [General] An uncaught exception was raised
2021-05-02 19:57:39.299518+0300 agent[12504:225879] [General] bundleProxyForCurrentProcess is nil: mainBundle.bundleURL file:///Users/mshneor/Library/Developer/Xcode/DerivedData/agent-dgvdlbtivmsjdgdkhhjwaxgrkyht/Build/Products/Debug/
Obviously the problem is bundleProxyForCurrentProcess is nil: mainBundle.bundleURL
Now... I could try to bundle my agent somehow, but that's a bit awkward, and I don't know how - it's not an App, and It's not a part of any App, and I don't know about a special "Code Bundle" type (like plugins etc.) that fits a LaunchAgent. Moreover - it will never be "launched" by it's info.plist in the bundle - only via the .plist in /Library/LaunchAgents by launchd.
So... is it possible to work around this? Could I somehow tell my Agent's process "Here is our main-bundle" at runtime, and provide a special bundle the agent is not embedded in?
what does UNUserNotificationCenter need from main bundle? maybe I can supply this programmatically in advance?
Any hint will be greatly appreciated.
Post not yet marked as solved
Hi.
I'm writing a framework, and invest a lot in commenting classes, methods, etc. My API is Objective-C, but the issue is same with Swift code too.
If I follow Apple's documentation about the Markup language of code-comments, then in Xcode QuickHelp lot of my formatting simply does not show.
Here are Apple docs on the matter
Here is a sample of class definition comment,
/*!
@brief Comprehensive set of prevention rules.
@discussion OITPreventionSettings instance encapsulates a complete set of prevention "rules" dictated and provided by Backend, controlling the behavior of ITProtector.
At any moment, there can only be a single "ruling" instance of OITPreventionSettings, assigned (synchronously and atomically) to the OITPrevention, while other instances may exist in other states of initialization/demise.
Responsibilities of the class:
* Receive and store a "Settings JSON" from backend (either as File, String or NSDictionary)
* Parse the settings JSON, extract relevant policy clauses, parse their array of prevention rules
* Provide comprehensive parsing errors if rules cannot be applied.
* Compile and own a hierarchy of OITPreventionPolicy and OITPreventionRule objects, with internal representation of the rules, that can be used to fast-decide authorization/prevention events.
* Apply rules to Endpoint-Security event, returning both verdict (actions bit-mask), and the rule-Id responsible for the decision.
Irresponsibilities of the class:
* to decide *when* to become the "active" settings
* to apply itself and evaluate ES events
* Being immutable, It can't change its policies and rules nor their internal representations. Any change of settings require a new instance of OITPreventionSettings.
*/
@interface OITPreventionSettings : NSObject {
}
As you can see in the attached Xcode quick-help window screenshot
, none of the lists appear as lists, and even line-breaks don't apply.
Many other formatting rules don't show either. Is this Apple bug? my misunderstanding? what's the point in documenting something that doesn't and actually never worked?
I apologize for attempting this monstrosity, but... It is forced on me.
I have a .jar implementing logic that I receive prebuilt. This .jar exports some API you can use (... in Java...) to request information about file-system items you hand in as paths.
This .jar is compatible with Java 11, and runs with the "Zulu" Java VM.
I need to "wrap" it in some way that will behave like a global daemon, launched and managed by launchd, available to other components (apps, user-agents and global-daemons) in our product.
Running it as a global daemon is a breeze - simply place a .plist in /Library/LaunchDaemons/myMonster.plist and have the java -jar <path to my .jar> arguments, throw in a 'keep alive' option, and it runs.
Now... It makes sense for other components to pass it "queries" and receive "results" via XPC connection. First, because this way I could deny connection to unknown components, I could have a secure connection, and also integrate nicely from the other components ObjC code.
However... XPC isn't something available in JDK, and the actual executable launched is the Zulu java command binary of course, that I can't modify.
So... I tried to use JNA (Java Native Access) and (with much tears and sweat) get my java code to create an xpc connection (as client! not "service") to another XPC Service already running.
Also, I was only able to do it via xpc.h (the old C API. not ObjC NSXPCConnection as of yet).
The documentation on old C-style XPC Services is very thin, almost nothing... and the only thing about Creating an XPC Service of this style says:
// If you are writing a low-level (C-based) XPC service, implement a minimal main function to register your event handler, as shown in the following code listing. Replace my_event_handler with the name of your event handler function.
int main(int argc, const char *argv[]) {
xpc_main(my_event_handler);
// The xpc_main() function never returns.
exit(EXIT_FAILURE);
}
Which of course, I can't do! I don't control the process 'main()' entry point (it's java...) and I can't block anything.
So here's my question:
Where in the lifecycle of a Java program can I call on my native code to set up The XPC Service?
Is there a non-blocking alternative to xpc_main(my_event_handler) I can use to start my service?
I know this calls for multi-disciplinary knowledge but any hint or idea will be greatly appreciated.
Thanks!
Post not yet marked as solved
Hi.
I'm implementing UNUserNotificationCenter delegate method:
userNotificationCenter(_:didReceive:withCompletionHandler:)
in MacOS Big-Sur and Catalina, in order to be notified when user dismisses local notifications of my App. (we also handle UNNotificationDefaultActionIdentifier to focus our UI on the item related to the clicked notification, and we also support 2 custom actionIDs.
It all basically works, and even the UNNotificationDismissActionIdentifier arrives at the delegate when user dismisses a single notification. (presses the X shaped button on the top-left).
However, when we have a thread of notifications (grouped by some unique threadID, and looks like a stack onscreen) and the user presses the X and then the "Clear all" button to dismiss the whole thread --
the delegate is only called once, for one arbitrary notification in the stack, and there is no way for me to know that a whole thread was dismissed.
Am I doing something wrong?
Is this a limitation of the delegate protocol?
Is this a bug in UNUserNotificationCenter implementation?
Is there a workaround, or some trick to know that a whole bunch of notifications were dismissed?
Here's my delegate code (sans irrelevant code...)
// Handle notification back-actions
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
didReceiveNotificationResponse:(nonnull UNNotificationResponse *)response
withCompletionHandler:(nonnull void (^)(void))completionHandler API_AVAILABLE(macos(10.14)) {
NSString *actionId = response.actionIdentifier;
UNNotificationRequest *request = response.notification.request;
NSString *requestId = request.identifier;
NSString *userActionIdentifier = request.content.threadIdentifier;
NSDictionary * myInfo = request.content.userInfo;
if ([actionId isEqualToString:UNNotificationDefaultActionIdentifier]) { // user opened the application from the notification
if ([self.delegate respondsToSelector:@selector(displayThread:forInfo)]) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.delegate displayThread:userActionIdentifier forInfo: myInfo];
});
}
completionHandler();
return;
}
NSString *userReply = nil;
if ([actionId isEqualToString:UNNotificationDismissActionIdentifier]) { // user dismissed the notification
os_log_debug(myLog, "Notification: %{public}@ dismissed", requestId);
}
else { // custom action
NSString *categoryId = response.notification.request.content.categoryIdentifier;
if ([categoryId isEqualToString:OITNotification.copyAction]) {
os_log_debug(myLog, "Notification: %{public}@ dismissed with custom action:%{public}@", requestId, actionId);
}
if ([categoryId isEqualToString:OITPreventionNotification.copyActionWithReply]) {
if ([actionId isEqualToString:@"other"]) {
userReply = [(UNTextInputNotificationResponse*)response userText];
os_log_debug(myLog, "Notification: %{public}@ User custom reply: %{public}@", requestId, userReply);
}
else {
userReply = actionId;
os_log_debug(myLog, "Notification: %{public}@ User Action: %{public}@", requestId, actionId);
}
}
}
if ([self.delegate respondsToSelector:@selector(notification:dismissedWithReply:)]) {
[self.delegate notification:myInfo dismissedWithReply:userReply];
}
[self removeModelIdentifiers:@[response.notification.request.identifier]];
completionHandler();
return;
}
Please ignore the tedious handling of custom actions - my problem is only with "Clear All" thread dismissals. I bring the code just for completeness, in the hopes that someone sees a fault I can't see ---
Thank you very much.
Post not yet marked as solved
I believe this is a general problem when writing low-level security and monitoring tools.
The EndpointSecurity framework provides lots of information for the events it allows to Monitor (and/or Authorize) but all these are "kernel level" details, that usually don't allow understanding (and aggregating) low-level events according to User Intent
e.g. Saving all attachments of an e-mail message from Apple Mail program to a USB-disk, will create a long series of low-level file-system events, some preliminary (touching and verifying the destination can fit the attachments) some for moving/copying, some for rounding-up, some for indexing those files on the new volume, and so on.
Is it possible to somehow obtain the NSUserActivity object/instance/Identifier related to such low-level event? Is the kernel itself aware of user activities?
Any hint or suggestion or strategy will be greatly appreciated
Post not yet marked as solved
My new EndpointSecurity client code receives event messages of type esmessaget. These contain 3 time values.
struct timespec time;
uint64_t mach_time;
uint64_t deadline;
To interpret the deadline I refer to the mach_time. However, when I wish to log/formet/otherwise-consider the "wall time" where the event was created - I need to translate the timespec into NSDate (hmm... NSTimeInterval?) and I fail to find any documentation or hint about the right way to do so.
What I tried so far looks like this:
NSDate * timestamp = [NSDate dateWithTimeIntervalSince1970:(double)(message->time.tv_sec) + (double)(message->time.tv_sec) / 1E9 ];
which at least mathematically seems reasonable, but I'm not sure this is the right answer, and I don't know anything about the behaviour of timespec, its origin and accuracy, and whether or not it is consistent.
Can anyone shed a little light on the relation between these two time formats?
Thanks!
Post not yet marked as solved
I have a global daemon managed by launchd, whose .plist is installed in /Library/LaunchDaemons).
To be correctly entitled and code-signed so it can communicate with EndpointSecurity framework, its executable resides in a normal Mac App bundle (main() will run as minimal UI when launched from UI, and as a daemon when launched by launchd).
This means that the ProgramArguments.0 in its .plist looks something like
/Library/PrivilegedHelperTools/MyDaemonApp.app/Contents/MacOS/MyDaemonApp
Now I need this daemon to publish an XPC Service (with few control commands) so that other components of our system (UI app, a user-context launchd-daemon and another launchd global-daemon) will be able to connect to The XPC Service and control it via the published protocol.
I read some answers here, and also found a working order sample code that does just this here - https://github.com/jdspoone/SampleOSXLaunchDaemon
But when I apply its content to my global daemon, word for word - it doesn't work - meaning, clients cannot create a connection to The XPC Service.
The daemon is up and running, and functional. its .plist is quite simple and looks like this:
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.mycompany.itm.service</string>
<key>KeepAlive</key>
<true/>
<key>RunAtLoad</key>
<true/>
<key>MachServices</key>
<dict>
<key>com.mycompany.itm.service</key>
<true/>
</dict>
<key>ProgramArguments</key>
<array>
<string>/Library/PrivilegedHelperTools/IMyDaemonApp.app/Contents/MacOS/MyDaemonApp</string>
<string>-monitor</string>
<string>-protectDeviceProtocol</string>
<string>USB</string>
</array>
</dict>
</plist>
It creates and starts an XPC listener in MYXPCListener.h like thus:
#import <Foundation/Foundation.h>
#import "MYXPCProtocol.h"
NS_ASSUME_NONNULL_BEGIN
@interface OITPreventionXPCService : NSObject (instancetype) init;
(void) start; /* Begin listening for incoming XPC connections */
(void) stop; /* Stop listening for incoming XPC connections */
@end
NS_ASSUME_NONNULL_END
and the implementation is:
/* AppDelegate.m */
@interface MYXPCService () <NSXPCListenerDelegate, OITPreventionXPCProtocol>
@property (nonatomic, strong, readwrite) NSXPCListener *listener;
@property (nonatomic, readwrite) BOOL started;
@end
@implementation OITPreventionXPCService (instancetype) init {
if ((self = [super init]) != nil) {
_listener = [[NSXPCListener alloc] initWithMachServiceName:@"com.mycompany.itm.service"];
_listener.delegate = self;
if (_listener == nil) {
os_log_error(myLog, "XPCListener failed to initialize");
}
_started = NO;
}
return self;
} (void) start {
assert(_started == NO);
[_listener resume];
os_log_info(myLog, "XPCListener resumed");
_started = YES;
} (void) stop {
assert(_started == YES);
[_listener suspend];
os_log_info(myLog, "XPCListener suspended");
_started = NO;
}
/* NSXPCListenerDelegate implementation */
(BOOL) listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection {
os_log_info(myLog, "Prevention XPCListener is bequsted a new connection");
assert(listener == _listener);
assert(newConnection != nil);
newConnection.exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(MYXPCProtocol)];
newConnection.exportedObject = self;
		[newConnection resume];
return YES;
}
/* Further down this implementation, I have implementations to all the methods in MYXPCProtocol. */
@end
Now the client code (and I tried EVERY kind of client, signed unsigned, daemon, UI, root privileged, or user-scoped - whatever). For example, in the AppDelegate of a UI app:
#import "AppDelegate.h"
#import "MYXPCProtocol.h"
@interface AppDelegate ()
@property (strong) IBOutlet NSWindow *window;
@property (nonatomic, strong, readwrite) NSXPCConnection *connection; /* lazy initialized */
@end
@implementation AppDelegate (NSXPCConnection *) connection
{
if (_connection == nil) {
_connection = [[NSXPCConnection alloc] initWithMachServiceName:daemonLabel options:NSXPCConnectionPrivileged];
_connection.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol(MYXPCProtocol)];
_connection.invalidationHandler = ^{
self->_connection = nil;
NSLog(@"connection has been invalidated");
};
[_connection resume]; /* New connections always start suspended */
}
return _connection;
}
(IBAction) getServiceStatus:(id)sender
{
[self.connection.remoteObjectProxy getStatus:^(NSString * _Nonnull status) {
NSLog(@"MY XPC Service status is: %@", status);
}];
}
@end
but no matter what I do - I always get the "connection invalidated".
The sample launchDaemon that works - is not code-signed at all!!! but mine, which is both signed and checking of which yields
$ spctl --assess --verbose IMyDaemonApp.app
IMyDaemonApp.app: accepted
source=Notarized Developer ID
I'm at a loss - and would like to get any advice, or any helpful documentation (I've been reading TN2083, and man launchctl and man launchd.plist and many other pages - to no avail. There seems to be no real "programming guide" for XPC and no reasonable sample code on Apple developer site to fit my needs.
Last - this is MacOS 10.15.7, and latest Xcode 12.3
My agent/service relies on Accessibility APIs. Being installed by IT on all corporate Macs, it receives its permission to use these APIs via a configuration profile installed on the Mac, and not via the System-Preferences Security & Privacy panel (Privacy tab, Accessibility item).
Problem is - if that profile is removed, or changed to remove this permission - The agent currently has no way to know it, and will hang on the next call to some AX API.
our code calls
@result Returns TRUE if the current process is a trusted accessibility client, FALSE if it is not.
*/
extern Boolean AXIsProcessTrustedWithOptions (CFDictionaryRef __nullable options) CF_AVAILABLE_MAC(10_9);
before using other AX APIs, but sadly - the method returns true even when accessibility has been denied by removing the profile.
By contrast - if If user manually un-checks the Accessibility for this agent in the System-Preferences panel - the function returns false immediately.
If after removing the profile, I kill my agent (launchd then relaunches it) - then calling AXIsProcessTrustedWithOptions returns false as expected.
This seems to be a bug of some kind or incomplete behaviour, but I need a workaround as soon as possible.
My first "wish" would be to be able to register for and receive some system-wide NSNotification about "configuration profile changes", at which time, I could decide to exit my agent, and relaunch with accessibility permissions synchronised.
Or is there any AX internal notification I could register for? haven't found any.
Any clue would be greatly appreciated.
Post not yet marked as solved
Hi. I watched the short "Optimize the Core Image pipeline for your video app" session several times, all excited, because it is at least 5 years that CI code-samples for MacOS are nonfunctional, and failed to make them work.
My application (for Microscopy) needs to apply (mostly built-in) CI filters onto live video coming from an external IIDC/DCam camera. My current code is AVFoundation based, but I never managed to apply filters onto the video, and as I said Documentation and code-samples deteriorated to the point of no use.
This beautiful session shows how to create an AVPlayerView and set it up for displaying CI-filtered video - but only for an "asset" (meaning - dead video from disk). How to do it for live "Preview" video?
Also, is it too much to ask for a simple working order modern MacOS sample of CoreImage use?
Thanks!
(BTW I would be glad to move to MTKView instead- have I known how to tie the camera input to it. Again - Docs are unusable, and no reasonable sample exists for MacOS. Not even for the simplest of tasks.