New file |
| | |
| | | // |
| | | // UICKeyChainStore.m |
| | | // UICKeyChainStore |
| | | // |
| | | // Created by Kishikawa Katsumi on 11/11/20. |
| | | // Copyright (c) 2011 Kishikawa Katsumi. All rights reserved. |
| | | // |
| | | |
| | | #import "UICKeyChainStore.h" |
| | | |
| | | NSString * const UICKeyChainStoreErrorDomain = @"com.kishikawakatsumi.uickeychainstore"; |
| | | static NSString *_defaultService; |
| | | |
| | | @interface UICKeyChainStore () |
| | | |
| | | @end |
| | | |
| | | @implementation UICKeyChainStore |
| | | |
| | | + (NSString *)defaultService |
| | | { |
| | | if (!_defaultService) { |
| | | _defaultService = [[NSBundle mainBundle] bundleIdentifier] ?: @""; |
| | | } |
| | | |
| | | return _defaultService; |
| | | } |
| | | |
| | | + (void)setDefaultService:(NSString *)defaultService |
| | | { |
| | | _defaultService = defaultService; |
| | | } |
| | | |
| | | #pragma mark - |
| | | |
| | | + (UICKeyChainStore *)keyChainStore |
| | | { |
| | | return [[self alloc] initWithService:nil accessGroup:nil]; |
| | | } |
| | | |
| | | + (UICKeyChainStore *)keyChainStoreWithService:(NSString *)service |
| | | { |
| | | return [[self alloc] initWithService:service accessGroup:nil]; |
| | | } |
| | | |
| | | + (UICKeyChainStore *)keyChainStoreWithService:(NSString *)service accessGroup:(NSString *)accessGroup |
| | | { |
| | | return [[self alloc] initWithService:service accessGroup:accessGroup]; |
| | | } |
| | | |
| | | #pragma mark - |
| | | |
| | | + (UICKeyChainStore *)keyChainStoreWithServer:(NSURL *)server protocolType:(UICKeyChainStoreProtocolType)protocolType |
| | | { |
| | | return [[self alloc] initWithServer:server protocolType:protocolType authenticationType:UICKeyChainStoreAuthenticationTypeDefault]; |
| | | } |
| | | |
| | | + (UICKeyChainStore *)keyChainStoreWithServer:(NSURL *)server protocolType:(UICKeyChainStoreProtocolType)protocolType authenticationType:(UICKeyChainStoreAuthenticationType)authenticationType |
| | | { |
| | | return [[self alloc] initWithServer:server protocolType:protocolType authenticationType:authenticationType]; |
| | | } |
| | | |
| | | #pragma mark - |
| | | |
| | | - (instancetype)init |
| | | { |
| | | return [self initWithService:[self.class defaultService] accessGroup:nil]; |
| | | } |
| | | |
| | | - (instancetype)initWithService:(NSString *)service |
| | | { |
| | | return [self initWithService:service accessGroup:nil]; |
| | | } |
| | | |
| | | - (instancetype)initWithService:(NSString *)service accessGroup:(NSString *)accessGroup |
| | | { |
| | | self = [super init]; |
| | | if (self) { |
| | | _itemClass = UICKeyChainStoreItemClassGenericPassword; |
| | | |
| | | if (!service) { |
| | | service = [self.class defaultService]; |
| | | } |
| | | _service = service.copy; |
| | | _accessGroup = accessGroup.copy; |
| | | [self commonInit]; |
| | | } |
| | | |
| | | return self; |
| | | } |
| | | |
| | | #pragma mark - |
| | | |
| | | - (instancetype)initWithServer:(NSURL *)server protocolType:(UICKeyChainStoreProtocolType)protocolType |
| | | { |
| | | return [self initWithServer:server protocolType:protocolType authenticationType:UICKeyChainStoreAuthenticationTypeDefault]; |
| | | } |
| | | |
| | | - (instancetype)initWithServer:(NSURL *)server protocolType:(UICKeyChainStoreProtocolType)protocolType authenticationType:(UICKeyChainStoreAuthenticationType)authenticationType |
| | | { |
| | | self = [super init]; |
| | | if (self) { |
| | | _itemClass = UICKeyChainStoreItemClassInternetPassword; |
| | | |
| | | _server = server.copy; |
| | | _protocolType = protocolType; |
| | | _authenticationType = authenticationType; |
| | | |
| | | [self commonInit]; |
| | | } |
| | | |
| | | return self; |
| | | } |
| | | |
| | | #pragma mark - |
| | | |
| | | - (void)commonInit |
| | | { |
| | | _accessibility = UICKeyChainStoreAccessibilityAfterFirstUnlock; |
| | | } |
| | | |
| | | #pragma mark - |
| | | |
| | | + (NSString *)stringForKey:(NSString *)key |
| | | { |
| | | return [self stringForKey:key service:nil accessGroup:nil error:nil]; |
| | | } |
| | | |
| | | + (NSString *)stringForKey:(NSString *)key error:(NSError *__autoreleasing *)error |
| | | { |
| | | return [self stringForKey:key service:nil accessGroup:nil error:error]; |
| | | } |
| | | |
| | | + (NSString *)stringForKey:(NSString *)key service:(NSString *)service |
| | | { |
| | | return [self stringForKey:key service:service accessGroup:nil error:nil]; |
| | | } |
| | | |
| | | + (NSString *)stringForKey:(NSString *)key service:(NSString *)service error:(NSError *__autoreleasing *)error |
| | | { |
| | | return [self stringForKey:key service:service accessGroup:nil error:error]; |
| | | } |
| | | |
| | | + (NSString *)stringForKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup |
| | | { |
| | | return [self stringForKey:key service:service accessGroup:accessGroup error:nil]; |
| | | } |
| | | |
| | | + (NSString *)stringForKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup error:(NSError *__autoreleasing *)error |
| | | { |
| | | if (!key) { |
| | | NSError *e = [self argumentError:NSLocalizedString(@"the key must not to be nil", nil)]; |
| | | if (error) { |
| | | *error = e; |
| | | } |
| | | return nil; |
| | | } |
| | | if (!service) { |
| | | service = [self defaultService]; |
| | | } |
| | | |
| | | UICKeyChainStore *keychain = [UICKeyChainStore keyChainStoreWithService:service accessGroup:accessGroup]; |
| | | return [keychain stringForKey:key error:error]; |
| | | } |
| | | |
| | | #pragma mark - |
| | | |
| | | + (BOOL)setString:(NSString *)value forKey:(NSString *)key |
| | | { |
| | | return [self setString:value forKey:key service:nil accessGroup:nil genericAttribute:nil error:nil]; |
| | | } |
| | | |
| | | + (BOOL)setString:(NSString *)value forKey:(NSString *)key error:(NSError *__autoreleasing *)error |
| | | { |
| | | return [self setString:value forKey:key service:nil accessGroup:nil genericAttribute:nil error:error]; |
| | | } |
| | | |
| | | + (BOOL)setString:(NSString *)value forKey:(NSString *)key genericAttribute:(id)genericAttribute |
| | | { |
| | | return [self setString:value forKey:key service:nil accessGroup:nil genericAttribute:genericAttribute error:nil]; |
| | | } |
| | | |
| | | + (BOOL)setString:(NSString *)value forKey:(NSString *)key genericAttribute:(id)genericAttribute error:(NSError * __autoreleasing *)error |
| | | { |
| | | return [self setString:value forKey:key service:nil accessGroup:nil genericAttribute:genericAttribute error:error]; |
| | | } |
| | | |
| | | + (BOOL)setString:(NSString *)value forKey:(NSString *)key service:(NSString *)service |
| | | { |
| | | return [self setString:value forKey:key service:service accessGroup:nil genericAttribute:nil error:nil]; |
| | | } |
| | | |
| | | + (BOOL)setString:(NSString *)value forKey:(NSString *)key service:(NSString *)service error:(NSError *__autoreleasing *)error |
| | | { |
| | | return [self setString:value forKey:key service:service accessGroup:nil genericAttribute:nil error:error]; |
| | | } |
| | | |
| | | + (BOOL)setString:(NSString *)value forKey:(NSString *)key service:(NSString *)service genericAttribute:(id)genericAttribute |
| | | { |
| | | return [self setString:value forKey:key service:service accessGroup:nil genericAttribute:genericAttribute error:nil]; |
| | | } |
| | | |
| | | + (BOOL)setString:(NSString *)value forKey:(NSString *)key service:(NSString *)service genericAttribute:(id)genericAttribute error:(NSError * __autoreleasing *)error |
| | | { |
| | | return [self setString:value forKey:key service:service accessGroup:nil genericAttribute:genericAttribute error:error]; |
| | | } |
| | | |
| | | + (BOOL)setString:(NSString *)value forKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup |
| | | { |
| | | return [self setString:value forKey:key service:service accessGroup:accessGroup genericAttribute:nil error:nil]; |
| | | } |
| | | |
| | | + (BOOL)setString:(NSString *)value forKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup error:(NSError *__autoreleasing *)error |
| | | { |
| | | return [self setString:value forKey:key service:service accessGroup:accessGroup genericAttribute:nil error:error]; |
| | | } |
| | | |
| | | + (BOOL)setString:(NSString *)value forKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup genericAttribute:(id)genericAttribute |
| | | { |
| | | return [self setString:value forKey:key service:service accessGroup:accessGroup genericAttribute:genericAttribute error:nil]; |
| | | } |
| | | |
| | | + (BOOL)setString:(NSString *)value forKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup genericAttribute:(id)genericAttribute error:(NSError * __autoreleasing *)error |
| | | { |
| | | if (!value) { |
| | | return [self removeItemForKey:key service:service accessGroup:accessGroup error:error]; |
| | | } |
| | | NSData *data = [value dataUsingEncoding:NSUTF8StringEncoding]; |
| | | if (data) { |
| | | return [self setData:data forKey:key service:service accessGroup:accessGroup genericAttribute:genericAttribute error:error]; |
| | | } |
| | | NSError *e = [self conversionError:NSLocalizedString(@"failed to convert string to data", nil)]; |
| | | if (error) { |
| | | *error = e; |
| | | } |
| | | return NO; |
| | | } |
| | | |
| | | #pragma mark - |
| | | |
| | | + (NSData *)dataForKey:(NSString *)key |
| | | { |
| | | return [self dataForKey:key service:nil accessGroup:nil error:nil]; |
| | | } |
| | | |
| | | + (NSData *)dataForKey:(NSString *)key error:(NSError *__autoreleasing *)error |
| | | { |
| | | return [self dataForKey:key service:nil accessGroup:nil error:error]; |
| | | } |
| | | |
| | | + (NSData *)dataForKey:(NSString *)key service:(NSString *)service |
| | | { |
| | | return [self dataForKey:key service:service accessGroup:nil error:nil]; |
| | | } |
| | | |
| | | + (NSData *)dataForKey:(NSString *)key service:(NSString *)service error:(NSError *__autoreleasing *)error |
| | | { |
| | | return [self dataForKey:key service:service accessGroup:nil error:error]; |
| | | } |
| | | |
| | | + (NSData *)dataForKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup |
| | | { |
| | | return [self dataForKey:key service:service accessGroup:accessGroup error:nil]; |
| | | } |
| | | |
| | | + (NSData *)dataForKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup error:(NSError *__autoreleasing *)error |
| | | { |
| | | if (!key) { |
| | | NSError *e = [self argumentError:NSLocalizedString(@"the key must not to be nil", nil)]; |
| | | if (error) { |
| | | *error = e; |
| | | } |
| | | return nil; |
| | | } |
| | | if (!service) { |
| | | service = [self defaultService]; |
| | | } |
| | | |
| | | UICKeyChainStore *keychain = [UICKeyChainStore keyChainStoreWithService:service accessGroup:accessGroup]; |
| | | return [keychain dataForKey:key error:error]; |
| | | } |
| | | |
| | | #pragma mark - |
| | | |
| | | + (BOOL)setData:(NSData *)data forKey:(NSString *)key |
| | | { |
| | | return [self setData:data forKey:key service:nil accessGroup:nil genericAttribute:nil error:nil]; |
| | | } |
| | | |
| | | + (BOOL)setData:(NSData *)data forKey:(NSString *)key error:(NSError *__autoreleasing *)error |
| | | { |
| | | return [self setData:data forKey:key service:nil accessGroup:nil genericAttribute:nil error:error]; |
| | | } |
| | | |
| | | + (BOOL)setData:(NSData *)data forKey:(NSString *)key genericAttribute:(id)genericAttribute |
| | | { |
| | | return [self setData:data forKey:key service:nil accessGroup:nil genericAttribute:genericAttribute error:nil]; |
| | | } |
| | | |
| | | + (BOOL)setData:(NSData *)data forKey:(NSString *)key genericAttribute:(id)genericAttribute error:(NSError * __autoreleasing *)error |
| | | { |
| | | return [self setData:data forKey:key service:nil accessGroup:nil genericAttribute:genericAttribute error:error]; |
| | | } |
| | | |
| | | + (BOOL)setData:(NSData *)data forKey:(NSString *)key service:(NSString *)service |
| | | { |
| | | return [self setData:data forKey:key service:service accessGroup:nil genericAttribute:nil error:nil]; |
| | | } |
| | | |
| | | + (BOOL)setData:(NSData *)data forKey:(NSString *)key service:(NSString *)service error:(NSError *__autoreleasing *)error |
| | | { |
| | | return [self setData:data forKey:key service:service accessGroup:nil genericAttribute:nil error:error]; |
| | | } |
| | | |
| | | + (BOOL)setData:(NSData *)data forKey:(NSString *)key service:(NSString *)service genericAttribute:(id)genericAttribute |
| | | { |
| | | return [self setData:data forKey:key service:service accessGroup:nil genericAttribute:genericAttribute error:nil]; |
| | | } |
| | | |
| | | + (BOOL)setData:(NSData *)data forKey:(NSString *)key service:(NSString *)service genericAttribute:(id)genericAttribute error:(NSError * __autoreleasing *)error |
| | | { |
| | | return [self setData:data forKey:key service:service accessGroup:nil genericAttribute:genericAttribute error:error]; |
| | | } |
| | | |
| | | + (BOOL)setData:(NSData *)data forKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup |
| | | { |
| | | return [self setData:data forKey:key service:service accessGroup:accessGroup genericAttribute:nil error:nil]; |
| | | } |
| | | |
| | | + (BOOL)setData:(NSData *)data forKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup error:(NSError *__autoreleasing *)error |
| | | { |
| | | return [self setData:data forKey:key service:service accessGroup:accessGroup genericAttribute:nil error:error]; |
| | | } |
| | | |
| | | + (BOOL)setData:(NSData *)data forKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup genericAttribute:(id)genericAttribute |
| | | { |
| | | return [self setData:data forKey:key service:service accessGroup:accessGroup genericAttribute:genericAttribute error:nil]; |
| | | } |
| | | |
| | | + (BOOL)setData:(NSData *)data forKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup genericAttribute:(id)genericAttribute error:(NSError * __autoreleasing *)error |
| | | { |
| | | if (!key) { |
| | | NSError *e = [self argumentError:NSLocalizedString(@"the key must not to be nil", nil)]; |
| | | if (error) { |
| | | *error = e; |
| | | } |
| | | return NO; |
| | | } |
| | | if (!service) { |
| | | service = [self defaultService]; |
| | | } |
| | | |
| | | UICKeyChainStore *keychain = [UICKeyChainStore keyChainStoreWithService:service accessGroup:accessGroup]; |
| | | return [keychain setData:data forKey:key genericAttribute:genericAttribute]; |
| | | } |
| | | |
| | | #pragma mark - |
| | | |
| | | - (BOOL)contains:(NSString *)key |
| | | { |
| | | NSMutableDictionary *query = [self query]; |
| | | query[(__bridge __strong id)kSecAttrAccount] = key; |
| | | |
| | | OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, NULL); |
| | | return status == errSecSuccess; |
| | | } |
| | | |
| | | #pragma mark - |
| | | |
| | | - (NSString *)stringForKey:(id)key |
| | | { |
| | | return [self stringForKey:key error:nil]; |
| | | } |
| | | |
| | | - (NSString *)stringForKey:(id)key error:(NSError *__autoreleasing *)error |
| | | { |
| | | NSData *data = [self dataForKey:key error:error]; |
| | | if (data) { |
| | | NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; |
| | | if (string) { |
| | | return string; |
| | | } |
| | | NSError *e = [self.class conversionError:NSLocalizedString(@"failed to convert data to string", nil)]; |
| | | if (error) { |
| | | *error = e; |
| | | } |
| | | return nil; |
| | | } |
| | | |
| | | return nil; |
| | | } |
| | | |
| | | #pragma mark - |
| | | |
| | | - (BOOL)setString:(NSString *)string forKey:(NSString *)key |
| | | { |
| | | return [self setString:string forKey:key genericAttribute:nil label:nil comment:nil error:nil]; |
| | | } |
| | | |
| | | - (BOOL)setString:(NSString *)string forKey:(NSString *)key error:(NSError *__autoreleasing *)error |
| | | { |
| | | return [self setString:string forKey:key genericAttribute:nil label:nil comment:nil error:error]; |
| | | } |
| | | |
| | | - (BOOL)setString:(NSString *)string forKey:(NSString *)key genericAttribute:(id)genericAttribute |
| | | { |
| | | return [self setString:string forKey:key genericAttribute:genericAttribute label:nil comment:nil error:nil]; |
| | | } |
| | | |
| | | - (BOOL)setString:(NSString *)string forKey:(NSString *)key genericAttribute:(id)genericAttribute error:(NSError * __autoreleasing *)error |
| | | { |
| | | return [self setString:string forKey:key genericAttribute:genericAttribute label:nil comment:nil error:error]; |
| | | } |
| | | |
| | | - (BOOL)setString:(NSString *)string forKey:(NSString *)key label:(NSString *)label comment:(NSString *)comment |
| | | { |
| | | return [self setString:string forKey:key genericAttribute:nil label:label comment:comment error:nil]; |
| | | } |
| | | |
| | | - (BOOL)setString:(NSString *)string forKey:(NSString *)key label:(NSString *)label comment:(NSString *)comment error:(NSError *__autoreleasing *)error |
| | | { |
| | | return [self setString:string forKey:key genericAttribute:nil label:label comment:comment error:error]; |
| | | } |
| | | |
| | | - (BOOL)setString:(NSString *)string forKey:(NSString *)key genericAttribute:(id)genericAttribute label:(NSString *)label comment:(NSString *)comment error:(NSError *__autoreleasing *)error |
| | | { |
| | | if (!string) { |
| | | return [self removeItemForKey:key error:error]; |
| | | } |
| | | NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding]; |
| | | if (data) { |
| | | return [self setData:data forKey:key genericAttribute:genericAttribute label:label comment:comment error:error]; |
| | | } |
| | | NSError *e = [self.class conversionError:NSLocalizedString(@"failed to convert string to data", nil)]; |
| | | if (error) { |
| | | *error = e; |
| | | } |
| | | return NO; |
| | | } |
| | | |
| | | #pragma mark - |
| | | |
| | | - (NSData *)dataForKey:(NSString *)key |
| | | { |
| | | return [self dataForKey:key error:nil]; |
| | | } |
| | | |
| | | - (NSData *)dataForKey:(NSString *)key error:(NSError *__autoreleasing *)error |
| | | { |
| | | NSMutableDictionary *query = [self query]; |
| | | query[(__bridge __strong id)kSecMatchLimit] = (__bridge id)kSecMatchLimitOne; |
| | | query[(__bridge __strong id)kSecReturnData] = (__bridge id)kCFBooleanTrue; |
| | | |
| | | query[(__bridge __strong id)kSecAttrAccount] = key; |
| | | |
| | | CFTypeRef data = nil; |
| | | OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &data); |
| | | |
| | | if (status == errSecSuccess) { |
| | | NSData *ret = [NSData dataWithData:(__bridge NSData *)data]; |
| | | if (data) { |
| | | CFRelease(data); |
| | | return ret; |
| | | } else { |
| | | NSError *e = [self.class unexpectedError:NSLocalizedString(@"Unexpected error has occurred.", nil)]; |
| | | if (error) { |
| | | *error = e; |
| | | } |
| | | return nil; |
| | | } |
| | | } else if (status == errSecItemNotFound) { |
| | | return nil; |
| | | } |
| | | |
| | | NSError *e = [self.class securityError:status]; |
| | | if (error) { |
| | | *error = e; |
| | | } |
| | | return nil; |
| | | } |
| | | |
| | | #pragma mark - |
| | | |
| | | - (BOOL)setData:(NSData *)data forKey:(NSString *)key |
| | | { |
| | | return [self setData:data forKey:key genericAttribute:nil label:nil comment:nil error:nil]; |
| | | } |
| | | |
| | | - (BOOL)setData:(NSData *)data forKey:(NSString *)key error:(NSError *__autoreleasing *)error |
| | | { |
| | | return [self setData:data forKey:key genericAttribute:nil label:nil comment:nil error:error]; |
| | | } |
| | | |
| | | - (BOOL)setData:(NSData *)data forKey:(NSString *)key genericAttribute:(id)genericAttribute |
| | | { |
| | | return [self setData:data forKey:key genericAttribute:genericAttribute label:nil comment:nil error:nil]; |
| | | } |
| | | |
| | | - (BOOL)setData:(NSData *)data forKey:(NSString *)key genericAttribute:(id)genericAttribute error:(NSError * __autoreleasing *)error |
| | | { |
| | | return [self setData:data forKey:key genericAttribute:genericAttribute label:nil comment:nil error:error]; |
| | | } |
| | | |
| | | - (BOOL)setData:(NSData *)data forKey:(NSString *)key label:(NSString *)label comment:(NSString *)comment |
| | | { |
| | | return [self setData:data forKey:key genericAttribute:nil label:label comment:comment error:nil]; |
| | | } |
| | | |
| | | - (BOOL)setData:(NSData *)data forKey:(NSString *)key label:(NSString *)label comment:(NSString *)comment error:(NSError *__autoreleasing *)error |
| | | { |
| | | return [self setData:data forKey:key genericAttribute:nil label:label comment:comment error:error]; |
| | | } |
| | | |
| | | - (BOOL)setData:(NSData *)data forKey:(NSString *)key genericAttribute:(id)genericAttribute label:(NSString *)label comment:(NSString *)comment error:(NSError *__autoreleasing *)error |
| | | { |
| | | if (!key) { |
| | | NSError *e = [self.class argumentError:NSLocalizedString(@"the key must not to be nil", nil)]; |
| | | if (error) { |
| | | *error = e; |
| | | } |
| | | return NO; |
| | | } |
| | | if (!data) { |
| | | return [self removeItemForKey:key error:error]; |
| | | } |
| | | |
| | | NSMutableDictionary *query = [self query]; |
| | | query[(__bridge __strong id)kSecAttrAccount] = key; |
| | | #if TARGET_OS_IOS |
| | | if (floor(NSFoundationVersionNumber) > floor(1144.17)) { // iOS 9+ |
| | | query[(__bridge __strong id)kSecUseAuthenticationUI] = (__bridge id)kSecUseAuthenticationUIFail; |
| | | #if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0 |
| | | } else if (floor(NSFoundationVersionNumber) > floor(1047.25)) { // iOS 8+ |
| | | query[(__bridge __strong id)kSecUseNoAuthenticationUI] = (__bridge id)kCFBooleanTrue; |
| | | #endif |
| | | } |
| | | #elif TARGET_OS_WATCH || TARGET_OS_TV |
| | | query[(__bridge __strong id)kSecUseAuthenticationUI] = (__bridge id)kSecUseAuthenticationUIFail; |
| | | #endif |
| | | |
| | | OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, NULL); |
| | | if (status == errSecSuccess || status == errSecInteractionNotAllowed) { |
| | | query = [self query]; |
| | | query[(__bridge __strong id)kSecAttrAccount] = key; |
| | | |
| | | NSError *unexpectedError = nil; |
| | | NSMutableDictionary *attributes = [self attributesWithKey:nil value:data error:&unexpectedError]; |
| | | |
| | | if (genericAttribute) { |
| | | attributes[(__bridge __strong id)kSecAttrGeneric] = genericAttribute; |
| | | } |
| | | if (label) { |
| | | attributes[(__bridge __strong id)kSecAttrLabel] = label; |
| | | } |
| | | if (comment) { |
| | | attributes[(__bridge __strong id)kSecAttrComment] = comment; |
| | | } |
| | | |
| | | if (unexpectedError) { |
| | | NSLog(@"error: [%@] %@", @(unexpectedError.code), NSLocalizedString(@"Unexpected error has occurred.", nil)); |
| | | if (error) { |
| | | *error = unexpectedError; |
| | | } |
| | | return NO; |
| | | } else { |
| | | |
| | | if (status == errSecInteractionNotAllowed && floor(NSFoundationVersionNumber) <= floor(1140.11)) { // iOS 8.0.x |
| | | if ([self removeItemForKey:key error:error]) { |
| | | return [self setData:data forKey:key label:label comment:comment error:error]; |
| | | } |
| | | } else { |
| | | status = SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)attributes); |
| | | } |
| | | if (status != errSecSuccess) { |
| | | NSError *e = [self.class securityError:status]; |
| | | if (error) { |
| | | *error = e; |
| | | } |
| | | return NO; |
| | | } |
| | | } |
| | | } else if (status == errSecItemNotFound) { |
| | | NSError *unexpectedError = nil; |
| | | NSMutableDictionary *attributes = [self attributesWithKey:key value:data error:&unexpectedError]; |
| | | |
| | | if (genericAttribute) { |
| | | attributes[(__bridge __strong id)kSecAttrGeneric] = genericAttribute; |
| | | } |
| | | if (label) { |
| | | attributes[(__bridge __strong id)kSecAttrLabel] = label; |
| | | } |
| | | if (comment) { |
| | | attributes[(__bridge __strong id)kSecAttrComment] = comment; |
| | | } |
| | | |
| | | if (unexpectedError) { |
| | | NSLog(@"error: [%@] %@", @(unexpectedError.code), NSLocalizedString(@"Unexpected error has occurred.", nil)); |
| | | if (error) { |
| | | *error = unexpectedError; |
| | | } |
| | | return NO; |
| | | } else { |
| | | status = SecItemAdd((__bridge CFDictionaryRef)attributes, NULL); |
| | | if (status != errSecSuccess) { |
| | | NSError *e = [self.class securityError:status]; |
| | | if (error) { |
| | | *error = e; |
| | | } |
| | | return NO; |
| | | } |
| | | } |
| | | } else { |
| | | NSError *e = [self.class securityError:status]; |
| | | if (error) { |
| | | *error = e; |
| | | } |
| | | return NO; |
| | | } |
| | | |
| | | return YES; |
| | | } |
| | | |
| | | #pragma mark - |
| | | |
| | | + (BOOL)removeItemForKey:(NSString *)key |
| | | { |
| | | return [self removeItemForKey:key service:nil accessGroup:nil error:nil]; |
| | | } |
| | | |
| | | + (BOOL)removeItemForKey:(NSString *)key error:(NSError *__autoreleasing *)error |
| | | { |
| | | return [self removeItemForKey:key service:nil accessGroup:nil error:error]; |
| | | } |
| | | |
| | | + (BOOL)removeItemForKey:(NSString *)key service:(NSString *)service |
| | | { |
| | | return [self removeItemForKey:key service:service accessGroup:nil error:nil]; |
| | | } |
| | | |
| | | + (BOOL)removeItemForKey:(NSString *)key service:(NSString *)service error:(NSError *__autoreleasing *)error |
| | | { |
| | | return [self removeItemForKey:key service:service accessGroup:nil error:error]; |
| | | } |
| | | |
| | | + (BOOL)removeItemForKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup |
| | | { |
| | | return [self removeItemForKey:key service:service accessGroup:accessGroup error:nil]; |
| | | } |
| | | |
| | | + (BOOL)removeItemForKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup error:(NSError *__autoreleasing *)error |
| | | { |
| | | if (!key) { |
| | | NSError *e = [self.class argumentError:NSLocalizedString(@"the key must not to be nil", nil)]; |
| | | if (error) { |
| | | *error = e; |
| | | } |
| | | return NO; |
| | | } |
| | | if (!service) { |
| | | service = [self defaultService]; |
| | | } |
| | | |
| | | UICKeyChainStore *keychain = [UICKeyChainStore keyChainStoreWithService:service accessGroup:accessGroup]; |
| | | return [keychain removeItemForKey:key error:error]; |
| | | } |
| | | |
| | | #pragma mark - |
| | | |
| | | + (BOOL)removeAllItems |
| | | { |
| | | return [self removeAllItemsForService:nil accessGroup:nil error:nil]; |
| | | } |
| | | |
| | | + (BOOL)removeAllItemsWithError:(NSError *__autoreleasing *)error |
| | | { |
| | | return [self removeAllItemsForService:nil accessGroup:nil error:error]; |
| | | } |
| | | |
| | | + (BOOL)removeAllItemsForService:(NSString *)service |
| | | { |
| | | return [self removeAllItemsForService:service accessGroup:nil error:nil]; |
| | | } |
| | | |
| | | + (BOOL)removeAllItemsForService:(NSString *)service error:(NSError *__autoreleasing *)error |
| | | { |
| | | return [self removeAllItemsForService:service accessGroup:nil error:error]; |
| | | } |
| | | |
| | | + (BOOL)removeAllItemsForService:(NSString *)service accessGroup:(NSString *)accessGroup |
| | | { |
| | | return [self removeAllItemsForService:service accessGroup:accessGroup error:nil]; |
| | | } |
| | | |
| | | + (BOOL)removeAllItemsForService:(NSString *)service accessGroup:(NSString *)accessGroup error:(NSError *__autoreleasing *)error |
| | | { |
| | | UICKeyChainStore *keychain = [UICKeyChainStore keyChainStoreWithService:service accessGroup:accessGroup]; |
| | | return [keychain removeAllItemsWithError:error]; |
| | | } |
| | | |
| | | #pragma mark - |
| | | |
| | | - (BOOL)removeItemForKey:(NSString *)key |
| | | { |
| | | return [self removeItemForKey:key error:nil]; |
| | | } |
| | | |
| | | - (BOOL)removeItemForKey:(NSString *)key error:(NSError *__autoreleasing *)error |
| | | { |
| | | NSMutableDictionary *query = [self query]; |
| | | query[(__bridge __strong id)kSecAttrAccount] = key; |
| | | |
| | | OSStatus status = SecItemDelete((__bridge CFDictionaryRef)query); |
| | | if (status != errSecSuccess && status != errSecItemNotFound) { |
| | | NSError *e = [self.class securityError:status]; |
| | | if (error) { |
| | | *error = e; |
| | | } |
| | | return NO; |
| | | } |
| | | |
| | | return YES; |
| | | } |
| | | |
| | | #pragma mark - |
| | | |
| | | - (BOOL)removeAllItems |
| | | { |
| | | return [self removeAllItemsWithError:nil]; |
| | | } |
| | | |
| | | - (BOOL)removeAllItemsWithError:(NSError *__autoreleasing *)error |
| | | { |
| | | NSMutableDictionary *query = [self query]; |
| | | #if !TARGET_OS_IPHONE |
| | | query[(__bridge id)kSecMatchLimit] = (__bridge id)kSecMatchLimitAll; |
| | | #endif |
| | | |
| | | OSStatus status = SecItemDelete((__bridge CFDictionaryRef)query); |
| | | if (status != errSecSuccess && status != errSecItemNotFound) { |
| | | NSError *e = [self.class securityError:status]; |
| | | if (error) { |
| | | *error = e; |
| | | } |
| | | return NO; |
| | | } |
| | | |
| | | return YES; |
| | | } |
| | | |
| | | #pragma mark - |
| | | |
| | | - (NSString *)objectForKeyedSubscript:(NSString <NSCopying> *)key |
| | | { |
| | | return [self stringForKey:key]; |
| | | } |
| | | |
| | | - (void)setObject:(NSString *)obj forKeyedSubscript:(NSString <NSCopying> *)key |
| | | { |
| | | if (!obj) { |
| | | [self removeItemForKey:key]; |
| | | } else { |
| | | [self setString:obj forKey:key]; |
| | | } |
| | | } |
| | | |
| | | #pragma mark - |
| | | |
| | | - (NSArray UIC_KEY_TYPE *)allKeys |
| | | { |
| | | NSArray *items = [self.class prettify:[self itemClassObject] items:[self items]]; |
| | | NSMutableArray *keys = [[NSMutableArray alloc] init]; |
| | | for (NSDictionary *item in items) { |
| | | NSString *key = item[@"key"]; |
| | | if (key) { |
| | | [keys addObject:key]; |
| | | } |
| | | } |
| | | return keys.copy; |
| | | } |
| | | |
| | | + (NSArray UIC_KEY_TYPE *)allKeysWithItemClass:(UICKeyChainStoreItemClass)itemClass |
| | | { |
| | | CFTypeRef itemClassObject = kSecClassGenericPassword; |
| | | if (itemClass == UICKeyChainStoreItemClassGenericPassword) { |
| | | itemClassObject = kSecClassGenericPassword; |
| | | } else if (itemClass == UICKeyChainStoreItemClassInternetPassword) { |
| | | itemClassObject = kSecClassInternetPassword; |
| | | } |
| | | |
| | | NSMutableDictionary *query = [[NSMutableDictionary alloc] init]; |
| | | query[(__bridge __strong id)kSecClass] = (__bridge id)itemClassObject; |
| | | query[(__bridge __strong id)kSecMatchLimit] = (__bridge id)kSecMatchLimitAll; |
| | | query[(__bridge __strong id)kSecReturnAttributes] = (__bridge id)kCFBooleanTrue; |
| | | |
| | | CFArrayRef result = nil; |
| | | CFDictionaryRef cfquery = (CFDictionaryRef)CFBridgingRetain(query); |
| | | OSStatus status = SecItemCopyMatching(cfquery, (CFTypeRef *)&result); |
| | | CFRelease(cfquery); |
| | | |
| | | if (status == errSecSuccess) { |
| | | NSArray *items = [self prettify:itemClassObject items:(__bridge NSArray *)result]; |
| | | NSMutableArray *keys = [[NSMutableArray alloc] init]; |
| | | for (NSDictionary *item in items) { |
| | | if (itemClassObject == kSecClassGenericPassword) { |
| | | [keys addObject:@{@"service": item[@"service"] ?: @"", @"key": item[@"key"] ?: @""}]; |
| | | } else if (itemClassObject == kSecClassInternetPassword) { |
| | | [keys addObject:@{@"server": item[@"service"] ?: @"", @"key": item[@"key"] ?: @""}]; |
| | | } |
| | | } |
| | | return keys.copy; |
| | | } else if (status == errSecItemNotFound) { |
| | | return @[]; |
| | | } |
| | | |
| | | return nil; |
| | | } |
| | | |
| | | + (NSArray *)allItemsWithItemClass:(UICKeyChainStoreItemClass)itemClass |
| | | { |
| | | CFTypeRef itemClassObject = kSecClassGenericPassword; |
| | | if (itemClass == UICKeyChainStoreItemClassGenericPassword) { |
| | | itemClassObject = kSecClassGenericPassword; |
| | | } else if (itemClass == UICKeyChainStoreItemClassInternetPassword) { |
| | | itemClassObject = kSecClassInternetPassword; |
| | | } |
| | | |
| | | NSMutableDictionary *query = [[NSMutableDictionary alloc] init]; |
| | | query[(__bridge __strong id)kSecClass] = (__bridge id)itemClassObject; |
| | | query[(__bridge __strong id)kSecMatchLimit] = (__bridge id)kSecMatchLimitAll; |
| | | query[(__bridge __strong id)kSecReturnAttributes] = (__bridge id)kCFBooleanTrue; |
| | | #if TARGET_OS_IPHONE |
| | | query[(__bridge __strong id)kSecReturnData] = (__bridge id)kCFBooleanTrue; |
| | | #endif |
| | | |
| | | CFArrayRef result = nil; |
| | | CFDictionaryRef cfquery = (CFDictionaryRef)CFBridgingRetain(query); |
| | | OSStatus status = SecItemCopyMatching(cfquery, (CFTypeRef *)&result); |
| | | CFRelease(cfquery); |
| | | |
| | | if (status == errSecSuccess) { |
| | | return [self prettify:itemClassObject items:(__bridge NSArray *)result]; |
| | | } else if (status == errSecItemNotFound) { |
| | | return @[]; |
| | | } |
| | | |
| | | return nil; |
| | | } |
| | | |
| | | - (NSArray *)allItems |
| | | { |
| | | return [self.class prettify:[self itemClassObject] items:[self items]]; |
| | | } |
| | | |
| | | - (NSArray *)items |
| | | { |
| | | NSMutableDictionary *query = [self query]; |
| | | query[(__bridge __strong id)kSecMatchLimit] = (__bridge id)kSecMatchLimitAll; |
| | | query[(__bridge __strong id)kSecReturnAttributes] = (__bridge id)kCFBooleanTrue; |
| | | #if TARGET_OS_IPHONE |
| | | query[(__bridge __strong id)kSecReturnData] = (__bridge id)kCFBooleanTrue; |
| | | #endif |
| | | |
| | | CFArrayRef result = nil; |
| | | OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query,(CFTypeRef *)&result); |
| | | |
| | | if (status == errSecSuccess) { |
| | | return CFBridgingRelease(result); |
| | | } else if (status == errSecItemNotFound) { |
| | | return @[]; |
| | | } |
| | | |
| | | return nil; |
| | | } |
| | | |
| | | + (NSArray *)prettify:(CFTypeRef)itemClass items:(NSArray *)items |
| | | { |
| | | NSMutableArray *prettified = [[NSMutableArray alloc] init]; |
| | | |
| | | for (NSDictionary *attributes in items) { |
| | | NSMutableDictionary *item = [[NSMutableDictionary alloc] init]; |
| | | if (itemClass == kSecClassGenericPassword) { |
| | | item[@"class"] = @"GenericPassword"; |
| | | id service = attributes[(__bridge id)kSecAttrService]; |
| | | if (service) { |
| | | item[@"service"] = service; |
| | | } |
| | | id accessGroup = attributes[(__bridge id)kSecAttrAccessGroup]; |
| | | if (accessGroup) { |
| | | item[@"accessGroup"] = accessGroup; |
| | | } |
| | | } else if (itemClass == kSecClassInternetPassword) { |
| | | item[@"class"] = @"InternetPassword"; |
| | | id server = attributes[(__bridge id)kSecAttrServer]; |
| | | if (server) { |
| | | item[@"server"] = server; |
| | | } |
| | | id protocolType = attributes[(__bridge id)kSecAttrProtocol]; |
| | | if (protocolType) { |
| | | item[@"protocol"] = protocolType; |
| | | } |
| | | id authenticationType = attributes[(__bridge id)kSecAttrAuthenticationType]; |
| | | if (authenticationType) { |
| | | item[@"authenticationType"] = authenticationType; |
| | | } |
| | | } |
| | | id key = attributes[(__bridge id)kSecAttrAccount]; |
| | | if (key) { |
| | | item[@"key"] = key; |
| | | } |
| | | NSData *data = attributes[(__bridge id)kSecValueData]; |
| | | NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; |
| | | if (string) { |
| | | item[@"value"] = string; |
| | | } else { |
| | | item[@"value"] = data; |
| | | } |
| | | |
| | | id accessible = attributes[(__bridge id)kSecAttrAccessible]; |
| | | if (accessible) { |
| | | item[@"accessibility"] = accessible; |
| | | } |
| | | |
| | | if (floor(NSFoundationVersionNumber) > floor(993.00)) { // iOS 7+ |
| | | id synchronizable = attributes[(__bridge id)kSecAttrSynchronizable]; |
| | | if (synchronizable) { |
| | | item[@"synchronizable"] = synchronizable; |
| | | } |
| | | } |
| | | |
| | | [prettified addObject:item]; |
| | | } |
| | | |
| | | return prettified.copy; |
| | | } |
| | | |
| | | #pragma mark - |
| | | |
| | | - (void)setSynchronizable:(BOOL)synchronizable |
| | | { |
| | | _synchronizable = synchronizable; |
| | | if (_authenticationPolicy) { |
| | | NSLog(@"%@", @"Cannot specify both an authenticationPolicy and a synchronizable"); |
| | | } |
| | | } |
| | | |
| | | - (void)setAccessibility:(UICKeyChainStoreAccessibility)accessibility authenticationPolicy:(UICKeyChainStoreAuthenticationPolicy)authenticationPolicy |
| | | { |
| | | _accessibility = accessibility; |
| | | _authenticationPolicy = authenticationPolicy; |
| | | if (_synchronizable) { |
| | | NSLog(@"%@", @"Cannot specify both an authenticationPolicy and a synchronizable"); |
| | | } |
| | | } |
| | | |
| | | #pragma mark - |
| | | |
| | | #if TARGET_OS_IOS |
| | | - (void)sharedPasswordWithCompletion:(void (^)(NSString *account, NSString *password, NSError *error))completion |
| | | { |
| | | NSString *domain = self.server.host; |
| | | if (domain.length > 0) { |
| | | [self.class requestSharedWebCredentialForDomain:domain account:nil completion:^(NSArray *credentials, NSError *error) { |
| | | NSDictionary *credential = credentials.firstObject; |
| | | if (credential) { |
| | | NSString *account = credential[@"account"]; |
| | | NSString *password = credential[@"password"]; |
| | | if (completion) { |
| | | completion(account, password, error); |
| | | } |
| | | } else { |
| | | if (completion) { |
| | | completion(nil, nil, error); |
| | | } |
| | | } |
| | | }]; |
| | | } else { |
| | | NSError *error = [self.class argumentError:NSLocalizedString(@"the server property must not to be nil, should use 'keyChainStoreWithServer:protocolType:' initializer to instantiate keychain store", nil)]; |
| | | if (completion) { |
| | | completion(nil, nil, error); |
| | | } |
| | | } |
| | | } |
| | | |
| | | - (void)sharedPasswordForAccount:(NSString *)account completion:(void (^)(NSString *password, NSError *error))completion |
| | | { |
| | | NSString *domain = self.server.host; |
| | | if (domain.length > 0) { |
| | | [self.class requestSharedWebCredentialForDomain:domain account:account completion:^(NSArray *credentials, NSError *error) { |
| | | NSDictionary *credential = credentials.firstObject; |
| | | if (credential) { |
| | | NSString *password = credential[@"password"]; |
| | | if (completion) { |
| | | completion(password, error); |
| | | } |
| | | } else { |
| | | if (completion) { |
| | | completion(nil, error); |
| | | } |
| | | } |
| | | }]; |
| | | } else { |
| | | NSError *error = [self.class argumentError:NSLocalizedString(@"the server property must not to be nil, should use 'keyChainStoreWithServer:protocolType:' initializer to instantiate keychain store", nil)]; |
| | | if (completion) { |
| | | completion(nil, error); |
| | | } |
| | | } |
| | | } |
| | | |
| | | - (void)setSharedPassword:(NSString *)password forAccount:(NSString *)account completion:(void (^)(NSError *error))completion |
| | | { |
| | | NSString *domain = self.server.host; |
| | | if (domain.length > 0) { |
| | | SecAddSharedWebCredential((__bridge CFStringRef)domain, (__bridge CFStringRef)account, (__bridge CFStringRef)password, ^(CFErrorRef error) { |
| | | if (completion) { |
| | | completion((__bridge NSError *)error); |
| | | } |
| | | }); |
| | | } else { |
| | | NSError *error = [self.class argumentError:NSLocalizedString(@"the server property must not to be nil, should use 'keyChainStoreWithServer:protocolType:' initializer to instantiate keychain store", nil)]; |
| | | if (completion) { |
| | | completion(error); |
| | | } |
| | | } |
| | | } |
| | | |
| | | - (void)removeSharedPasswordForAccount:(NSString *)account completion:(void (^)(NSError *error))completion |
| | | { |
| | | [self setSharedPassword:nil forAccount:account completion:completion]; |
| | | } |
| | | |
| | | + (void)requestSharedWebCredentialWithCompletion:(void (^)(NSArray UIC_CREDENTIAL_TYPE *credentials, NSError *error))completion |
| | | { |
| | | [self requestSharedWebCredentialForDomain:nil account:nil completion:completion]; |
| | | } |
| | | |
| | | + (void)requestSharedWebCredentialForDomain:(NSString *)domain account:(NSString *)account completion:(void (^)(NSArray UIC_CREDENTIAL_TYPE *credentials, NSError *error))completion |
| | | { |
| | | SecRequestSharedWebCredential((__bridge CFStringRef)domain, (__bridge CFStringRef)account, ^(CFArrayRef credentials, CFErrorRef error) { |
| | | if (error) { |
| | | NSError *e = (__bridge NSError *)error; |
| | | if (e.code != errSecItemNotFound) { |
| | | NSLog(@"error: [%@] %@", @(e.code), e.localizedDescription); |
| | | } |
| | | } |
| | | |
| | | NSMutableArray *sharedCredentials = [[NSMutableArray alloc] init]; |
| | | for (NSDictionary *credential in (__bridge NSArray *)credentials) { |
| | | NSMutableDictionary *sharedCredential = [[NSMutableDictionary alloc] init]; |
| | | NSString *server = credential[(__bridge __strong id)kSecAttrServer]; |
| | | if (server) { |
| | | sharedCredential[@"server"] = server; |
| | | } |
| | | NSString *account = credential[(__bridge __strong id)kSecAttrAccount]; |
| | | if (account) { |
| | | sharedCredential[@"account"] = account; |
| | | } |
| | | NSString *password = credential[(__bridge __strong id)kSecSharedPassword]; |
| | | if (password) { |
| | | sharedCredential[@"password"] = password; |
| | | } |
| | | [sharedCredentials addObject:sharedCredential]; |
| | | } |
| | | |
| | | if (completion) { |
| | | completion(sharedCredentials.copy, (__bridge NSError *)error); |
| | | } |
| | | }); |
| | | } |
| | | |
| | | + (NSString *)generatePassword |
| | | { |
| | | return (NSString *)CFBridgingRelease(SecCreateSharedWebCredentialPassword()); |
| | | } |
| | | |
| | | #endif |
| | | |
| | | #pragma mark - |
| | | |
| | | - (NSString *)description |
| | | { |
| | | NSArray *items = [self allItems]; |
| | | if (items.count == 0) { |
| | | return @"()"; |
| | | } |
| | | NSMutableString *description = [[NSMutableString alloc] initWithString:@"(\n"]; |
| | | for (NSDictionary *item in items) { |
| | | [description appendFormat:@" %@", item]; |
| | | } |
| | | [description appendString:@")"]; |
| | | return description.copy; |
| | | } |
| | | |
| | | - (NSString *)debugDescription |
| | | { |
| | | return [NSString stringWithFormat:@"%@", [self items]]; |
| | | } |
| | | |
| | | #pragma mark - |
| | | |
| | | - (NSMutableDictionary *)query |
| | | { |
| | | NSMutableDictionary *query = [[NSMutableDictionary alloc] init]; |
| | | |
| | | CFTypeRef itemClass = [self itemClassObject]; |
| | | query[(__bridge __strong id)kSecClass] =(__bridge id)itemClass; |
| | | if (floor(NSFoundationVersionNumber) > floor(993.00)) { // iOS 7+ (NSFoundationVersionNumber_iOS_6_1) |
| | | query[(__bridge __strong id)kSecAttrSynchronizable] = (__bridge id)kSecAttrSynchronizableAny; |
| | | } |
| | | |
| | | if (itemClass == kSecClassGenericPassword) { |
| | | query[(__bridge __strong id)(kSecAttrService)] = _service; |
| | | #if !TARGET_OS_SIMULATOR |
| | | if (_accessGroup) { |
| | | query[(__bridge __strong id)kSecAttrAccessGroup] = _accessGroup; |
| | | } |
| | | #endif |
| | | } else { |
| | | if (_server.host) { |
| | | query[(__bridge __strong id)kSecAttrServer] = _server.host; |
| | | } |
| | | if (_server.port) { |
| | | query[(__bridge __strong id)kSecAttrPort] = _server.port; |
| | | } |
| | | CFTypeRef protocolTypeObject = [self protocolTypeObject]; |
| | | if (protocolTypeObject) { |
| | | query[(__bridge __strong id)kSecAttrProtocol] = (__bridge id)protocolTypeObject; |
| | | } |
| | | CFTypeRef authenticationTypeObject = [self authenticationTypeObject]; |
| | | if (authenticationTypeObject) { |
| | | query[(__bridge __strong id)kSecAttrAuthenticationType] = (__bridge id)authenticationTypeObject; |
| | | } |
| | | } |
| | | |
| | | #if TARGET_OS_IOS |
| | | if (_authenticationPrompt) { |
| | | if (floor(NSFoundationVersionNumber) > floor(1047.25)) { // iOS 8+ (NSFoundationVersionNumber_iOS_7_1) |
| | | query[(__bridge __strong id)kSecUseOperationPrompt] = _authenticationPrompt; |
| | | } else { |
| | | NSLog(@"%@", @"Unavailable 'authenticationPrompt' attribute on iOS versions prior to 8.0."); |
| | | } |
| | | } |
| | | #endif |
| | | |
| | | return query; |
| | | } |
| | | |
| | | - (NSMutableDictionary *)attributesWithKey:(NSString *)key value:(NSData *)value error:(NSError *__autoreleasing *)error |
| | | { |
| | | NSMutableDictionary *attributes; |
| | | |
| | | if (key) { |
| | | attributes = [self query]; |
| | | attributes[(__bridge __strong id)kSecAttrAccount] = key; |
| | | } else { |
| | | attributes = [[NSMutableDictionary alloc] init]; |
| | | } |
| | | |
| | | attributes[(__bridge __strong id)kSecValueData] = value; |
| | | |
| | | #if TARGET_OS_IOS |
| | | double iOS_7_1_or_10_9_2 = 1047.25; // NSFoundationVersionNumber_iOS_7_1 |
| | | #else |
| | | double iOS_7_1_or_10_9_2 = 1056.13; // NSFoundationVersionNumber10_9_2 |
| | | #endif |
| | | CFTypeRef accessibilityObject = [self accessibilityObject]; |
| | | if (_authenticationPolicy && accessibilityObject) { |
| | | if (floor(NSFoundationVersionNumber) > floor(iOS_7_1_or_10_9_2)) { // iOS 8+ or OS X 10.10+ |
| | | CFErrorRef securityError = NULL; |
| | | SecAccessControlRef accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibilityObject, (SecAccessControlCreateFlags)_authenticationPolicy, &securityError); |
| | | if (securityError) { |
| | | NSError *e = (__bridge NSError *)securityError; |
| | | NSLog(@"error: [%@] %@", @(e.code), e.localizedDescription); |
| | | if (error) { |
| | | *error = e; |
| | | CFRelease(accessControl); |
| | | return nil; |
| | | } |
| | | } |
| | | if (!accessControl) { |
| | | NSString *message = NSLocalizedString(@"Unexpected error has occurred.", nil); |
| | | NSError *e = [self.class unexpectedError:message]; |
| | | if (error) { |
| | | *error = e; |
| | | } |
| | | return nil; |
| | | } |
| | | attributes[(__bridge __strong id)kSecAttrAccessControl] = (__bridge_transfer id)accessControl; |
| | | } else { |
| | | #if TARGET_OS_IOS |
| | | NSLog(@"%@", @"Unavailable 'Touch ID integration' on iOS versions prior to 8.0."); |
| | | #else |
| | | NSLog(@"%@", @"Unavailable 'Touch ID integration' on OS X versions prior to 10.10."); |
| | | #endif |
| | | } |
| | | } else { |
| | | if (floor(NSFoundationVersionNumber) <= floor(iOS_7_1_or_10_9_2) && _accessibility == UICKeyChainStoreAccessibilityWhenPasscodeSetThisDeviceOnly) { |
| | | #if TARGET_OS_IOS |
| | | NSLog(@"%@", @"Unavailable 'UICKeyChainStoreAccessibilityWhenPasscodeSetThisDeviceOnly' attribute on iOS versions prior to 8.0."); |
| | | #else |
| | | NSLog(@"%@", @"Unavailable 'UICKeyChainStoreAccessibilityWhenPasscodeSetThisDeviceOnly' attribute on OS X versions prior to 10.10."); |
| | | #endif |
| | | } else { |
| | | if (accessibilityObject) { |
| | | attributes[(__bridge __strong id)kSecAttrAccessible] = (__bridge id)accessibilityObject; |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (floor(NSFoundationVersionNumber) > floor(993.00)) { // iOS 7+ |
| | | attributes[(__bridge __strong id)kSecAttrSynchronizable] = @(_synchronizable); |
| | | } |
| | | |
| | | return attributes; |
| | | } |
| | | |
| | | #pragma mark - |
| | | |
| | | - (CFTypeRef)itemClassObject |
| | | { |
| | | switch (_itemClass) { |
| | | case UICKeyChainStoreItemClassGenericPassword: |
| | | return kSecClassGenericPassword; |
| | | case UICKeyChainStoreItemClassInternetPassword: |
| | | return kSecClassInternetPassword; |
| | | default: |
| | | return nil; |
| | | } |
| | | } |
| | | |
| | | - (CFTypeRef)protocolTypeObject |
| | | { |
| | | switch (_protocolType) { |
| | | case UICKeyChainStoreProtocolTypeFTP: |
| | | return kSecAttrProtocolFTP; |
| | | case UICKeyChainStoreProtocolTypeFTPAccount: |
| | | return kSecAttrProtocolFTPAccount; |
| | | case UICKeyChainStoreProtocolTypeHTTP: |
| | | return kSecAttrProtocolHTTP; |
| | | case UICKeyChainStoreProtocolTypeIRC: |
| | | return kSecAttrProtocolIRC; |
| | | case UICKeyChainStoreProtocolTypeNNTP: |
| | | return kSecAttrProtocolNNTP; |
| | | case UICKeyChainStoreProtocolTypePOP3: |
| | | return kSecAttrProtocolPOP3; |
| | | case UICKeyChainStoreProtocolTypeSMTP: |
| | | return kSecAttrProtocolSMTP; |
| | | case UICKeyChainStoreProtocolTypeSOCKS: |
| | | return kSecAttrProtocolSOCKS; |
| | | case UICKeyChainStoreProtocolTypeIMAP: |
| | | return kSecAttrProtocolIMAP; |
| | | case UICKeyChainStoreProtocolTypeLDAP: |
| | | return kSecAttrProtocolLDAP; |
| | | case UICKeyChainStoreProtocolTypeAppleTalk: |
| | | return kSecAttrProtocolAppleTalk; |
| | | case UICKeyChainStoreProtocolTypeAFP: |
| | | return kSecAttrProtocolAFP; |
| | | case UICKeyChainStoreProtocolTypeTelnet: |
| | | return kSecAttrProtocolTelnet; |
| | | case UICKeyChainStoreProtocolTypeSSH: |
| | | return kSecAttrProtocolSSH; |
| | | case UICKeyChainStoreProtocolTypeFTPS: |
| | | return kSecAttrProtocolFTPS; |
| | | case UICKeyChainStoreProtocolTypeHTTPS: |
| | | return kSecAttrProtocolHTTPS; |
| | | case UICKeyChainStoreProtocolTypeHTTPProxy: |
| | | return kSecAttrProtocolHTTPProxy; |
| | | case UICKeyChainStoreProtocolTypeHTTPSProxy: |
| | | return kSecAttrProtocolHTTPSProxy; |
| | | case UICKeyChainStoreProtocolTypeFTPProxy: |
| | | return kSecAttrProtocolFTPProxy; |
| | | case UICKeyChainStoreProtocolTypeSMB: |
| | | return kSecAttrProtocolSMB; |
| | | case UICKeyChainStoreProtocolTypeRTSP: |
| | | return kSecAttrProtocolRTSP; |
| | | case UICKeyChainStoreProtocolTypeRTSPProxy: |
| | | return kSecAttrProtocolRTSPProxy; |
| | | case UICKeyChainStoreProtocolTypeDAAP: |
| | | return kSecAttrProtocolDAAP; |
| | | case UICKeyChainStoreProtocolTypeEPPC: |
| | | return kSecAttrProtocolEPPC; |
| | | case UICKeyChainStoreProtocolTypeNNTPS: |
| | | return kSecAttrProtocolNNTPS; |
| | | case UICKeyChainStoreProtocolTypeLDAPS: |
| | | return kSecAttrProtocolLDAPS; |
| | | case UICKeyChainStoreProtocolTypeTelnetS: |
| | | return kSecAttrProtocolTelnetS; |
| | | case UICKeyChainStoreProtocolTypeIRCS: |
| | | return kSecAttrProtocolIRCS; |
| | | case UICKeyChainStoreProtocolTypePOP3S: |
| | | return kSecAttrProtocolPOP3S; |
| | | default: |
| | | return nil; |
| | | } |
| | | } |
| | | |
| | | - (CFTypeRef)authenticationTypeObject |
| | | { |
| | | switch (_authenticationType) { |
| | | case UICKeyChainStoreAuthenticationTypeNTLM: |
| | | return kSecAttrAuthenticationTypeNTLM; |
| | | case UICKeyChainStoreAuthenticationTypeMSN: |
| | | return kSecAttrAuthenticationTypeMSN; |
| | | case UICKeyChainStoreAuthenticationTypeDPA: |
| | | return kSecAttrAuthenticationTypeDPA; |
| | | case UICKeyChainStoreAuthenticationTypeRPA: |
| | | return kSecAttrAuthenticationTypeRPA; |
| | | case UICKeyChainStoreAuthenticationTypeHTTPBasic: |
| | | return kSecAttrAuthenticationTypeHTTPBasic; |
| | | case UICKeyChainStoreAuthenticationTypeHTTPDigest: |
| | | return kSecAttrAuthenticationTypeHTTPDigest; |
| | | case UICKeyChainStoreAuthenticationTypeHTMLForm: |
| | | return kSecAttrAuthenticationTypeHTMLForm; |
| | | case UICKeyChainStoreAuthenticationTypeDefault: |
| | | return kSecAttrAuthenticationTypeDefault; |
| | | default: |
| | | return nil; |
| | | } |
| | | } |
| | | |
| | | - (CFTypeRef)accessibilityObject |
| | | { |
| | | switch (_accessibility) { |
| | | case UICKeyChainStoreAccessibilityWhenUnlocked: |
| | | return kSecAttrAccessibleWhenUnlocked; |
| | | case UICKeyChainStoreAccessibilityAfterFirstUnlock: |
| | | return kSecAttrAccessibleAfterFirstUnlock; |
| | | case UICKeyChainStoreAccessibilityAlways: |
| | | return kSecAttrAccessibleAlways; |
| | | case UICKeyChainStoreAccessibilityWhenPasscodeSetThisDeviceOnly: |
| | | return kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly; |
| | | case UICKeyChainStoreAccessibilityWhenUnlockedThisDeviceOnly: |
| | | return kSecAttrAccessibleWhenUnlockedThisDeviceOnly; |
| | | case UICKeyChainStoreAccessibilityAfterFirstUnlockThisDeviceOnly: |
| | | return kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly; |
| | | case UICKeyChainStoreAccessibilityAlwaysThisDeviceOnly: |
| | | return kSecAttrAccessibleAlwaysThisDeviceOnly; |
| | | default: |
| | | return nil; |
| | | } |
| | | } |
| | | |
| | | + (NSError *)argumentError:(NSString *)message |
| | | { |
| | | NSError *error = [NSError errorWithDomain:UICKeyChainStoreErrorDomain code:UICKeyChainStoreErrorInvalidArguments userInfo:@{NSLocalizedDescriptionKey: message}]; |
| | | NSLog(@"error: [%@] %@", @(error.code), error.localizedDescription); |
| | | return error; |
| | | } |
| | | |
| | | + (NSError *)conversionError:(NSString *)message |
| | | { |
| | | NSError *error = [NSError errorWithDomain:UICKeyChainStoreErrorDomain code:-67594 userInfo:@{NSLocalizedDescriptionKey: message}]; |
| | | NSLog(@"error: [%@] %@", @(error.code), error.localizedDescription); |
| | | return error; |
| | | } |
| | | |
| | | + (NSError *)securityError:(OSStatus)status |
| | | { |
| | | NSString *message = @"Security error has occurred."; |
| | | #if TARGET_OS_MAC && !TARGET_OS_IPHONE |
| | | CFStringRef description = SecCopyErrorMessageString(status, NULL); |
| | | if (description) { |
| | | message = (__bridge_transfer NSString *)description; |
| | | } |
| | | #endif |
| | | NSError *error = [NSError errorWithDomain:UICKeyChainStoreErrorDomain code:status userInfo:@{NSLocalizedDescriptionKey: message}]; |
| | | NSLog(@"OSStatus error: [%@] %@", @(error.code), error.localizedDescription); |
| | | return error; |
| | | } |
| | | |
| | | + (NSError *)unexpectedError:(NSString *)message |
| | | { |
| | | NSError *error = [NSError errorWithDomain:UICKeyChainStoreErrorDomain code:-99999 userInfo:@{NSLocalizedDescriptionKey: message}]; |
| | | NSLog(@"error: [%@] %@", @(error.code), error.localizedDescription); |
| | | return error; |
| | | } |
| | | |
| | | @end |
| | | |
| | | @implementation UICKeyChainStore (Deprecation) |
| | | |
| | | - (void)synchronize |
| | | { |
| | | // Deprecated, calling this method is no longer required |
| | | } |
| | | |
| | | - (BOOL)synchronizeWithError:(NSError *__autoreleasing *)error |
| | | { |
| | | // Deprecated, calling this method is no longer required |
| | | return true; |
| | | } |
| | | |
| | | @end |