From f6313ade30b91c8c89228c160b951f873dcc6b13 Mon Sep 17 00:00:00 2001 From: Leo Natan Date: Wed, 3 Oct 2018 20:57:03 +0300 Subject: [PATCH] Add support for biometric enrollment and authentication Closes #32 --- README.md | 31 ++++-- .../xcschemes/applesimutils.xcscheme | 18 ++- applesimutils/applesimutils/main.m | 105 +++++++++++++++++- 3 files changed, 135 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 9ef2a49..ec062de 100644 --- a/README.md +++ b/README.md @@ -20,20 +20,27 @@ Usage: applesimutils --byName --byOS --bundle --setPermissions ", , ..." applesimutils --simulator --restartSB applesimutils --list [--byName ] [--byOS ] [--byType ] [--maxResults ] + applesimutils --byId --biometricEnrollment + applesimutils --byId --matchFace Options: - --byId Filters simulators by identifier - --byName Filters simulators by name - --byType Filters simulators by device type - --byOS Filters simulators by operating system - --list Lists available simulators - --setPermissions Sets the specified permissions and restarts SpringBoard for the changes to take effect - --clearKeychain Clears the simulator's keychain - --restartSB Restarts SpringBoard - --bundle The app bundle identifier - --maxResults Limits the number of results returned from --list - --version, -v Prints version - --help, -h Prints usage + --byId Filters simulators by identifier + --byName Filters simulators by name + --byType Filters simulators by device type + --byOS Filters simulators by operating system + --list Lists available simulators + --setPermissions Sets the specified permissions and restarts SpringBoard for the changes to take effect + --clearKeychain Clears the simulator's keychain + --restartSB Restarts SpringBoard + --biometricEnrollment Enables or disables biometric (Face ID/Touch ID) enrollment. + --matchFace Approves Face ID authentication request with a matching face + --unmatchFace Fails Face ID authentication request with a non-matching face + --matchFinger Approves Touch ID authentication request with a matching finger + --unmatchFinger Fails Touch ID authentication request with a non-matching finger + --bundle The app bundle identifier + --maxResults Limits the number of results returned from --list + --version, -v Prints version + --help, -h Prints usage Available Permissions: calendar=YES|NO|unset diff --git a/applesimutils/applesimutils.xcodeproj/xcshareddata/xcschemes/applesimutils.xcscheme b/applesimutils/applesimutils.xcodeproj/xcshareddata/xcschemes/applesimutils.xcscheme index 121b4cd..8eeef99 100644 --- a/applesimutils/applesimutils.xcodeproj/xcshareddata/xcschemes/applesimutils.xcscheme +++ b/applesimutils/applesimutils.xcodeproj/xcshareddata/xcschemes/applesimutils.xcscheme @@ -26,7 +26,6 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - language = "" shouldUseLaunchSchemeArgsEnv = "YES"> @@ -46,7 +45,6 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - language = "" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" @@ -69,8 +67,8 @@ isEnabled = "NO"> + argument = "--byId "81D58764-BF68-4B18-BECD-BE407B921693"" + isEnabled = "YES"> + + + + + + diff --git a/applesimutils/applesimutils/main.m b/applesimutils/applesimutils/main.m index 40fc7ea..ec37264 100644 --- a/applesimutils/applesimutils/main.m +++ b/applesimutils/applesimutils/main.m @@ -204,7 +204,7 @@ static void restartSpringBoard(NSString* simulatorId) ?kTCCServiceKeyboardNetwork +kTCCServiceWillow +kTCCServiceMediaLibrary - ?kTCCServiceSpeechRecognition + +kTCCServiceSpeechRecognition +kTCCServiceMSO +kTCCServiceSiri ?kTCCServiceCalls @@ -311,6 +311,66 @@ static void performPermissionsPass(NSString* permissionsArgument, NSString* simu return [NSCompoundPredicate andPredicateWithSubpredicates:@[orig, append]]; } +/* + com.apple.BiometricKit.enrollmentChanged + */ +static void setBiometricEnrollment(NSString* simulatorId, BOOL enrolled) +{ + NSTask* setNotifyValueTask = [NSTask new]; + setNotifyValueTask.launchPath = [SimUtils xcrunURL].path; + setNotifyValueTask.arguments = @[@"simctl", @"spawn", simulatorId, @"notifyutil", @"-s", @"com.apple.BiometricKit.enrollmentChanged", enrolled ? @"1" : @"0"]; + [setNotifyValueTask launch]; + [setNotifyValueTask waitUntilExit]; + + NSTask* postNotifyTask = [NSTask new]; + postNotifyTask.launchPath = [SimUtils xcrunURL].path; + postNotifyTask.arguments = @[@"simctl", @"spawn", simulatorId, @"notifyutil", @"-p", @"com.apple.BiometricKit.enrollmentChanged"]; + [postNotifyTask launch]; + [postNotifyTask waitUntilExit]; +} + +typedef NS_ENUM(NSUInteger, ASUBiometricType) { + ASUBiometricTypeFinger, + ASUBiometricTypeFace, +}; + +/* + com.apple.BiometricKit_Sim.fingerTouch.match + com.apple.BiometricKit_Sim.fingerTouch.nomatch + com.apple.BiometricKit_Sim.pearl.match + com.apple.BiometricKit_Sim.pearl.nomatch + */ +static void sendBiometricMatch(NSString* simulatorId, ASUBiometricType biometricType, BOOL matching) +{ + NSMutableString* keyName = [@"com.apple.BiometricKit_Sim." mutableCopy]; + switch (biometricType) { + case ASUBiometricTypeFinger: + [keyName appendString:@"fingerTouch."]; + break; + case ASUBiometricTypeFace: + [keyName appendString:@"pearl."]; + break; + default: + exit(-666); + break; + } + + if(matching) + { + [keyName appendString:@"match"]; + } + else + { + [keyName appendString:@"nomatch"]; + } + + NSTask* postNotifyTask = [NSTask new]; + postNotifyTask.launchPath = [SimUtils xcrunURL].path; + postNotifyTask.arguments = @[@"simctl", @"spawn", simulatorId, @"notifyutil", @"-p", keyName]; + [postNotifyTask launch]; + [postNotifyTask waitUntilExit]; +} + int main(int argc, const char* argv[]) { @autoreleasepool { LNUsageSetIntroStrings(@[@"A collection of utils for Apple simulators."]); @@ -319,7 +379,9 @@ int main(int argc, const char* argv[]) { @"%@ --byId --bundle --setPermissions \", , ...\"", @"%@ --byName --byOS --bundle --setPermissions \", , ...\"", @"%@ --simulator --restartSB", - @"%@ --list [--byName ] [--byOS ] [--byType ] [--maxResults ]" + @"%@ --list [--byName ] [--byOS ] [--byType ] [--maxResults ]", + @"%@ --byId --biometricEnrollment ", + @"%@ --byId --matchFace" ]); LNUsageSetOptions(@[ @@ -333,6 +395,12 @@ int main(int argc, const char* argv[]) { [LNUsageOption optionWithName:@"clearKeychain" valueRequirement:GBValueNone description:@"Clears the simulator's keychain"], [LNUsageOption optionWithName:@"restartSB" valueRequirement:GBValueNone description:@"Restarts SpringBoard"], + [LNUsageOption optionWithName:@"biometricEnrollment" valueRequirement:GBValueRequired description:@"Enables or disables biometric (Face ID/Touch ID) enrollment."], + [LNUsageOption optionWithName:@"matchFace" valueRequirement:GBValueNone description:@"Approves Face ID authentication request with a matching face"], + [LNUsageOption optionWithName:@"unmatchFace" valueRequirement:GBValueNone description:@"Fails Face ID authentication request with a non-matching face"], + [LNUsageOption optionWithName:@"matchFinger" valueRequirement:GBValueNone description:@"Approves Touch ID authentication request with a matching finger"], + [LNUsageOption optionWithName:@"unmatchFinger" valueRequirement:GBValueNone description:@"Fails Touch ID authentication request with a non-matching finger"], + [LNUsageOption optionWithName:@"bundle" valueRequirement:GBValueRequired description:@"The app bundle identifier"], [LNUsageOption optionWithName:@"maxResults" valueRequirement:GBValueRequired description:@"Limits the number of results returned from --list"], @@ -376,7 +444,13 @@ int main(int argc, const char* argv[]) { ![settings objectForKey:@"setPermissions"] && ![settings boolForKey:@"restartSB"] && ![settings boolForKey:@"clearKeychain"] && - ![settings objectForKey:@"list"]) + ![settings objectForKey:@"list"] && + ![settings objectForKey:@"biometricEnrollment"] && + ![settings boolForKey:@"matchFace"] && + ![settings boolForKey:@"unmatchFace"] && + ![settings boolForKey:@"matchFinger"] && + ![settings boolForKey:@"unmatchFinger"] + ) { LNUsagePrintMessage(nil, LNLogLevelStdOut); exit(-1); @@ -531,6 +605,31 @@ int main(int argc, const char* argv[]) { needsSpringBoardRestart = YES; } + NSString* biometricEnrollment = [settings objectForKey:@"biometricEnrollment"]; + if(biometricEnrollment) + { + assertStringInArrayValues(biometricEnrollment, @[@"YES", @"NO"], -10, [NSString stringWithFormat:@"Error: Value “%@” cannot be parsed for biometricEnrollment; expected YES|NO", biometricEnrollment]); + + setBiometricEnrollment(simulatorId, [biometricEnrollment boolValue]); + } + + if([settings boolForKey:@"matchFace"]) + { + sendBiometricMatch(simulatorId, ASUBiometricTypeFace, YES); + } + if([settings boolForKey:@"unmatchFace"]) + { + sendBiometricMatch(simulatorId, ASUBiometricTypeFace, NO); + } + if([settings boolForKey:@"matchFinger"]) + { + sendBiometricMatch(simulatorId, ASUBiometricTypeFinger, YES); + } + if([settings boolForKey:@"unmatchFinger"]) + { + sendBiometricMatch(simulatorId, ASUBiometricTypeFinger, NO); + } + if(needsSpringBoardRestart) { restartSpringBoard(simulatorId);