/Pods/AWSCore/AWSCore/UICKeyChainStore/AWSUICKeyChainStore.m

https://gitlab.com/lorostudios/bazl-ios · Objective C · 1377 lines · 1166 code · 202 blank · 9 comment · 201 complexity · 9ea3e07cddf7e1eaa72148635dc0aace MD5 · raw file

  1. //
  2. // UICKeyChainStore.m
  3. // UICKeyChainStore
  4. //
  5. // Created by Kishikawa Katsumi on 11/11/20.
  6. // Copyright (c) 2011 Kishikawa Katsumi. All rights reserved.
  7. //
  8. #import "AWSUICKeyChainStore.h"
  9. NSString * const AWSUICKeyChainStoreErrorDomain = @"com.kishikawakatsumi.uickeychainstore";
  10. static NSString *_defaultService;
  11. @interface AWSUICKeyChainStore ()
  12. @end
  13. @implementation AWSUICKeyChainStore
  14. + (NSString *)defaultService
  15. {
  16. if (!_defaultService) {
  17. _defaultService = [[NSBundle mainBundle] bundleIdentifier] ?: @"";
  18. }
  19. return _defaultService;
  20. }
  21. + (void)setDefaultService:(NSString *)defaultService
  22. {
  23. _defaultService = defaultService;
  24. }
  25. #pragma mark -
  26. + (AWSUICKeyChainStore *)keyChainStore
  27. {
  28. return [[self alloc] initWithService:nil accessGroup:nil];
  29. }
  30. + (AWSUICKeyChainStore *)keyChainStoreWithService:(NSString *)service
  31. {
  32. return [[self alloc] initWithService:service accessGroup:nil];
  33. }
  34. + (AWSUICKeyChainStore *)keyChainStoreWithService:(NSString *)service accessGroup:(NSString *)accessGroup
  35. {
  36. return [[self alloc] initWithService:service accessGroup:accessGroup];
  37. }
  38. #pragma mark -
  39. + (AWSUICKeyChainStore *)keyChainStoreWithServer:(NSURL *)server protocolType:(AWSUICKeyChainStoreProtocolType)protocolType
  40. {
  41. return [[self alloc] initWithServer:server protocolType:protocolType authenticationType:AWSUICKeyChainStoreAuthenticationTypeDefault];
  42. }
  43. + (AWSUICKeyChainStore *)keyChainStoreWithServer:(NSURL *)server protocolType:(AWSUICKeyChainStoreProtocolType)protocolType authenticationType:(AWSUICKeyChainStoreAuthenticationType)authenticationType
  44. {
  45. return [[self alloc] initWithServer:server protocolType:protocolType authenticationType:authenticationType];
  46. }
  47. #pragma mark -
  48. - (instancetype)init
  49. {
  50. return [self initWithService:[self.class defaultService] accessGroup:nil];
  51. }
  52. - (instancetype)initWithService:(NSString *)service
  53. {
  54. return [self initWithService:service accessGroup:nil];
  55. }
  56. - (instancetype)initWithService:(NSString *)service accessGroup:(NSString *)accessGroup
  57. {
  58. self = [super init];
  59. if (self) {
  60. _itemClass = AWSUICKeyChainStoreItemClassGenericPassword;
  61. if (!service) {
  62. service = [self.class defaultService];
  63. }
  64. _service = service.copy;
  65. _accessGroup = accessGroup.copy;
  66. [self commonInit];
  67. }
  68. return self;
  69. }
  70. #pragma mark -
  71. - (instancetype)initWithServer:(NSURL *)server protocolType:(AWSUICKeyChainStoreProtocolType)protocolType
  72. {
  73. return [self initWithServer:server protocolType:protocolType authenticationType:AWSUICKeyChainStoreAuthenticationTypeDefault];
  74. }
  75. - (instancetype)initWithServer:(NSURL *)server protocolType:(AWSUICKeyChainStoreProtocolType)protocolType authenticationType:(AWSUICKeyChainStoreAuthenticationType)authenticationType
  76. {
  77. self = [super init];
  78. if (self) {
  79. _itemClass = AWSUICKeyChainStoreItemClassInternetPassword;
  80. _server = server.copy;
  81. _protocolType = protocolType;
  82. _authenticationType = authenticationType;
  83. [self commonInit];
  84. }
  85. return self;
  86. }
  87. #pragma mark -
  88. - (void)commonInit
  89. {
  90. _accessibility = AWSUICKeyChainStoreAccessibilityAfterFirstUnlock;
  91. }
  92. #pragma mark -
  93. + (NSString *)stringForKey:(NSString *)key
  94. {
  95. return [self stringForKey:key service:nil accessGroup:nil error:nil];
  96. }
  97. + (NSString *)stringForKey:(NSString *)key error:(NSError *__autoreleasing *)error
  98. {
  99. return [self stringForKey:key service:nil accessGroup:nil error:error];
  100. }
  101. + (NSString *)stringForKey:(NSString *)key service:(NSString *)service
  102. {
  103. return [self stringForKey:key service:service accessGroup:nil error:nil];
  104. }
  105. + (NSString *)stringForKey:(NSString *)key service:(NSString *)service error:(NSError *__autoreleasing *)error
  106. {
  107. return [self stringForKey:key service:service accessGroup:nil error:error];
  108. }
  109. + (NSString *)stringForKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup
  110. {
  111. return [self stringForKey:key service:service accessGroup:accessGroup error:nil];
  112. }
  113. + (NSString *)stringForKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup error:(NSError *__autoreleasing *)error
  114. {
  115. if (!key) {
  116. NSError *e = [self argumentError:NSLocalizedString(@"the key must not to be nil", nil)];
  117. if (error) {
  118. *error = e;
  119. }
  120. return nil;
  121. }
  122. if (!service) {
  123. service = [self defaultService];
  124. }
  125. AWSUICKeyChainStore *keychain = [AWSUICKeyChainStore keyChainStoreWithService:service accessGroup:accessGroup];
  126. return [keychain stringForKey:key error:error];
  127. }
  128. #pragma mark -
  129. + (BOOL)setString:(NSString *)value forKey:(NSString *)key
  130. {
  131. return [self setString:value forKey:key service:nil accessGroup:nil genericAttribute:nil error:nil];
  132. }
  133. + (BOOL)setString:(NSString *)value forKey:(NSString *)key error:(NSError *__autoreleasing *)error
  134. {
  135. return [self setString:value forKey:key service:nil accessGroup:nil genericAttribute:nil error:error];
  136. }
  137. + (BOOL)setString:(NSString *)value forKey:(NSString *)key genericAttribute:(id)genericAttribute
  138. {
  139. return [self setString:value forKey:key service:nil accessGroup:nil genericAttribute:genericAttribute error:nil];
  140. }
  141. + (BOOL)setString:(NSString *)value forKey:(NSString *)key genericAttribute:(id)genericAttribute error:(NSError * __autoreleasing *)error
  142. {
  143. return [self setString:value forKey:key service:nil accessGroup:nil genericAttribute:genericAttribute error:error];
  144. }
  145. + (BOOL)setString:(NSString *)value forKey:(NSString *)key service:(NSString *)service
  146. {
  147. return [self setString:value forKey:key service:service accessGroup:nil genericAttribute:nil error:nil];
  148. }
  149. + (BOOL)setString:(NSString *)value forKey:(NSString *)key service:(NSString *)service error:(NSError *__autoreleasing *)error
  150. {
  151. return [self setString:value forKey:key service:service accessGroup:nil genericAttribute:nil error:error];
  152. }
  153. + (BOOL)setString:(NSString *)value forKey:(NSString *)key service:(NSString *)service genericAttribute:(id)genericAttribute
  154. {
  155. return [self setString:value forKey:key service:service accessGroup:nil genericAttribute:genericAttribute error:nil];
  156. }
  157. + (BOOL)setString:(NSString *)value forKey:(NSString *)key service:(NSString *)service genericAttribute:(id)genericAttribute error:(NSError * __autoreleasing *)error
  158. {
  159. return [self setString:value forKey:key service:service accessGroup:nil genericAttribute:genericAttribute error:error];
  160. }
  161. + (BOOL)setString:(NSString *)value forKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup
  162. {
  163. return [self setString:value forKey:key service:service accessGroup:accessGroup genericAttribute:nil error:nil];
  164. }
  165. + (BOOL)setString:(NSString *)value forKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup error:(NSError *__autoreleasing *)error
  166. {
  167. return [self setString:value forKey:key service:service accessGroup:accessGroup genericAttribute:nil error:error];
  168. }
  169. + (BOOL)setString:(NSString *)value forKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup genericAttribute:(id)genericAttribute
  170. {
  171. return [self setString:value forKey:key service:service accessGroup:accessGroup genericAttribute:genericAttribute error:nil];
  172. }
  173. + (BOOL)setString:(NSString *)value forKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup genericAttribute:(id)genericAttribute error:(NSError * __autoreleasing *)error
  174. {
  175. if (!value) {
  176. return [self removeItemForKey:key service:service accessGroup:accessGroup error:error];
  177. }
  178. NSData *data = [value dataUsingEncoding:NSUTF8StringEncoding];
  179. if (data) {
  180. return [self setData:data forKey:key service:service accessGroup:accessGroup genericAttribute:genericAttribute error:error];
  181. }
  182. NSError *e = [self conversionError:NSLocalizedString(@"failed to convert string to data", nil)];
  183. if (error) {
  184. *error = e;
  185. }
  186. return NO;
  187. }
  188. #pragma mark -
  189. + (NSData *)dataForKey:(NSString *)key
  190. {
  191. return [self dataForKey:key service:nil accessGroup:nil error:nil];
  192. }
  193. + (NSData *)dataForKey:(NSString *)key error:(NSError *__autoreleasing *)error
  194. {
  195. return [self dataForKey:key service:nil accessGroup:nil error:error];
  196. }
  197. + (NSData *)dataForKey:(NSString *)key service:(NSString *)service
  198. {
  199. return [self dataForKey:key service:service accessGroup:nil error:nil];
  200. }
  201. + (NSData *)dataForKey:(NSString *)key service:(NSString *)service error:(NSError *__autoreleasing *)error
  202. {
  203. return [self dataForKey:key service:service accessGroup:nil error:error];
  204. }
  205. + (NSData *)dataForKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup
  206. {
  207. return [self dataForKey:key service:service accessGroup:accessGroup error:nil];
  208. }
  209. + (NSData *)dataForKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup error:(NSError *__autoreleasing *)error
  210. {
  211. if (!key) {
  212. NSError *e = [self argumentError:NSLocalizedString(@"the key must not to be nil", nil)];
  213. if (error) {
  214. *error = e;
  215. }
  216. return nil;
  217. }
  218. if (!service) {
  219. service = [self defaultService];
  220. }
  221. AWSUICKeyChainStore *keychain = [AWSUICKeyChainStore keyChainStoreWithService:service accessGroup:accessGroup];
  222. return [keychain dataForKey:key error:error];
  223. }
  224. #pragma mark -
  225. + (BOOL)setData:(NSData *)data forKey:(NSString *)key
  226. {
  227. return [self setData:data forKey:key service:nil accessGroup:nil genericAttribute:nil error:nil];
  228. }
  229. + (BOOL)setData:(NSData *)data forKey:(NSString *)key error:(NSError *__autoreleasing *)error
  230. {
  231. return [self setData:data forKey:key service:nil accessGroup:nil genericAttribute:nil error:error];
  232. }
  233. + (BOOL)setData:(NSData *)data forKey:(NSString *)key genericAttribute:(id)genericAttribute
  234. {
  235. return [self setData:data forKey:key service:nil accessGroup:nil genericAttribute:genericAttribute error:nil];
  236. }
  237. + (BOOL)setData:(NSData *)data forKey:(NSString *)key genericAttribute:(id)genericAttribute error:(NSError * __autoreleasing *)error
  238. {
  239. return [self setData:data forKey:key service:nil accessGroup:nil genericAttribute:genericAttribute error:error];
  240. }
  241. + (BOOL)setData:(NSData *)data forKey:(NSString *)key service:(NSString *)service
  242. {
  243. return [self setData:data forKey:key service:service accessGroup:nil genericAttribute:nil error:nil];
  244. }
  245. + (BOOL)setData:(NSData *)data forKey:(NSString *)key service:(NSString *)service error:(NSError *__autoreleasing *)error
  246. {
  247. return [self setData:data forKey:key service:service accessGroup:nil genericAttribute:nil error:error];
  248. }
  249. + (BOOL)setData:(NSData *)data forKey:(NSString *)key service:(NSString *)service genericAttribute:(id)genericAttribute
  250. {
  251. return [self setData:data forKey:key service:service accessGroup:nil genericAttribute:genericAttribute error:nil];
  252. }
  253. + (BOOL)setData:(NSData *)data forKey:(NSString *)key service:(NSString *)service genericAttribute:(id)genericAttribute error:(NSError * __autoreleasing *)error
  254. {
  255. return [self setData:data forKey:key service:service accessGroup:nil genericAttribute:genericAttribute error:error];
  256. }
  257. + (BOOL)setData:(NSData *)data forKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup
  258. {
  259. return [self setData:data forKey:key service:service accessGroup:accessGroup genericAttribute:nil error:nil];
  260. }
  261. + (BOOL)setData:(NSData *)data forKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup error:(NSError *__autoreleasing *)error
  262. {
  263. return [self setData:data forKey:key service:service accessGroup:accessGroup genericAttribute:nil error:error];
  264. }
  265. + (BOOL)setData:(NSData *)data forKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup genericAttribute:(id)genericAttribute
  266. {
  267. return [self setData:data forKey:key service:service accessGroup:accessGroup genericAttribute:genericAttribute error:nil];
  268. }
  269. + (BOOL)setData:(NSData *)data forKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup genericAttribute:(id)genericAttribute error:(NSError * __autoreleasing *)error
  270. {
  271. if (!key) {
  272. NSError *e = [self argumentError:NSLocalizedString(@"the key must not to be nil", nil)];
  273. if (error) {
  274. *error = e;
  275. }
  276. return NO;
  277. }
  278. if (!service) {
  279. service = [self defaultService];
  280. }
  281. AWSUICKeyChainStore *keychain = [AWSUICKeyChainStore keyChainStoreWithService:service accessGroup:accessGroup];
  282. return [keychain setData:data forKey:key genericAttribute:genericAttribute];
  283. }
  284. #pragma mark -
  285. - (BOOL)contains:(NSString *)key
  286. {
  287. NSMutableDictionary *query = [self query];
  288. query[(__bridge __strong id)kSecAttrAccount] = key;
  289. OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, NULL);
  290. return status == errSecSuccess;
  291. }
  292. #pragma mark -
  293. - (NSString *)stringForKey:(id)key
  294. {
  295. return [self stringForKey:key error:nil];
  296. }
  297. - (NSString *)stringForKey:(id)key error:(NSError *__autoreleasing *)error
  298. {
  299. NSData *data = [self dataForKey:key error:error];
  300. if (data) {
  301. NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
  302. if (string) {
  303. return string;
  304. }
  305. NSError *e = [self.class conversionError:NSLocalizedString(@"failed to convert data to string", nil)];
  306. if (error) {
  307. *error = e;
  308. }
  309. return nil;
  310. }
  311. return nil;
  312. }
  313. #pragma mark -
  314. - (BOOL)setString:(NSString *)string forKey:(NSString *)key
  315. {
  316. return [self setString:string forKey:key genericAttribute:nil label:nil comment:nil error:nil];
  317. }
  318. - (BOOL)setString:(NSString *)string forKey:(NSString *)key error:(NSError *__autoreleasing *)error
  319. {
  320. return [self setString:string forKey:key genericAttribute:nil label:nil comment:nil error:error];
  321. }
  322. - (BOOL)setString:(NSString *)string forKey:(NSString *)key genericAttribute:(id)genericAttribute
  323. {
  324. return [self setString:string forKey:key genericAttribute:genericAttribute label:nil comment:nil error:nil];
  325. }
  326. - (BOOL)setString:(NSString *)string forKey:(NSString *)key genericAttribute:(id)genericAttribute error:(NSError * __autoreleasing *)error
  327. {
  328. return [self setString:string forKey:key genericAttribute:genericAttribute label:nil comment:nil error:error];
  329. }
  330. - (BOOL)setString:(NSString *)string forKey:(NSString *)key label:(NSString *)label comment:(NSString *)comment
  331. {
  332. return [self setString:string forKey:key genericAttribute:nil label:label comment:comment error:nil];
  333. }
  334. - (BOOL)setString:(NSString *)string forKey:(NSString *)key label:(NSString *)label comment:(NSString *)comment error:(NSError *__autoreleasing *)error
  335. {
  336. return [self setString:string forKey:key genericAttribute:nil label:label comment:comment error:error];
  337. }
  338. - (BOOL)setString:(NSString *)string forKey:(NSString *)key genericAttribute:(id)genericAttribute label:(NSString *)label comment:(NSString *)comment error:(NSError *__autoreleasing *)error
  339. {
  340. if (!string) {
  341. return [self removeItemForKey:key error:error];
  342. }
  343. NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
  344. if (data) {
  345. return [self setData:data forKey:key genericAttribute:genericAttribute label:label comment:comment error:error];
  346. }
  347. NSError *e = [self.class conversionError:NSLocalizedString(@"failed to convert string to data", nil)];
  348. if (error) {
  349. *error = e;
  350. }
  351. return NO;
  352. }
  353. #pragma mark -
  354. - (NSData *)dataForKey:(NSString *)key
  355. {
  356. return [self dataForKey:key error:nil];
  357. }
  358. - (NSData *)dataForKey:(NSString *)key error:(NSError *__autoreleasing *)error
  359. {
  360. NSMutableDictionary *query = [self query];
  361. query[(__bridge __strong id)kSecMatchLimit] = (__bridge id)kSecMatchLimitOne;
  362. query[(__bridge __strong id)kSecReturnData] = (__bridge id)kCFBooleanTrue;
  363. query[(__bridge __strong id)kSecAttrAccount] = key;
  364. CFTypeRef data = nil;
  365. OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &data);
  366. if (status == errSecSuccess) {
  367. NSData *ret = [NSData dataWithData:(__bridge NSData *)data];
  368. if (data) {
  369. CFRelease(data);
  370. return ret;
  371. } else {
  372. NSError *e = [self.class unexpectedError:NSLocalizedString(@"Unexpected error has occurred.", nil)];
  373. if (error) {
  374. *error = e;
  375. }
  376. return nil;
  377. }
  378. } else if (status == errSecItemNotFound) {
  379. return nil;
  380. }
  381. NSError *e = [self.class securityError:status];
  382. if (error) {
  383. *error = e;
  384. }
  385. return nil;
  386. }
  387. #pragma mark -
  388. - (BOOL)setData:(NSData *)data forKey:(NSString *)key
  389. {
  390. return [self setData:data forKey:key genericAttribute:nil label:nil comment:nil error:nil];
  391. }
  392. - (BOOL)setData:(NSData *)data forKey:(NSString *)key error:(NSError *__autoreleasing *)error
  393. {
  394. return [self setData:data forKey:key genericAttribute:nil label:nil comment:nil error:error];
  395. }
  396. - (BOOL)setData:(NSData *)data forKey:(NSString *)key genericAttribute:(id)genericAttribute
  397. {
  398. return [self setData:data forKey:key genericAttribute:genericAttribute label:nil comment:nil error:nil];
  399. }
  400. - (BOOL)setData:(NSData *)data forKey:(NSString *)key genericAttribute:(id)genericAttribute error:(NSError * __autoreleasing *)error
  401. {
  402. return [self setData:data forKey:key genericAttribute:genericAttribute label:nil comment:nil error:error];
  403. }
  404. - (BOOL)setData:(NSData *)data forKey:(NSString *)key label:(NSString *)label comment:(NSString *)comment
  405. {
  406. return [self setData:data forKey:key genericAttribute:nil label:label comment:comment error:nil];
  407. }
  408. - (BOOL)setData:(NSData *)data forKey:(NSString *)key label:(NSString *)label comment:(NSString *)comment error:(NSError *__autoreleasing *)error
  409. {
  410. return [self setData:data forKey:key genericAttribute:nil label:label comment:comment error:error];
  411. }
  412. - (BOOL)setData:(NSData *)data forKey:(NSString *)key genericAttribute:(id)genericAttribute label:(NSString *)label comment:(NSString *)comment error:(NSError *__autoreleasing *)error
  413. {
  414. if (!key) {
  415. NSError *e = [self.class argumentError:NSLocalizedString(@"the key must not to be nil", nil)];
  416. if (error) {
  417. *error = e;
  418. }
  419. return NO;
  420. }
  421. if (!data) {
  422. return [self removeItemForKey:key error:error];
  423. }
  424. NSMutableDictionary *query = [self query];
  425. query[(__bridge __strong id)kSecAttrAccount] = key;
  426. #if TARGET_OS_IOS
  427. #pragma clang diagnostic push
  428. #pragma clang diagnostic ignored "-Wdeprecated-declarations"
  429. if (floor(NSFoundationVersionNumber) > floor(1144.17)) { // iOS 9+
  430. query[(__bridge __strong id)kSecUseAuthenticationUI] = (__bridge id)kSecUseAuthenticationUIFail;
  431. } else if (floor(NSFoundationVersionNumber) > floor(1047.25)) { // iOS 8+
  432. query[(__bridge __strong id)kSecUseNoAuthenticationUI] = (__bridge id)kCFBooleanTrue;
  433. }
  434. #pragma clang diagnostic pop
  435. #elif TARGET_OS_WATCH || TARGET_OS_TV
  436. query[(__bridge __strong id)kSecUseAuthenticationUI] = (__bridge id)kSecUseAuthenticationUIFail;
  437. #endif
  438. OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, NULL);
  439. if (status == errSecSuccess || status == errSecInteractionNotAllowed) {
  440. query = [self query];
  441. query[(__bridge __strong id)kSecAttrAccount] = key;
  442. NSError *unexpectedError = nil;
  443. NSMutableDictionary *attributes = [self attributesWithKey:nil value:data error:&unexpectedError];
  444. if (genericAttribute) {
  445. attributes[(__bridge __strong id)kSecAttrGeneric] = genericAttribute;
  446. }
  447. if (label) {
  448. attributes[(__bridge __strong id)kSecAttrLabel] = label;
  449. }
  450. if (comment) {
  451. attributes[(__bridge __strong id)kSecAttrComment] = comment;
  452. }
  453. if (unexpectedError) {
  454. NSLog(@"error: [%@] %@", @(unexpectedError.code), NSLocalizedString(@"Unexpected error has occurred.", nil));
  455. if (error) {
  456. *error = unexpectedError;
  457. }
  458. return NO;
  459. } else {
  460. if (status == errSecInteractionNotAllowed && floor(NSFoundationVersionNumber) <= floor(1140.11)) { // iOS 8.0.x
  461. if ([self removeItemForKey:key error:error]) {
  462. return [self setData:data forKey:key label:label comment:comment error:error];
  463. }
  464. } else {
  465. status = SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)attributes);
  466. }
  467. if (status != errSecSuccess) {
  468. NSError *e = [self.class securityError:status];
  469. if (error) {
  470. *error = e;
  471. }
  472. return NO;
  473. }
  474. }
  475. } else if (status == errSecItemNotFound) {
  476. NSError *unexpectedError = nil;
  477. NSMutableDictionary *attributes = [self attributesWithKey:key value:data error:&unexpectedError];
  478. if (genericAttribute) {
  479. attributes[(__bridge __strong id)kSecAttrGeneric] = genericAttribute;
  480. }
  481. if (label) {
  482. attributes[(__bridge __strong id)kSecAttrLabel] = label;
  483. }
  484. if (comment) {
  485. attributes[(__bridge __strong id)kSecAttrComment] = comment;
  486. }
  487. if (unexpectedError) {
  488. NSLog(@"error: [%@] %@", @(unexpectedError.code), NSLocalizedString(@"Unexpected error has occurred.", nil));
  489. if (error) {
  490. *error = unexpectedError;
  491. }
  492. return NO;
  493. } else {
  494. status = SecItemAdd((__bridge CFDictionaryRef)attributes, NULL);
  495. if (status != errSecSuccess) {
  496. NSError *e = [self.class securityError:status];
  497. if (error) {
  498. *error = e;
  499. }
  500. return NO;
  501. }
  502. }
  503. } else {
  504. NSError *e = [self.class securityError:status];
  505. if (error) {
  506. *error = e;
  507. }
  508. return NO;
  509. }
  510. return YES;
  511. }
  512. #pragma mark -
  513. + (BOOL)removeItemForKey:(NSString *)key
  514. {
  515. return [self removeItemForKey:key service:nil accessGroup:nil error:nil];
  516. }
  517. + (BOOL)removeItemForKey:(NSString *)key error:(NSError *__autoreleasing *)error
  518. {
  519. return [self removeItemForKey:key service:nil accessGroup:nil error:error];
  520. }
  521. + (BOOL)removeItemForKey:(NSString *)key service:(NSString *)service
  522. {
  523. return [self removeItemForKey:key service:service accessGroup:nil error:nil];
  524. }
  525. + (BOOL)removeItemForKey:(NSString *)key service:(NSString *)service error:(NSError *__autoreleasing *)error
  526. {
  527. return [self removeItemForKey:key service:service accessGroup:nil error:error];
  528. }
  529. + (BOOL)removeItemForKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup
  530. {
  531. return [self removeItemForKey:key service:service accessGroup:accessGroup error:nil];
  532. }
  533. + (BOOL)removeItemForKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup error:(NSError *__autoreleasing *)error
  534. {
  535. if (!key) {
  536. NSError *e = [self.class argumentError:NSLocalizedString(@"the key must not to be nil", nil)];
  537. if (error) {
  538. *error = e;
  539. }
  540. return NO;
  541. }
  542. if (!service) {
  543. service = [self defaultService];
  544. }
  545. AWSUICKeyChainStore *keychain = [AWSUICKeyChainStore keyChainStoreWithService:service accessGroup:accessGroup];
  546. return [keychain removeItemForKey:key error:error];
  547. }
  548. #pragma mark -
  549. + (BOOL)removeAllItems
  550. {
  551. return [self removeAllItemsForService:nil accessGroup:nil error:nil];
  552. }
  553. + (BOOL)removeAllItemsWithError:(NSError *__autoreleasing *)error
  554. {
  555. return [self removeAllItemsForService:nil accessGroup:nil error:error];
  556. }
  557. + (BOOL)removeAllItemsForService:(NSString *)service
  558. {
  559. return [self removeAllItemsForService:service accessGroup:nil error:nil];
  560. }
  561. + (BOOL)removeAllItemsForService:(NSString *)service error:(NSError *__autoreleasing *)error
  562. {
  563. return [self removeAllItemsForService:service accessGroup:nil error:error];
  564. }
  565. + (BOOL)removeAllItemsForService:(NSString *)service accessGroup:(NSString *)accessGroup
  566. {
  567. return [self removeAllItemsForService:service accessGroup:accessGroup error:nil];
  568. }
  569. + (BOOL)removeAllItemsForService:(NSString *)service accessGroup:(NSString *)accessGroup error:(NSError *__autoreleasing *)error
  570. {
  571. AWSUICKeyChainStore *keychain = [AWSUICKeyChainStore keyChainStoreWithService:service accessGroup:accessGroup];
  572. return [keychain removeAllItemsWithError:error];
  573. }
  574. #pragma mark -
  575. - (BOOL)removeItemForKey:(NSString *)key
  576. {
  577. return [self removeItemForKey:key error:nil];
  578. }
  579. - (BOOL)removeItemForKey:(NSString *)key error:(NSError *__autoreleasing *)error
  580. {
  581. NSMutableDictionary *query = [self query];
  582. query[(__bridge __strong id)kSecAttrAccount] = key;
  583. OSStatus status = SecItemDelete((__bridge CFDictionaryRef)query);
  584. if (status != errSecSuccess && status != errSecItemNotFound) {
  585. NSError *e = [self.class securityError:status];
  586. if (error) {
  587. *error = e;
  588. }
  589. return NO;
  590. }
  591. return YES;
  592. }
  593. #pragma mark -
  594. - (BOOL)removeAllItems
  595. {
  596. return [self removeAllItemsWithError:nil];
  597. }
  598. - (BOOL)removeAllItemsWithError:(NSError *__autoreleasing *)error
  599. {
  600. NSMutableDictionary *query = [self query];
  601. #if !TARGET_OS_IPHONE
  602. query[(__bridge id)kSecMatchLimit] = (__bridge id)kSecMatchLimitAll;
  603. #endif
  604. OSStatus status = SecItemDelete((__bridge CFDictionaryRef)query);
  605. if (status != errSecSuccess && status != errSecItemNotFound) {
  606. NSError *e = [self.class securityError:status];
  607. if (error) {
  608. *error = e;
  609. }
  610. return NO;
  611. }
  612. return YES;
  613. }
  614. #pragma mark -
  615. - (NSString *)objectForKeyedSubscript:(NSString <NSCopying> *)key
  616. {
  617. return [self stringForKey:key];
  618. }
  619. - (void)setObject:(NSString *)obj forKeyedSubscript:(NSString <NSCopying> *)key
  620. {
  621. if (!obj) {
  622. [self removeItemForKey:key];
  623. } else {
  624. [self setString:obj forKey:key];
  625. }
  626. }
  627. #pragma mark -
  628. - (NSArray UIC_KEY_TYPE *)allKeys
  629. {
  630. NSArray *items = [self.class prettify:[self itemClassObject] items:[self items]];
  631. NSMutableArray *keys = [[NSMutableArray alloc] init];
  632. for (NSDictionary *item in items) {
  633. [keys addObject:item[@"key"]];
  634. }
  635. return keys.copy;
  636. }
  637. + (NSArray UIC_KEY_TYPE *)allKeysWithItemClass:(AWSUICKeyChainStoreItemClass)itemClass
  638. {
  639. CFTypeRef itemClassObject = kSecClassGenericPassword;
  640. if (itemClass == AWSUICKeyChainStoreItemClassGenericPassword) {
  641. itemClassObject = kSecClassGenericPassword;
  642. } else if (itemClass == AWSUICKeyChainStoreItemClassInternetPassword) {
  643. itemClassObject = kSecClassInternetPassword;
  644. }
  645. NSMutableDictionary *query = [[NSMutableDictionary alloc] init];
  646. query[(__bridge __strong id)kSecClass] = (__bridge id)itemClassObject;
  647. query[(__bridge __strong id)kSecMatchLimit] = (__bridge id)kSecMatchLimitAll;
  648. query[(__bridge __strong id)kSecReturnAttributes] = (__bridge id)kCFBooleanTrue;
  649. CFArrayRef result = nil;
  650. CFDictionaryRef cfquery = (CFDictionaryRef)CFBridgingRetain(query);
  651. OSStatus status = SecItemCopyMatching(cfquery, (CFTypeRef *)&result);
  652. CFRelease(cfquery);
  653. if (status == errSecSuccess) {
  654. NSArray *items = [self prettify:itemClassObject items:(__bridge NSArray *)result];
  655. NSMutableArray *keys = [[NSMutableArray alloc] init];
  656. for (NSDictionary *item in items) {
  657. if (itemClassObject == kSecClassGenericPassword) {
  658. [keys addObject:@{@"service": item[@"service"] ?: @"", @"key": item[@"key"] ?: @""}];
  659. } else if (itemClassObject == kSecClassInternetPassword) {
  660. [keys addObject:@{@"server": item[@"service"] ?: @"", @"key": item[@"key"] ?: @""}];
  661. }
  662. }
  663. return keys.copy;
  664. } else if (status == errSecItemNotFound) {
  665. return @[];
  666. }
  667. return nil;
  668. }
  669. + (NSArray *)allItemsWithItemClass:(AWSUICKeyChainStoreItemClass)itemClass
  670. {
  671. CFTypeRef itemClassObject = kSecClassGenericPassword;
  672. if (itemClass == AWSUICKeyChainStoreItemClassGenericPassword) {
  673. itemClassObject = kSecClassGenericPassword;
  674. } else if (itemClass == AWSUICKeyChainStoreItemClassInternetPassword) {
  675. itemClassObject = kSecClassInternetPassword;
  676. }
  677. NSMutableDictionary *query = [[NSMutableDictionary alloc] init];
  678. query[(__bridge __strong id)kSecClass] = (__bridge id)itemClassObject;
  679. query[(__bridge __strong id)kSecMatchLimit] = (__bridge id)kSecMatchLimitAll;
  680. query[(__bridge __strong id)kSecReturnAttributes] = (__bridge id)kCFBooleanTrue;
  681. #if TARGET_OS_IPHONE
  682. query[(__bridge __strong id)kSecReturnData] = (__bridge id)kCFBooleanTrue;
  683. #endif
  684. CFArrayRef result = nil;
  685. CFDictionaryRef cfquery = (CFDictionaryRef)CFBridgingRetain(query);
  686. OSStatus status = SecItemCopyMatching(cfquery, (CFTypeRef *)&result);
  687. CFRelease(cfquery);
  688. if (status == errSecSuccess) {
  689. return [self prettify:itemClassObject items:(__bridge NSArray *)result];
  690. } else if (status == errSecItemNotFound) {
  691. return @[];
  692. }
  693. return nil;
  694. }
  695. - (NSArray *)allItems
  696. {
  697. return [self.class prettify:[self itemClassObject] items:[self items]];
  698. }
  699. - (NSArray *)items
  700. {
  701. NSMutableDictionary *query = [self query];
  702. query[(__bridge __strong id)kSecMatchLimit] = (__bridge id)kSecMatchLimitAll;
  703. query[(__bridge __strong id)kSecReturnAttributes] = (__bridge id)kCFBooleanTrue;
  704. #if TARGET_OS_IPHONE
  705. query[(__bridge __strong id)kSecReturnData] = (__bridge id)kCFBooleanTrue;
  706. #endif
  707. CFArrayRef result = nil;
  708. OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query,(CFTypeRef *)&result);
  709. if (status == errSecSuccess) {
  710. return CFBridgingRelease(result);
  711. } else if (status == errSecItemNotFound) {
  712. return @[];
  713. }
  714. return nil;
  715. }
  716. + (NSArray *)prettify:(CFTypeRef)itemClass items:(NSArray *)items
  717. {
  718. NSMutableArray *prettified = [[NSMutableArray alloc] init];
  719. for (NSDictionary *attributes in items) {
  720. NSMutableDictionary *item = [[NSMutableDictionary alloc] init];
  721. if (itemClass == kSecClassGenericPassword) {
  722. item[@"class"] = @"GenericPassword";
  723. id service = attributes[(__bridge id)kSecAttrService];
  724. if (service) {
  725. item[@"service"] = service;
  726. }
  727. id accessGroup = attributes[(__bridge id)kSecAttrAccessGroup];
  728. if (accessGroup) {
  729. item[@"accessGroup"] = accessGroup;
  730. }
  731. } else if (itemClass == kSecClassInternetPassword) {
  732. item[@"class"] = @"InternetPassword";
  733. id server = attributes[(__bridge id)kSecAttrServer];
  734. if (server) {
  735. item[@"server"] = server;
  736. }
  737. id protocolType = attributes[(__bridge id)kSecAttrProtocol];
  738. if (protocolType) {
  739. item[@"protocol"] = protocolType;
  740. }
  741. id authenticationType = attributes[(__bridge id)kSecAttrAuthenticationType];
  742. if (authenticationType) {
  743. item[@"authenticationType"] = authenticationType;
  744. }
  745. }
  746. id key = attributes[(__bridge id)kSecAttrAccount];
  747. if (key) {
  748. item[@"key"] = key;
  749. }
  750. NSData *data = attributes[(__bridge id)kSecValueData];
  751. NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
  752. if (string) {
  753. item[@"value"] = string;
  754. } else {
  755. item[@"value"] = data;
  756. }
  757. id accessible = attributes[(__bridge id)kSecAttrAccessible];
  758. if (accessible) {
  759. item[@"accessibility"] = accessible;
  760. }
  761. if (floor(NSFoundationVersionNumber) > floor(993.00)) { // iOS 7+
  762. id synchronizable = attributes[(__bridge id)kSecAttrSynchronizable];
  763. if (synchronizable) {
  764. item[@"synchronizable"] = synchronizable;
  765. }
  766. }
  767. [prettified addObject:item];
  768. }
  769. return prettified.copy;
  770. }
  771. #pragma mark -
  772. - (void)setSynchronizable:(BOOL)synchronizable
  773. {
  774. _synchronizable = synchronizable;
  775. if (_authenticationPolicy) {
  776. NSLog(@"%@", @"Cannot specify both an authenticationPolicy and a synchronizable");
  777. }
  778. }
  779. - (void)setAccessibility:(AWSUICKeyChainStoreAccessibility)accessibility authenticationPolicy:(AWSUICKeyChainStoreAuthenticationPolicy)authenticationPolicy
  780. {
  781. _accessibility = accessibility;
  782. _authenticationPolicy = authenticationPolicy;
  783. if (_synchronizable) {
  784. NSLog(@"%@", @"Cannot specify both an authenticationPolicy and a synchronizable");
  785. }
  786. }
  787. #pragma mark -
  788. #if TARGET_OS_IOS
  789. - (void)sharedPasswordWithCompletion:(void (^)(NSString *account, NSString *password, NSError *error))completion
  790. {
  791. NSString *domain = self.server.host;
  792. if (domain.length > 0) {
  793. [self.class requestSharedWebCredentialForDomain:domain account:nil completion:^(NSArray *credentials, NSError *error) {
  794. NSDictionary *credential = credentials.firstObject;
  795. if (credential) {
  796. NSString *account = credential[@"account"];
  797. NSString *password = credential[@"password"];
  798. if (completion) {
  799. completion(account, password, error);
  800. }
  801. } else {
  802. if (completion) {
  803. completion(nil, nil, error);
  804. }
  805. }
  806. }];
  807. } else {
  808. NSError *error = [self.class argumentError:NSLocalizedString(@"the server property must not to be nil, should use 'keyChainStoreWithServer:protocolType:' initializer to instantiate keychain store", nil)];
  809. if (completion) {
  810. completion(nil, nil, error);
  811. }
  812. }
  813. }
  814. - (void)sharedPasswordForAccount:(NSString *)account completion:(void (^)(NSString *password, NSError *error))completion
  815. {
  816. NSString *domain = self.server.host;
  817. if (domain.length > 0) {
  818. [self.class requestSharedWebCredentialForDomain:domain account:account completion:^(NSArray *credentials, NSError *error) {
  819. NSDictionary *credential = credentials.firstObject;
  820. if (credential) {
  821. NSString *password = credential[@"password"];
  822. if (completion) {
  823. completion(password, error);
  824. }
  825. } else {
  826. if (completion) {
  827. completion(nil, error);
  828. }
  829. }
  830. }];
  831. } else {
  832. NSError *error = [self.class argumentError:NSLocalizedString(@"the server property must not to be nil, should use 'keyChainStoreWithServer:protocolType:' initializer to instantiate keychain store", nil)];
  833. if (completion) {
  834. completion(nil, error);
  835. }
  836. }
  837. }
  838. - (void)setSharedPassword:(NSString *)password forAccount:(NSString *)account completion:(void (^)(NSError *error))completion
  839. {
  840. NSString *domain = self.server.host;
  841. if (domain.length > 0) {
  842. SecAddSharedWebCredential((__bridge CFStringRef)domain, (__bridge CFStringRef)account, (__bridge CFStringRef)password, ^(CFErrorRef error) {
  843. if (completion) {
  844. completion((__bridge NSError *)error);
  845. }
  846. });
  847. } else {
  848. NSError *error = [self.class argumentError:NSLocalizedString(@"the server property must not to be nil, should use 'keyChainStoreWithServer:protocolType:' initializer to instantiate keychain store", nil)];
  849. if (completion) {
  850. completion(error);
  851. }
  852. }
  853. }
  854. - (void)removeSharedPasswordForAccount:(NSString *)account completion:(void (^)(NSError *error))completion
  855. {
  856. [self setSharedPassword:nil forAccount:account completion:completion];
  857. }
  858. + (void)requestSharedWebCredentialWithCompletion:(void (^)(NSArray UIC_CREDENTIAL_TYPE *credentials, NSError *error))completion
  859. {
  860. [self requestSharedWebCredentialForDomain:nil account:nil completion:completion];
  861. }
  862. + (void)requestSharedWebCredentialForDomain:(NSString *)domain account:(NSString *)account completion:(void (^)(NSArray UIC_CREDENTIAL_TYPE *credentials, NSError *error))completion
  863. {
  864. SecRequestSharedWebCredential((__bridge CFStringRef)domain, (__bridge CFStringRef)account, ^(CFArrayRef credentials, CFErrorRef error) {
  865. if (error) {
  866. NSError *e = (__bridge NSError *)error;
  867. if (e.code != errSecItemNotFound) {
  868. NSLog(@"error: [%@] %@", @(e.code), e.localizedDescription);
  869. }
  870. }
  871. NSMutableArray *sharedCredentials = [[NSMutableArray alloc] init];
  872. for (NSDictionary *credential in (__bridge NSArray *)credentials) {
  873. NSMutableDictionary *sharedCredential = [[NSMutableDictionary alloc] init];
  874. NSString *server = credential[(__bridge __strong id)kSecAttrServer];
  875. if (server) {
  876. sharedCredential[@"server"] = server;
  877. }
  878. NSString *account = credential[(__bridge __strong id)kSecAttrAccount];
  879. if (account) {
  880. sharedCredential[@"account"] = account;
  881. }
  882. NSString *password = credential[(__bridge __strong id)kSecSharedPassword];
  883. if (password) {
  884. sharedCredential[@"password"] = password;
  885. }
  886. [sharedCredentials addObject:sharedCredential];
  887. }
  888. if (completion) {
  889. completion(sharedCredentials.copy, (__bridge NSError *)error);
  890. }
  891. });
  892. }
  893. + (NSString *)generatePassword
  894. {
  895. return CFBridgingRelease(SecCreateSharedWebCredentialPassword());
  896. }
  897. #endif
  898. #pragma mark -
  899. - (void)synchronize
  900. {
  901. // Deprecated, calling this method is no longer required
  902. }
  903. - (BOOL)synchronizeWithError:(NSError *__autoreleasing *)error
  904. {
  905. // Deprecated, calling this method is no longer required
  906. return true;
  907. }
  908. #pragma mark -
  909. - (NSString *)description
  910. {
  911. NSArray *items = [self allItems];
  912. if (items.count == 0) {
  913. return @"()";
  914. }
  915. NSMutableString *description = [[NSMutableString alloc] initWithString:@"(\n"];
  916. for (NSDictionary *item in items) {
  917. [description appendFormat:@" %@", item];
  918. }
  919. [description appendString:@")"];
  920. return description.copy;
  921. }
  922. - (NSString *)debugDescription
  923. {
  924. return [NSString stringWithFormat:@"%@", [self items]];
  925. }
  926. #pragma mark -
  927. - (NSMutableDictionary *)query
  928. {
  929. NSMutableDictionary *query = [[NSMutableDictionary alloc] init];
  930. CFTypeRef itemClass = [self itemClassObject];
  931. query[(__bridge __strong id)kSecClass] =(__bridge id)itemClass;
  932. if (floor(NSFoundationVersionNumber) > floor(993.00)) { // iOS 7+ (NSFoundationVersionNumber_iOS_6_1)
  933. query[(__bridge __strong id)kSecAttrSynchronizable] = (__bridge id)kSecAttrSynchronizableAny;
  934. }
  935. if (itemClass == kSecClassGenericPassword) {
  936. query[(__bridge __strong id)(kSecAttrService)] = _service;
  937. #if !TARGET_OS_SIMULATOR
  938. if (_accessGroup) {
  939. query[(__bridge __strong id)kSecAttrAccessGroup] = _accessGroup;
  940. }
  941. #endif
  942. } else {
  943. if (_server.host) {
  944. query[(__bridge __strong id)kSecAttrServer] = _server.host;
  945. }
  946. if (_server.port) {
  947. query[(__bridge __strong id)kSecAttrPort] = _server.port;
  948. }
  949. CFTypeRef protocolTypeObject = [self protocolTypeObject];
  950. if (protocolTypeObject) {
  951. query[(__bridge __strong id)kSecAttrProtocol] = (__bridge id)protocolTypeObject;
  952. }
  953. CFTypeRef authenticationTypeObject = [self authenticationTypeObject];
  954. if (authenticationTypeObject) {
  955. query[(__bridge __strong id)kSecAttrAuthenticationType] = (__bridge id)authenticationTypeObject;
  956. }
  957. }
  958. #if TARGET_OS_IOS
  959. if (_authenticationPrompt) {
  960. if (floor(NSFoundationVersionNumber) > floor(1047.25)) { // iOS 8+ (NSFoundationVersionNumber_iOS_7_1)
  961. query[(__bridge __strong id)kSecUseOperationPrompt] = _authenticationPrompt;
  962. } else {
  963. NSLog(@"%@", @"Unavailable 'authenticationPrompt' attribute on iOS versions prior to 8.0.");
  964. }
  965. }
  966. #endif
  967. return query;
  968. }
  969. - (NSMutableDictionary *)attributesWithKey:(NSString *)key value:(NSData *)value error:(NSError *__autoreleasing *)error
  970. {
  971. NSMutableDictionary *attributes;
  972. if (key) {
  973. attributes = [self query];
  974. attributes[(__bridge __strong id)kSecAttrAccount] = key;
  975. } else {
  976. attributes = [[NSMutableDictionary alloc] init];
  977. }
  978. attributes[(__bridge __strong id)kSecValueData] = value;
  979. #if TARGET_OS_IOS
  980. double iOS_7_1_or_10_9_2 = 1047.25; // NSFoundationVersionNumber_iOS_7_1
  981. #else
  982. double iOS_7_1_or_10_9_2 = 1056.13; // NSFoundationVersionNumber10_9_2
  983. #endif
  984. CFTypeRef accessibilityObject = [self accessibilityObject];
  985. if (_authenticationPolicy && accessibilityObject) {
  986. if (floor(NSFoundationVersionNumber) > floor(iOS_7_1_or_10_9_2)) { // iOS 8+ or OS X 10.10+
  987. CFErrorRef securityError = NULL;
  988. SecAccessControlRef accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibilityObject, (SecAccessControlCreateFlags)_authenticationPolicy, &securityError);
  989. if (securityError) {
  990. NSError *e = (__bridge NSError *)securityError;
  991. NSLog(@"error: [%@] %@", @(e.code), e.localizedDescription);
  992. if (error) {
  993. *error = e;
  994. CFRelease(accessControl);
  995. return nil;
  996. }
  997. }
  998. if (!accessControl) {
  999. NSString *message = NSLocalizedString(@"Unexpected error has occurred.", nil);
  1000. NSError *e = [self.class unexpectedError:message];
  1001. if (error) {
  1002. *error = e;
  1003. }
  1004. return nil;
  1005. }
  1006. attributes[(__bridge __strong id)kSecAttrAccessControl] = (__bridge_transfer id)accessControl;
  1007. } else {
  1008. #if TARGET_OS_IOS
  1009. NSLog(@"%@", @"Unavailable 'Touch ID integration' on iOS versions prior to 8.0.");
  1010. #else
  1011. NSLog(@"%@", @"Unavailable 'Touch ID integration' on OS X versions prior to 10.10.");
  1012. #endif
  1013. }
  1014. } else {
  1015. if (floor(NSFoundationVersionNumber) <= floor(iOS_7_1_or_10_9_2) && _accessibility == AWSUICKeyChainStoreAccessibilityWhenPasscodeSetThisDeviceOnly) {
  1016. #if TARGET_OS_IOS
  1017. NSLog(@"%@", @"Unavailable 'UICKeyChainStoreAccessibilityWhenPasscodeSetThisDeviceOnly' attribute on iOS versions prior to 8.0.");
  1018. #else
  1019. NSLog(@"%@", @"Unavailable 'UICKeyChainStoreAccessibilityWhenPasscodeSetThisDeviceOnly' attribute on OS X versions prior to 10.10.");
  1020. #endif
  1021. } else {
  1022. if (accessibilityObject) {
  1023. attributes[(__bridge __strong id)kSecAttrAccessible] = (__bridge id)accessibilityObject;
  1024. }
  1025. }
  1026. }
  1027. if (floor(NSFoundationVersionNumber) > floor(993.00)) { // iOS 7+
  1028. attributes[(__bridge __strong id)kSecAttrSynchronizable] = @(_synchronizable);
  1029. }
  1030. return attributes;
  1031. }
  1032. #pragma mark -
  1033. - (CFTypeRef)itemClassObject
  1034. {
  1035. switch (_itemClass) {
  1036. case AWSUICKeyChainStoreItemClassGenericPassword:
  1037. return kSecClassGenericPassword;
  1038. case AWSUICKeyChainStoreItemClassInternetPassword:
  1039. return kSecClassInternetPassword;
  1040. default:
  1041. return nil;
  1042. }
  1043. }
  1044. - (CFTypeRef)protocolTypeObject
  1045. {
  1046. switch (_protocolType) {
  1047. case AWSUICKeyChainStoreProtocolTypeFTP:
  1048. return kSecAttrProtocolFTP;
  1049. case AWSUICKeyChainStoreProtocolTypeFTPAccount:
  1050. return kSecAttrProtocolFTPAccount;
  1051. case AWSUICKeyChainStoreProtocolTypeHTTP:
  1052. return kSecAttrProtocolHTTP;
  1053. case AWSUICKeyChainStoreProtocolTypeIRC:
  1054. return kSecAttrProtocolIRC;
  1055. case AWSUICKeyChainStoreProtocolTypeNNTP:
  1056. return kSecAttrProtocolNNTP;
  1057. case AWSUICKeyChainStoreProtocolTypePOP3:
  1058. return kSecAttrProtocolPOP3;
  1059. case AWSUICKeyChainStoreProtocolTypeSMTP:
  1060. return kSecAttrProtocolSMTP;
  1061. case AWSUICKeyChainStoreProtocolTypeSOCKS:
  1062. return kSecAttrProtocolSOCKS;
  1063. case AWSUICKeyChainStoreProtocolTypeIMAP:
  1064. return kSecAttrProtocolIMAP;
  1065. case AWSUICKeyChainStoreProtocolTypeLDAP:
  1066. return kSecAttrProtocolLDAP;
  1067. case AWSUICKeyChainStoreProtocolTypeAppleTalk:
  1068. return kSecAttrProtocolAppleTalk;
  1069. case AWSUICKeyChainStoreProtocolTypeAFP:
  1070. return kSecAttrProtocolAFP;
  1071. case AWSUICKeyChainStoreProtocolTypeTelnet:
  1072. return kSecAttrProtocolTelnet;
  1073. case AWSUICKeyChainStoreProtocolTypeSSH:
  1074. return kSecAttrProtocolSSH;
  1075. case AWSUICKeyChainStoreProtocolTypeFTPS:
  1076. return kSecAttrProtocolFTPS;
  1077. case AWSUICKeyChainStoreProtocolTypeHTTPS:
  1078. return kSecAttrProtocolHTTPS;
  1079. case AWSUICKeyChainStoreProtocolTypeHTTPProxy:
  1080. return kSecAttrProtocolHTTPProxy;
  1081. case AWSUICKeyChainStoreProtocolTypeHTTPSProxy:
  1082. return kSecAttrProtocolHTTPSProxy;
  1083. case AWSUICKeyChainStoreProtocolTypeFTPProxy:
  1084. return kSecAttrProtocolFTPProxy;
  1085. case AWSUICKeyChainStoreProtocolTypeSMB:
  1086. return kSecAttrProtocolSMB;
  1087. case AWSUICKeyChainStoreProtocolTypeRTSP:
  1088. return kSecAttrProtocolRTSP;
  1089. case AWSUICKeyChainStoreProtocolTypeRTSPProxy:
  1090. return kSecAttrProtocolRTSPProxy;
  1091. case AWSUICKeyChainStoreProtocolTypeDAAP:
  1092. return kSecAttrProtocolDAAP;
  1093. case AWSUICKeyChainStoreProtocolTypeEPPC:
  1094. return kSecAttrProtocolEPPC;
  1095. case AWSUICKeyChainStoreProtocolTypeNNTPS:
  1096. return kSecAttrProtocolNNTPS;
  1097. case AWSUICKeyChainStoreProtocolTypeLDAPS:
  1098. return kSecAttrProtocolLDAPS;
  1099. case AWSUICKeyChainStoreProtocolTypeTelnetS:
  1100. return kSecAttrProtocolTelnetS;
  1101. case AWSUICKeyChainStoreProtocolTypeIRCS:
  1102. return kSecAttrProtocolIRCS;
  1103. case AWSUICKeyChainStoreProtocolTypePOP3S:
  1104. return kSecAttrProtocolPOP3S;
  1105. default:
  1106. return nil;
  1107. }
  1108. }
  1109. - (CFTypeRef)authenticationTypeObject
  1110. {
  1111. switch (_authenticationType) {
  1112. case AWSUICKeyChainStoreAuthenticationTypeNTLM:
  1113. return kSecAttrAuthenticationTypeNTLM;
  1114. case AWSUICKeyChainStoreAuthenticationTypeMSN:
  1115. return kSecAttrAuthenticationTypeMSN;
  1116. case AWSUICKeyChainStoreAuthenticationTypeDPA:
  1117. return kSecAttrAuthenticationTypeDPA;
  1118. case AWSUICKeyChainStoreAuthenticationTypeRPA:
  1119. return kSecAttrAuthenticationTypeRPA;
  1120. case AWSUICKeyChainStoreAuthenticationTypeHTTPBasic:
  1121. return kSecAttrAuthenticationTypeHTTPBasic;
  1122. case AWSUICKeyChainStoreAuthenticationTypeHTTPDigest:
  1123. return kSecAttrAuthenticationTypeHTTPDigest;
  1124. case AWSUICKeyChainStoreAuthenticationTypeHTMLForm:
  1125. return kSecAttrAuthenticationTypeHTMLForm;
  1126. case AWSUICKeyChainStoreAuthenticationTypeDefault:
  1127. return kSecAttrAuthenticationTypeDefault;
  1128. default:
  1129. return nil;
  1130. }
  1131. }
  1132. - (CFTypeRef)accessibilityObject
  1133. {
  1134. switch (_accessibility) {
  1135. case AWSUICKeyChainStoreAccessibilityWhenUnlocked:
  1136. return kSecAttrAccessibleWhenUnlocked;
  1137. case AWSUICKeyChainStoreAccessibilityAfterFirstUnlock:
  1138. return kSecAttrAccessibleAfterFirstUnlock;
  1139. case AWSUICKeyChainStoreAccessibilityAlways:
  1140. return kSecAttrAccessibleAlways;
  1141. case AWSUICKeyChainStoreAccessibilityWhenPasscodeSetThisDeviceOnly:
  1142. return kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly;
  1143. case AWSUICKeyChainStoreAccessibilityWhenUnlockedThisDeviceOnly:
  1144. return kSecAttrAccessibleWhenUnlockedThisDeviceOnly;
  1145. case AWSUICKeyChainStoreAccessibilityAfterFirstUnlockThisDeviceOnly:
  1146. return kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly;
  1147. case AWSUICKeyChainStoreAccessibilityAlwaysThisDeviceOnly:
  1148. return kSecAttrAccessibleAlwaysThisDeviceOnly;
  1149. default:
  1150. return nil;
  1151. }
  1152. }
  1153. + (NSError *)argumentError:(NSString *)message
  1154. {
  1155. NSError *error = [NSError errorWithDomain:AWSUICKeyChainStoreErrorDomain code:AWSUICKeyChainStoreErrorInvalidArguments userInfo:@{NSLocalizedDescriptionKey: message}];
  1156. NSLog(@"error: [%@] %@", @(error.code), error.localizedDescription);
  1157. return error;
  1158. }
  1159. + (NSError *)conversionError:(NSString *)message
  1160. {
  1161. NSError *error = [NSError errorWithDomain:AWSUICKeyChainStoreErrorDomain code:-67594 userInfo:@{NSLocalizedDescriptionKey: message}];
  1162. NSLog(@"error: [%@] %@", @(error.code), error.localizedDescription);
  1163. return error;
  1164. }
  1165. + (NSError *)securityError:(OSStatus)status
  1166. {
  1167. NSString *message = @"Security error has occurred.";
  1168. #if TARGET_OS_MAC && !TARGET_OS_IPHONE
  1169. CFStringRef description = SecCopyErrorMessageString(status, NULL);
  1170. if (description) {
  1171. message = (__bridge_transfer NSString *)description;
  1172. }
  1173. #endif
  1174. NSError *error = [NSError errorWithDomain:AWSUICKeyChainStoreErrorDomain code:status userInfo:@{NSLocalizedDescriptionKey: message}];
  1175. NSLog(@"OSStatus error: [%@] %@", @(error.code), error.localized