| OLD | NEW |
| (Empty) |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #if !defined(__has_feature) || !__has_feature(objc_arc) | |
| 6 #error "This file requires ARC support." | |
| 7 #endif | |
| 8 | |
| 9 #import "remoting/client/ios/keychain_wrapper.h" | |
| 10 | |
| 11 #import "remoting/client/ios/domain/host_info.h" | |
| 12 | |
| 13 static const UInt8 kKeychainItemIdentifier[] = "org.chromium.RemoteDesktop\0"; | |
| 14 | |
| 15 @interface KeychainWrapper () { | |
| 16 NSMutableDictionary* _keychainData; | |
| 17 NSMutableDictionary* _userInfoQuery; | |
| 18 } | |
| 19 @end | |
| 20 | |
| 21 @implementation KeychainWrapper | |
| 22 | |
| 23 - (id)init { | |
| 24 if ((self = [super init])) { | |
| 25 OSStatus keychainErr = noErr; | |
| 26 _userInfoQuery = [[NSMutableDictionary alloc] init]; | |
| 27 [_userInfoQuery setObject:(__bridge id)kSecClassGenericPassword | |
| 28 forKey:(__bridge id)kSecClass]; | |
| 29 NSData* keychainItemID = | |
| 30 [NSData dataWithBytes:kKeychainItemIdentifier | |
| 31 length:strlen((const char*)kKeychainItemIdentifier)]; | |
| 32 [_userInfoQuery setObject:keychainItemID | |
| 33 forKey:(__bridge id)kSecAttrGeneric]; | |
| 34 [_userInfoQuery setObject:(__bridge id)kSecMatchLimitOne | |
| 35 forKey:(__bridge id)kSecMatchLimit]; | |
| 36 [_userInfoQuery setObject:(__bridge id)kCFBooleanTrue | |
| 37 forKey:(__bridge id)kSecReturnAttributes]; | |
| 38 | |
| 39 CFMutableDictionaryRef outDictionary = nil; | |
| 40 keychainErr = SecItemCopyMatching((__bridge CFDictionaryRef)_userInfoQuery, | |
| 41 (CFTypeRef*)&outDictionary); | |
| 42 if (keychainErr == noErr) { | |
| 43 _keychainData = [self | |
| 44 secItemFormatToDictionary:(__bridge_transfer NSMutableDictionary*) | |
| 45 outDictionary]; | |
| 46 } else if (keychainErr == errSecItemNotFound) { | |
| 47 [self resetKeychainItem]; | |
| 48 | |
| 49 if (outDictionary) { | |
| 50 CFRelease(outDictionary); | |
| 51 _keychainData = nil; | |
| 52 } | |
| 53 } else { | |
| 54 NSLog(@"Serious error."); | |
| 55 if (outDictionary) { | |
| 56 CFRelease(outDictionary); | |
| 57 _keychainData = nil; | |
| 58 } | |
| 59 } | |
| 60 } | |
| 61 return self; | |
| 62 } | |
| 63 | |
| 64 - (void)setRefreshToken:(NSString*)refreshToken { | |
| 65 [self setObject:refreshToken forKey:(__bridge id)kSecValueData]; | |
| 66 } | |
| 67 | |
| 68 - (NSString*)refreshToken { | |
| 69 return [self objectForKey:(__bridge id)kSecValueData]; | |
| 70 } | |
| 71 | |
| 72 // Implement the mySetObject:forKey method, which writes attributes to the | |
| 73 // keychain: | |
| 74 - (void)setObject:(id)inObject forKey:(id)key { | |
| 75 if (inObject == nil) | |
| 76 return; | |
| 77 id currentObject = [_keychainData objectForKey:key]; | |
| 78 if (![currentObject isEqual:inObject]) { | |
| 79 [_keychainData setObject:inObject forKey:key]; | |
| 80 [self writeToKeychain]; | |
| 81 } | |
| 82 } | |
| 83 | |
| 84 // Implement the myObjectForKey: method, which reads an attribute value from a | |
| 85 // dictionary: | |
| 86 - (id)objectForKey:(id)key { | |
| 87 return [_keychainData objectForKey:key]; | |
| 88 } | |
| 89 | |
| 90 - (void)resetKeychainItem { | |
| 91 if (!_keychainData) { | |
| 92 _keychainData = [[NSMutableDictionary alloc] init]; | |
| 93 } else if (_keychainData) { | |
| 94 NSMutableDictionary* tmpDictionary = | |
| 95 [self dictionaryToSecItemFormat:_keychainData]; | |
| 96 OSStatus errorcode = SecItemDelete((__bridge CFDictionaryRef)tmpDictionary); | |
| 97 if (errorcode == errSecItemNotFound) { | |
| 98 // this is ok. | |
| 99 } else if (errorcode != noErr) { | |
| 100 NSLog(@"Problem deleting current keychain item."); | |
| 101 } | |
| 102 } | |
| 103 | |
| 104 [_keychainData setObject:@"gaia_refresh_token" | |
| 105 forKey:(__bridge id)kSecAttrLabel]; | |
| 106 [_keychainData setObject:@"Gaia fresh token" | |
| 107 forKey:(__bridge id)kSecAttrDescription]; | |
| 108 [_keychainData setObject:@"" forKey:(__bridge id)kSecValueData]; | |
| 109 } | |
| 110 | |
| 111 - (NSMutableDictionary*)dictionaryToSecItemFormat: | |
| 112 (NSDictionary*)dictionaryToConvert { | |
| 113 NSMutableDictionary* returnDictionary = | |
| 114 [NSMutableDictionary dictionaryWithDictionary:dictionaryToConvert]; | |
| 115 | |
| 116 NSData* keychainItemID = | |
| 117 [NSData dataWithBytes:kKeychainItemIdentifier | |
| 118 length:strlen((const char*)kKeychainItemIdentifier)]; | |
| 119 [returnDictionary setObject:keychainItemID | |
| 120 forKey:(__bridge id)kSecAttrGeneric]; | |
| 121 [returnDictionary setObject:(__bridge id)kSecClassGenericPassword | |
| 122 forKey:(__bridge id)kSecClass]; | |
| 123 | |
| 124 NSString* passwordString = | |
| 125 [dictionaryToConvert objectForKey:(__bridge id)kSecValueData]; | |
| 126 [returnDictionary | |
| 127 setObject:[passwordString dataUsingEncoding:NSUTF8StringEncoding] | |
| 128 forKey:(__bridge id)kSecValueData]; | |
| 129 return returnDictionary; | |
| 130 } | |
| 131 | |
| 132 - (NSMutableDictionary*)secItemFormatToDictionary: | |
| 133 (NSDictionary*)dictionaryToConvert { | |
| 134 NSMutableDictionary* returnDictionary = | |
| 135 [NSMutableDictionary dictionaryWithDictionary:dictionaryToConvert]; | |
| 136 | |
| 137 [returnDictionary setObject:(__bridge id)kCFBooleanTrue | |
| 138 forKey:(__bridge id)kSecReturnData]; | |
| 139 [returnDictionary setObject:(__bridge id)kSecClassGenericPassword | |
| 140 forKey:(__bridge id)kSecClass]; | |
| 141 | |
| 142 CFDataRef passwordData = NULL; | |
| 143 OSStatus keychainError = noErr; | |
| 144 keychainError = SecItemCopyMatching( | |
| 145 (__bridge CFDictionaryRef)returnDictionary, (CFTypeRef*)&passwordData); | |
| 146 if (keychainError == noErr) { | |
| 147 [returnDictionary removeObjectForKey:(__bridge id)kSecReturnData]; | |
| 148 | |
| 149 NSString* password = [[NSString alloc] | |
| 150 initWithBytes:[(__bridge_transfer NSData*)passwordData bytes] | |
| 151 length:[(__bridge NSData*)passwordData length] | |
| 152 encoding:NSUTF8StringEncoding]; | |
| 153 [returnDictionary setObject:password forKey:(__bridge id)kSecValueData]; | |
| 154 } else if (keychainError == errSecItemNotFound) { | |
| 155 NSLog(@"Nothing was found in the keychain."); | |
| 156 if (passwordData) { | |
| 157 CFRelease(passwordData); | |
| 158 passwordData = nil; | |
| 159 } | |
| 160 } else { | |
| 161 NSLog(@"Serious error.\n"); | |
| 162 if (passwordData) { | |
| 163 CFRelease(passwordData); | |
| 164 passwordData = nil; | |
| 165 } | |
| 166 } | |
| 167 return returnDictionary; | |
| 168 } | |
| 169 | |
| 170 - (void)writeToKeychain { | |
| 171 CFDictionaryRef attributes = nil; | |
| 172 NSMutableDictionary* updateItem = nil; | |
| 173 | |
| 174 if (SecItemCopyMatching((__bridge CFDictionaryRef)_userInfoQuery, | |
| 175 (CFTypeRef*)&attributes) == noErr) { | |
| 176 updateItem = [NSMutableDictionary | |
| 177 dictionaryWithDictionary:(__bridge_transfer NSDictionary*)attributes]; | |
| 178 | |
| 179 [updateItem setObject:[_userInfoQuery objectForKey:(__bridge id)kSecClass] | |
| 180 forKey:(__bridge id)kSecClass]; | |
| 181 | |
| 182 NSMutableDictionary* tempCheck = | |
| 183 [self dictionaryToSecItemFormat:_keychainData]; | |
| 184 [tempCheck removeObjectForKey:(__bridge id)kSecClass]; | |
| 185 | |
| 186 OSStatus errorcode = SecItemUpdate((__bridge CFDictionaryRef)updateItem, | |
| 187 (__bridge CFDictionaryRef)tempCheck); | |
| 188 if (errorcode != noErr) { | |
| 189 NSLog(@"Couldn't update the Keychain Item. %d", (int)errorcode); | |
| 190 } | |
| 191 } else { | |
| 192 OSStatus errorcode = | |
| 193 SecItemAdd((__bridge CFDictionaryRef) | |
| 194 [self dictionaryToSecItemFormat:_keychainData], | |
| 195 NULL); | |
| 196 if (errorcode != noErr) { | |
| 197 NSLog(@"Couldn't add the Keychain Item. %d", (int)errorcode); | |
| 198 } | |
| 199 if (attributes) { | |
| 200 CFRelease(attributes); | |
| 201 attributes = nil; | |
| 202 } | |
| 203 } | |
| 204 } | |
| 205 | |
| 206 @end | |
| OLD | NEW |