| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262 |
- //
- // 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;
- @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 != noErr && error != NULL) {
- *error = [NSError errorWithDomain:kSSKeychainErrorDomain code:status userInfo:nil];
- 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 = [NSError errorWithDomain:kSSKeychainErrorDomain code:status userInfo:nil];
- }
- 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 != noErr && error != NULL) {
- *error = [NSError errorWithDomain:kSSKeychainErrorDomain code:status userInfo:nil];
- 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 __has_feature(objc_arc)
- status = SecItemDelete((__bridge CFDictionaryRef)query);
- #else
- status = SecItemDelete((CFDictionaryRef)query);
- #endif
- }
- if (status != noErr && error != NULL) {
- *error = [NSError errorWithDomain:kSSKeychainErrorDomain code:status userInfo:nil];
- }
- return (status == noErr);
-
- }
- #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 != noErr && error != NULL) {
- *error = [NSError errorWithDomain:kSSKeychainErrorDomain code:status userInfo:nil];
- }
- return (status == noErr);
- }
- #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;
- }
- @end
|