Skip to content

Commit

Permalink
Merge pull request #19 from square/emuller+federman/nullable
Browse files Browse the repository at this point in the history
Add support for new nullable specifiers
  • Loading branch information
dfed committed Jul 1, 2015
2 parents a2995c0 + 4940c00 commit 81f061c
Show file tree
Hide file tree
Showing 8 changed files with 67 additions and 41 deletions.
2 changes: 1 addition & 1 deletion Valet.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'Valet'
s.version = '1.2.1'
s.version = '1.3'
s.license = 'Apache'
s.summary = 'Valet lets you securely store data in the iOS or OS X Keychain without knowing a thing about how the Keychain works. It\'s easy. We promise.'
s.homepage = 'https://github.com/square/Valet'
Expand Down
2 changes: 2 additions & 0 deletions Valet.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,7 @@
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
Expand Down Expand Up @@ -548,6 +549,7 @@
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
Expand Down
26 changes: 16 additions & 10 deletions Valet/VALSecureEnclaveValet.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,28 +21,31 @@
#import "VALValet.h"


NS_ASSUME_NONNULL_BEGIN


/// Reads and writes keychain elements that are stored on the Secure Enclave (supported on iOS 8.0 or later) using accessibility attribute VALAccessibilityWhenPasscodeSetThisDeviceOnly. Accessing or modifying these items will require the user to confirm their presence via Touch ID or passcode entry. If no passcode is set on the device, the below methods will fail. Data is removed from the Secure Enclave when the user removes a passcode from the device. Use the userPrompt methods to display custom text to the user in Apple's Touch ID and passcode entry UI.
NS_CLASS_AVAILABLE_IOS(8_0)
@interface VALSecureEnclaveValet : VALValet

/// Retuns YES if Secure Enclave storage is supported on the current iOS version (8.0 and later).
/// @return YES if Secure Enclave storage is supported on the current iOS version (8.0 and later).
+ (BOOL)supportsSecureEnclaveKeychainItems;

/// Creates a Valet that reads/writes Secure Enclave keychain elements.
- (instancetype)initWithIdentifier:(NSString *)identifier __attribute__((nonnull(1)));
- (nullable instancetype)initWithIdentifier:(NSString *)identifier;

/// Creates a Valet that reads/writes Secure Enclave keychain elements that can be shared across applications written by the same development team. The sharedAccessGroupIdentifier must correspond with the value for keychain-access-groups in your Entitlements file.
- (instancetype)initWithSharedAccessGroupIdentifier:(NSString *)sharedAccessGroupIdentifier __attribute__((nonnull(1)));
- (nullable instancetype)initWithSharedAccessGroupIdentifier:(NSString *)sharedAccessGroupIdentifier;

/// Convenience method for inserting data into the keychain with a user prompt. The userPrompt is displayed to the user in Apple's Touch ID and passcode entry UI when updating a value.
- (BOOL)setObject:(NSData *)value forKey:(NSString *)key userPrompt:(NSString *)userPrompt __attribute__((nonnull(1,2)));
/// Convenience method for retreiving data from the keychain with a user prompt. The userPrompt is displayed to the user in Apple's Touch ID and passcode entry UI.
- (NSData *)objectForKey:(NSString *)key userPrompt:(NSString *)userPrompt __attribute__((nonnull(1)));
- (BOOL)setObject:(NSData *)value forKey:(NSString *)key userPrompt:(NSString *)userPrompt;
/// Convenience method for retrieving data from the keychain with a user prompt. The userPrompt is displayed to the user in Apple's Touch ID and passcode entry UI.
- (nullable NSData *)objectForKey:(NSString *)key userPrompt:(NSString *)userPrompt;

/// Convenience method for retreiving a string into the keychain with a user prompt. The userPrompt is displayed to the user in Apple's Touch ID and passcode entry UI when updating a value.
- (BOOL)setString:(NSString *)string forKey:(NSString *)key userPrompt:(NSString *)userPrompt __attribute__((nonnull(1,2)));
/// Convenience method for retreiving a string from the keychain with a user prompt. The userPrompt is displayed to the user in Apple's Touch ID and passcode entry UI.
- (NSString *)stringForKey:(NSString *)key userPrompt:(NSString *)userPrompt __attribute__((nonnull(1)));
/// Convenience method for retrieving a string into the keychain with a user prompt. The userPrompt is displayed to the user in Apple's Touch ID and passcode entry UI when updating a value.
- (BOOL)setString:(NSString *)string forKey:(NSString *)key userPrompt:(NSString *)userPrompt;
/// Convenience method for retrieving a string from the keychain with a user prompt. The userPrompt is displayed to the user in Apple's Touch ID and passcode entry UI.
- (nullable NSString *)stringForKey:(NSString *)key userPrompt:(NSString *)userPrompt;

/// This method is not supported on VALSecureEnclaveValet.
- (NSSet *)allKeys __attribute__((unavailable("VALSecureEnclaveValet does not support -allKeys")));
Expand All @@ -51,3 +54,6 @@ NS_CLASS_AVAILABLE_IOS(8_0)
- (BOOL)removeAllObjects __attribute__((unavailable("VALSecureEnclaveValet does not support -removeAllObjects")));

@end


NS_ASSUME_NONNULL_END
2 changes: 1 addition & 1 deletion Valet/VALSynchronizableValet.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
/// Reads and writes keychain elements that are synchronized with iCloud (supported on devices on iOS 7.0.3 and later). Accessibility must not be scoped to this device.
@interface VALSynchronizableValet : VALValet

/// Returns YES if iCloud syncronizable keychain is supported on the current iOS version (7.0.3 and later).
/// @return YES if iCloud syncronizable keychain is supported on the current iOS version (7.0.3 and later).
+ (BOOL)supportsSynchronizableKeychainItems;

@end
39 changes: 24 additions & 15 deletions Valet/VALValet.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
#import <Foundation/Foundation.h>


NS_ASSUME_NONNULL_BEGIN


typedef NS_ENUM(NSUInteger, VALAccessibility) {
/// Valet data can only be accessed while the device is unlocked. This attribute is recommended for data that only needs to be accesible while the application is in the foreground. Valet data with this accessibility will migrate to a new device when using encrypted backups.
VALAccessibilityWhenUnlocked = 1,
Expand Down Expand Up @@ -67,42 +70,48 @@ typedef NS_ENUM(NSUInteger, VALMigrationError) {
@interface VALValet : NSObject <NSCopying>

/// Creates a Valet that reads/writes keychain elements with the desired accessibility.
- (instancetype)initWithIdentifier:(NSString *)identifier accessibility:(VALAccessibility)accessibility __attribute__((nonnull(1))) __attribute((objc_designated_initializer));
- (nullable instancetype)initWithIdentifier:(NSString *)identifier accessibility:(VALAccessibility)accessibility __attribute((objc_designated_initializer));

/// Creates a Valet that reads/writes keychain elements that can be shared across applications written by the same development team. The sharedAccessGroupIdentifier must correspond with the value for keychain-access-groups in your Entitlements file.
- (instancetype)initWithSharedAccessGroupIdentifier:(NSString *)sharedAccessGroupIdentifier accessibility:(VALAccessibility)accessibility __attribute__((nonnull(1))) __attribute((objc_designated_initializer));
- (nullable instancetype)initWithSharedAccessGroupIdentifier:(NSString *)sharedAccessGroupIdentifier accessibility:(VALAccessibility)accessibility __attribute((objc_designated_initializer));

@property (copy, readonly) NSString *identifier;
@property (readonly, getter=isSharedAcrossApplications) BOOL sharedAcrossApplications;
@property (readonly) VALAccessibility accessibility;

/// Returns YES if otherValet reads from and writes to the same sandbox within keychain as the receiver.
/// @return YES if otherValet reads from and writes to the same sandbox within keychain as the receiver.
- (BOOL)isEqualToValet:(VALValet *)otherValet;

/// Checks whether the keychain is currently accessible by writing a value to the keychain and then reading it back out.
- (BOOL)canAccessKeychain;

/// Inserts data into the keychain. Returns NO if the keychain is not accessible.
- (BOOL)setObject:(NSData *)value forKey:(NSString *)key __attribute__((nonnull(1,2)));
/// Inserts data into the keychain.
/// @return NO if the keychain is not accessible.
- (BOOL)setObject:(NSData *)value forKey:(NSString *)key;
/// Retreives data from the keychain.
- (NSData *)objectForKey:(NSString *)key __attribute__((nonnull(1)));
- (nullable NSData *)objectForKey:(NSString *)key;

/// Convenience method for adding a string to the keychain.
- (BOOL)setString:(NSString *)string forKey:(NSString *)key __attribute__((nonnull(1,2)));
/// Convenience method for retreiving a string from the keychain.
- (NSString *)stringForKey:(NSString *)key __attribute__((nonnull(1)));
- (BOOL)setString:(NSString *)string forKey:(NSString *)key;
/// Convenience method for retrieving a string from the keychain.
- (nullable NSString *)stringForKey:(NSString *)key;

- (BOOL)containsObjectForKey:(NSString *)key __attribute__((nonnull(1)));
- (BOOL)containsObjectForKey:(NSString *)key;
- (NSSet *)allKeys;

/// Removes a key/object pair from the keychain. Returns NO if the keychain is not accessible.
- (BOOL)removeObjectForKey:(NSString *)key __attribute__((nonnull(1)));
/// Removes all key/object pairs accessible by this Valet instance from the keychain. Returns NO if the keychain is not accessible.
/// Removes a key/object pair from the keychain.
/// @return NO if the keychain is not accessible.
- (BOOL)removeObjectForKey:(NSString *)key;
/// Removes all key/object pairs accessible by this Valet instance from the keychain.
/// @return NO if the keychain is not accessible.
- (BOOL)removeAllObjects;

/// Migrates objects matching the secItemQuery into the receiving Valet instance. Error domain will be VALMigrationErrorDomain, and codes can will be from VALMigrationError. The keychain is not modified if a failure occurs.
- (NSError *)migrateObjectsMatchingQuery:(NSDictionary *)secItemQuery removeOnCompletion:(BOOL)remove;
- (nullable NSError *)migrateObjectsMatchingQuery:(NSDictionary *)secItemQuery removeOnCompletion:(BOOL)remove;
/// Migrates objects from the passed-in Valet into the receiving Valet instance.
- (NSError *)migrateObjectsFromValet:(VALValet *)valet removeOnCompletion:(BOOL)remove;
- (nullable NSError *)migrateObjectsFromValet:(VALValet *)valet removeOnCompletion:(BOOL)remove;

@end


NS_ASSUME_NONNULL_END
2 changes: 1 addition & 1 deletion Valet/VALValet.m
Original file line number Diff line number Diff line change
Expand Up @@ -512,7 +512,7 @@ - (OSStatus)containsObjectForKey:(NSString *)key options:(NSDictionary *)options

- (NSSet *)allKeysWithOptions:(NSDictionary *)options;
{
NSSet *keys = nil;
NSSet *keys = [NSSet set];
NSMutableDictionary *query = [self.baseQuery mutableCopy];
[query addEntriesFromDictionary:@{ (__bridge id)kSecMatchLimit : (__bridge id)kSecMatchLimitAll,
(__bridge id)kSecReturnAttributes : @YES }];
Expand Down
29 changes: 19 additions & 10 deletions Valet/VALValet_Protected.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// Header.h
// VALValet_Protected.h
// Valet
//
// Created by Dan Federman on 3/16/15.
Expand All @@ -18,20 +18,29 @@
// limitations under the License.
//

#import "VALValet.h"


NS_ASSUME_NONNULL_BEGIN


extern NSString *VALStringForAccessibility(VALAccessibility accessibility);


@interface VALValet ()

- (NSMutableDictionary *)mutableBaseQueryWithIdentifier:(NSString *)identifier initializer:(SEL)initializer accessibility:(VALAccessibility)accessibility;

- (BOOL)setObject:(NSData *)value forKey:(NSString *)key options:(NSDictionary *)options;
- (NSData *)objectForKey:(NSString *)key options:(NSDictionary *)options;
- (BOOL)setString:(NSString *)string forKey:(NSString *)key options:(NSDictionary *)options;
- (NSString *)stringForKey:(NSString *)key options:(NSDictionary *)options;
- (OSStatus)containsObjectForKey:(NSString *)key options:(NSDictionary *)options;
- (NSSet *)allKeysWithOptions:(NSDictionary *)options;
- (BOOL)removeObjectForKey:(NSString *)key options:(NSDictionary *)options;
- (BOOL)removeAllObjectsWithOptions:(NSDictionary *)options;
- (BOOL)setObject:(NSData *)value forKey:(NSString *)key options:(nullable NSDictionary *)options;
- (nullable NSData *)objectForKey:(NSString *)key options:(nullable NSDictionary *)options;
- (BOOL)setString:(NSString *)string forKey:(NSString *)key options:(nullable NSDictionary *)options;
- (nullable NSString *)stringForKey:(NSString *)key options:(nullable NSDictionary *)options;
- (OSStatus)containsObjectForKey:(NSString *)key options:(nullable NSDictionary *)options;
- (NSSet *)allKeysWithOptions:(nullable NSDictionary *)options;
- (BOOL)removeObjectForKey:(NSString *)key options:(nullable NSDictionary *)options;
- (BOOL)removeAllObjectsWithOptions:(nullable NSDictionary *)options;

@end


@end
NS_ASSUME_NONNULL_END
6 changes: 3 additions & 3 deletions ValetTests/ValetTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -401,10 +401,10 @@ - (void)test_containsObjectForKey_returnsNOWhenKeyDoesNotExist;
XCTAssertFalse([self.valet containsObjectForKey:self.key]);
}

- (void)test_allKeys_returnsNilWhenNoAllKeysPresent;
- (void)test_allKeys_returnsEmptySetWhenNoKeysArePresent;
{
XCTAssertNil([self.valet stringForKey:self.key]);
XCTAssertNil([self.valet allKeys]);
XCTAssertEqual(0, [self.valet allKeys].count);
}

- (void)test_allKeys_returnsOneKeyWhenOnlyOneKey;
Expand Down Expand Up @@ -436,7 +436,7 @@ - (void)test_allKeys_differentIdentifierReturnsNil;
[self.additionalValets addObject:otherValet];

NSSet *allKeys = [otherValet allKeys];
XCTAssertNil(allKeys, @"Expected allKeys with different identifier to be nil but instead it was %@", allKeys);
XCTAssertEqual(0, allKeys.count, @"Expected allKeys with different identifier to be an empty set but instead it was %@", allKeys);
}

- (void)test_removeObjectForKey_succeedsWhenNoKeyExists;
Expand Down

0 comments on commit 81f061c

Please sign in to comment.