//
|
// 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
|