From b5be03947c2ca506b5e53a855d685e323807c45e Mon Sep 17 00:00:00 2001 From: N2S Development Date: Mon, 3 Aug 2015 15:32:50 +1000 Subject: [PATCH 1/3] Added support for Shared Keychains via Access Groups --- VENTouchLock/VENTouchLock.h | 16 ++++++++++++++ VENTouchLock/VENTouchLock.m | 44 +++++++++++++++++++++++++++---------- 2 files changed, 49 insertions(+), 11 deletions(-) diff --git a/VENTouchLock/VENTouchLock.h b/VENTouchLock/VENTouchLock.h index 642ee90..f88ccce 100644 --- a/VENTouchLock/VENTouchLock.h +++ b/VENTouchLock/VENTouchLock.h @@ -37,6 +37,22 @@ typedef NS_ENUM(NSUInteger, VENTouchLockTouchIDResponse) { passcodeAttemptLimit:(NSUInteger)attemptLimit splashViewControllerClass:(Class)splashViewControllerClass; +/** + Set the defaults. This method should be called at launch. Access group is needed for keychain sharing. + @param service The keychain service for which to set and return a passcode + @param account The keychain account for which to set and return a passcode + @param accessGroup The keychain access group for which to set and return a shared passcode + @param splashViewControllerClass The class of the custom splash view controller. This class should be a subclass of VENTouchLockSplashViewController and any of its custom initialization must be in its init function + @param reason The default message displayed on the TouchID prompt + */ +- (void)setKeychainService:(NSString *)service + keychainAccount:(NSString *)account + keychainAccessGroup:(NSString *)accessGroup + touchIDReason:(NSString *)reason + passcodeAttemptLimit:(NSUInteger)attemptLimit + splashViewControllerClass:(Class)splashViewControllerClass; + + /** Returns YES if a passcode exists, and NO otherwise. */ diff --git a/VENTouchLock/VENTouchLock.m b/VENTouchLock/VENTouchLock.m index a6272e8..00ff159 100644 --- a/VENTouchLock/VENTouchLock.m +++ b/VENTouchLock/VENTouchLock.m @@ -10,6 +10,7 @@ @interface VENTouchLock () @property (copy, nonatomic) NSString *keychainService; @property (copy, nonatomic) NSString *keychainAccount; +@property (copy, nonatomic) NSString *keychainAccessGroup; @property (copy, nonatomic) NSString *touchIDReason; @property (assign, nonatomic) NSUInteger passcodeAttemptLimit; @property (assign, nonatomic) Class splashViewControllerClass; @@ -62,6 +63,20 @@ - (void)setKeychainService:(NSString *)service self.splashViewControllerClass = splashViewControllerClass; } +- (void)setKeychainService:(NSString *)service + keychainAccount:(NSString *)account + keychainAccessGroup:(NSString *)accessGroup + touchIDReason:(NSString *)reason + passcodeAttemptLimit:(NSUInteger)attemptLimit + splashViewControllerClass:(Class)splashViewControllerClass { + + [self setKeychainService:service + keychainAccount:account + touchIDReason:reason + passcodeAttemptLimit:attemptLimit + splashViewControllerClass:splashViewControllerClass]; + self.keychainAccessGroup = accessGroup; +} #pragma mark - Keychain Methods @@ -70,11 +85,13 @@ - (BOOL)isPasscodeSet return !![self currentPasscode]; } -- (NSString *)currentPasscode -{ - NSString *service = self.keychainService; - NSString *account = self.keychainAccount; - return [SSKeychain passwordForService:service account:account]; +- (NSString *)currentPasscode { + + SSKeychainQuery *query = [[SSKeychainQuery alloc] init]; + query.service = self.keychainService; + query.account = self.keychainAccount; + query.accessGroup = self.keychainAccessGroup; + return query.password; } - (BOOL)isPasscodeValid:(NSString *)passcode @@ -84,9 +101,12 @@ - (BOOL)isPasscodeValid:(NSString *)passcode - (void)setPasscode:(NSString *)passcode { - NSString *service = self.keychainService; - NSString *account = self.keychainAccount; - [SSKeychain setPassword:passcode forService:service account:account]; + SSKeychainQuery *query = [[SSKeychainQuery alloc] init]; + query.service = self.keychainService; + query.account = self.keychainAccount; + query.accessGroup = self.keychainAccessGroup; + query.password = passcode; + [query save:nil]; } - (void)deletePasscode @@ -95,9 +115,11 @@ - (void)deletePasscode [VENTouchLockEnterPasscodeViewController resetPasscodeAttemptHistory]; [[NSUserDefaults standardUserDefaults] synchronize]; - NSString *service = self.keychainService; - NSString *account = self.keychainAccount; - [SSKeychain deletePasswordForService:service account:account]; + SSKeychainQuery *query = [[SSKeychainQuery alloc] init]; + query.service = self.keychainService; + query.account = self.keychainAccount; + query.accessGroup = self.keychainAccessGroup; + [query deleteItem:nil]; } From c9f8f97b72bc954da11f9d58621281e12dc90b61 Mon Sep 17 00:00:00 2001 From: N2S Development Date: Mon, 3 Aug 2015 15:49:42 +1000 Subject: [PATCH 2/3] currentPasscode now actually retrieves the password... --- VENTouchLock/VENTouchLock.m | 1 + 1 file changed, 1 insertion(+) diff --git a/VENTouchLock/VENTouchLock.m b/VENTouchLock/VENTouchLock.m index 00ff159..74ae5bc 100644 --- a/VENTouchLock/VENTouchLock.m +++ b/VENTouchLock/VENTouchLock.m @@ -91,6 +91,7 @@ - (NSString *)currentPasscode { query.service = self.keychainService; query.account = self.keychainAccount; query.accessGroup = self.keychainAccessGroup; + [query fetch:nil]; return query.password; } From 796d605a13b5f268d6afb42f8c90cf5258f194ee Mon Sep 17 00:00:00 2001 From: Tupps Date: Mon, 3 Aug 2015 19:51:52 +1000 Subject: [PATCH 3/3] Updated the VENTouchLockSpec.m to include tests for AccessGroups --- VENTouchLockTests/VENTouchLockSpec.m | 62 +++++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/VENTouchLockTests/VENTouchLockSpec.m b/VENTouchLockTests/VENTouchLockSpec.m index 9616d50..7d30c34 100644 --- a/VENTouchLockTests/VENTouchLockSpec.m +++ b/VENTouchLockTests/VENTouchLockSpec.m @@ -97,4 +97,64 @@ }); -SpecEnd \ No newline at end of file +SpecEnd + +SpecBegin(VENTouchLockAccessGroup) + +beforeAll(^{ + [[VENTouchLock sharedInstance] setKeychainService:@"keychainService" + keychainAccount:@"keychainAccount" + keychainAccessGroup:@"keychainAccessGroupAccount" + touchIDReason:@"touchIDReason" + passcodeAttemptLimit:0 + splashViewControllerClass:NULL]; +}); + +beforeEach(^{ + [[VENTouchLock sharedInstance] deletePasscode]; +}); + +describe(@"setPasscode:", ^{ + + it(@"should register a passcode with VENTouchLock", ^{ + VENTouchLock *touchLock = [VENTouchLock sharedInstance]; + expect([touchLock isPasscodeSet]).to.equal(NO); + expect([touchLock currentPasscode]).to.beNil(); + + [[VENTouchLock sharedInstance] setPasscode:@"testPasscode"]; + + expect([touchLock isPasscodeSet]).to.equal(YES); + expect([touchLock currentPasscode]).to.equal(@"testPasscode"); + }); + +}); + +describe(@"isPasscodeValid", ^{ + + it(@"should return YES if the parameter sent is equal to the set passcode and NO otherwise", ^{ + VENTouchLock *touchLock = [VENTouchLock sharedInstance]; + [touchLock setPasscode:@"testPasscode"]; + expect([touchLock isPasscodeValid:@"testPasscode"]).to.equal(YES); + expect([touchLock isPasscodeValid:@"wrongPasscode"]).to.equal(NO); + }); + +}); + +describe(@"deletePasscode", ^{ + + it(@"should register a passcode with VENTouchLock", ^{ + VENTouchLock *touchLock = [VENTouchLock sharedInstance]; + + [[VENTouchLock sharedInstance] setPasscode:@"testPasscode"]; + expect([touchLock isPasscodeSet]).to.equal(YES); + expect([touchLock currentPasscode]).to.equal(@"testPasscode"); + + [touchLock deletePasscode]; + + expect([touchLock isPasscodeSet]).to.equal(NO); + expect([touchLock currentPasscode]).to.beNil(); + }); + +}); + +SpecEnd