Skip to content

Commit

Permalink
Add support for biometric enrollment and authentication
Browse files Browse the repository at this point in the history
Closes #32
  • Loading branch information
LeoNatan committed Oct 3, 2018
1 parent 46a7a5f commit f6313ad
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 19 deletions.
31 changes: 19 additions & 12 deletions README.md
Expand Up @@ -20,20 +20,27 @@ Usage:
applesimutils --byName <simulator name> --byOS <simulator OS version> --bundle <bundle identifier> --setPermissions "<permission1>, <permission2>, ..."
applesimutils --simulator <simulator name/identifier> --restartSB
applesimutils --list [--byName <simulator name>] [--byOS <simulator OS version>] [--byType <simulator OS version>] [--maxResults <int>]
applesimutils --byId <simulator identifier> --biometricEnrollment <YES/NO>
applesimutils --byId <simulator identifier> --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
Expand Down
Expand Up @@ -26,7 +26,6 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
Expand All @@ -46,7 +45,6 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
Expand All @@ -69,8 +67,8 @@
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "--byId &quot;4200D07C-5323-4F3A-AA13-F73CB3AFC97C&quot;"
isEnabled = "NO">
argument = "--byId &quot;81D58764-BF68-4B18-BECD-BE407B921693&quot;"
isEnabled = "YES">
</CommandLineArgument>
<CommandLineArgument
argument = "--byType &quot;iPhone X&quot;"
Expand Down Expand Up @@ -108,6 +106,18 @@
argument = "--restartSB"
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "--biometricEnrollment YES"
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "--matchFace"
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "--unmatchFace"
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "--help"
isEnabled = "YES">
Expand Down
105 changes: 102 additions & 3 deletions applesimutils/applesimutils/main.m
Expand Up @@ -204,7 +204,7 @@ static void restartSpringBoard(NSString* simulatorId)
?kTCCServiceKeyboardNetwork
+kTCCServiceWillow
+kTCCServiceMediaLibrary
?kTCCServiceSpeechRecognition
+kTCCServiceSpeechRecognition
+kTCCServiceMSO
+kTCCServiceSiri
?kTCCServiceCalls
Expand Down Expand Up @@ -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."]);
Expand All @@ -319,7 +379,9 @@ int main(int argc, const char* argv[]) {
@"%@ --byId <simulator identifier> --bundle <bundle identifier> --setPermissions \"<permission1>, <permission2>, ...\"",
@"%@ --byName <simulator name> --byOS <simulator OS version> --bundle <bundle identifier> --setPermissions \"<permission1>, <permission2>, ...\"",
@"%@ --simulator <simulator name/identifier> --restartSB",
@"%@ --list [--byName <simulator name>] [--byOS <simulator OS version>] [--byType <simulator OS version>] [--maxResults <int>]"
@"%@ --list [--byName <simulator name>] [--byOS <simulator OS version>] [--byType <simulator OS version>] [--maxResults <int>]",
@"%@ --byId <simulator identifier> --biometricEnrollment <YES/NO>",
@"%@ --byId <simulator identifier> --matchFace"
]);

LNUsageSetOptions(@[
Expand All @@ -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"],
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit f6313ad

Please sign in to comment.