├── VERSION ├── .gitignore ├── SSKeychain.podspec ├── Tests ├── SSKeychainTests-Info.plist ├── SSKeychainTestsARC-Info.plist ├── SSKeychainTests.m └── SSKeychain.xcodeproj │ └── project.pbxproj ├── Changelog.markdown ├── LICENSE ├── Rakefile ├── Readme.markdown ├── SSKeychain.m └── SSKeychain.h /VERSION: -------------------------------------------------------------------------------- 1 | 0.1.4 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.mode1v3 3 | *.pbxuser 4 | *.perspectivev3 5 | *.xcworkspace 6 | xcuserdata 7 | Documentation 8 | -------------------------------------------------------------------------------- /SSKeychain.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'SSKeychain' 3 | s.version = '0.1.4' 4 | s.summary = 'Simple Cocoa wrapper for the keychain that works on Mac and iOS' 5 | s.homepage = 'https://github.com/samsoffes/sskeychain' 6 | s.author = { 'Sam Soffes' => 'sam@samsoff.es' } 7 | s.source = { :git => 'https://github.com/samsoffes/sskeychain.git', :tag => '0.1.4' } 8 | s.description = 'SSKeychain is a simple utility class for making the system keychain less sucky.' 9 | s.source_files = 'SSKeychain.*' 10 | s.frameworks = 'Security' 11 | s.license = { :type => 'MIT', :file => 'LICENSE' } 12 | end 13 | -------------------------------------------------------------------------------- /Tests/SSKeychainTests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | com.samsoffes.${PRODUCT_NAME:rfc1034identifier} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Tests/SSKeychainTestsARC-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | com.samsoffes.${PRODUCT_NAME:rfc1034identifier} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Changelog.markdown: -------------------------------------------------------------------------------- 1 | # SSKeychain Changelog 2 | 3 | ### Version 0.1.3 4 | 5 | [Released October 18, 2011](https://github.com/samsoffes/sskeychain/tree/0.1.2) 6 | 7 | * Added ARC support 8 | 9 | ### Version 0.1.2 10 | 11 | [Released October 18, 2011](https://github.com/samsoffes/sskeychain/tree/0.1.2) 12 | 13 | * Added documentation 14 | * Added string constants for keys in returned dictionaries 15 | * Renamed `SSKeychainErrorDomain` to `kSSKeychainErrorDomain` 16 | * Added Rakefile for generating documentation 17 | * Added documentation installation instructions to readme 18 | 19 | ### Version 0.1.1 20 | 21 | [Released October 3, 2011](https://github.com/samsoffes/sskeychain/tree/0.1.1) 22 | 23 | * Renamed `+[SSKeychain accounts]` to `+[SSKeychain allAccounts]` 24 | * Added basic tests 25 | 26 | ### Version 0.1.0 27 | 28 | [Released September 18, 2011](https://github.com/samsoffes/sskeychain/tree/0.1.0) 29 | 30 | * Initial release 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010-2012 Sam Soffes. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | header_path = '*.h' 2 | 3 | appledoc_options = [ 4 | '--output Documentation', 5 | '--project-name SSKeychain', 6 | '--project-company \'Sam Soffes\'', 7 | '--company-id com.samsoffes', 8 | "--project-version #{`cat VERSION`.strip}", 9 | '--keep-intermediate-files', 10 | '--create-html', 11 | '--templates ~/Library/Application\ Support/appledoc/Templates/', 12 | '--no-repeat-first-par', 13 | '--verbose'] 14 | 15 | namespace :docs do 16 | desc 'Clean docs' 17 | task :clean do 18 | `rm -rf Documentation` 19 | end 20 | 21 | desc 'Install docs' 22 | task :install => [:'docs:clean'] do 23 | `appledoc #{appledoc_options.join(' ')} --create-docset --install-docset #{header_path}` 24 | end 25 | 26 | desc 'Publish docs' 27 | task :publish => [:'docs:clean'] do 28 | extra_options = [ 29 | '--create-docset', 30 | '--publish-docset', 31 | '--install-docset', 32 | '--docset-atom-filename com.samsoffes.sskeychain.atom', 33 | '--docset-feed-url http://docs.samsoff.es/%DOCSETATOMFILENAME', 34 | '--docset-package-url http://docs.samsoff.es/%DOCSETPACKAGEFILENAME' 35 | ] 36 | `appledoc #{appledoc_options.join(' ')} #{extra_options.join(' ')} #{header_path}` 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /Tests/SSKeychainTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // SSKeychainTests.m 3 | // SSKeychainTests 4 | // 5 | // Created by Sam Soffes on 10/3/11. 6 | // Copyright (c) 2011 Sam Soffes. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "SSKeychain.h" 11 | 12 | static NSString *kSSToolkitTestsServiceName = @"SSToolkitTestService"; 13 | static NSString *kSSToolkitTestsAccountName = @"SSToolkitTestAccount"; 14 | static NSString *kSSToolkitTestsPassword = @"SSToolkitTestPassword"; 15 | 16 | @interface SSKeychainTests : SenTestCase 17 | 18 | - (BOOL)_accounts:(NSArray *)accounts containsAccountWithName:(NSString *)name; 19 | 20 | @end 21 | 22 | @implementation SSKeychainTests 23 | 24 | - (void)testAll { 25 | // Getting & Setings Passwords 26 | [SSKeychain setPassword:kSSToolkitTestsPassword forService:kSSToolkitTestsServiceName account:kSSToolkitTestsAccountName]; 27 | NSString *password = [SSKeychain passwordForService:kSSToolkitTestsServiceName account:kSSToolkitTestsAccountName]; 28 | STAssertEqualObjects(password, kSSToolkitTestsPassword, @"Password reads and writes"); 29 | 30 | // Getting Accounts 31 | NSArray *accounts = [SSKeychain allAccounts]; 32 | STAssertTrue([self _accounts:accounts containsAccountWithName:kSSToolkitTestsAccountName], @"All accounts"); 33 | 34 | accounts = [SSKeychain accountsForService:kSSToolkitTestsServiceName]; 35 | STAssertTrue([self _accounts:accounts containsAccountWithName:kSSToolkitTestsAccountName], @"Account for service"); 36 | 37 | // Deleting Passwords 38 | [SSKeychain deletePasswordForService:kSSToolkitTestsServiceName account:kSSToolkitTestsAccountName]; 39 | password = [SSKeychain passwordForService:kSSToolkitTestsServiceName account:kSSToolkitTestsAccountName]; 40 | STAssertNil(password, @"Password deletes"); 41 | } 42 | 43 | 44 | - (BOOL)_accounts:(NSArray *)accounts containsAccountWithName:(NSString *)name { 45 | for (NSDictionary *dictionary in accounts) { 46 | if ([[dictionary objectForKey:@"acct"] isEqualToString:name]) { 47 | return YES; 48 | } 49 | } 50 | return NO; 51 | } 52 | 53 | @end 54 | -------------------------------------------------------------------------------- /Readme.markdown: -------------------------------------------------------------------------------- 1 | # SSKeychain 2 | 3 | SSKeychain is a simple wrapper for accessing accounts, getting passwords, setting passwords, and deleting passwords using the system Keychain on Mac OS X and iOS. SSKeychain works in ARC and non-ARC projects. 4 | 5 | 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). 6 | 7 | ## Adding to your project 8 | 9 | 1. Add `Security.framework` to your target 10 | 2. Add `SSKeychain.h` and `SSKeychain.m` to your project. 11 | 12 | You don't need to do anything regarding ARC. SSKeychain will detect if you're not using ARC and add the required memory management code. 13 | 14 | Note: Currently SSKeychain does not support Mac OS 10.6. 15 | 16 | ## Working with the keychain 17 | 18 | SSKeychain has the following class methods for working with the system keychain: 19 | 20 | ```objective-c 21 | + (NSArray *)allAccounts; 22 | + (NSArray *)accountsForService:(NSString *)serviceName; 23 | + (NSString *)passwordForService:(NSString *)serviceName account:(NSString *)account; 24 | + (BOOL)deletePasswordForService:(NSString *)serviceName account:(NSString *)account; 25 | + (BOOL)setPassword:(NSString *)password forService:(NSString *)serviceName account:(NSString *)account; 26 | ``` 27 | 28 | Easy as that. (See [SSKeychain.h](https://github.com/samsoffes/sskeychain/blob/master/SSKeychain.h) for all of the methods.) 29 | 30 | ## Documentation 31 | 32 | Install the documentation into Xcode with the following steps: 33 | 34 | 1. Open Xcode Preferences 35 | 2. Choose Downloads 36 | 3. Choose the Documentation tab 37 | 4. Click the plus button in the bottom right and enter the following URL: 38 | 39 | http://docs.samsoff.es/com.samsoffes.sskeychain.atom 40 | 41 | 5. Click Install next the new row reading "SSKeychain Documentation". (If you don't see it and didn't get an error, try restarting Xcode.) 42 | 43 | Be sure you have the docset selected in the organizer to see results for SSKeychain. 44 | 45 | You can also **read the [SSKeychain Documentation](http://docs.samsoff.es/SSKeychain/Classes/SSKeychain.html) online.** 46 | 47 | ## Debugging 48 | 49 | If you saving to the keychain fails, you use the error codes provided in SSKeychain.h. Here's an example: 50 | 51 | ```objective-c 52 | NSError *error = nil; 53 | NSString *password = [SSKeychain passwordForService:@"MyService" account:@"samsoffes" error:&error]; 54 | 55 | if ([error code] == SSKeychainErrorNotFound) { 56 | NSLog(@"Password not found"); 57 | } 58 | ``` 59 | 60 | Obviously, you should do something more sophisticated. Working with the keychain is pretty sucky. You should really check for errors and failures. This library doesn't make it any more stable, it just wraps up all of the annoying C APIs. 61 | -------------------------------------------------------------------------------- /SSKeychain.m: -------------------------------------------------------------------------------- 1 | // 2 | // SSKeychain.m 3 | // SSToolkit 4 | // 5 | // Created by Sam Soffes on 5/19/10. 6 | // Copyright (c) 2009-2011 Sam Soffes. All rights reserved. 7 | // 8 | 9 | #import "SSKeychain.h" 10 | 11 | NSString *const kSSKeychainErrorDomain = @"com.samsoffes.sskeychain"; 12 | 13 | NSString *const kSSKeychainAccountKey = @"acct"; 14 | NSString *const kSSKeychainCreatedAtKey = @"cdat"; 15 | NSString *const kSSKeychainClassKey = @"labl"; 16 | NSString *const kSSKeychainDescriptionKey = @"desc"; 17 | NSString *const kSSKeychainLabelKey = @"labl"; 18 | NSString *const kSSKeychainLastModifiedKey = @"mdat"; 19 | NSString *const kSSKeychainWhereKey = @"svce"; 20 | 21 | #if __IPHONE_4_0 && TARGET_OS_IPHONE 22 | CFTypeRef SSKeychainAccessibilityType = NULL; 23 | #endif 24 | 25 | @interface SSKeychain () 26 | + (NSMutableDictionary *)_queryForService:(NSString *)service account:(NSString *)account; 27 | @end 28 | 29 | @implementation SSKeychain 30 | 31 | #pragma mark - Getting Accounts 32 | 33 | + (NSArray *)allAccounts { 34 | return [self accountsForService:nil error:nil]; 35 | } 36 | 37 | 38 | + (NSArray *)allAccounts:(NSError **)error { 39 | return [self accountsForService:nil error:error]; 40 | } 41 | 42 | 43 | + (NSArray *)accountsForService:(NSString *)service { 44 | return [self accountsForService:service error:nil]; 45 | } 46 | 47 | 48 | + (NSArray *)accountsForService:(NSString *)service error:(NSError **)error { 49 | OSStatus status = SSKeychainErrorBadArguments; 50 | NSMutableDictionary *query = [self _queryForService:service account:nil]; 51 | #if __has_feature(objc_arc) 52 | [query setObject:(__bridge id)kCFBooleanTrue forKey:(__bridge id)kSecReturnAttributes]; 53 | [query setObject:(__bridge id)kSecMatchLimitAll forKey:(__bridge id)kSecMatchLimit]; 54 | #else 55 | [query setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnAttributes]; 56 | [query setObject:(id)kSecMatchLimitAll forKey:(id)kSecMatchLimit]; 57 | #endif 58 | 59 | CFTypeRef result = NULL; 60 | #if __has_feature(objc_arc) 61 | status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &result); 62 | #else 63 | status = SecItemCopyMatching((CFDictionaryRef)query, &result); 64 | #endif 65 | if (status != noErr && error != NULL) { 66 | *error = [NSError errorWithDomain:kSSKeychainErrorDomain code:status userInfo:nil]; 67 | return nil; 68 | } 69 | 70 | #if __has_feature(objc_arc) 71 | return (__bridge_transfer NSArray *)result; 72 | #else 73 | return [(NSArray *)result autorelease]; 74 | #endif 75 | } 76 | 77 | 78 | #pragma mark - Getting Passwords 79 | 80 | + (NSString *)passwordForService:(NSString *)service account:(NSString *)account { 81 | return [self passwordForService:service account:account error:nil]; 82 | } 83 | 84 | 85 | + (NSString *)passwordForService:(NSString *)service account:(NSString *)account error:(NSError **)error { 86 | NSData *data = [self passwordDataForService:service account:account error:error]; 87 | if (data.length > 0) { 88 | NSString *string = [[NSString alloc] initWithData:(NSData *)data encoding:NSUTF8StringEncoding]; 89 | #if !__has_feature(objc_arc) 90 | [string autorelease]; 91 | #endif 92 | return string; 93 | } 94 | 95 | return nil; 96 | } 97 | 98 | 99 | + (NSData *)passwordDataForService:(NSString *)service account:(NSString *)account { 100 | return [self passwordDataForService:service account:account error:nil]; 101 | } 102 | 103 | 104 | + (NSData *)passwordDataForService:(NSString *)service account:(NSString *)account error:(NSError **)error { 105 | OSStatus status = SSKeychainErrorBadArguments; 106 | if (!service || !account) { 107 | if (error) { 108 | *error = [NSError errorWithDomain:kSSKeychainErrorDomain code:status userInfo:nil]; 109 | } 110 | return nil; 111 | } 112 | 113 | CFTypeRef result = NULL; 114 | NSMutableDictionary *query = [self _queryForService:service account:account]; 115 | #if __has_feature(objc_arc) 116 | [query setObject:(__bridge id)kCFBooleanTrue forKey:(__bridge id)kSecReturnData]; 117 | [query setObject:(__bridge id)kSecMatchLimitOne forKey:(__bridge id)kSecMatchLimit]; 118 | status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &result); 119 | #else 120 | [query setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnData]; 121 | [query setObject:(id)kSecMatchLimitOne forKey:(id)kSecMatchLimit]; 122 | status = SecItemCopyMatching((CFDictionaryRef)query, &result); 123 | #endif 124 | 125 | if (status != noErr && error != NULL) { 126 | *error = [NSError errorWithDomain:kSSKeychainErrorDomain code:status userInfo:nil]; 127 | return nil; 128 | } 129 | 130 | #if __has_feature(objc_arc) 131 | return (__bridge_transfer NSData *)result; 132 | #else 133 | return [(NSData *)result autorelease]; 134 | #endif 135 | } 136 | 137 | 138 | #pragma mark - Deleting Passwords 139 | 140 | + (BOOL)deletePasswordForService:(NSString *)service account:(NSString *)account { 141 | return [self deletePasswordForService:service account:account error:nil]; 142 | } 143 | 144 | 145 | + (BOOL)deletePasswordForService:(NSString *)service account:(NSString *)account error:(NSError **)error { 146 | OSStatus status = SSKeychainErrorBadArguments; 147 | if (service && account) { 148 | NSMutableDictionary *query = [self _queryForService:service account:account]; 149 | #if __has_feature(objc_arc) 150 | status = SecItemDelete((__bridge CFDictionaryRef)query); 151 | #else 152 | status = SecItemDelete((CFDictionaryRef)query); 153 | #endif 154 | } 155 | if (status != noErr && error != NULL) { 156 | *error = [NSError errorWithDomain:kSSKeychainErrorDomain code:status userInfo:nil]; 157 | } 158 | return (status == noErr); 159 | 160 | } 161 | 162 | 163 | #pragma mark - Setting Passwords 164 | 165 | + (BOOL)setPassword:(NSString *)password forService:(NSString *)service account:(NSString *)account { 166 | return [self setPassword:password forService:service account:account error:nil]; 167 | } 168 | 169 | 170 | + (BOOL)setPassword:(NSString *)password forService:(NSString *)service account:(NSString *)account error:(NSError **)error { 171 | NSData *data = [password dataUsingEncoding:NSUTF8StringEncoding]; 172 | return [self setPasswordData:data forService:service account:account error:error]; 173 | } 174 | 175 | 176 | + (BOOL)setPasswordData:(NSData *)password forService:(NSString *)service account:(NSString *)account { 177 | return [self setPasswordData:password forService:service account:account error:nil]; 178 | } 179 | 180 | 181 | + (BOOL)setPasswordData:(NSData *)password forService:(NSString *)service account:(NSString *)account error:(NSError **)error { 182 | OSStatus status = SSKeychainErrorBadArguments; 183 | if (password && service && account) { 184 | [self deletePasswordForService:service account:account]; 185 | NSMutableDictionary *query = [self _queryForService:service account:account]; 186 | #if __has_feature(objc_arc) 187 | [query setObject:password forKey:(__bridge id)kSecValueData]; 188 | #else 189 | [query setObject:password forKey:(id)kSecValueData]; 190 | #endif 191 | 192 | #if __IPHONE_4_0 && TARGET_OS_IPHONE 193 | if (SSKeychainAccessibilityType) { 194 | #if __has_feature(objc_arc) 195 | [query setObject:(id)[self accessibilityType] forKey:(__bridge id)kSecAttrAccessible]; 196 | #else 197 | [query setObject:(id)[self accessibilityType] forKey:(id)kSecAttrAccessible]; 198 | #endif 199 | } 200 | #endif 201 | 202 | #if __has_feature(objc_arc) 203 | status = SecItemAdd((__bridge CFDictionaryRef)query, NULL); 204 | #else 205 | status = SecItemAdd((CFDictionaryRef)query, NULL); 206 | #endif 207 | } 208 | if (status != noErr && error != NULL) { 209 | *error = [NSError errorWithDomain:kSSKeychainErrorDomain code:status userInfo:nil]; 210 | } 211 | return (status == noErr); 212 | } 213 | 214 | 215 | #pragma mark - Configuration 216 | 217 | #if __IPHONE_4_0 && TARGET_OS_IPHONE 218 | + (CFTypeRef)accessibilityType { 219 | return SSKeychainAccessibilityType; 220 | } 221 | 222 | 223 | + (void)setAccessibilityType:(CFTypeRef)accessibilityType { 224 | CFRetain(accessibilityType); 225 | if (SSKeychainAccessibilityType) { 226 | CFRelease(SSKeychainAccessibilityType); 227 | } 228 | SSKeychainAccessibilityType = accessibilityType; 229 | } 230 | #endif 231 | 232 | 233 | #pragma mark - Private 234 | 235 | + (NSMutableDictionary *)_queryForService:(NSString *)service account:(NSString *)account { 236 | NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithCapacity:3]; 237 | #if __has_feature(objc_arc) 238 | [dictionary setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass]; 239 | #else 240 | [dictionary setObject:(id)kSecClassGenericPassword forKey:(id)kSecClass]; 241 | #endif 242 | 243 | if (service) { 244 | #if __has_feature(objc_arc) 245 | [dictionary setObject:service forKey:(__bridge id)kSecAttrService]; 246 | #else 247 | [dictionary setObject:service forKey:(id)kSecAttrService]; 248 | #endif 249 | } 250 | 251 | if (account) { 252 | #if __has_feature(objc_arc) 253 | [dictionary setObject:account forKey:(__bridge id)kSecAttrAccount]; 254 | #else 255 | [dictionary setObject:account forKey:(id)kSecAttrAccount]; 256 | #endif 257 | } 258 | 259 | return dictionary; 260 | } 261 | 262 | @end 263 | -------------------------------------------------------------------------------- /SSKeychain.h: -------------------------------------------------------------------------------- 1 | // 2 | // SSKeychain.h 3 | // SSToolkit 4 | // 5 | // Created by Sam Soffes on 5/19/10. 6 | // Copyright (c) 2009-2011 Sam Soffes. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | /** Error codes that can be returned in NSError objects. */ 13 | typedef enum { 14 | /** No error. */ 15 | SSKeychainErrorNone = noErr, 16 | 17 | /** Some of the arguments were invalid. */ 18 | SSKeychainErrorBadArguments = -1001, 19 | 20 | /** There was no password. */ 21 | SSKeychainErrorNoPassword = -1002, 22 | 23 | /** One or more parameters passed internally were not valid. */ 24 | SSKeychainErrorInvalidParameter = errSecParam, 25 | 26 | /** Failed to allocate memory. */ 27 | SSKeychainErrorFailedToAllocated = errSecAllocate, 28 | 29 | /** No trust results are available. */ 30 | SSKeychainErrorNotAvailable = errSecNotAvailable, 31 | 32 | /** Authorization/Authentication failed. */ 33 | SSKeychainErrorAuthorizationFailed = errSecAuthFailed, 34 | 35 | /** The item already exists. */ 36 | SSKeychainErrorDuplicatedItem = errSecDuplicateItem, 37 | 38 | /** The item cannot be found.*/ 39 | SSKeychainErrorNotFound = errSecItemNotFound, 40 | 41 | /** Interaction with the Security Server is not allowed. */ 42 | SSKeychainErrorInteractionNotAllowed = errSecInteractionNotAllowed, 43 | 44 | /** Unable to decode the provided data. */ 45 | SSKeychainErrorFailedToDecode = errSecDecode 46 | } SSKeychainErrorCode; 47 | 48 | extern NSString *const kSSKeychainErrorDomain; 49 | 50 | /** Account name. */ 51 | extern NSString *const kSSKeychainAccountKey; 52 | 53 | /** 54 | Time the item was created. 55 | 56 | The value will be a string. 57 | */ 58 | extern NSString *const kSSKeychainCreatedAtKey; 59 | 60 | /** Item class. */ 61 | extern NSString *const kSSKeychainClassKey; 62 | 63 | /** Item description. */ 64 | extern NSString *const kSSKeychainDescriptionKey; 65 | 66 | /** Item label. */ 67 | extern NSString *const kSSKeychainLabelKey; 68 | 69 | /** Time the item was last modified. 70 | 71 | The value will be a string. 72 | */ 73 | extern NSString *const kSSKeychainLastModifiedKey; 74 | 75 | /** Where the item was created. */ 76 | extern NSString *const kSSKeychainWhereKey; 77 | 78 | /** 79 | Simple wrapper for accessing accounts, getting passwords, setting passwords, and deleting passwords using the system 80 | Keychain on Mac OS X and iOS. 81 | 82 | This was originally inspired by EMKeychain and SDKeychain (both of which are now gone). Thanks to the authors. 83 | SSKeychain has since switched to a simpler implementation that was abstracted from [SSToolkit](http://sstoolk.it). 84 | */ 85 | @interface SSKeychain : NSObject 86 | 87 | ///----------------------- 88 | /// @name Getting Accounts 89 | ///----------------------- 90 | 91 | /** 92 | Returns an array containing the Keychain's accounts, or `nil` if the Keychain has no accounts. 93 | 94 | See the `NSString` constants declared in SSKeychain.h for a list of keys that can be used when accessing the 95 | dictionaries returned by this method. 96 | 97 | @return An array of dictionaries containing the Keychain's accounts, or `nil` if the Keychain doesn't have any 98 | accounts. The order of the objects in the array isn't defined. 99 | 100 | @see allAccounts: 101 | */ 102 | + (NSArray *)allAccounts; 103 | 104 | /** 105 | Returns an array containing the Keychain's accounts, or `nil` if the Keychain doesn't have any 106 | accounts. 107 | 108 | See the `NSString` constants declared in SSKeychain.h for a list of keys that can be used when accessing the 109 | dictionaries returned by this method. 110 | 111 | @param error If accessing the accounts fails, upon return contains an error that describes the problem. 112 | 113 | @return An array of dictionaries containing the Keychain's accounts, or `nil` if the Keychain doesn't have any 114 | accounts. The order of the objects in the array isn't defined. 115 | 116 | @see allAccounts 117 | */ 118 | + (NSArray *)allAccounts:(NSError **)error; 119 | 120 | /** 121 | Returns an array containing the Keychain's accounts for a given service, or `nil` if the Keychain doesn't have any 122 | accounts for the given service. 123 | 124 | See the `NSString` constants declared in SSKeychain.h for a list of keys that can be used when accessing the 125 | dictionaries returned by this method. 126 | 127 | @param serviceName The service for which to return the corresponding accounts. 128 | 129 | @return An array of dictionaries containing the Keychain's accountsfor a given `serviceName`, or `nil` if the Keychain 130 | doesn't have any accounts for the given `serviceName`. The order of the objects in the array isn't defined. 131 | 132 | @see accountsForService:error: 133 | */ 134 | + (NSArray *)accountsForService:(NSString *)serviceName; 135 | 136 | /** 137 | Returns an array containing the Keychain's accounts for a given service, or `nil` if the Keychain doesn't have any 138 | accounts for the given service. 139 | 140 | @param serviceName The service for which to return the corresponding accounts. 141 | 142 | @param error If accessing the accounts fails, upon return contains an error that describes the problem. 143 | 144 | @return An array of dictionaries containing the Keychain's accountsfor a given `serviceName`, or `nil` if the Keychain 145 | doesn't have any accounts for the given `serviceName`. The order of the objects in the array isn't defined. 146 | 147 | @see accountsForService: 148 | */ 149 | + (NSArray *)accountsForService:(NSString *)serviceName error:(NSError **)error; 150 | 151 | 152 | ///------------------------ 153 | /// @name Getting Passwords 154 | ///------------------------ 155 | 156 | /** 157 | Returns a string containing the password for a given account and service, or `nil` if the Keychain doesn't have a 158 | password for the given parameters. 159 | 160 | @param serviceName The service for which to return the corresponding password. 161 | 162 | @param account The account for which to return the corresponding password. 163 | 164 | @return Returns a string containing the password for a given account and service, or `nil` if the Keychain doesn't 165 | have a password for the given parameters. 166 | 167 | @see passwordForService:account:error: 168 | */ 169 | + (NSString *)passwordForService:(NSString *)serviceName account:(NSString *)account; 170 | 171 | /** 172 | Returns a string containing the password for a given account and service, or `nil` if the Keychain doesn't have a 173 | password for the given parameters. 174 | 175 | @param serviceName The service for which to return the corresponding password. 176 | 177 | @param account The account for which to return the corresponding password. 178 | 179 | @param error If accessing the password fails, upon return contains an error that describes the problem. 180 | 181 | @return Returns a string containing the password for a given account and service, or `nil` if the Keychain doesn't 182 | have a password for the given parameters. 183 | 184 | @see passwordForService:account: 185 | */ 186 | + (NSString *)passwordForService:(NSString *)serviceName account:(NSString *)account error:(NSError **)error; 187 | 188 | /** 189 | Returns the password data for a given account and service, or `nil` if the Keychain doesn't have data 190 | for the given parameters. 191 | 192 | @param serviceName The service for which to return the corresponding password. 193 | 194 | @param account The account for which to return the corresponding password. 195 | 196 | @param error If accessing the password fails, upon return contains an error that describes the problem. 197 | 198 | @return Returns a the password data for the given account and service, or `nil` if the Keychain doesn't 199 | have data for the given parameters. 200 | 201 | @see passwordDataForService:account:error: 202 | */ 203 | + (NSData *)passwordDataForService:(NSString *)serviceName account:(NSString *)account; 204 | 205 | /** 206 | Returns the password data for a given account and service, or `nil` if the Keychain doesn't have data 207 | for the given parameters. 208 | 209 | @param serviceName The service for which to return the corresponding password. 210 | 211 | @param account The account for which to return the corresponding password. 212 | 213 | @param error If accessing the password fails, upon return contains an error that describes the problem. 214 | 215 | @return Returns a the password data for the given account and service, or `nil` if the Keychain doesn't 216 | have a password for the given parameters. 217 | 218 | @see passwordDataForService:account: 219 | */ 220 | + (NSData *)passwordDataForService:(NSString *)serviceName account:(NSString *)account error:(NSError **)error; 221 | 222 | 223 | ///------------------------- 224 | /// @name Deleting Passwords 225 | ///------------------------- 226 | 227 | /** 228 | Deletes a password from the Keychain. 229 | 230 | @param serviceName The service for which to delete the corresponding password. 231 | 232 | @param account The account for which to delete the corresponding password. 233 | 234 | @return Returns `YES` on success, or `NO` on failure. 235 | 236 | @see deletePasswordForService:account:error: 237 | */ 238 | + (BOOL)deletePasswordForService:(NSString *)serviceName account:(NSString *)account; 239 | 240 | /** 241 | Deletes a password from the Keychain. 242 | 243 | @param serviceName The service for which to delete the corresponding password. 244 | 245 | @param account The account for which to delete the corresponding password. 246 | 247 | @param error If deleting the password fails, upon return contains an error that describes the problem. 248 | 249 | @return Returns `YES` on success, or `NO` on failure. 250 | 251 | @see deletePasswordForService:account: 252 | */ 253 | + (BOOL)deletePasswordForService:(NSString *)serviceName account:(NSString *)account error:(NSError **)error; 254 | 255 | 256 | ///------------------------ 257 | /// @name Setting Passwords 258 | ///------------------------ 259 | 260 | /** 261 | Sets a password in the Keychain. 262 | 263 | @param password The password to store in the Keychain. 264 | 265 | @param serviceName The service for which to set the corresponding password. 266 | 267 | @param account The account for which to set the corresponding password. 268 | 269 | @return Returns `YES` on success, or `NO` on failure. 270 | 271 | @see setPassword:forService:account:error: 272 | */ 273 | + (BOOL)setPassword:(NSString *)password forService:(NSString *)serviceName account:(NSString *)account; 274 | 275 | /** 276 | Sets a password in the Keychain. 277 | 278 | @param password The password to store in the Keychain. 279 | 280 | @param serviceName The service for which to set the corresponding password. 281 | 282 | @param account The account for which to set the corresponding password. 283 | 284 | @param error If setting the password fails, upon return contains an error that describes the problem. 285 | 286 | @return Returns `YES` on success, or `NO` on failure. 287 | 288 | @see setPassword:forService:account: 289 | */ 290 | + (BOOL)setPassword:(NSString *)password forService:(NSString *)serviceName account:(NSString *)account error:(NSError **)error; 291 | 292 | /** 293 | Sets arbirary data in the Keychain. 294 | 295 | @param password The data to store in the Keychain. 296 | 297 | @param serviceName The service for which to set the corresponding password. 298 | 299 | @param account The account for which to set the corresponding password. 300 | 301 | @param error If setting the password fails, upon return contains an error that describes the problem. 302 | 303 | @return Returns `YES` on success, or `NO` on failure. 304 | 305 | @see setPasswordData:forService:account:error: 306 | */ 307 | + (BOOL)setPasswordData:(NSData *)password forService:(NSString *)serviceName account:(NSString *)account; 308 | 309 | /** 310 | Sets arbirary data in the Keychain. 311 | 312 | @param password The data to store in the Keychain. 313 | 314 | @param serviceName The service for which to set the corresponding password. 315 | 316 | @param account The account for which to set the corresponding password. 317 | 318 | @param error If setting the password fails, upon return contains an error that describes the problem. 319 | 320 | @return Returns `YES` on success, or `NO` on failure. 321 | 322 | @see setPasswordData:forService:account: 323 | */ 324 | + (BOOL)setPasswordData:(NSData *)password forService:(NSString *)serviceName account:(NSString *)account error:(NSError **)error; 325 | 326 | 327 | ///-------------------- 328 | /// @name Configuration 329 | ///-------------------- 330 | 331 | #if __IPHONE_4_0 && TARGET_OS_IPHONE 332 | /** 333 | Returns the accessibility type for all future passwords saved to the Keychain. 334 | 335 | @return Returns the accessibility type. 336 | 337 | The return value will be `NULL` or one of the "Keychain Item Accessibility Constants" used for determining when a 338 | keychain item should be readable. 339 | 340 | @see accessibilityType 341 | */ 342 | + (CFTypeRef)accessibilityType; 343 | 344 | /** 345 | Sets the accessibility type for all future passwords saved to the Keychain. 346 | 347 | @param accessibilityType One of the "Keychain Item Accessibility Constants" used for determining when a keychain item 348 | should be readable. 349 | 350 | If the value is `NULL` (the default), the Keychain default will be used. 351 | 352 | @see accessibilityType 353 | */ 354 | + (void)setAccessibilityType:(CFTypeRef)accessibilityType; 355 | #endif 356 | 357 | @end 358 | -------------------------------------------------------------------------------- /Tests/SSKeychain.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | B2059B5D1559058C003D2FAC /* SSKeychainTests.m in Sources */ = {isa = PBXBuildFile; fileRef = B2A5FACE143AC25C000F6011 /* SSKeychainTests.m */; }; 11 | B2059B5E1559058C003D2FAC /* SSKeychain.m in Sources */ = {isa = PBXBuildFile; fileRef = B25737E1143AC2EC003FACED /* SSKeychain.m */; }; 12 | B2059B601559058C003D2FAC /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B25737E4143AC308003FACED /* Security.framework */; }; 13 | B2059B611559058C003D2FAC /* SenTestingKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B2A5FAB1143AC134000F6011 /* SenTestingKit.framework */; }; 14 | B2059B621559058C003D2FAC /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B2A5FA93143AC133000F6011 /* Cocoa.framework */; }; 15 | B25737E2143AC2EC003FACED /* SSKeychain.m in Sources */ = {isa = PBXBuildFile; fileRef = B25737E1143AC2EC003FACED /* SSKeychain.m */; }; 16 | B25737E5143AC308003FACED /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B25737E4143AC308003FACED /* Security.framework */; }; 17 | B2A5FAB2143AC134000F6011 /* SenTestingKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B2A5FAB1143AC134000F6011 /* SenTestingKit.framework */; }; 18 | B2A5FAB3143AC134000F6011 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B2A5FA93143AC133000F6011 /* Cocoa.framework */; }; 19 | B2A5FAD0143AC25C000F6011 /* SSKeychainTests.m in Sources */ = {isa = PBXBuildFile; fileRef = B2A5FACE143AC25C000F6011 /* SSKeychainTests.m */; }; 20 | /* End PBXBuildFile section */ 21 | 22 | /* Begin PBXFileReference section */ 23 | B2059B681559058C003D2FAC /* SSKeychainTestsARC.octest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SSKeychainTestsARC.octest; sourceTree = BUILT_PRODUCTS_DIR; }; 24 | B2059B691559058C003D2FAC /* SSKeychainTestsARC-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "SSKeychainTestsARC-Info.plist"; path = "/Users/samsoffes/Code/sskeychain/Tests/SSKeychainTestsARC-Info.plist"; sourceTree = ""; }; 25 | B25737E0143AC2EC003FACED /* SSKeychain.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SSKeychain.h; path = ../SSKeychain.h; sourceTree = ""; }; 26 | B25737E1143AC2EC003FACED /* SSKeychain.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SSKeychain.m; path = ../SSKeychain.m; sourceTree = ""; }; 27 | B25737E4143AC308003FACED /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; 28 | B2A5FA93143AC133000F6011 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; 29 | B2A5FA96143AC133000F6011 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; 30 | B2A5FA97143AC133000F6011 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; }; 31 | B2A5FA98143AC133000F6011 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 32 | B2A5FAB0143AC134000F6011 /* SSKeychainTests.octest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SSKeychainTests.octest; sourceTree = BUILT_PRODUCTS_DIR; }; 33 | B2A5FAB1143AC134000F6011 /* SenTestingKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SenTestingKit.framework; path = Library/Frameworks/SenTestingKit.framework; sourceTree = DEVELOPER_DIR; }; 34 | B2A5FACC143AC25C000F6011 /* SSKeychainTests-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "SSKeychainTests-Info.plist"; sourceTree = SOURCE_ROOT; }; 35 | B2A5FACE143AC25C000F6011 /* SSKeychainTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SSKeychainTests.m; sourceTree = SOURCE_ROOT; }; 36 | /* End PBXFileReference section */ 37 | 38 | /* Begin PBXFrameworksBuildPhase section */ 39 | B2059B5F1559058C003D2FAC /* Frameworks */ = { 40 | isa = PBXFrameworksBuildPhase; 41 | buildActionMask = 2147483647; 42 | files = ( 43 | B2059B601559058C003D2FAC /* Security.framework in Frameworks */, 44 | B2059B611559058C003D2FAC /* SenTestingKit.framework in Frameworks */, 45 | B2059B621559058C003D2FAC /* Cocoa.framework in Frameworks */, 46 | ); 47 | runOnlyForDeploymentPostprocessing = 0; 48 | }; 49 | B2A5FAAC143AC134000F6011 /* Frameworks */ = { 50 | isa = PBXFrameworksBuildPhase; 51 | buildActionMask = 2147483647; 52 | files = ( 53 | B25737E5143AC308003FACED /* Security.framework in Frameworks */, 54 | B2A5FAB2143AC134000F6011 /* SenTestingKit.framework in Frameworks */, 55 | B2A5FAB3143AC134000F6011 /* Cocoa.framework in Frameworks */, 56 | ); 57 | runOnlyForDeploymentPostprocessing = 0; 58 | }; 59 | /* End PBXFrameworksBuildPhase section */ 60 | 61 | /* Begin PBXGroup section */ 62 | B25737E3143AC2F4003FACED /* SSKeychain */ = { 63 | isa = PBXGroup; 64 | children = ( 65 | B25737E0143AC2EC003FACED /* SSKeychain.h */, 66 | B25737E1143AC2EC003FACED /* SSKeychain.m */, 67 | ); 68 | name = SSKeychain; 69 | sourceTree = ""; 70 | }; 71 | B2A5FA84143AC133000F6011 = { 72 | isa = PBXGroup; 73 | children = ( 74 | B25737E3143AC2F4003FACED /* SSKeychain */, 75 | B2A5FAB6143AC134000F6011 /* SSKeychainTests */, 76 | B2A5FA92143AC133000F6011 /* Frameworks */, 77 | B2A5FA90143AC133000F6011 /* Products */, 78 | ); 79 | sourceTree = ""; 80 | }; 81 | B2A5FA90143AC133000F6011 /* Products */ = { 82 | isa = PBXGroup; 83 | children = ( 84 | B2A5FAB0143AC134000F6011 /* SSKeychainTests.octest */, 85 | B2059B681559058C003D2FAC /* SSKeychainTestsARC.octest */, 86 | ); 87 | name = Products; 88 | sourceTree = ""; 89 | }; 90 | B2A5FA92143AC133000F6011 /* Frameworks */ = { 91 | isa = PBXGroup; 92 | children = ( 93 | B25737E4143AC308003FACED /* Security.framework */, 94 | B2A5FA93143AC133000F6011 /* Cocoa.framework */, 95 | B2A5FAB1143AC134000F6011 /* SenTestingKit.framework */, 96 | B2A5FA95143AC133000F6011 /* Other Frameworks */, 97 | ); 98 | name = Frameworks; 99 | sourceTree = ""; 100 | }; 101 | B2A5FA95143AC133000F6011 /* Other Frameworks */ = { 102 | isa = PBXGroup; 103 | children = ( 104 | B2A5FA96143AC133000F6011 /* AppKit.framework */, 105 | B2A5FA97143AC133000F6011 /* CoreData.framework */, 106 | B2A5FA98143AC133000F6011 /* Foundation.framework */, 107 | ); 108 | name = "Other Frameworks"; 109 | sourceTree = ""; 110 | }; 111 | B2A5FAB6143AC134000F6011 /* SSKeychainTests */ = { 112 | isa = PBXGroup; 113 | children = ( 114 | B2A5FACE143AC25C000F6011 /* SSKeychainTests.m */, 115 | B2A5FACC143AC25C000F6011 /* SSKeychainTests-Info.plist */, 116 | B2059B691559058C003D2FAC /* SSKeychainTestsARC-Info.plist */, 117 | ); 118 | path = SSKeychainTests; 119 | sourceTree = ""; 120 | }; 121 | /* End PBXGroup section */ 122 | 123 | /* Begin PBXNativeTarget section */ 124 | B2059B5B1559058C003D2FAC /* SSKeychainTestsARC */ = { 125 | isa = PBXNativeTarget; 126 | buildConfigurationList = B2059B651559058C003D2FAC /* Build configuration list for PBXNativeTarget "SSKeychainTestsARC" */; 127 | buildPhases = ( 128 | B2059B5C1559058C003D2FAC /* Sources */, 129 | B2059B5F1559058C003D2FAC /* Frameworks */, 130 | B2059B631559058C003D2FAC /* Resources */, 131 | B2059B641559058C003D2FAC /* ShellScript */, 132 | ); 133 | buildRules = ( 134 | ); 135 | dependencies = ( 136 | ); 137 | name = SSKeychainTestsARC; 138 | productName = SSKeychainTests; 139 | productReference = B2059B681559058C003D2FAC /* SSKeychainTestsARC.octest */; 140 | productType = "com.apple.product-type.bundle"; 141 | }; 142 | B2A5FAAF143AC134000F6011 /* SSKeychainTests */ = { 143 | isa = PBXNativeTarget; 144 | buildConfigurationList = B2A5FAC4143AC134000F6011 /* Build configuration list for PBXNativeTarget "SSKeychainTests" */; 145 | buildPhases = ( 146 | B2A5FAAB143AC134000F6011 /* Sources */, 147 | B2A5FAAC143AC134000F6011 /* Frameworks */, 148 | B2A5FAAD143AC134000F6011 /* Resources */, 149 | B2A5FAAE143AC134000F6011 /* ShellScript */, 150 | ); 151 | buildRules = ( 152 | ); 153 | dependencies = ( 154 | ); 155 | name = SSKeychainTests; 156 | productName = SSKeychainTests; 157 | productReference = B2A5FAB0143AC134000F6011 /* SSKeychainTests.octest */; 158 | productType = "com.apple.product-type.bundle"; 159 | }; 160 | /* End PBXNativeTarget section */ 161 | 162 | /* Begin PBXProject section */ 163 | B2A5FA86143AC133000F6011 /* Project object */ = { 164 | isa = PBXProject; 165 | attributes = { 166 | LastUpgradeCheck = 0420; 167 | ORGANIZATIONNAME = "Sam Soffes"; 168 | }; 169 | buildConfigurationList = B2A5FA89143AC133000F6011 /* Build configuration list for PBXProject "SSKeychain" */; 170 | compatibilityVersion = "Xcode 3.2"; 171 | developmentRegion = English; 172 | hasScannedForEncodings = 0; 173 | knownRegions = ( 174 | en, 175 | ); 176 | mainGroup = B2A5FA84143AC133000F6011; 177 | productRefGroup = B2A5FA90143AC133000F6011 /* Products */; 178 | projectDirPath = ""; 179 | projectRoot = ""; 180 | targets = ( 181 | B2A5FAAF143AC134000F6011 /* SSKeychainTests */, 182 | B2059B5B1559058C003D2FAC /* SSKeychainTestsARC */, 183 | ); 184 | }; 185 | /* End PBXProject section */ 186 | 187 | /* Begin PBXResourcesBuildPhase section */ 188 | B2059B631559058C003D2FAC /* Resources */ = { 189 | isa = PBXResourcesBuildPhase; 190 | buildActionMask = 2147483647; 191 | files = ( 192 | ); 193 | runOnlyForDeploymentPostprocessing = 0; 194 | }; 195 | B2A5FAAD143AC134000F6011 /* Resources */ = { 196 | isa = PBXResourcesBuildPhase; 197 | buildActionMask = 2147483647; 198 | files = ( 199 | ); 200 | runOnlyForDeploymentPostprocessing = 0; 201 | }; 202 | /* End PBXResourcesBuildPhase section */ 203 | 204 | /* Begin PBXShellScriptBuildPhase section */ 205 | B2059B641559058C003D2FAC /* ShellScript */ = { 206 | isa = PBXShellScriptBuildPhase; 207 | buildActionMask = 2147483647; 208 | files = ( 209 | ); 210 | inputPaths = ( 211 | ); 212 | outputPaths = ( 213 | ); 214 | runOnlyForDeploymentPostprocessing = 0; 215 | shellPath = /bin/sh; 216 | shellScript = "# Run the unit tests in this test bundle.\n\"${SYSTEM_DEVELOPER_DIR}/Tools/RunUnitTests\"\n"; 217 | }; 218 | B2A5FAAE143AC134000F6011 /* ShellScript */ = { 219 | isa = PBXShellScriptBuildPhase; 220 | buildActionMask = 2147483647; 221 | files = ( 222 | ); 223 | inputPaths = ( 224 | ); 225 | outputPaths = ( 226 | ); 227 | runOnlyForDeploymentPostprocessing = 0; 228 | shellPath = /bin/sh; 229 | shellScript = "# Run the unit tests in this test bundle.\n\"${SYSTEM_DEVELOPER_DIR}/Tools/RunUnitTests\"\n"; 230 | }; 231 | /* End PBXShellScriptBuildPhase section */ 232 | 233 | /* Begin PBXSourcesBuildPhase section */ 234 | B2059B5C1559058C003D2FAC /* Sources */ = { 235 | isa = PBXSourcesBuildPhase; 236 | buildActionMask = 2147483647; 237 | files = ( 238 | B2059B5D1559058C003D2FAC /* SSKeychainTests.m in Sources */, 239 | B2059B5E1559058C003D2FAC /* SSKeychain.m in Sources */, 240 | ); 241 | runOnlyForDeploymentPostprocessing = 0; 242 | }; 243 | B2A5FAAB143AC134000F6011 /* Sources */ = { 244 | isa = PBXSourcesBuildPhase; 245 | buildActionMask = 2147483647; 246 | files = ( 247 | B2A5FAD0143AC25C000F6011 /* SSKeychainTests.m in Sources */, 248 | B25737E2143AC2EC003FACED /* SSKeychain.m in Sources */, 249 | ); 250 | runOnlyForDeploymentPostprocessing = 0; 251 | }; 252 | /* End PBXSourcesBuildPhase section */ 253 | 254 | /* Begin XCBuildConfiguration section */ 255 | B2059B661559058C003D2FAC /* Debug */ = { 256 | isa = XCBuildConfiguration; 257 | buildSettings = { 258 | CLANG_ENABLE_OBJC_ARC = YES; 259 | FRAMEWORK_SEARCH_PATHS = "$(DEVELOPER_LIBRARY_DIR)/Frameworks"; 260 | INFOPLIST_FILE = "SSKeychainTestsARC-Info.plist"; 261 | PRODUCT_NAME = SSKeychainTestsARC; 262 | RUN_CLANG_STATIC_ANALYZER = YES; 263 | TEST_HOST = "$(BUNDLE_LOADER)"; 264 | WRAPPER_EXTENSION = octest; 265 | }; 266 | name = Debug; 267 | }; 268 | B2059B671559058C003D2FAC /* Release */ = { 269 | isa = XCBuildConfiguration; 270 | buildSettings = { 271 | CLANG_ENABLE_OBJC_ARC = YES; 272 | FRAMEWORK_SEARCH_PATHS = "$(DEVELOPER_LIBRARY_DIR)/Frameworks"; 273 | INFOPLIST_FILE = "SSKeychainTestsARC-Info.plist"; 274 | PRODUCT_NAME = SSKeychainTestsARC; 275 | RUN_CLANG_STATIC_ANALYZER = YES; 276 | TEST_HOST = "$(BUNDLE_LOADER)"; 277 | WRAPPER_EXTENSION = octest; 278 | }; 279 | name = Release; 280 | }; 281 | B2A5FABF143AC134000F6011 /* Debug */ = { 282 | isa = XCBuildConfiguration; 283 | buildSettings = { 284 | ALWAYS_SEARCH_USER_PATHS = NO; 285 | ARCHS = "$(ARCHS_STANDARD_64_BIT)"; 286 | COPY_PHASE_STRIP = NO; 287 | GCC_C_LANGUAGE_STANDARD = gnu99; 288 | GCC_DYNAMIC_NO_PIC = NO; 289 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 290 | GCC_OPTIMIZATION_LEVEL = 0; 291 | GCC_PREPROCESSOR_DEFINITIONS = ( 292 | "DEBUG=1", 293 | "$(inherited)", 294 | ); 295 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 296 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0; 297 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 298 | GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; 299 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 300 | GCC_WARN_UNUSED_VARIABLE = YES; 301 | MACOSX_DEPLOYMENT_TARGET = 10.7; 302 | ONLY_ACTIVE_ARCH = YES; 303 | SDKROOT = macosx; 304 | }; 305 | name = Debug; 306 | }; 307 | B2A5FAC0143AC134000F6011 /* Release */ = { 308 | isa = XCBuildConfiguration; 309 | buildSettings = { 310 | ALWAYS_SEARCH_USER_PATHS = NO; 311 | ARCHS = "$(ARCHS_STANDARD_64_BIT)"; 312 | COPY_PHASE_STRIP = YES; 313 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 314 | GCC_C_LANGUAGE_STANDARD = gnu99; 315 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 316 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0; 317 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 318 | GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; 319 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 320 | GCC_WARN_UNUSED_VARIABLE = YES; 321 | MACOSX_DEPLOYMENT_TARGET = 10.7; 322 | SDKROOT = macosx; 323 | }; 324 | name = Release; 325 | }; 326 | B2A5FAC5143AC134000F6011 /* Debug */ = { 327 | isa = XCBuildConfiguration; 328 | buildSettings = { 329 | FRAMEWORK_SEARCH_PATHS = "$(DEVELOPER_LIBRARY_DIR)/Frameworks"; 330 | INFOPLIST_FILE = "SSKeychainTests-Info.plist"; 331 | PRODUCT_NAME = "$(TARGET_NAME)"; 332 | RUN_CLANG_STATIC_ANALYZER = YES; 333 | TEST_HOST = "$(BUNDLE_LOADER)"; 334 | WRAPPER_EXTENSION = octest; 335 | }; 336 | name = Debug; 337 | }; 338 | B2A5FAC6143AC134000F6011 /* Release */ = { 339 | isa = XCBuildConfiguration; 340 | buildSettings = { 341 | FRAMEWORK_SEARCH_PATHS = "$(DEVELOPER_LIBRARY_DIR)/Frameworks"; 342 | INFOPLIST_FILE = "SSKeychainTests-Info.plist"; 343 | PRODUCT_NAME = "$(TARGET_NAME)"; 344 | RUN_CLANG_STATIC_ANALYZER = YES; 345 | TEST_HOST = "$(BUNDLE_LOADER)"; 346 | WRAPPER_EXTENSION = octest; 347 | }; 348 | name = Release; 349 | }; 350 | /* End XCBuildConfiguration section */ 351 | 352 | /* Begin XCConfigurationList section */ 353 | B2059B651559058C003D2FAC /* Build configuration list for PBXNativeTarget "SSKeychainTestsARC" */ = { 354 | isa = XCConfigurationList; 355 | buildConfigurations = ( 356 | B2059B661559058C003D2FAC /* Debug */, 357 | B2059B671559058C003D2FAC /* Release */, 358 | ); 359 | defaultConfigurationIsVisible = 0; 360 | defaultConfigurationName = Release; 361 | }; 362 | B2A5FA89143AC133000F6011 /* Build configuration list for PBXProject "SSKeychain" */ = { 363 | isa = XCConfigurationList; 364 | buildConfigurations = ( 365 | B2A5FABF143AC134000F6011 /* Debug */, 366 | B2A5FAC0143AC134000F6011 /* Release */, 367 | ); 368 | defaultConfigurationIsVisible = 0; 369 | defaultConfigurationName = Release; 370 | }; 371 | B2A5FAC4143AC134000F6011 /* Build configuration list for PBXNativeTarget "SSKeychainTests" */ = { 372 | isa = XCConfigurationList; 373 | buildConfigurations = ( 374 | B2A5FAC5143AC134000F6011 /* Debug */, 375 | B2A5FAC6143AC134000F6011 /* Release */, 376 | ); 377 | defaultConfigurationIsVisible = 0; 378 | defaultConfigurationName = Release; 379 | }; 380 | /* End XCConfigurationList section */ 381 | }; 382 | rootObject = B2A5FA86143AC133000F6011 /* Project object */; 383 | } 384 | --------------------------------------------------------------------------------