Last active
March 17, 2023 18:06
-
-
Save erikdoe/5845330 to your computer and use it in GitHub Desktop.
It took me way too long to wade through Keychain documentation and examples, but, finally, I got to a sane implementation of a basic Objective-C interface for managing internet passwords in Keychain. This is from my CCMenu project (http://ccmenu.org).
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import "CCMKeychainHelper.h" | |
@implementation CCMKeychainHelper | |
+ (BOOL)setPassword:(NSString *)password forURLString:(NSString *)aString error:(NSError **)errorPtr | |
{ | |
return [self setPassword:password forURL:[NSURL URLWithString:aString] error:errorPtr]; | |
} | |
+ (BOOL)setPassword:(NSString *)password forURL:(NSURL *)aURL error:(NSError **)errorPtr | |
{ | |
NSDictionary *query = @{ | |
(id)kSecClass: (id)kSecClassInternetPassword, | |
(id)kSecAttrServer: [aURL host], | |
(id)kSecAttrPort: [aURL port], | |
(id)kSecAttrAccount: [aURL user] | |
}; | |
NSDictionary *item = @{ | |
(id)kSecClass: (id)kSecClassInternetPassword, | |
(id)kSecAttrServer: [aURL host], | |
(id)kSecAttrPort: [aURL port], | |
(id)kSecAttrAccount: [aURL user], | |
(id)kSecAttrProtocol: [aURL scheme], | |
(id)kSecValueData:[password dataUsingEncoding:NSUTF8StringEncoding] | |
}; | |
OSStatus status = SecItemAdd((CFDictionaryRef)item, NULL); | |
if(status == errSecDuplicateItem) | |
status = SecItemUpdate((CFDictionaryRef)query, (CFDictionaryRef)item); | |
if(status != noErr) | |
{ | |
if(errorPtr != NULL) | |
*errorPtr = [NSError errorWithDomain:NSOSStatusErrorDomain code:status userInfo:nil]; | |
return NO; | |
} | |
return YES; | |
} | |
+ (NSString *)passwordForURLString:(NSString *)aString error:(NSError **)errorPtr | |
{ | |
return [self passwordForURL:[NSURL URLWithString:aString] error:errorPtr]; | |
} | |
+ (NSString *)passwordForURL:(NSURL *)aURL error:(NSError **)errorPtr | |
{ | |
if([aURL user] == nil) | |
return nil; | |
NSDictionary *query = @{ | |
(id)kSecClass: (id)kSecClassInternetPassword, | |
(id)kSecAttrServer: [aURL host], | |
(id)kSecAttrPort: [aURL port], | |
(id)kSecAttrAccount: [aURL user], | |
(id)kSecReturnData: @YES | |
}; | |
NSData *data = NULL; | |
OSStatus status = SecItemCopyMatching((CFDictionaryRef)query, (CFTypeRef*)&data); | |
if(status != noErr) | |
{ | |
if(errorPtr != NULL) | |
*errorPtr = [NSError errorWithDomain:NSOSStatusErrorDomain code:status userInfo:nil]; | |
return nil; | |
} | |
return [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]; | |
} | |
+ (NSString *)accountForURLString:(NSString *)aString error:(NSError **)errorPtr | |
{ | |
return [self accountForURL:[NSURL URLWithString:aString] error:errorPtr]; | |
} | |
+ (NSString *)accountForURL:(NSURL *)aURL error:(NSError **)errorPtr | |
{ | |
if([aURL host] == nil) | |
return nil; | |
NSDictionary *query = @{ | |
(id)kSecClass: (id)kSecClassInternetPassword, | |
(id)kSecAttrServer: [aURL host], | |
(id)kSecReturnAttributes: @YES | |
}; | |
NSDictionary *attributes = nil; | |
OSStatus status = SecItemCopyMatching((CFDictionaryRef)query, (CFTypeRef*)&attributes); | |
if(status != noErr) | |
{ | |
if(errorPtr != NULL) | |
*errorPtr = [NSError errorWithDomain:NSOSStatusErrorDomain code:status userInfo:nil]; | |
return nil; | |
} | |
return [attributes objectForKey:kSecAttrAccount]; | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment