Proyectos de Subversion Iphone Microlearning

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
/*
2
 * Copyright 2019 Google
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
 
17
#import "GoogleUtilities/Environment/Public/GoogleUtilities/GULKeychainUtils.h"
18
 
19
NSString *const kGULKeychainUtilsErrorDomain = @"com.gul.keychain.ErrorDomain";
20
 
21
@implementation GULKeychainUtils
22
 
23
+ (nullable NSData *)getItemWithQuery:(NSDictionary *)query
24
                                error:(NSError *_Nullable *_Nullable)outError {
25
  NSMutableDictionary *mutableQuery = [query mutableCopy];
26
 
27
  mutableQuery[(__bridge id)kSecReturnData] = @YES;
28
  mutableQuery[(__bridge id)kSecMatchLimit] = (__bridge id)kSecMatchLimitOne;
29
 
30
  CFDataRef result = NULL;
31
  OSStatus status =
32
      SecItemCopyMatching((__bridge CFDictionaryRef)mutableQuery, (CFTypeRef *)&result);
33
 
34
  if (status == errSecSuccess && result != NULL) {
35
    if (outError) {
36
      *outError = nil;
37
    }
38
 
39
    return (__bridge_transfer NSData *)result;
40
  }
41
 
42
  if (status == errSecItemNotFound) {
43
    if (outError) {
44
      *outError = nil;
45
    }
46
  } else {
47
    if (outError) {
48
      *outError = [self keychainErrorWithFunction:@"SecItemCopyMatching" status:status];
49
    }
50
  }
51
  return nil;
52
}
53
 
54
+ (BOOL)setItem:(NSData *)item
55
      withQuery:(NSDictionary *)query
56
          error:(NSError *_Nullable *_Nullable)outError {
57
  NSData *existingItem = [self getItemWithQuery:query error:outError];
58
  if (outError && *outError) {
59
    return NO;
60
  }
61
 
62
  NSMutableDictionary *mutableQuery = [query mutableCopy];
63
  mutableQuery[(__bridge id)kSecAttrAccessible] =
64
      (__bridge id)kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly;
65
 
66
  OSStatus status;
67
  if (!existingItem) {
68
    mutableQuery[(__bridge id)kSecValueData] = item;
69
    status = SecItemAdd((__bridge CFDictionaryRef)mutableQuery, NULL);
70
  } else {
71
    NSDictionary *attributes = @{(__bridge id)kSecValueData : item};
72
    status = SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)attributes);
73
  }
74
 
75
  if (status == noErr) {
76
    if (outError) {
77
      *outError = nil;
78
    }
79
    return YES;
80
  }
81
 
82
  NSString *function = existingItem ? @"SecItemUpdate" : @"SecItemAdd";
83
  if (outError) {
84
    *outError = [self keychainErrorWithFunction:function status:status];
85
  }
86
  return NO;
87
}
88
 
89
+ (BOOL)removeItemWithQuery:(NSDictionary *)query error:(NSError *_Nullable *_Nullable)outError {
90
  OSStatus status = SecItemDelete((__bridge CFDictionaryRef)query);
91
 
92
  if (status == noErr || status == errSecItemNotFound) {
93
    if (outError) {
94
      *outError = nil;
95
    }
96
    return YES;
97
  }
98
 
99
  if (outError) {
100
    *outError = [self keychainErrorWithFunction:@"SecItemDelete" status:status];
101
  }
102
  return NO;
103
}
104
 
105
#pragma mark - Errors
106
 
107
+ (NSError *)keychainErrorWithFunction:(NSString *)keychainFunction status:(OSStatus)status {
108
  NSString *failureReason = [NSString stringWithFormat:@"%@ (%li)", keychainFunction, (long)status];
109
  NSDictionary *userInfo = @{NSLocalizedFailureReasonErrorKey : failureReason};
110
  return [NSError errorWithDomain:kGULKeychainUtilsErrorDomain code:0 userInfo:userInfo];
111
}
112
 
113
@end