diff --git a/Application/AppDelegate.m b/Application/AppDelegate.m
index c175d01..a9f7a08 100644
--- a/Application/AppDelegate.m
+++ b/Application/AppDelegate.m
@@ -66,7 +66,7 @@ -(void)applicationDidFinishLaunching:(NSNotification *)notification
NSArray* args = NSProcessInfo.processInfo.arguments;
NSMutableDictionary* initialPreferences = [NSMutableDictionary dictionary];
- NSArray* prefKeys = @[PREF_PASSIVE_MODE, PREF_TOUCH_ID_MODE];
+ NSArray* prefKeys = @[PREF_PASSIVE_MODE, PREF_TOUCH_ID_MODE, PREF_APPLE_WATCH_MODE];
//extract set key/value pairs
for(NSString* key in prefKeys) {
diff --git a/Application/Preferences.xib b/Application/Preferences.xib
index 43ef7cc..a4e2122 100644
--- a/Application/Preferences.xib
+++ b/Application/Preferences.xib
@@ -30,7 +30,7 @@
-
+
@@ -84,11 +84,11 @@
-
+
-
+
@@ -108,7 +108,7 @@
-
+
@@ -117,7 +117,7 @@
-
+
@@ -137,7 +137,7 @@
-
+
@@ -145,8 +145,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
@@ -166,7 +195,7 @@
-
+
@@ -175,7 +204,7 @@
-
+
@@ -496,6 +525,15 @@ Install Telegram, create a free bot and paste your token below. Then scan the QR
+
diff --git a/Application/PrefsWindowController.m b/Application/PrefsWindowController.m
index ac819c6..9a569b9 100644
--- a/Application/PrefsWindowController.m
+++ b/Application/PrefsWindowController.m
@@ -50,6 +50,7 @@ @implementation PrefsWindowController
#define BUTTON_NO_REMOTE_ALERTS_MODE 5
#define BUTTON_EXECUTE_ACTION 6
#define BUTTON_NO_UPDATE_MODE 7
+#define BUTTON_APPLE_WATCH_MODE 8
//init 'general' view
// add it, and make it selected
@@ -119,6 +120,7 @@ -(void)showToolbarView:(NSInteger)tag
view = self.modesView;
((NSButton*)[view viewWithTag:BUTTON_NO_ICON_MODE]).state = [self.preferences[PREF_NO_ICON_MODE] boolValue];
+ ((NSButton*)[view viewWithTag:BUTTON_APPLE_WATCH_MODE]).state = [self.preferences[PREF_APPLE_WATCH_MODE] boolValue];
((NSButton*)[view viewWithTag:BUTTON_TOUCH_ID_MODE]).state = [self.preferences[PREF_TOUCH_ID_MODE] boolValue];
break;
@@ -240,6 +242,11 @@ -(IBAction)togglePreference:(id)sender
case BUTTON_TOUCH_ID_MODE:
updatedPreferences[PREF_TOUCH_ID_MODE] = state;
break;
+
+ //apple watch mode
+ case BUTTON_APPLE_WATCH_MODE:
+ updatedPreferences[PREF_APPLE_WATCH_MODE] = state;
+ break;
//include image mode
case BUTTON_ALERT_IMAGE_MODE:
diff --git a/Daemon/Monitor.h b/Daemon/Monitor.h
index 5fa96aa..8bdb222 100644
--- a/Daemon/Monitor.h
+++ b/Daemon/Monitor.h
@@ -47,6 +47,8 @@
//last touch ID auth timestamp (set by persistent ES client)
@property(atomic, retain)NSDate* lastTouchIDAuth;
+// last Apple Watch auth timetstamp (set by persistent ES client)
+@property(atomic, retain)NSDate* lastAppleWatchAuth;
/* METHODS */
@@ -54,6 +56,6 @@
-(BOOL)start;
-(BOOL)isExternalDisplayActive;
-(void)processEvent:(NSString*)timestamp;
--(BOOL)waitForTouchID:(NSTimeInterval)timeout;
+-(BOOL)waitForSecureAuth:(NSTimeInterval)timeout :(BOOL)touchIdAllowed :(BOOL)appleWatchAllowed :(NSString*) authMethodUsed;
@end
diff --git a/Daemon/Monitor.m b/Daemon/Monitor.m
index 887e059..12135e3 100644
--- a/Daemon/Monitor.m
+++ b/Daemon/Monitor.m
@@ -107,17 +107,21 @@ static void pmDomainChange(void *refcon, io_service_t service, uint32_t messageT
// log to file
os_log_info(logHandle, "[NEW EVENT] lid state: open (sleep state: %d)", sleepState);
- //touch id mode?
+ BOOL touchIdAllowed = YES == [preferences.preferences[PREF_TOUCH_ID_MODE] boolValue];
+ BOOL appleWatchAllowed = YES == [preferences.preferences[PREF_APPLE_WATCH_MODE] boolValue];
+
+ //is a mode of secure authentication set to skip an alert?
// wait up to 7 seconds, and ignore event if user auth'd via biometrics
- if(YES == [preferences.preferences[PREF_TOUCH_ID_MODE] boolValue])
+ if(touchIdAllowed || appleWatchAllowed)
{
//dbg msg
- os_log_debug(logHandle, "'touch ID' mode enabled, waiting for biometric auth event");
+ os_log_debug(logHandle, "'secure auth' mode enabled, waiting for event");
- //wait for touch ID
- if(YES == [monitor waitForTouchID:7.0])
+ //wait for a trustworthy authentication event
+ NSString* authMethodUsed = NULL;
+ if(YES == [monitor waitForSecureAuth:touchIdAllowed:appleWatchAllowed:7.0:authMethodUsed])
{
- os_log_info(logHandle, "user authenticated via touch ID, ignoring event");
+ os_log_info(logHandle, "user authenticated via %@, ignoring event", authMethodUsed);
goto bail;
}
}
@@ -250,8 +254,8 @@ -(BOOL)start
goto bail;
}
- //start touch ID monitoring
- [self startTouchIDMonitor];
+ //start authentication monitoring
+ [self startAuthMonitor];
//happy
registered = YES;
@@ -285,8 +289,8 @@ -(void)stop
//mark stopped
running = NO;
- //stop touch id monitoring
- [self stopTouchIDMonitor];
+ //stop authentication monitoring
+ [self stopAuthMonitor];
//have a dispatch queue?
// serialize teardown with in-flight callbacks
@@ -358,8 +362,8 @@ -(BOOL)isExternalDisplayActive
return NO;
}
-//start persistent ES client for touch ID auth monitoring
--(void)startTouchIDMonitor
+//start persistent ES client for authentication event monitoring
+-(void)startAuthMonitor
{
//already running?
if(esAuthClient) return;
@@ -370,18 +374,29 @@ -(void)startTouchIDMonitor
//only care about auth events
if(msg->event_type != ES_EVENT_TYPE_NOTIFY_AUTHENTICATION) return;
- //only care about Touch ID successes
- if(msg->event.authentication->type != ES_AUTHENTICATION_TYPE_TOUCHID) return;
+ //only care about auth events that unlocked the account
if(msg->event.authentication->success != YES) return;
- //record timestamp
- self.lastTouchIDAuth = [NSDate date];
-
- os_log_debug(logHandle, "touch ID auth detected");
+ // only care about Touch ID or Apple Watch successes
+ switch(msg->event.authentication->type) {
+ //record timestamp
+ case ES_AUTHENTICATION_TYPE_TOUCHID:
+ self.lastTouchIDAuth = [NSDate date];
+ os_log_debug(logHandle, "touch ID auth detected");
+ break;
+ case ES_AUTHENTICATION_TYPE_AUTO_UNLOCK:
+ //only care about when the Apple Watch unlocked the machine itself
+ if(msg->event.authentication->data.auto_unlock->type != ES_AUTO_UNLOCK_MACHINE_UNLOCK) return;
+ self.lastAppleWatchAuth = [NSDate date];
+ os_log_debug(logHandle, "apple watch auth detected");
+ break;
+ default:
+ return;
+ }
});
if(ES_NEW_CLIENT_RESULT_SUCCESS != result) {
- os_log_error(logHandle, "ERROR: failed to create ES client for touch ID monitoring (result: %d)", result);
+ os_log_error(logHandle, "ERROR: failed to create ES client for authentication monitoring (result: %d)", result);
esAuthClient = NULL;
return;
}
@@ -395,43 +410,56 @@ -(void)startTouchIDMonitor
return;
}
- os_log_debug(logHandle, "persistent touch ID monitor started");
+ os_log_debug(logHandle, "persistent authentication monitor started");
}
//stop persistent ES client
--(void)stopTouchIDMonitor
+-(void)stopAuthMonitor
{
if(esAuthClient) {
es_unsubscribe_all(esAuthClient);
es_delete_client(esAuthClient);
esAuthClient = NULL;
- os_log_debug(logHandle, "persistent touch ID monitor stopped");
+ os_log_debug(logHandle, "persistent authentication monitor stopped");
}
}
-//wait for a touch ID auth event
+//wait for a trustworhy auth event, Apple Watch or touch ID
// polls the persistent ES client's timestamp
--(BOOL)waitForTouchID:(NSTimeInterval)timeout
+-(BOOL)waitForSecureAuth:(NSTimeInterval)timeout :(BOOL)touchIdAllowed :(BOOL)appleWatchAllowed :(NSString*) authMethodUsed
{
//no ES client?
if(!esAuthClient) {
- os_log_error(logHandle, "waitForTouchID: no ES client (FDA not granted?)");
+ os_log_error(logHandle, "waitForSecureAuth: no ES client (FDA not granted?)");
return NO;
}
//reference time (lid just opened)
NSDate* lidOpenTime = [NSDate date];
- //poll for touch ID auth
+ //poll for auth
NSTimeInterval elapsed = 0;
while(elapsed < timeout)
{
- //check if a touch ID auth occurred after lid open
- NSDate* authTime = self.lastTouchIDAuth;
+ NSDate* authTime = NULL;
+ NSString* authTypeFound = NULL;
+ if(touchIdAllowed) {
+ //check if a touch ID auth occurred after lid open
+ authTime = self.lastTouchIDAuth;
+ authTypeFound = @"touch ID";
+ }
+
+ if(appleWatchAllowed) {
+ //check if an apple watch auth occured after lid open
+ authTime = self.lastAppleWatchAuth;
+ authTypeFound = @"Apple Watch";
+ }
+
if(authTime && [authTime timeIntervalSinceDate:lidOpenTime] >= 0)
{
- os_log_debug(logHandle, "touch ID auth detected (%.1fs relative to lid open)",
- [authTime timeIntervalSinceDate:lidOpenTime]);
+ authMethodUsed = authTypeFound;
+ os_log_debug(logHandle, "%@ auth detected (%.1fs relative to lid open)",
+ authTypeFound, [authTime timeIntervalSinceDate:lidOpenTime]);
return YES;
}
@@ -440,7 +468,7 @@ -(BOOL)waitForTouchID:(NSTimeInterval)timeout
elapsed += 0.25;
}
- os_log_debug(logHandle, "waitForTouchID: timed out after %.1fs", timeout);
+ os_log_debug(logHandle, "waitForSecureAuth: timed out after %.1fs", timeout);
return NO;
}
diff --git a/Installer/Source/ConfigureWindowController.h b/Installer/Source/ConfigureWindowController.h
index 39c0063..dc6b380 100644
--- a/Installer/Source/ConfigureWindowController.h
+++ b/Installer/Source/ConfigureWindowController.h
@@ -49,6 +49,7 @@
@property (strong) IBOutlet NSView *configureView;
@property (weak) IBOutlet NSButton *passiveMode;
+@property (weak) IBOutlet NSButton *appleWatchMode;
@property (weak) IBOutlet NSButton *touchIDMode;
//preferences
diff --git a/Installer/Source/ConfigureWindowController.m b/Installer/Source/ConfigureWindowController.m
index ad92e9a..b0f6574 100644
--- a/Installer/Source/ConfigureWindowController.m
+++ b/Installer/Source/ConfigureWindowController.m
@@ -163,6 +163,7 @@ -(IBAction)configureButtonHandler:(id)sender {
if( (ACTION_SHOW_CONFIGURATION+1) == action) {
self.preferences = @{
PREF_PASSIVE_MODE: @(self.passiveMode.state),
+ PREF_APPLE_WATCH_MODE: @(self.appleWatchMode.state),
PREF_TOUCH_ID_MODE: @(self.touchIDMode.state)
};
}
@@ -293,6 +294,7 @@ -(IBAction)configureButtonHandler:(id)sender {
NSDictionary* preferences = [NSDictionary dictionaryWithContentsOfFile:[INSTALL_DIRECTORY stringByAppendingPathComponent:PREFS_FILE]];
if(preferences) {
self.passiveMode.state = [preferences[PREF_PASSIVE_MODE] integerValue];
+ self.appleWatchMode.state = [preferences[PREF_APPLE_WATCH_MODE] integerValue];
self.touchIDMode.state = [preferences[PREF_TOUCH_ID_MODE] integerValue];
}
@@ -345,6 +347,7 @@ -(IBAction)configureButtonHandler:(id)sender {
execTask(OPEN, @[[@"/Applications" stringByAppendingPathComponent:APP_NAME],
@"--args", INITIAL_LAUNCH,
PREF_PASSIVE_MODE, [self.preferences[PREF_PASSIVE_MODE] description],
+ PREF_APPLE_WATCH_MODE, [self.preferences[PREF_APPLE_WATCH_MODE] description],
PREF_TOUCH_ID_MODE, [self.preferences[PREF_TOUCH_ID_MODE] description]],
NO, NO);
}
diff --git a/shared/Consts.h b/shared/Consts.h
index 9418598..c276b86 100644
--- a/shared/Consts.h
+++ b/shared/Consts.h
@@ -104,6 +104,7 @@
#define PREF_NO_ICON_MODE @"noIconMode"
#define PREF_PASSIVE_MODE @"passiveMode"
+#define PREF_APPLE_WATCH_MODE @"appleWatchMode"
#define PREF_TOUCH_ID_MODE @"touchIDMode"
#define PREF_CHAT_ID @"telegramChatID"