2016-02-05 11:23:49 +01:00

185 lines
6.6 KiB
Objective-C

// AFOAuthCredential.m
//
// Copyright (c) 2012-2014 AFNetworking (http://afnetworking.com)
//
// 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
#import "AFOAuthCredential.h"
NSString * const kAFOAuth2CredentialServiceName = @"AFOAuthCredentialService";
static NSDictionary * AFKeychainQueryDictionaryWithIdentifier(NSString *identifier) {
NSCParameterAssert(identifier);
return @{
(__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
(__bridge id)kSecAttrService: kAFOAuth2CredentialServiceName,
(__bridge id)kSecAttrAccount: identifier
};
}
@interface AFOAuthCredential()
@property (readwrite, nonatomic, copy) NSString *accessToken;
@property (readwrite, nonatomic, copy) NSString *tokenType;
@property (readwrite, nonatomic, copy) NSString *refreshToken;
@property (readwrite, nonatomic, copy) NSDate *expiration;
@end
@implementation AFOAuthCredential
//@dynamic expired;
#pragma mark -
+ (instancetype)credentialWithOAuthToken:(NSString *)token
tokenType:(NSString *)type
{
return [[self alloc] initWithOAuthToken:token tokenType:type];
}
- (id)initWithOAuthToken:(NSString *)token
tokenType:(NSString *)type
{
self = [super init];
if (!self) {
return nil;
}
self.accessToken = token;
self.tokenType = type;
return self;
}
- (NSString *)description {
return [NSString stringWithFormat:@"<%@ accessToken:\"%@\" tokenType:\"%@\" refreshToken:\"%@\" expiration:\"%@\">", [self class], self.accessToken, self.tokenType, self.refreshToken, self.expiration];
}
- (void)setRefreshToken:(NSString *)refreshToken
{
_refreshToken = refreshToken;
}
- (void)setExpiration:(NSDate *)expiration
{
_expiration = expiration;
}
- (void)setRefreshToken:(NSString *)refreshToken
expiration:(NSDate *)expiration
{
NSParameterAssert(refreshToken);
NSParameterAssert(expiration);
self.refreshToken = refreshToken;
self.expiration = expiration;
}
- (BOOL)isExpired {
return [self.expiration compare:[NSDate date]] == NSOrderedAscending;
}
#pragma mark Keychain
+ (BOOL)storeCredential:(AFOAuthCredential *)credential
withIdentifier:(NSString *)identifier
{
id securityAccessibility = nil;
#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 43000) || (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1090)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wtautological-compare"
if (&kSecAttrAccessibleWhenUnlocked != NULL) {
securityAccessibility = (__bridge id)kSecAttrAccessibleWhenUnlocked;
}
#pragma clang diagnostic pop
#endif
return [[self class] storeCredential:credential withIdentifier:identifier withAccessibility:securityAccessibility];
}
+ (BOOL)storeCredential:(AFOAuthCredential *)credential
withIdentifier:(NSString *)identifier
withAccessibility:(id)securityAccessibility
{
NSMutableDictionary *queryDictionary = [AFKeychainQueryDictionaryWithIdentifier(identifier) mutableCopy];
NSMutableDictionary *updateDictionary = [NSMutableDictionary dictionary];
updateDictionary[(__bridge id)kSecValueData] = [NSKeyedArchiver archivedDataWithRootObject:credential];
if (securityAccessibility) {
updateDictionary[(__bridge id)kSecAttrAccessible] = securityAccessibility;
}
OSStatus status;
BOOL exists = ([self retrieveCredentialWithIdentifier:identifier] != nil);
if (exists) {
status = SecItemUpdate((__bridge CFDictionaryRef)queryDictionary, (__bridge CFDictionaryRef)updateDictionary);
} else {
[queryDictionary addEntriesFromDictionary:updateDictionary];
status = SecItemAdd((__bridge CFDictionaryRef)queryDictionary, NULL);
}
return (status == errSecSuccess);
}
+ (BOOL)deleteCredentialWithIdentifier:(NSString *)identifier {
NSMutableDictionary *queryDictionary = [AFKeychainQueryDictionaryWithIdentifier(identifier) mutableCopy];
OSStatus status = SecItemDelete((__bridge CFDictionaryRef)queryDictionary);
return (status == errSecSuccess);
}
+ (AFOAuthCredential *)retrieveCredentialWithIdentifier:(NSString *)identifier {
NSMutableDictionary *queryDictionary = [AFKeychainQueryDictionaryWithIdentifier(identifier) mutableCopy];
queryDictionary[(__bridge id)kSecReturnData] = (__bridge id)kCFBooleanTrue;
queryDictionary[(__bridge id)kSecMatchLimit] = (__bridge id)kSecMatchLimitOne;
CFDataRef result = nil;
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)queryDictionary, (CFTypeRef *)&result);
if (status != errSecSuccess) {
return nil;
}
return [NSKeyedUnarchiver unarchiveObjectWithData:(__bridge_transfer NSData *)result];
}
#pragma mark - NSCoding
- (id)initWithCoder:(NSCoder *)decoder {
self = [super init];
self.accessToken = [decoder decodeObjectForKey:NSStringFromSelector(@selector(accessToken))];
self.tokenType = [decoder decodeObjectForKey:NSStringFromSelector(@selector(tokenType))];
self.refreshToken = [decoder decodeObjectForKey:NSStringFromSelector(@selector(refreshToken))];
self.expiration = [decoder decodeObjectForKey:NSStringFromSelector(@selector(expiration))];
return self;
}
- (void)encodeWithCoder:(NSCoder *)encoder {
[encoder encodeObject:self.accessToken forKey:NSStringFromSelector(@selector(accessToken))];
[encoder encodeObject:self.tokenType forKey:NSStringFromSelector(@selector(tokenType))];
[encoder encodeObject:self.refreshToken forKey:NSStringFromSelector(@selector(refreshToken))];
[encoder encodeObject:self.expiration forKey:NSStringFromSelector(@selector(expiration))];
}
@end