@@ -80,6 +80,26 @@ - (NSString *)description;
80
80
}
81
81
82
82
83
+ #pragma mark NSCoding
84
+
85
+ - (void )encodeWithCoder : (NSCoder *)aCoder
86
+ {
87
+ [aCoder encodeObject: accessToken forKey: @" accessToken" ];
88
+ [aCoder encodeObject: refreshToken forKey: @" refreshToken" ];
89
+ [aCoder encodeObject: expiresAt forKey: @" expiresAt" ];
90
+ }
91
+
92
+ - (id )initWithCoder : (NSCoder *)aDecoder
93
+ {
94
+ if (self = [super init ]) {
95
+ accessToken = [[aDecoder decodeObjectForKey: @" accessToken" ] copy ];
96
+ refreshToken = [[aDecoder decodeObjectForKey: @" refreshToken" ] copy ];
97
+ expiresAt = [[aDecoder decodeObjectForKey: @" expiresAt" ] retain ];
98
+ }
99
+ return self;
100
+ }
101
+
102
+
83
103
#pragma mark Keychain Support
84
104
85
105
+ (NSString *)serviceNameWithProvider : (NSString *)provider ;
@@ -89,6 +109,8 @@ + (NSString *)serviceNameWithProvider:(NSString *)provider;
89
109
return [NSString stringWithFormat: @" %@ ::OAuth2::%@ " , appName, provider];
90
110
}
91
111
112
+ #if TARGET_OS_IPHONE
113
+
92
114
+ (id )tokenFromDefaultKeychainWithServiceProviderName : (NSString *)provider ;
93
115
{
94
116
NSString *serviceName = [[self class ] serviceNameWithProvider: provider];
@@ -135,26 +157,102 @@ - (void)removeFromDefaultKeychainWithServiceProviderName:(NSString *)provider;
135
157
NSAssert1 ((err == noErr || err == errSecItemNotFound), @"error while deleting token from keychain: %d", err);
136
158
}
137
159
160
+ #else
138
161
139
- #pragma mark NSCoding
162
+ + (id )tokenFromDefaultKeychainWithServiceProviderName : (NSString *)provider ;
163
+ {
164
+ NSString *serviceName = [[self class ] serviceNameWithProvider: provider];
165
+
166
+ SecKeychainItemRef item = nil ;
167
+ OSStatus err = SecKeychainFindGenericPassword (NULL ,
168
+ strlen ([serviceName UTF8String ]),
169
+ [serviceName UTF8String ],
170
+ 0 ,
171
+ NULL ,
172
+ NULL ,
173
+ NULL ,
174
+ &item);
175
+ if (err != noErr) {
176
+ NSAssert1 (err == errSecItemNotFound, @" unexpected error while fetching token from keychain: %d " , err);
177
+ return nil ;
178
+ }
179
+
180
+ // from Advanced Mac OS X Programming, ch. 16
181
+ UInt32 length;
182
+ char *password;
183
+ NSData *result = nil ;
184
+ SecKeychainAttribute attributes[8 ];
185
+ SecKeychainAttributeList list;
186
+
187
+ attributes[0 ].tag = kSecAccountItemAttr ;
188
+ attributes[1 ].tag = kSecDescriptionItemAttr ;
189
+ attributes[2 ].tag = kSecLabelItemAttr ;
190
+ attributes[3 ].tag = kSecModDateItemAttr ;
191
+
192
+ list.count = 4 ;
193
+ list.attr = attributes;
194
+
195
+ err = SecKeychainItemCopyContent (item, NULL , &list, &length, (void **)&password);
196
+ if (err == noErr) {
197
+ if (password != NULL ) {
198
+ result = [NSData dataWithBytes: password length: length];
199
+ }
200
+ SecKeychainItemFreeContent (&list, password);
201
+ } else {
202
+ // TODO find out why this always works in i386 and always fails on ppc
203
+ NSLog (@" Error from SecKeychainItemCopyContent: %d " , err);
204
+ return nil ;
205
+ }
206
+ CFRelease (item);
207
+ return [NSKeyedUnarchiver unarchiveObjectWithData: [result objectForKey: (NSString *)kSecAttrGeneric ]];
208
+ }
140
209
141
- - (void )encodeWithCoder : ( NSCoder *)aCoder
210
+ - (void )storeInDefaultKeychainWithServiceProviderName : ( NSString *)provider ;
142
211
{
143
- [aCoder encodeObject: accessToken forKey: @" accessToken" ];
144
- [aCoder encodeObject: refreshToken forKey: @" refreshToken" ];
145
- [aCoder encodeObject: expiresAt forKey: @" expiresAt" ];
212
+ NSString *serviceName = [[self class ] serviceNameWithProvider: provider];
213
+ NSData *data = [NSKeyedArchiver archivedDataWithRootObject: self ];
214
+
215
+ OSStatus err = SecKeychainAddGenericPassword (NULL ,
216
+ [serviceName cStringLength ],
217
+ [serviceName cString ],
218
+ NULL ,
219
+ NULL ,
220
+ [data length ],
221
+ [data bytes ],
222
+ NULL );
223
+
224
+
225
+ NSAssert1 (err == noErr, @" error while adding token to keychain: %d " , err);
146
226
}
147
227
148
- - (id ) initWithCoder : ( NSCoder *)aDecoder
228
+ - (void ) removeFromDefaultKeychainWithServiceProviderName : ( NSString *)provider ;
149
229
{
150
- if (self = [super init ]) {
151
- accessToken = [[aDecoder decodeObjectForKey: @" accessToken" ] copy ];
152
- refreshToken = [[aDecoder decodeObjectForKey: @" refreshToken" ] copy ];
153
- expiresAt = [[aDecoder decodeObjectForKey: @" expiresAt" ] retain ];
230
+ NSString *serviceName = [[self class ] serviceNameWithProvider: provider];
231
+ NSDictionary *query = [NSDictionary dictionaryWithObjectsAndKeys:
232
+ (NSString *)kSecClassGenericPassword , kSecClass ,
233
+ serviceName, kSecAttrService ,
234
+ nil ];
235
+ OSStatus err = SecItemDelete ((CFDictionaryRef)query);
236
+ NSAssert1 ((err == noErr || err == errSecItemNotFound), @"error while deleting token from keychain: %d", err);
237
+
238
+
239
+
240
+ SecKeychainItemRef item = nil ;
241
+ OSStatus err = SecKeychainFindGenericPassword (NULL ,
242
+ [serviceName cStringLength ],
243
+ [serviceName cString ],
244
+ 0 ,
245
+ NULL ,
246
+ NULL ,
247
+ NULL ,
248
+ &item);
249
+ NSAssert1 ((err == noErr || err == errSecItemNotFound), @"error while deleting token from keychain: %d", err);
250
+ if (err == noErr) {
251
+ err = SecKeychainItemDelete (item);
154
252
}
155
- return self;
253
+ CFRelease (item);
254
+ NSAssert1 ((err == noErr || err == errSecItemNotFound), @"error while deleting token from keychain: %d", err);
156
255
}
157
256
158
-
159
-
257
+ #endif
160
258
@end
0 commit comments