diff options
| author | Ronny Fenrich <Fenrich@Gmail.com> | 2013-06-13 13:40:44 -0600 |
|---|---|---|
| committer | Ronny Fenrich <Fenrich@Gmail.com> | 2013-06-13 13:40:44 -0600 |
| commit | bf6c97cdee2264656211126ee01066c3c5d4bd8d (patch) | |
| tree | df4a6a9ed1b76109a57d1bf71c85b5632a6e3a0b /Volta/Libraries/SSKeychain | |
| parent | d6d01c9dd86561ad2121f0f85f0a4529142d5093 (diff) | |
added Xcode project and converted to CocoaPods (added a bunch of libraries)
Diffstat (limited to 'Volta/Libraries/SSKeychain')
| -rwxr-xr-x | Volta/Libraries/SSKeychain/SSKeychain.h | 333 | ||||
| -rwxr-xr-x | Volta/Libraries/SSKeychain/SSKeychain.m | 312 |
2 files changed, 645 insertions, 0 deletions
diff --git a/Volta/Libraries/SSKeychain/SSKeychain.h b/Volta/Libraries/SSKeychain/SSKeychain.h new file mode 100755 index 0000000..6e92123 --- /dev/null +++ b/Volta/Libraries/SSKeychain/SSKeychain.h @@ -0,0 +1,333 @@ +// +// SSKeychain.h +// SSToolkit +// +// Created by Sam Soffes on 5/19/10. +// Copyright (c) 2009-2011 Sam Soffes. All rights reserved. +// + +#import <Foundation/Foundation.h> +#import <Security/Security.h> + + +/** + Error code specific to SSKeychain that can be returned in NSError objects. + For codes returned by the operating system, refer to SecBase.h for your platform. + */ +typedef enum { + + /** Some of the arguments were invalid. */ + SSKeychainErrorBadArguments = -1001, + +} SSKeychainErrorCode; + +extern NSString *const kSSKeychainErrorDomain; + +/** Account name. */ +extern NSString *const kSSKeychainAccountKey; + +/** + Time the item was created. + + The value will be a string. + */ +extern NSString *const kSSKeychainCreatedAtKey; + +/** Item class. */ +extern NSString *const kSSKeychainClassKey; + +/** Item description. */ +extern NSString *const kSSKeychainDescriptionKey; + +/** Item label. */ +extern NSString *const kSSKeychainLabelKey; + +/** Time the item was last modified. + + The value will be a string. + */ +extern NSString *const kSSKeychainLastModifiedKey; + +/** Where the item was created. */ +extern NSString *const kSSKeychainWhereKey; + +/** + Simple wrapper for accessing accounts, getting passwords, setting passwords, and deleting passwords using the system + Keychain on Mac OS X and iOS. + + This was originally inspired by EMKeychain and SDKeychain (both of which are now gone). Thanks to the authors. + SSKeychain has since switched to a simpler implementation that was abstracted from [SSToolkit](http://sstoolk.it). + */ +@interface SSKeychain : NSObject + +///----------------------- +/// @name Getting Accounts +///----------------------- + +/** + Returns an array containing the Keychain's accounts, or `nil` if the Keychain has no accounts. + + See the `NSString` constants declared in SSKeychain.h for a list of keys that can be used when accessing the + dictionaries returned by this method. + + @return An array of dictionaries containing the Keychain's accounts, or `nil` if the Keychain doesn't have any + accounts. The order of the objects in the array isn't defined. + + @see allAccounts: + */ ++ (NSArray *)allAccounts; + +/** + Returns an array containing the Keychain's accounts, or `nil` if the Keychain doesn't have any + accounts. + + See the `NSString` constants declared in SSKeychain.h for a list of keys that can be used when accessing the + dictionaries returned by this method. + + @param error If accessing the accounts fails, upon return contains an error that describes the problem. + + @return An array of dictionaries containing the Keychain's accounts, or `nil` if the Keychain doesn't have any + accounts. The order of the objects in the array isn't defined. + + @see allAccounts + */ ++ (NSArray *)allAccounts:(NSError **)error; + +/** + Returns an array containing the Keychain's accounts for a given service, or `nil` if the Keychain doesn't have any + accounts for the given service. + + See the `NSString` constants declared in SSKeychain.h for a list of keys that can be used when accessing the + dictionaries returned by this method. + + @param serviceName The service for which to return the corresponding accounts. + + @return An array of dictionaries containing the Keychain's accountsfor a given `serviceName`, or `nil` if the Keychain + doesn't have any accounts for the given `serviceName`. The order of the objects in the array isn't defined. + + @see accountsForService:error: + */ ++ (NSArray *)accountsForService:(NSString *)serviceName; + +/** + Returns an array containing the Keychain's accounts for a given service, or `nil` if the Keychain doesn't have any + accounts for the given service. + + @param serviceName The service for which to return the corresponding accounts. + + @param error If accessing the accounts fails, upon return contains an error that describes the problem. + + @return An array of dictionaries containing the Keychain's accountsfor a given `serviceName`, or `nil` if the Keychain + doesn't have any accounts for the given `serviceName`. The order of the objects in the array isn't defined. + + @see accountsForService: + */ ++ (NSArray *)accountsForService:(NSString *)serviceName error:(NSError **)error; + + +///------------------------ +/// @name Getting Passwords +///------------------------ + +/** + Returns a string containing the password for a given account and service, or `nil` if the Keychain doesn't have a + password for the given parameters. + + @param serviceName The service for which to return the corresponding password. + + @param account The account for which to return the corresponding password. + + @return Returns a string containing the password for a given account and service, or `nil` if the Keychain doesn't + have a password for the given parameters. + + @see passwordForService:account:error: + */ ++ (NSString *)passwordForService:(NSString *)serviceName account:(NSString *)account; + +/** + Returns a string containing the password for a given account and service, or `nil` if the Keychain doesn't have a + password for the given parameters. + + @param serviceName The service for which to return the corresponding password. + + @param account The account for which to return the corresponding password. + + @param error If accessing the password fails, upon return contains an error that describes the problem. + + @return Returns a string containing the password for a given account and service, or `nil` if the Keychain doesn't + have a password for the given parameters. + + @see passwordForService:account: + */ ++ (NSString *)passwordForService:(NSString *)serviceName account:(NSString *)account error:(NSError **)error; + +/** + Returns the password data for a given account and service, or `nil` if the Keychain doesn't have data + for the given parameters. + + @param serviceName The service for which to return the corresponding password. + + @param account The account for which to return the corresponding password. + + @param error If accessing the password fails, upon return contains an error that describes the problem. + + @return Returns a the password data for the given account and service, or `nil` if the Keychain doesn't + have data for the given parameters. + + @see passwordDataForService:account:error: + */ ++ (NSData *)passwordDataForService:(NSString *)serviceName account:(NSString *)account; + +/** + Returns the password data for a given account and service, or `nil` if the Keychain doesn't have data + for the given parameters. + + @param serviceName The service for which to return the corresponding password. + + @param account The account for which to return the corresponding password. + + @param error If accessing the password fails, upon return contains an error that describes the problem. + + @return Returns a the password data for the given account and service, or `nil` if the Keychain doesn't + have a password for the given parameters. + + @see passwordDataForService:account: + */ ++ (NSData *)passwordDataForService:(NSString *)serviceName account:(NSString *)account error:(NSError **)error; + + +///------------------------- +/// @name Deleting Passwords +///------------------------- + +/** + Deletes a password from the Keychain. + + @param serviceName The service for which to delete the corresponding password. + + @param account The account for which to delete the corresponding password. + + @return Returns `YES` on success, or `NO` on failure. + + @see deletePasswordForService:account:error: + */ ++ (BOOL)deletePasswordForService:(NSString *)serviceName account:(NSString *)account; + +/** + Deletes a password from the Keychain. + + @param serviceName The service for which to delete the corresponding password. + + @param account The account for which to delete the corresponding password. + + @param error If deleting the password fails, upon return contains an error that describes the problem. + + @return Returns `YES` on success, or `NO` on failure. + + @see deletePasswordForService:account: + */ ++ (BOOL)deletePasswordForService:(NSString *)serviceName account:(NSString *)account error:(NSError **)error; + + +///------------------------ +/// @name Setting Passwords +///------------------------ + +/** + Sets a password in the Keychain. + + @param password The password to store in the Keychain. + + @param serviceName The service for which to set the corresponding password. + + @param account The account for which to set the corresponding password. + + @return Returns `YES` on success, or `NO` on failure. + + @see setPassword:forService:account:error: + */ ++ (BOOL)setPassword:(NSString *)password forService:(NSString *)serviceName account:(NSString *)account; + +/** + Sets a password in the Keychain. + + @param password The password to store in the Keychain. + + @param serviceName The service for which to set the corresponding password. + + @param account The account for which to set the corresponding password. + + @param error If setting the password fails, upon return contains an error that describes the problem. + + @return Returns `YES` on success, or `NO` on failure. + + @see setPassword:forService:account: + */ ++ (BOOL)setPassword:(NSString *)password forService:(NSString *)serviceName account:(NSString *)account error:(NSError **)error; + +/** + Sets arbirary data in the Keychain. + + @param password The data to store in the Keychain. + + @param serviceName The service for which to set the corresponding password. + + @param account The account for which to set the corresponding password. + + @param error If setting the password fails, upon return contains an error that describes the problem. + + @return Returns `YES` on success, or `NO` on failure. + + @see setPasswordData:forService:account:error: + */ ++ (BOOL)setPasswordData:(NSData *)password forService:(NSString *)serviceName account:(NSString *)account; + +/** + Sets arbirary data in the Keychain. + + @param password The data to store in the Keychain. + + @param serviceName The service for which to set the corresponding password. + + @param account The account for which to set the corresponding password. + + @param error If setting the password fails, upon return contains an error that describes the problem. + + @return Returns `YES` on success, or `NO` on failure. + + @see setPasswordData:forService:account: + */ ++ (BOOL)setPasswordData:(NSData *)password forService:(NSString *)serviceName account:(NSString *)account error:(NSError **)error; + + +///-------------------- +/// @name Configuration +///-------------------- + +#if __IPHONE_4_0 && TARGET_OS_IPHONE +/** + Returns the accessibility type for all future passwords saved to the Keychain. + + @return Returns the accessibility type. + + The return value will be `NULL` or one of the "Keychain Item Accessibility Constants" used for determining when a + keychain item should be readable. + + @see accessibilityType + */ ++ (CFTypeRef)accessibilityType; + +/** + Sets the accessibility type for all future passwords saved to the Keychain. + + @param accessibilityType One of the "Keychain Item Accessibility Constants" used for determining when a keychain item + should be readable. + + If the value is `NULL` (the default), the Keychain default will be used. + + @see accessibilityType + */ ++ (void)setAccessibilityType:(CFTypeRef)accessibilityType; +#endif + +@end diff --git a/Volta/Libraries/SSKeychain/SSKeychain.m b/Volta/Libraries/SSKeychain/SSKeychain.m new file mode 100755 index 0000000..5af4b87 --- /dev/null +++ b/Volta/Libraries/SSKeychain/SSKeychain.m @@ -0,0 +1,312 @@ +// +// SSKeychain.m +// SSToolkit +// +// Created by Sam Soffes on 5/19/10. +// Copyright (c) 2009-2011 Sam Soffes. All rights reserved. +// + +#import "SSKeychain.h" + +NSString *const kSSKeychainErrorDomain = @"com.samsoffes.sskeychain"; + +NSString *const kSSKeychainAccountKey = @"acct"; +NSString *const kSSKeychainCreatedAtKey = @"cdat"; +NSString *const kSSKeychainClassKey = @"labl"; +NSString *const kSSKeychainDescriptionKey = @"desc"; +NSString *const kSSKeychainLabelKey = @"labl"; +NSString *const kSSKeychainLastModifiedKey = @"mdat"; +NSString *const kSSKeychainWhereKey = @"svce"; + +#if __IPHONE_4_0 && TARGET_OS_IPHONE +CFTypeRef SSKeychainAccessibilityType = NULL; +#endif + +@interface SSKeychain () ++ (NSMutableDictionary *)_queryForService:(NSString *)service account:(NSString *)account; ++ (NSError *)_errorWithCode:(OSStatus) code; +@end + +@implementation SSKeychain + +#pragma mark - Getting Accounts + ++ (NSArray *)allAccounts { + return [self accountsForService:nil error:nil]; +} + + ++ (NSArray *)allAccounts:(NSError **)error { + return [self accountsForService:nil error:error]; +} + + ++ (NSArray *)accountsForService:(NSString *)service { + return [self accountsForService:service error:nil]; +} + + ++ (NSArray *)accountsForService:(NSString *)service error:(NSError **)error { + OSStatus status = SSKeychainErrorBadArguments; + NSMutableDictionary *query = [self _queryForService:service account:nil]; +#if __has_feature(objc_arc) + [query setObject:(__bridge id)kCFBooleanTrue forKey:(__bridge id)kSecReturnAttributes]; + [query setObject:(__bridge id)kSecMatchLimitAll forKey:(__bridge id)kSecMatchLimit]; +#else + [query setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnAttributes]; + [query setObject:(id)kSecMatchLimitAll forKey:(id)kSecMatchLimit]; +#endif + + CFTypeRef result = NULL; +#if __has_feature(objc_arc) + status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &result); +#else + status = SecItemCopyMatching((CFDictionaryRef)query, &result); +#endif + if (status != errSecSuccess && error != NULL) { + *error = [self _errorWithCode:status]; + return nil; + } + +#if __has_feature(objc_arc) + return (__bridge_transfer NSArray *)result; +#else + return [(NSArray *)result autorelease]; +#endif +} + + +#pragma mark - Getting Passwords + ++ (NSString *)passwordForService:(NSString *)service account:(NSString *)account { + return [self passwordForService:service account:account error:nil]; +} + + ++ (NSString *)passwordForService:(NSString *)service account:(NSString *)account error:(NSError **)error { + NSData *data = [self passwordDataForService:service account:account error:error]; + if (data.length > 0) { + NSString *string = [[NSString alloc] initWithData:(NSData *)data encoding:NSUTF8StringEncoding]; +#if !__has_feature(objc_arc) + [string autorelease]; +#endif + return string; + } + + return nil; +} + + ++ (NSData *)passwordDataForService:(NSString *)service account:(NSString *)account { + return [self passwordDataForService:service account:account error:nil]; +} + + ++ (NSData *)passwordDataForService:(NSString *)service account:(NSString *)account error:(NSError **)error { + OSStatus status = SSKeychainErrorBadArguments; + if (!service || !account) { + if (error) { + *error = [self _errorWithCode:status]; + } + return nil; + } + + CFTypeRef result = NULL; + NSMutableDictionary *query = [self _queryForService:service account:account]; +#if __has_feature(objc_arc) + [query setObject:(__bridge id)kCFBooleanTrue forKey:(__bridge id)kSecReturnData]; + [query setObject:(__bridge id)kSecMatchLimitOne forKey:(__bridge id)kSecMatchLimit]; + status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &result); +#else + [query setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnData]; + [query setObject:(id)kSecMatchLimitOne forKey:(id)kSecMatchLimit]; + status = SecItemCopyMatching((CFDictionaryRef)query, &result); +#endif + + if (status != errSecSuccess && error != NULL) { + *error = [self _errorWithCode:status]; + return nil; + } + +#if __has_feature(objc_arc) + return (__bridge_transfer NSData *)result; +#else + return [(NSData *)result autorelease]; +#endif +} + + +#pragma mark - Deleting Passwords + ++ (BOOL)deletePasswordForService:(NSString *)service account:(NSString *)account { + return [self deletePasswordForService:service account:account error:nil]; +} + + ++ (BOOL)deletePasswordForService:(NSString *)service account:(NSString *)account error:(NSError **)error { + OSStatus status = SSKeychainErrorBadArguments; + if (service && account) { + NSMutableDictionary *query = [self _queryForService:service account:account]; +#if TARGET_OS_IPHONE && __has_feature(objc_arc) + status = SecItemDelete((__bridge CFDictionaryRef)query); +#elif TARGET_OS_IPHONE + status = SecItemDelete((CFDictionaryRef)query); +#else + CFTypeRef result; + #if __has_feature(objc_arc) + [query setObject:(__bridge id)kCFBooleanTrue forKey:(__bridge id)kSecReturnRef]; + status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &result); + #else + [query setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnRef]; + status = SecItemCopyMatching((CFDictionaryRef)query, &result); + #endif + if (errSecSuccess == status) { + status = SecKeychainItemDelete((SecKeychainItemRef) result); + CFRelease(result); + } +#endif + } + if (status != errSecSuccess && error != NULL) { + *error = [self _errorWithCode:status]; + } + return (status == errSecSuccess); + +} + + +#pragma mark - Setting Passwords + ++ (BOOL)setPassword:(NSString *)password forService:(NSString *)service account:(NSString *)account { + return [self setPassword:password forService:service account:account error:nil]; +} + + ++ (BOOL)setPassword:(NSString *)password forService:(NSString *)service account:(NSString *)account error:(NSError **)error { + NSData *data = [password dataUsingEncoding:NSUTF8StringEncoding]; + return [self setPasswordData:data forService:service account:account error:error]; +} + + ++ (BOOL)setPasswordData:(NSData *)password forService:(NSString *)service account:(NSString *)account { + return [self setPasswordData:password forService:service account:account error:nil]; +} + + ++ (BOOL)setPasswordData:(NSData *)password forService:(NSString *)service account:(NSString *)account error:(NSError **)error { + OSStatus status = SSKeychainErrorBadArguments; + if (password && service && account) { + [self deletePasswordForService:service account:account]; + NSMutableDictionary *query = [self _queryForService:service account:account]; +#if __has_feature(objc_arc) + [query setObject:password forKey:(__bridge id)kSecValueData]; +#else + [query setObject:password forKey:(id)kSecValueData]; +#endif + +#if __IPHONE_4_0 && TARGET_OS_IPHONE + if (SSKeychainAccessibilityType) { +#if __has_feature(objc_arc) + [query setObject:(id)[self accessibilityType] forKey:(__bridge id)kSecAttrAccessible]; +#else + [query setObject:(id)[self accessibilityType] forKey:(id)kSecAttrAccessible]; +#endif + } +#endif + +#if __has_feature(objc_arc) + status = SecItemAdd((__bridge CFDictionaryRef)query, NULL); +#else + status = SecItemAdd((CFDictionaryRef)query, NULL); +#endif + } + if (status != errSecSuccess && error != NULL) { + *error = [self _errorWithCode:status]; + } + return (status == errSecSuccess); +} + + +#pragma mark - Configuration + +#if __IPHONE_4_0 && TARGET_OS_IPHONE ++ (CFTypeRef)accessibilityType { + return SSKeychainAccessibilityType; +} + + ++ (void)setAccessibilityType:(CFTypeRef)accessibilityType { + CFRetain(accessibilityType); + if (SSKeychainAccessibilityType) { + CFRelease(SSKeychainAccessibilityType); + } + SSKeychainAccessibilityType = accessibilityType; +} +#endif + + +#pragma mark - Private + ++ (NSMutableDictionary *)_queryForService:(NSString *)service account:(NSString *)account { + NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithCapacity:3]; +#if __has_feature(objc_arc) + [dictionary setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass]; +#else + [dictionary setObject:(id)kSecClassGenericPassword forKey:(id)kSecClass]; +#endif + + if (service) { +#if __has_feature(objc_arc) + [dictionary setObject:service forKey:(__bridge id)kSecAttrService]; +#else + [dictionary setObject:service forKey:(id)kSecAttrService]; +#endif + } + + if (account) { +#if __has_feature(objc_arc) + [dictionary setObject:account forKey:(__bridge id)kSecAttrAccount]; +#else + [dictionary setObject:account forKey:(id)kSecAttrAccount]; +#endif + } + + return dictionary; +} + + ++ (NSError *)_errorWithCode:(OSStatus) code { + NSString *message = nil; + switch (code) { + case errSecSuccess: return nil; + case SSKeychainErrorBadArguments: message = @"Some of the arguments were invalid"; break; + +#if TARGET_OS_IPHONE + case errSecUnimplemented: message = @"Function or operation not implemented"; break; + case errSecParam: message = @"One or more parameters passed to a function were not valid"; break; + case errSecAllocate: message = @"Failed to allocate memory"; break; + case errSecNotAvailable: message = @"No keychain is available. You may need to restart your computer"; break; + case errSecDuplicateItem: message = @"The specified item already exists in the keychain"; break; + case errSecItemNotFound: message = @"The specified item could not be found in the keychain"; break; + case errSecInteractionNotAllowed: message = @"User interaction is not allowed"; break; + case errSecDecode: message = @"Unable to decode the provided data"; break; + case errSecAuthFailed: message = @"The user name or passphrase you entered is not correct"; break; + default: message = @"Refer to SecBase.h for description"; +#elif __has_feature(objc_arc) + default: + message = (__bridge_transfer NSString *)SecCopyErrorMessageString(code, NULL); +#else + default: + message = [(id) SecCopyErrorMessageString(code, NULL) autorelease]; +#endif + } + + NSDictionary *userInfo = nil; + if (message != nil) { + userInfo = @{ NSLocalizedDescriptionKey : message }; + } + return [NSError errorWithDomain:kSSKeychainErrorDomain + code:code + userInfo:userInfo]; +} + +@end |
