/ OSX / Keychain / KDSecItems.m
KDSecItems.m
  1  /*
  2   * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved.
  3   *
  4   * @APPLE_LICENSE_HEADER_START@
  5   * 
  6   * This file contains Original Code and/or Modifications of Original Code
  7   * as defined in and that are subject to the Apple Public Source License
  8   * Version 2.0 (the 'License'). You may not use this file except in
  9   * compliance with the License. Please obtain a copy of the License at
 10   * http://www.opensource.apple.com/apsl/ and read it before using this
 11   * file.
 12   * 
 13   * The Original Code and all software distributed under the License are
 14   * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 15   * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 16   * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 17   * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 18   * Please see the License for the specific language governing rights and
 19   * limitations under the License.
 20   * 
 21   * @APPLE_LICENSE_HEADER_END@
 22   */
 23  
 24  
 25  #import "KDSecItems.h"
 26  #include <Security/Security.h>
 27  #include <Security/SecItemPriv.h>
 28  
 29  
 30  NSString *kKDSecItemsUpdated = @"KDSecItemsUpdated";
 31  
 32  @interface KDSecItems ()
 33  @property NSMutableArray *items;
 34  @end
 35  
 36  @implementation KDSecItems
 37  
 38  -(NSInteger)numberOfRowsInTableView:(NSTableView*)t
 39  {
 40      return [self.items count];
 41  }
 42  
 43  +(NSString*)nameOfItem:(NSDictionary*)item
 44  {
 45      id name = item[(id)kSecAttrService];
 46      if (name) {
 47          return name;
 48      }
 49      
 50      NSString *path = item[(id)kSecAttrPath];
 51      if (!path) {
 52          path = @"/";
 53      }
 54      NSString *port = item[(id)kSecAttrPort];
 55      if ([@"0" isEqualToString:port] || [@0 isEqual:port]) {
 56          port = @"";
 57      } else {
 58          port = [NSString stringWithFormat:@":%@", port];
 59      }
 60      
 61      return [NSString stringWithFormat:@"%@://%@%@%@", item[(id)kSecAttrProtocol], item[(id)kSecAttrServer], port, path];
 62  }
 63  
 64  - (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex
 65  {
 66      NSString *identifier = [aTableColumn identifier];
 67      
 68      if ([@"account" isEqualToString:identifier]) {
 69          return self.items[rowIndex][(id)kSecAttrAccount];
 70      }
 71      if ([@"name" isEqualToString:identifier]) {
 72          return [KDSecItems nameOfItem:self.items[rowIndex]];
 73      }
 74      
 75      return [NSString stringWithFormat:@"*** c=%@ r%ld", [aTableColumn identifier], (long)rowIndex];
 76  }
 77  
 78  -(NSArray*)fetchItemsMatching:(NSDictionary *)query
 79  {
 80      CFTypeRef raw_items = NULL;
 81      OSStatus result = SecItemCopyMatching((__bridge CFDictionaryRef)(query), &raw_items);
 82      if (result) {
 83          // XXX: UI
 84          NSLog(@"Error result %d - query: %@", result, query);
 85          return nil;
 86      }
 87      if (CFArrayGetTypeID() == CFGetTypeID(raw_items)) {
 88          return (__bridge NSArray*)raw_items;
 89      }
 90      
 91      NSLog(@"Unexpected result type from copyMatching: %@ (query=%@)", raw_items, query);
 92      CFRelease(raw_items);
 93  
 94      return nil;
 95  }
 96  
 97  -(void)loadItems
 98  {
 99      NSDictionary *query_genp = @{(id)kSecClass: (id)kSecClassGenericPassword,
100                                   (__bridge id)kSecAttrSynchronizable: @1,
101                                   (id)kSecMatchLimit: (id)kSecMatchLimitAll,
102                                   (id)kSecReturnAttributes: (id)kCFBooleanTrue};
103      NSDictionary *query_inet = @{(id)kSecClass: (id)kSecClassInternetPassword,
104                                   (__bridge id)kSecAttrSynchronizable: @1,
105                                   (id)kSecMatchLimit: (id)kSecMatchLimitAll,
106                                   (id)kSecReturnAttributes: (id)kCFBooleanTrue};
107      NSArray *nextItems = [[self fetchItemsMatching:query_genp] arrayByAddingObjectsFromArray:[self fetchItemsMatching:query_inet]];
108      self.items = [[nextItems sortedArrayUsingComparator:^NSComparisonResult(id a, id b) {
109          NSDictionary *da = a, *db = b;
110          return [da[(id)kSecAttrService] caseInsensitiveCompare:db[(id)kSecAttrService]];
111      }] mutableCopy];
112          
113      dispatch_async(dispatch_get_main_queue(), ^{
114          [[NSNotificationCenter defaultCenter] postNotificationName:kKDSecItemsUpdated object:self];
115      });
116  }
117  
118  -(id)init
119  {
120      [self loadItems];
121      return self;
122  }
123  
124  @end