- Upgrade to 1.0

This commit is contained in:
giuseppenuc committed 2016-12-28 18:49:02 +01:00
1 parent 4e66c377fd
commit 0c2b3f1c25
452 files changed
+33888 -16806

No files matched your search

+19
View File
@@ -0,0 +1,19 @@
Copyright (c) 2014 axldyb <aksel.dybdal@shortcut.no>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
@@ -0,0 +1,46 @@
//
// DDDKeychainWrapper.h
// Aksel Dybdal
//
// Created by Aksel Dybdal on 02.04.14.
// Copyright (c) 2014 Aksel Dybdal. All rights reserved.
//
/**
A small wrapper for Keychain access.
Inspired by:
http://useyourloaf.com/blog/2010/03/29/simple-iphone-keychain-access.html
*/
#import <Foundation/Foundation.h>
@interface DDDKeychainWrapper : NSObject
+ (void)setString:(NSString *)string forKey:(NSString *)key;
+ (NSString *)stringForKey:(NSString *)key;
+ (void)setDate:(NSDate *)date forKey:(NSString *)key;
+ (NSDate *)dateForKey:(NSString *)key;
+ (void)setData:(NSData *)data forKey:(NSString *)key;
+ (NSData *)dataForKey:(NSString *)key;
+ (void)setArray:(NSArray *)array forKey:(NSString *)key;
+ (NSArray *)arrayForKey:(NSString *)key;
+ (void)setDictionary:(NSDictionary *)dictionary forKey:(NSString *)key;
+ (NSDictionary *)dictionaryForKey:(NSString *)key;
+ (void)setNumber:(NSNumber *)number forKey:(NSString *)key;
+ (NSNumber *)numberForKey:(NSString *)key;
+ (void)setBoolean:(BOOL)boolean forKey:(NSString *)key;
+ (BOOL)booleanForKey:(NSString *)key;
+ (void)setObject:(id)object forKey:(NSString *)key;
+ (id)objectForKey:(NSString *)key;
+ (void)wipeKeychain;
@end
@@ -0,0 +1,373 @@
//
// DDDKeychainWrapper.m
// Aksel Dybdal
//
// Created by Aksel Dybdal on 02.04.14.
// Copyright (c) 2014 Aksel Dybdal. All rights reserved.
//
#import "DDDKeychainWrapper.h"
#import <Security/Security.h>
typedef NS_ENUM(NSUInteger, DDDKeychainWrapperErrorCode) {
DDDKeychainWrapperErrorCreatingKeychainValue = 1,
DDDKeychainWrapperErrorUpdatingKeychainValue,
DDDKeychainWrapperErrorDeletingKeychainValue,
DDDKeychainWrapperErrorSearchingKeychainValue
};
NSString *const kDDDKeychainWrapperServiceName = @"com.dddkeychainwrapper.keychainService";
NSString *const kDDDKeychainWrapperErrorDomain = @"DDDKeychainWrapperErrorDomain";
#ifdef DEBUG
# warning "Including NSLog"
# define DDDLOG(s, ...) NSLog(s, ## __VA_ARGS__)
#else
# define DDDLOG(s, ...) while(0){}
#endif
@implementation DDDKeychainWrapper
#pragma mark - String
+ (void)setString:(NSString *)string forKey:(NSString *)key
{
NSData *stringData = [string dataUsingEncoding:NSUTF8StringEncoding];
[self setData:stringData forIdentifier:key];
}
+ (NSString *)stringForKey:(NSString *)key
{
NSData *stringData = [self dataForIdentifier:key];
return [[NSString alloc] initWithData:stringData encoding:NSUTF8StringEncoding];
}
#pragma mark - Date
+ (void)setDate:(NSDate *)date forKey:(NSString *)key
{
NSData *dateData = [NSKeyedArchiver archivedDataWithRootObject:date];
[self setData:dateData forIdentifier:key];
}
+ (NSDate *)dateForKey:(NSString *)key
{
NSData *dateData = [self dataForIdentifier:key];
return (NSDate *)[NSKeyedUnarchiver unarchiveObjectWithData:dateData];
}
#pragma mark - Data
+ (void)setData:(NSData *)data forKey:(NSString *)key
{
[self setData:data forIdentifier:key];
}
+ (NSData *)dataForKey:(NSString *)key
{
return [self dataForIdentifier:key];
}
#pragma mark - Array
+ (void)setArray:(NSArray *)array forKey:(NSString *)key
{
for (id obj in array) {
NSAssert([obj conformsToProtocol:@protocol(NSCoding)], @"Objects must confirm to NSCoding protocol in order to be stored in keychain");
}
NSData *arrayData = [NSKeyedArchiver archivedDataWithRootObject:array];
[self setData:arrayData forIdentifier:key];
}
+ (NSArray *)arrayForKey:(NSString *)key
{
NSData *arrayData = [self dataForIdentifier:key];
return (NSArray *)[NSKeyedUnarchiver unarchiveObjectWithData:arrayData];
}
#pragma mark - Dictionary
+ (void)setDictionary:(NSDictionary *)dictionary forKey:(NSString *)key
{
[dictionary enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
NSAssert([key conformsToProtocol:@protocol(NSCoding)], @"Keys must confirm to NSCoding protocol in order to be stored in keychain");
NSAssert([obj conformsToProtocol:@protocol(NSCoding)], @"Objects must confirm to NSCoding protocol in order to be stored in keychain");
}];
NSData *dictionaryData = [NSKeyedArchiver archivedDataWithRootObject:dictionary];
[self setData:dictionaryData forIdentifier:key];
}
+ (NSDictionary *)dictionaryForKey:(NSString *)key
{
NSData *dictionaryData = [self dataForIdentifier:key];
return (NSDictionary *)[NSKeyedUnarchiver unarchiveObjectWithData:dictionaryData];
}
#pragma mark - Number
+ (void)setNumber:(NSNumber *)number forKey:(NSString *)key
{
NSData *numberData = [NSKeyedArchiver archivedDataWithRootObject:number];
[self setData:numberData forIdentifier:key];
}
+ (NSNumber *)numberForKey:(NSString *)key
{
NSData *numberData = [self dataForIdentifier:key];
return (NSNumber *)[NSKeyedUnarchiver unarchiveObjectWithData:numberData];
}
#pragma mark - BOOL
+ (void)setBoolean:(BOOL)boolean forKey:(NSString *)key
{
NSNumber *boolNumber = [NSNumber numberWithBool:boolean];
[self setNumber:boolNumber forKey:key];
}
+ (BOOL)booleanForKey:(NSString *)key
{
NSNumber *boolNumber = [self numberForKey:key];
return [boolNumber boolValue];
}
#pragma mark - Object
+ (void)setObject:(id)object forKey:(NSString *)key
{
NSAssert([object conformsToProtocol:@protocol(NSCoding)], @"Object must confirm to NSCoding protocol in order to be stored in keychain");
NSData *objectData = [NSKeyedArchiver archivedDataWithRootObject:object];
[self setData:objectData forIdentifier:key];
}
+ (id)objectForKey:(NSString *)key
{
NSData *objectData = [self dataForIdentifier:key];
return (id)[NSKeyedUnarchiver unarchiveObjectWithData:objectData];
}
#pragma mark - Clear Keychain
+ (void)wipeKeychain
{
NSArray *secItemClasses = @[(__bridge id)kSecClassGenericPassword,
(__bridge id)kSecClassInternetPassword,
(__bridge id)kSecClassCertificate,
(__bridge id)kSecClassKey,
(__bridge id)kSecClassIdentity];
for (id secItemClass in secItemClasses) {
NSDictionary *spec = @{(__bridge id)kSecClass: (id)secItemClass};
SecItemDelete((__bridge CFDictionaryRef)spec);
}
}
#pragma mark - Private
+ (void)setData:(NSData *)data forIdentifier:(NSString *)identifier
{
NSError *error = nil;
// If no data provided we assume we want to delete the value
if (nil == data || NO == [data bytes]) {
[self deleteKeychainValueForIdentifier:identifier error:&error];
if (error) {
DDDLOG(@"Error deleting keychain value for key: \"%@\" Error: %@", identifier, [error localizedDescription]);
}
return;
}
// We first look up the key in order to see if we need to update or create the value
if ([self searchKeychainCopyMatching:identifier error:&error]) {
if (error) {
DDDLOG(@"Error finding keychain value for key: \"%@\" Error: %@", identifier, [error localizedDescription]);
return;
}
if (![self updateKeychainValue:data forIdentifier:identifier error:&error]) {
DDDLOG(@"Error updating keychain value for key: \"%@\" Error: %@", identifier, [error localizedDescription]);
}
} else {
if (![self createKeychainValue:data forIdentifier:identifier error:&error]) {
DDDLOG(@"Error creating keychain value for key: \"%@\" Error: %@", identifier, [error localizedDescription]);
}
}
}
+ (NSData *)dataForIdentifier:(NSString *)identifier
{
NSError *error = nil;
NSData *stringData = [self searchKeychainCopyMatching:identifier error:&error];
if (error) {
DDDLOG(@"Error finding keychain value for key: \"%@\" Error: %@", identifier, [error localizedDescription]);
return nil;
}
return stringData;
}
+ (NSMutableDictionary *)newSearchDictionary:(NSString *)identifier
{
NSMutableDictionary *searchDictionary = [[NSMutableDictionary alloc] init];
[searchDictionary setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
NSData *encodedIdentifier = [identifier dataUsingEncoding:NSUTF8StringEncoding];
[searchDictionary setObject:encodedIdentifier forKey:(__bridge id)kSecAttrGeneric];
[searchDictionary setObject:encodedIdentifier forKey:(__bridge id)kSecAttrAccount];
[searchDictionary setObject:(__bridge id)kSecAttrAccessibleAfterFirstUnlock forKey:(__bridge id)kSecAttrAccessible];
[searchDictionary setObject:kDDDKeychainWrapperServiceName forKey:(__bridge id)kSecAttrService];
return searchDictionary;
}
+ (NSData *)searchKeychainCopyMatching:(NSString *)identifier error:(NSError **)error
{
NSMutableDictionary *searchDictionary = [self newSearchDictionary:identifier];
[searchDictionary setObject:(__bridge id)kSecMatchLimitOne forKey:(__bridge id)kSecMatchLimit];
[searchDictionary setObject:(__bridge id)kCFBooleanTrue forKey:(__bridge id)kSecReturnData];
CFDataRef result;
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)searchDictionary, (CFTypeRef *)&result);
if (status != errSecSuccess) {
[self keychainError:error forStatus:status domain:DDDKeychainWrapperErrorSearchingKeychainValue];
return nil;
}
NSData *data = (__bridge NSData *)result;
return data;
}
+ (BOOL)createKeychainValue:(NSData *)data forIdentifier:(NSString *)identifier error:(NSError **)error
{
NSMutableDictionary *dictionary = [self newSearchDictionary:identifier];
[dictionary setObject:data forKey:(__bridge id)kSecValueData];
OSStatus status = SecItemAdd((__bridge CFDictionaryRef)dictionary, NULL);
if (status == errSecSuccess) {
return YES;
}
[self keychainError:error forStatus:status domain:DDDKeychainWrapperErrorCreatingKeychainValue];
return NO;
}
+ (BOOL)updateKeychainValue:(NSData *)data forIdentifier:(NSString *)identifier error:(NSError **)error
{
NSMutableDictionary *searchDictionary = [self newSearchDictionary:identifier];
NSMutableDictionary *updateDictionary = [[NSMutableDictionary alloc] init];
[updateDictionary setObject:data forKey:(__bridge id)kSecValueData];
OSStatus status = SecItemUpdate((__bridge CFDictionaryRef)searchDictionary,
(__bridge CFDictionaryRef)updateDictionary);
if (status == errSecSuccess) {
return YES;
}
[self keychainError:error forStatus:status domain:DDDKeychainWrapperErrorUpdatingKeychainValue];
return NO;
}
+ (BOOL)deleteKeychainValueForIdentifier:(NSString *)identifier error:(NSError **)error
{
NSMutableDictionary *searchDictionary = [self newSearchDictionary:identifier];
OSStatus status = SecItemDelete((__bridge CFDictionaryRef)searchDictionary);
if (status == errSecSuccess) {
return YES;
}
[self keychainError:error forStatus:status domain:DDDKeychainWrapperErrorDeletingKeychainValue];
return NO;
}
#pragma mark - Error
+ (void)keychainError:(NSError **)error forStatus:(OSStatus)status domain:(NSUInteger)domain
{
NSString *errorString = @"";
switch (status) {
case errSecUnimplemented:
errorString = @"Function or operation not implemented.";
break;
case errSecIO:
errorString = @"I/O error (bummers)";
break;
case errSecOpWr:
errorString = @"File already open with write permission";
break;
case errSecParam:
errorString = @"One or more parameters passed to a function where not valid.";
break;
case errSecAllocate:
errorString = @"Failed to allocate memory.";
break;
case errSecUserCanceled:
errorString = @"User canceled the operation.";
break;
case errSecBadReq:
errorString = @"Bad parameter or invalid state for operation.";
break;
case errSecInternalComponent:
errorString = @"errSecInternalComponent";
break;
case errSecNotAvailable:
errorString = @"No keychain is available. You may need to restart your computer.";
break;
case errSecDuplicateItem:
errorString = @"The specified item already exists in the keychain.";
break;
case errSecItemNotFound:
errorString = @"The specified item could not be found in the keychain.";
break;
case errSecInteractionNotAllowed:
errorString = @"User interaction is not allowed.";
break;
case errSecDecode:
errorString = @"Unable to decode the provided data.";
break;
case errSecAuthFailed:
errorString = @"The user name or passphrase you entered is not correct.";
break;
default:
errorString = @"Unknown error";
break;
}
*error = [NSError errorWithDomain:kDDDKeychainWrapperErrorDomain
code:domain
userInfo:@{NSLocalizedDescriptionKey: errorString}];
}
@end
+47
View File
@@ -0,0 +1,47 @@
# DDDKeychainWrapper
[![CI Status](http://img.shields.io/travis/axldyb/DDDKeychainWrapper.svg?style=flat)](https://travis-ci.org/axldyb/DDDKeychainWrapper)
[![Version](https://img.shields.io/cocoapods/v/DDDKeychainWrapper.svg?style=flat)](http://cocoadocs.org/docsets/DDDKeychainWrapper)
[![License](https://img.shields.io/cocoapods/l/DDDKeychainWrapper.svg?style=flat)](http://cocoadocs.org/docsets/DDDKeychainWrapper)
[![Platform](https://img.shields.io/cocoapods/p/DDDKeychainWrapper.svg?style=flat)](http://cocoadocs.org/docsets/DDDKeychainWrapper)
## Usage
Storing your sensitive data in the keychain can take up a lot of time and effort. It should be easy to just drop something in there and retrive it with a few simple lines of code. DDDKeychainWrapper offers this simplicity and here is how we do it:
```objective-c
// Writing to the Keychain
[DDDKeychainWrapper setString:@"Secret string" forKey:@"my_key"];
// Reading from the Keychain
NSString *secretString = [DDDKeychainWrapper stringForKey:@"my_key"];
```
DDDKeychainWrapper has support for the following types
* NSString
* NSDate
* NSData
* NSArray
* NSDictionary
* NSNumber
* BOOL
* Objects (Must confirm to NSCoding)
A method for wiping the keychain data inserted via the wrapper exists as well.
## Installation
DDDKeychainWrapper is available through [CocoaPods](http://cocoapods.org). To install
it, simply add the following line to your Podfile:
pod "DDDKeychainWrapper"
## Author
axldyb, aksel.dybdal@shortcut.no
## License
DDDKeychainWrapper is available under the MIT license. See the LICENSE file for more info.