├── 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 |
--------------------------------------------------------------------------------