add failing tests for forward compatibility from v1

This commit is contained in:
Fuji, Goro (gfx)
2015-02-17 16:07:00 +09:00
parent 7ebb3ea714
commit 2c0e3e04e9
4 changed files with 779 additions and 0 deletions

View File

@@ -21,6 +21,14 @@
14A59D271A62F4DA006561CC /* libUICKeyChainStore.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 14A59D1C1A62F4DA006561CC /* libUICKeyChainStore.a */; };
14A59D331A62F510006561CC /* UICKeyChainStoreTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 14A59CAF1A62CF6E006561CC /* UICKeyChainStoreTests.m */; };
14A59D361A641129006561CC /* UICKeyChainStore.m in Sources */ = {isa = PBXBuildFile; fileRef = 14A59CD71A62D4C3006561CC /* UICKeyChainStore.m */; };
3ACDC27F1A931BCE00C7A63A /* UICv1KeyChainStore.m in Sources */ = {isa = PBXBuildFile; fileRef = 3ACDC27E1A931BCE00C7A63A /* UICv1KeyChainStore.m */; };
3ACDC2801A931BCE00C7A63A /* UICv1KeyChainStore.m in Sources */ = {isa = PBXBuildFile; fileRef = 3ACDC27E1A931BCE00C7A63A /* UICv1KeyChainStore.m */; };
3ACDC2811A931BCE00C7A63A /* UICv1KeyChainStore.m in Sources */ = {isa = PBXBuildFile; fileRef = 3ACDC27E1A931BCE00C7A63A /* UICv1KeyChainStore.m */; };
3ACDC2821A931BCE00C7A63A /* UICv1KeyChainStore.m in Sources */ = {isa = PBXBuildFile; fileRef = 3ACDC27E1A931BCE00C7A63A /* UICv1KeyChainStore.m */; };
3ACDC2891A931CE900C7A63A /* UICKeyChainStoreForwardCompatibilityTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3ACDC2881A931CE900C7A63A /* UICKeyChainStoreForwardCompatibilityTests.m */; };
3ACDC28A1A931CE900C7A63A /* UICKeyChainStoreForwardCompatibilityTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3ACDC2881A931CE900C7A63A /* UICKeyChainStoreForwardCompatibilityTests.m */; };
3ACDC28B1A931CE900C7A63A /* UICKeyChainStoreForwardCompatibilityTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3ACDC2881A931CE900C7A63A /* UICKeyChainStoreForwardCompatibilityTests.m */; };
3ACDC28C1A931CE900C7A63A /* UICKeyChainStoreForwardCompatibilityTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3ACDC2881A931CE900C7A63A /* UICKeyChainStoreForwardCompatibilityTests.m */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -80,6 +88,9 @@
14A59D081A62F336006561CC /* libUICKeyChainStore-iOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "libUICKeyChainStore-iOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
14A59D1C1A62F4DA006561CC /* libUICKeyChainStore.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libUICKeyChainStore.a; sourceTree = BUILT_PRODUCTS_DIR; };
14A59D261A62F4DA006561CC /* libUICKeyChainStore-MacTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "libUICKeyChainStore-MacTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
3ACDC27D1A931BCE00C7A63A /* UICv1KeyChainStore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UICv1KeyChainStore.h; sourceTree = "<group>"; };
3ACDC27E1A931BCE00C7A63A /* UICv1KeyChainStore.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UICv1KeyChainStore.m; sourceTree = "<group>"; };
3ACDC2881A931CE900C7A63A /* UICKeyChainStoreForwardCompatibilityTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UICKeyChainStoreForwardCompatibilityTests.m; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -191,7 +202,9 @@
14A59CAC1A62CF6E006561CC /* UICKeyChainStoreTests */ = {
isa = PBXGroup;
children = (
3ACDC27C1A931BCE00C7A63A /* v1.1.1-Lib */,
14A59CAF1A62CF6E006561CC /* UICKeyChainStoreTests.m */,
3ACDC2881A931CE900C7A63A /* UICKeyChainStoreForwardCompatibilityTests.m */,
14A59CAD1A62CF6E006561CC /* Supporting Files */,
);
path = UICKeyChainStoreTests;
@@ -205,6 +218,15 @@
name = "Supporting Files";
sourceTree = "<group>";
};
3ACDC27C1A931BCE00C7A63A /* v1.1.1-Lib */ = {
isa = PBXGroup;
children = (
3ACDC27D1A931BCE00C7A63A /* UICv1KeyChainStore.h */,
3ACDC27E1A931BCE00C7A63A /* UICv1KeyChainStore.m */,
);
path = "v1.1.1-Lib";
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
@@ -494,6 +516,8 @@
buildActionMask = 2147483647;
files = (
14A59CB01A62CF6E006561CC /* UICKeyChainStoreTests.m in Sources */,
3ACDC2891A931CE900C7A63A /* UICKeyChainStoreForwardCompatibilityTests.m in Sources */,
3ACDC27F1A931BCE00C7A63A /* UICv1KeyChainStore.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -510,6 +534,8 @@
buildActionMask = 2147483647;
files = (
14A59CDA1A62D6B0006561CC /* UICKeyChainStoreTests.m in Sources */,
3ACDC28A1A931CE900C7A63A /* UICKeyChainStoreForwardCompatibilityTests.m in Sources */,
3ACDC2801A931BCE00C7A63A /* UICv1KeyChainStore.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -526,6 +552,8 @@
buildActionMask = 2147483647;
files = (
14A59D151A62F3BD006561CC /* UICKeyChainStoreTests.m in Sources */,
3ACDC28B1A931CE900C7A63A /* UICKeyChainStoreForwardCompatibilityTests.m in Sources */,
3ACDC2811A931BCE00C7A63A /* UICv1KeyChainStore.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -542,6 +570,8 @@
buildActionMask = 2147483647;
files = (
14A59D331A62F510006561CC /* UICKeyChainStoreTests.m in Sources */,
3ACDC28C1A931CE900C7A63A /* UICKeyChainStoreForwardCompatibilityTests.m in Sources */,
3ACDC2821A931BCE00C7A63A /* UICv1KeyChainStore.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View File

@@ -0,0 +1,49 @@
//
// UICKeyChainStoreForwardCompatibilityTests.m
// UICKeyChainStore
//
// Created by goro-fuji on 2/17/15.
// Copyright (c) 2015 kishikawa katsumi. All rights reserved.
//
#import <XCTest/XCTest.h>
#import "UICKeyChainStore.h"
#import "UICv1KeyChainStore.h"
@interface UICKeyChainStoreForwardCompatibilityTests : XCTestCase
@end
@implementation UICKeyChainStoreForwardCompatibilityTests
- (void)setUp {
[super setUp];
[UICKeyChainStore setDefaultService:@(__FILE__)];
[UICv1KeyChainStore setDefaultService:@(__FILE__)];
[UICKeyChainStore removeAllItems];
}
- (void)tearDown {
[UICKeyChainStore removeAllItems];
[super tearDown];
}
- (void)testReadV1DataFromV2 {
[UICv1KeyChainStore setString:@"http://example.com/" forKey:@"url"];
XCTAssertEqualObjects([UICKeyChainStore stringForKey:@"url"], @"http://example.com/");
}
- (void)testReadV2DataFromV1 {
[UICKeyChainStore setString:@"http://example.com/" forKey:@"url"];
XCTAssertEqualObjects([UICv1KeyChainStore stringForKey:@"url"], @"http://example.com/");
}
@end

View File

@@ -0,0 +1,94 @@
//
// a copy of UICKeyChainStore.h v1.1.1 for testing
//
// Created by Kishikawa Katsumi on 11/11/20.
// Copyright (c) 2011 Kishikawa Katsumi. All rights reserved.
//
#import <Foundation/Foundation.h>
extern NSString * const UICv1KeyChainStoreErrorDomain;
typedef NS_ENUM(NSInteger, UICv1KeyChainStoreErrorCode) {
UICv1KeyChainStoreErrorInvalidArguments = 1,
};
@interface UICv1KeyChainStore : NSObject
@property (nonatomic, readonly) NSString *service;
@property (nonatomic, readonly) NSString *accessGroup;
+ (NSString *)defaultService;
+ (void)setDefaultService:(NSString *)defaultService;
+ (UICv1KeyChainStore *)keyChainStore;
+ (UICv1KeyChainStore *)keyChainStoreWithService:(NSString *)service;
+ (UICv1KeyChainStore *)keyChainStoreWithService:(NSString *)service accessGroup:(NSString *)accessGroup;
- (instancetype)init;
- (instancetype)initWithService:(NSString *)service;
- (instancetype)initWithService:(NSString *)service accessGroup:(NSString *)accessGroup;
+ (NSString *)stringForKey:(NSString *)key;
+ (NSString *)stringForKey:(NSString *)key error:(NSError * __autoreleasing *)error;
+ (NSString *)stringForKey:(NSString *)key service:(NSString *)service;
+ (NSString *)stringForKey:(NSString *)key service:(NSString *)service error:(NSError * __autoreleasing *)error;
+ (NSString *)stringForKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup;
+ (NSString *)stringForKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup error:(NSError * __autoreleasing *)error;
+ (BOOL)setString:(NSString *)value forKey:(NSString *)key;
+ (BOOL)setString:(NSString *)value forKey:(NSString *)key error:(NSError * __autoreleasing *)error;
+ (BOOL)setString:(NSString *)value forKey:(NSString *)key service:(NSString *)service;
+ (BOOL)setString:(NSString *)value forKey:(NSString *)key service:(NSString *)service error:(NSError * __autoreleasing *)error;
+ (BOOL)setString:(NSString *)value forKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup;
+ (BOOL)setString:(NSString *)value forKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup error:(NSError * __autoreleasing *)error;
+ (NSData *)dataForKey:(NSString *)key;
+ (NSData *)dataForKey:(NSString *)key error:(NSError * __autoreleasing *)error;
+ (NSData *)dataForKey:(NSString *)key service:(NSString *)service;
+ (NSData *)dataForKey:(NSString *)key service:(NSString *)service error:(NSError * __autoreleasing *)error;
+ (NSData *)dataForKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup;
+ (NSData *)dataForKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup error:(NSError * __autoreleasing *)error;
+ (BOOL)setData:(NSData *)data forKey:(NSString *)key;
+ (BOOL)setData:(NSData *)data forKey:(NSString *)key error:(NSError * __autoreleasing *)error;
+ (BOOL)setData:(NSData *)data forKey:(NSString *)key service:(NSString *)service;
+ (BOOL)setData:(NSData *)data forKey:(NSString *)key service:(NSString *)service error:(NSError * __autoreleasing *)error;
+ (BOOL)setData:(NSData *)data forKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup;
+ (BOOL)setData:(NSData *)data forKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup error:(NSError * __autoreleasing *)error;
- (void)setString:(NSString *)string forKey:(NSString *)key;
- (BOOL)setString:(NSString *)string forKey:(NSString *)key error:(NSError * __autoreleasing *)error;
- (NSString *)stringForKey:(NSString *)key;
- (NSString *)stringForKey:(NSString *)key error:(NSError * __autoreleasing *)error;
- (void)setData:(NSData *)data forKey:(NSString *)key;
- (BOOL)setData:(NSData *)data forKey:(NSString *)key error:(NSError * __autoreleasing *)error;
- (NSData *)dataForKey:(NSString *)key;
- (NSData *)dataForKey:(NSString *)key error:(NSError * __autoreleasing *)error;
+ (BOOL)removeItemForKey:(NSString *)key;
+ (BOOL)removeItemForKey:(NSString *)key error:(NSError * __autoreleasing *)error;
+ (BOOL)removeItemForKey:(NSString *)key service:(NSString *)service;
+ (BOOL)removeItemForKey:(NSString *)key service:(NSString *)service error:(NSError * __autoreleasing *)error;
+ (BOOL)removeItemForKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup;
+ (BOOL)removeItemForKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup error:(NSError * __autoreleasing *)error;
+ (BOOL)removeAllItems;
+ (BOOL)removeAllItemsWithError:(NSError * __autoreleasing *)error;
+ (BOOL)removeAllItemsForService:(NSString *)service;
+ (BOOL)removeAllItemsForService:(NSString *)service error:(NSError * __autoreleasing *)error;
+ (BOOL)removeAllItemsForService:(NSString *)service accessGroup:(NSString *)accessGroup;
+ (BOOL)removeAllItemsForService:(NSString *)service accessGroup:(NSString *)accessGroup error:(NSError * __autoreleasing *)error;
- (void)removeItemForKey:(NSString *)key;
- (BOOL)removeItemForKey:(NSString *)key error:(NSError * __autoreleasing *)error;
- (void)removeAllItems;
- (BOOL)removeAllItemsWithError:(NSError * __autoreleasing *)error;
- (void)synchronize;
- (BOOL)synchronizeWithError:(NSError *__autoreleasing *)error;
// object subscripting
- (NSString *)objectForKeyedSubscript:(NSString <NSCopying> *)key;
- (void)setObject:(NSString *)obj forKeyedSubscript:(NSString <NSCopying> *)key;
@end

View File

@@ -0,0 +1,606 @@
//
// a copy of UICKeyChainStore.m v1.1.1 for testing
//
// Created by Kishikawa Katsumi on 11/11/20.
// Copyright (c) 2011 Kishikawa Katsumi. All rights reserved.
//
#import "UICv1KeyChainStore.h"
NSString * const UICv1KeyChainStoreErrorDomain = @"com.kishikawakatsumi.uickeychainstore";
static NSString *_defaultService;
@interface UICv1KeyChainStore () {
NSMutableDictionary *itemsToUpdate;
}
@end
@implementation UICv1KeyChainStore
+ (NSString *)defaultService
{
if (!_defaultService) {
_defaultService = [[NSBundle mainBundle] bundleIdentifier];
}
return _defaultService;
}
+ (void)setDefaultService:(NSString *)defaultService
{
_defaultService = defaultService;
}
#pragma mark -
+ (UICv1KeyChainStore *)keyChainStore
{
return [[self alloc] initWithService:[self defaultService]];
}
+ (UICv1KeyChainStore *)keyChainStoreWithService:(NSString *)service
{
return [[self alloc] initWithService:service];
}
+ (UICv1KeyChainStore *)keyChainStoreWithService:(NSString *)service accessGroup:(NSString *)accessGroup
{
return [[self alloc] initWithService:service accessGroup:accessGroup];
}
- (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) {
if (!service) {
service = [self.class defaultService];
}
_service = [service copy];
_accessGroup = [accessGroup copy];
itemsToUpdate = [[NSMutableDictionary alloc] init];
}
return self;
}
#pragma mark -
+ (NSString *)stringForKey:(NSString *)key
{
return [self stringForKey:key error:nil];
}
+ (NSString *)stringForKey:(NSString *)key error:(NSError *__autoreleasing *)error
{
return [self stringForKey:key service:nil error:error];
}
+ (NSString *)stringForKey:(NSString *)key service:(NSString *)service
{
return [self stringForKey:key service:service 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
{
NSData *data = [self dataForKey:key service:service accessGroup:accessGroup error:error];
if (data) {
return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}
return nil;
}
+ (BOOL)setString:(NSString *)value forKey:(NSString *)key
{
return [self setString:value forKey:key error:nil];
}
+ (BOOL)setString:(NSString *)value forKey:(NSString *)key error:(NSError *__autoreleasing *)error
{
return [self setString:value forKey:key service:nil error:error];
}
+ (BOOL)setString:(NSString *)value forKey:(NSString *)key service:(NSString *)service
{
return [self setString:value forKey:key service:service 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 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 error:nil];
}
+ (BOOL)setString:(NSString *)value forKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup error:(NSError *__autoreleasing *)error
{
NSData *data = [value dataUsingEncoding:NSUTF8StringEncoding];
return [self setData:data forKey:key service:service accessGroup:accessGroup error:error];
}
#pragma mark -
+ (NSData *)dataForKey:(NSString *)key
{
return [self dataForKey:key error:nil];
}
+ (NSData *)dataForKey:(NSString *)key error:(NSError *__autoreleasing *)error
{
return [self dataForKey:key service:nil error:error];
}
+ (NSData *)dataForKey:(NSString *)key service:(NSString *)service
{
return [self dataForKey:key service:service 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) {
if (error) {
*error = [NSError errorWithDomain:UICv1KeyChainStoreErrorDomain code:UICv1KeyChainStoreErrorInvalidArguments userInfo:@{NSLocalizedDescriptionKey: NSLocalizedString(@"`key` must not to be nil", nil)}];
}
return nil;
}
if (!service) {
service = [self defaultService];
}
NSMutableDictionary *query = [[NSMutableDictionary alloc] init];
[query setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
[query setObject:(__bridge id)kCFBooleanTrue forKey:(__bridge id)kSecReturnData];
[query setObject:(__bridge id)kSecMatchLimitOne forKey:(__bridge id)kSecMatchLimit];
[query setObject:service forKey:(__bridge id)kSecAttrService];
[query setObject:key forKey:(__bridge id)kSecAttrGeneric];
[query setObject:key forKey:(__bridge id)kSecAttrAccount];
#if !TARGET_IPHONE_SIMULATOR && defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
if (accessGroup) {
[query setObject:accessGroup forKey:(__bridge id)kSecAttrAccessGroup];
}
#endif
CFTypeRef data = nil;
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &data);
if (status != errSecSuccess) {
if (status != errSecItemNotFound) {
if (error) {
*error = [NSError errorWithDomain:UICv1KeyChainStoreErrorDomain code:status userInfo:nil];
}
}
return nil;
}
NSData *ret = [NSData dataWithData:(__bridge NSData *)data];
if (data) {
CFRelease(data);
}
return ret;
}
+ (BOOL)setData:(NSData *)data forKey:(NSString *)key
{
return [self setData:data forKey:key error:nil];
}
+ (BOOL)setData:(NSData *)data forKey:(NSString *)key error:(NSError *__autoreleasing *)error
{
return [self setData:data forKey:key service:nil error:error];
}
+ (BOOL)setData:(NSData *)data forKey:(NSString *)key service:(NSString *)service
{
return [self setData:data forKey:key service:service 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 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 error:nil];
}
+ (BOOL)setData:(NSData *)data forKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup error:(NSError *__autoreleasing *)error
{
if (!key) {
if (error) {
*error = [NSError errorWithDomain:UICv1KeyChainStoreErrorDomain code:UICv1KeyChainStoreErrorInvalidArguments userInfo:@{NSLocalizedDescriptionKey: NSLocalizedString(@"`key` must not to be nil", nil)}];
}
return NO;
}
if (!service) {
service = [self defaultService];
}
NSMutableDictionary *query = [[NSMutableDictionary alloc] init];
[query setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
[query setObject:service forKey:(__bridge id)kSecAttrService];
[query setObject:key forKey:(__bridge id)kSecAttrGeneric];
[query setObject:key forKey:(__bridge id)kSecAttrAccount];
#if !TARGET_IPHONE_SIMULATOR && defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
if (accessGroup) {
[query setObject:accessGroup forKey:(__bridge id)kSecAttrAccessGroup];
}
#endif
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, NULL);
if (status == errSecSuccess) {
if (data) {
NSMutableDictionary *attributesToUpdate = [[NSMutableDictionary alloc] init];
[attributesToUpdate setObject:data forKey:(__bridge id)kSecValueData];
status = SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)attributesToUpdate);
if (status != errSecSuccess) {
if (error) {
*error = [NSError errorWithDomain:UICv1KeyChainStoreErrorDomain code:status userInfo:nil];
}
return NO;
}
} else {
[self removeItemForKey:key service:service accessGroup:accessGroup];
}
} else if (status == errSecItemNotFound) {
if (!data) {
return YES;
}
NSMutableDictionary *attributes = [[NSMutableDictionary alloc] init];
[attributes setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
[attributes setObject:service forKey:(__bridge id)kSecAttrService];
[attributes setObject:key forKey:(__bridge id)kSecAttrGeneric];
[attributes setObject:key forKey:(__bridge id)kSecAttrAccount];
#if TARGET_OS_IPHONE || (defined(MAC_OS_X_VERSION_10_9) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9)
[attributes setObject:(__bridge id)kSecAttrAccessibleAfterFirstUnlock forKey:(__bridge id)kSecAttrAccessible];
#endif
[attributes setObject:data forKey:(__bridge id)kSecValueData];
#if !TARGET_IPHONE_SIMULATOR && defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
if (accessGroup) {
[attributes setObject:accessGroup forKey:(__bridge id)kSecAttrAccessGroup];
}
#endif
status = SecItemAdd((__bridge CFDictionaryRef)attributes, NULL);
if (status != errSecSuccess) {
if (error) {
*error = [NSError errorWithDomain:UICv1KeyChainStoreErrorDomain code:status userInfo:nil];
}
return NO;
}
} else {
if (error) {
*error = [NSError errorWithDomain:UICv1KeyChainStoreErrorDomain code:status userInfo:nil];
}
return NO;
}
return YES;
}
#pragma mark -
- (void)setString:(NSString *)string forKey:(NSString *)key
{
[self setData:[string dataUsingEncoding:NSUTF8StringEncoding] forKey:key error:nil];
}
- (BOOL)setString:(NSString *)string forKey:(NSString *)key error:(NSError *__autoreleasing *)error
{
[self setData:[string dataUsingEncoding:NSUTF8StringEncoding] forKey:key error:error];
return error == nil;
}
- (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) {
return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}
return nil;
}
#pragma mark -
- (void)setData:(NSData *)data forKey:(NSString *)key
{
[self setData:data forKey:key error:nil];
}
- (BOOL)setData:(NSData *)data forKey:(NSString *)key error:(NSError *__autoreleasing *)error
{
if (!key) {
if (error) {
*error = [NSError errorWithDomain:UICv1KeyChainStoreErrorDomain code:UICv1KeyChainStoreErrorInvalidArguments userInfo:@{NSLocalizedDescriptionKey: NSLocalizedString(@"`key` must not to be nil", nil)}];
}
return error == nil;
}
if (!data) {
[self removeItemForKey:key error:error];
} else {
[itemsToUpdate setObject:data forKey:key];
}
return error == nil;
}
- (NSData *)dataForKey:(NSString *)key
{
return [self dataForKey:key error:nil];
}
- (NSData *)dataForKey:(NSString *)key error:(NSError *__autoreleasing *)error
{
NSData *data = [itemsToUpdate objectForKey:key];
if (!data) {
data = [self.class dataForKey:key service:self.service accessGroup:self.accessGroup error:error];
}
return data;
}
#pragma mark -
+ (BOOL)removeItemForKey:(NSString *)key
{
return [self removeItemForKey:key error:nil];
}
+ (BOOL)removeItemForKey:(NSString *)key error:(NSError *__autoreleasing *)error
{
return [self removeItemForKey:key service:nil error:error];
}
+ (BOOL)removeItemForKey:(NSString *)key service:(NSString *)service
{
return [self removeItemForKey:key service:service 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) {
if (error) {
*error = [NSError errorWithDomain:UICv1KeyChainStoreErrorDomain code:UICv1KeyChainStoreErrorInvalidArguments userInfo:@{NSLocalizedDescriptionKey: NSLocalizedString(@"`key` must not to be nil", nil)}];
}
return NO;
}
if (!service) {
service = [self defaultService];
}
NSMutableDictionary *itemToDelete = [[NSMutableDictionary alloc] init];
[itemToDelete setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
[itemToDelete setObject:service forKey:(__bridge id)kSecAttrService];
[itemToDelete setObject:key forKey:(__bridge id)kSecAttrGeneric];
[itemToDelete setObject:key forKey:(__bridge id)kSecAttrAccount];
#if !TARGET_IPHONE_SIMULATOR && defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
if (accessGroup) {
[itemToDelete setObject:accessGroup forKey:(__bridge id)kSecAttrAccessGroup];
}
#endif
OSStatus status = SecItemDelete((__bridge CFDictionaryRef)itemToDelete);
if (status != errSecSuccess && status != errSecItemNotFound) {
if (error) {
*error = [NSError errorWithDomain:UICv1KeyChainStoreErrorDomain code:status userInfo:nil];
}
return NO;
}
return YES;
}
+ (NSArray *)itemsForService:(NSString *)service accessGroup:(NSString *)accessGroup
{
if (!service) {
service = [self defaultService];
}
NSMutableDictionary *query = [[NSMutableDictionary alloc] init];
[query setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
[query setObject:(id)kCFBooleanTrue forKey:(__bridge id)kSecReturnAttributes];
[query setObject:(id)kCFBooleanTrue forKey:(__bridge id)kSecReturnData];
[query setObject:(__bridge id)kSecMatchLimitAll forKey:(__bridge id)kSecMatchLimit];
[query setObject:service forKey:(__bridge id)kSecAttrService];
#if !TARGET_IPHONE_SIMULATOR && defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
if (accessGroup) {
[query setObject:accessGroup forKey:(__bridge id)kSecAttrAccessGroup];
}
#endif
CFArrayRef result = nil;
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&result);
if (status == errSecSuccess || status == errSecItemNotFound) {
return CFBridgingRelease(result);
} else {
return nil;
}
}
+ (BOOL)removeAllItems
{
return [self removeAllItemsWithError:nil];
}
+ (BOOL)removeAllItemsWithError:(NSError *__autoreleasing *)error
{
return [self removeAllItemsForService:nil error:error];
}
+ (BOOL)removeAllItemsForService:(NSString *)service
{
return [self removeAllItemsForService:service 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
{
NSArray *items = [UICv1KeyChainStore itemsForService:service accessGroup:accessGroup];
for (NSDictionary *item in items) {
NSMutableDictionary *itemToDelete = [[NSMutableDictionary alloc] initWithDictionary:item];
[itemToDelete setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
OSStatus status = SecItemDelete((__bridge CFDictionaryRef)itemToDelete);
if (status != errSecSuccess) {
if (error) {
*error = [NSError errorWithDomain:UICv1KeyChainStoreErrorDomain code:status userInfo:nil];
}
return NO;
}
}
return YES;
}
#pragma mark -
- (void)removeItemForKey:(NSString *)key
{
if ([itemsToUpdate objectForKey:key]) {
[itemsToUpdate removeObjectForKey:key];
} else {
[self.class removeItemForKey:key service:self.service accessGroup:self.accessGroup error:nil];
}
}
- (BOOL)removeItemForKey:(NSString *)key error:(NSError *__autoreleasing *)error
{
if ([itemsToUpdate objectForKey:key]) {
[itemsToUpdate removeObjectForKey:key];
} else {
[self.class removeItemForKey:key service:self.service accessGroup:self.accessGroup error:error];
}
return error == nil;
}
- (void)removeAllItems
{
[self removeAllItemsWithError:nil];
}
- (BOOL)removeAllItemsWithError:(NSError *__autoreleasing *)error
{
[itemsToUpdate removeAllObjects];
return [self.class removeAllItemsForService:self.service accessGroup:self.accessGroup error:error];
}
#pragma mark -
- (void)synchronize
{
for (NSString *key in itemsToUpdate) {
[self.class setData:[itemsToUpdate objectForKey:key] forKey:key service:self.service accessGroup:self.accessGroup error:nil];
}
[itemsToUpdate removeAllObjects];
}
- (BOOL)synchronizeWithError:(NSError *__autoreleasing *)error
{
for (NSString *key in itemsToUpdate) {
[self.class setData:[itemsToUpdate objectForKey:key] forKey:key service:self.service accessGroup:self.accessGroup error:error];
}
[itemsToUpdate removeAllObjects];
return error == nil;
}
#pragma mark -
- (NSString *)description
{
NSArray *items = [UICv1KeyChainStore itemsForService:self.service accessGroup:self.accessGroup];
NSMutableArray *list = [[NSMutableArray alloc] initWithCapacity:items.count];
for (NSDictionary *attributes in items) {
NSMutableDictionary *attrs = [[NSMutableDictionary alloc] init];
[attrs setObject:[attributes objectForKey:(__bridge id)kSecAttrService] forKey:@"Service"];
[attrs setObject:[attributes objectForKey:(__bridge id)kSecAttrAccount] forKey:@"Account"];
#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
[attrs setObject:[attributes objectForKey:(__bridge id)kSecAttrAccessGroup] forKey:@"AccessGroup"];
#endif
NSData *data = [attributes objectForKey:(__bridge id)kSecValueData];
NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
if (string) {
[attrs setObject:string forKey:@"Value"];
} else {
[attrs setObject:data forKey:@"Value"];
}
[list addObject:attrs];
}
return [list description];
}
#pragma mark - Object Subscripting
- (NSString *)objectForKeyedSubscript:(NSString <NSCopying> *)key
{
return [self stringForKey:key];
}
- (void)setObject:(NSString *)obj forKeyedSubscript:(NSString <NSCopying> *)key
{
[self setString:obj forKey:key];
}
@end