I have been playing around with Cocoa for the last couple of days and I was wondering how I would go about listing all Name/Account pairs of a keychain that I created? the little key chain access app that comes with Mac OS X does that, so it must be possible I presume? Is SecItemCopyMatching what I'm looking for? How do I specify the keychain I want to search, though? And what's a service name in this context?
...am I the only one who thinks the Keychain API in Cocoa is absolutely horrible? I have been reading the documentation up and down for the last couple of hours or so and I'm still getting nowhere :-/
you iterate over the items in your keychain with SecItemCopyMatching and access the password with SecKeychainFindInternetPassword or SecKeychainFindGenericPassword.
Iterate over Keychain:
// iterates over keychain and pass every item found by the query to PrintAccount.
static void IterateOverKeychain() {
// create query
CFMutableDictionaryRef query = CFDictionaryCreateMutable(kCFAllocatorDefault, 3, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFDictionaryAddValue(query, kSecReturnAttributes, kCFBooleanTrue);
CFDictionaryAddValue(query, kSecMatchLimit, kSecMatchLimitAll);
CFDictionaryAddValue(query, kSecClass, kSecClassInternetPassword);
// get search results
CFArrayRef result = nil;
OSStatus status = SecItemCopyMatching(query, (CFTypeRef*)&result);
assert(status == 0);
// do something with the result
CFRange range = CFRangeMake(0, CFArrayGetCount(result));
CFArrayApplyFunction(result, range, PrintAccount, nil);
}
// prints the password for a item from the keychain.
static void PrintAccount(const void *value, void *context) {
CFDictionaryRef dict = value;
CFStringRef acct = CFDictionaryGetValue(dict, kSecAttrAccount);
NSLog(#"%#", acct);
}
Print Password:
static void PrintPassword() {
const char *acct = "foo.bar#googlemail.com";
UInt32 acctLen = (UInt32)strlen(acct);
const char *srvr = "calendar.google.com";
UInt32 srvrLen = (UInt32)strlen(srvr);
UInt32 pwLen = 0;
void *pw = 0;
SecKeychainFindInternetPassword(nil, srvrLen, srvr, 0, nil, acctLen, acct, 0, nil, 0, kSecProtocolTypeAny, kSecAuthenticationTypeAny, &pwLen, &pw, nil);
CFStringRef pwString = CFStringCreateWithBytes(kCFAllocatorDefault, pw, pwLen, kCFStringEncodingUTF8, NO);
NSLog(#"%s %#", acct, pwString);
}
Well, I managed to enumerate over the keychain entries, however the password field is empty. I thought if authorization was required, the program would ask for the keychain password automatically like it usually does?
NSDictionary *query = [NSDictionary dictionaryWithObjectsAndKeys:
(id)kSecClassInternetPassword, kSecClass,
(id)kCFBooleanTrue, kSecReturnData,
(id)kCFBooleanTrue, kSecReturnAttributes,
kSecMatchLimitAll, kSecMatchLimit,
nil];
NSArray *itemDicts = nil;
OSStatus status = SecItemCopyMatching((CFDictionaryRef)query, (CFTypeRef *)&itemDicts);
if (status)
[MessageBox Show:(NSString*)SecCopyErrorMessageString(status, NULL)];
NSMutableArray *arr = [[NSMutableArray alloc] init];
for (NSDictionary *itemDict in itemDicts) {
NSData *data = [itemDict objectForKey:(id)kSecValueData];
NSString *pwd = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease];
NSString *acc = [itemDict objectForKey:(id)kSecAttrAccount];
NSString *name = [itemDict objectForKey:(id)kSecAttrLabel];
if(acc != nil) {
NSArray *values = [NSArray arrayWithObjects: (id)name, (id)acc, (id)pwd, nil];
[arr addObject:(id)values];
}
}
[itemDicts release];
NSInteger c = arr.count;
NSString *cnt = [NSString stringWithFormat:#"%d", c];
[MessageBox Show: [arr objectAtIndex:10]];
Related
im working on an that search in the content of allot of files, i planed to use SearchKit but i can't figure out to make Apple's sample code to work, and i can't find any other ressources (NSHipster code didn't work either), here's my code:
#define kSearchMax 1000
#interface ViewController()
#property(nonatomic) SKIndexRef mySKIndex;
#end
#implementation ViewController
#synthesize mySKIndex;
- (void)viewDidLoad {
[super viewDidLoad];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
[self openIndex];
[self addDoc];
SKIndexFlush(self.mySKIndex);
// i thought that the indexation may need some time ..
sleep(2);
dispatch_async(dispatch_get_main_queue(), ^{
[self searchterm:#"var"];
});
});
}
- (void) openIndex {
NSString *path = [[NSHomeDirectory() stringByAppendingPathComponent:#"index"] stringByAppendingPathExtension:#"txt"]; // 1
NSURL *url = [NSURL fileURLWithPath:path];
NSString *name = #"extension_index";
if ([name length] == 0) name = nil;
SKIndexType type = kSKIndexInverted;
if ([[NSFileManager defaultManager] fileExistsAtPath:path]) {
mySKIndex = SKIndexOpenWithURL ((__bridge CFURLRef) url,
(__bridge CFStringRef) name,
true
);
}else{
self.mySKIndex = SKIndexCreateWithURL((__bridge CFURLRef) url,
(__bridge CFStringRef) name,
(SKIndexType) type,
(CFDictionaryRef) NULL);
}
}
- (void) addDoc {
SKLoadDefaultExtractorPlugIns ();
NSString *path = [NSBundle.mainBundle pathForResource:#"Products" ofType:#"rtf"]; // 1
NSURL *url = [NSURL fileURLWithPath: path]; // 2
SKDocumentRef doc = SKDocumentCreateWithURL ((__bridge CFURLRef) url);
NSString *mimeTypeHint = #"text/rtf";
BOOL added = SKIndexAddDocument ((SKIndexRef) mySKIndex,
(SKDocumentRef) doc,
(__bridge CFStringRef)mimeTypeHint,
(Boolean) true
);
NSLog(added ? #"added" : #"not added");
}
- (void) searchterm:(NSString*)query{
SKSearchOptions options = kSKSearchOptionDefault;
BOOL more = YES;
UInt32 totalCount = 0;
SKSearchRef search = SKSearchCreate (mySKIndex,
(__bridge CFStringRef) query,
options);
while (more) {
SKDocumentID foundDocIDs [kSearchMax];
float foundScores [kSearchMax];
float *scores;
Boolean unranked =
options & kSKSearchOptionNoRelevanceScores;
if (unranked) {
scores = NULL;
} else {
scores = foundScores;
}
CFIndex foundCount = 0;
more = SKSearchFindMatches (
search,
kSearchMax,
foundDocIDs,
scores,
100,
&foundCount
);
NSLog(#"%#", [NSString stringWithFormat:#"current count = %i", totalCount]);
totalCount += foundCount;
}
}
#end
it always print "current count = 0" and the loop is executed only one time.
this is my code to generate a new keypair
//Create RSA Key Pair
CFMutableDictionaryRef parameters = CFDictionaryCreateMutable(
kCFAllocatorDefault,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
CFDictionarySetValue(parameters, kSecAttrKeyType, kSecAttrKeyTypeRSA);
int32_t rawnum = 2048;
CFNumberRef num = CFNumberCreate(kCFAllocatorDefault,
kCFNumberIntType, &rawnum);
CFDictionarySetValue(parameters,
kSecAttrKeySizeInBits,
num);
publicKey = NULL;
privateKey = NULL;
SecKeyGeneratePair(parameters, &publicKey, &privateKey);
and i've tried to get the data using this method
- (NSData *)getRSAKeyBitsFromKey:(SecKeyRef)givenKey {
static const uint8_t publicKeyIdentifier[] = "com.company";
NSData *publicTag = [[NSData alloc] initWithBytes:publicKeyIdentifier length:sizeof(publicKeyIdentifier)];
OSStatus sanityCheck = noErr;
NSData * publicKeyBits = nil;
NSMutableDictionary * queryPublicKey = [[NSMutableDictionary alloc] init];
[queryPublicKey setObject:(__bridge id)kSecClassKey forKey:(__bridge id)kSecClass];
//[queryPublicKey setObject:publicTag forKey:(__bridge id)kSecAttrApplicationTag];
[queryPublicKey setObject:(__bridge id)kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
// Temporarily add key to the Keychain, return as data:
NSMutableDictionary * attributes = [queryPublicKey mutableCopy];
[attributes setObject:(__bridge id)givenKey forKey:(__bridge id)kSecValueRef];
[attributes setObject:#YES forKey:(__bridge id)kSecReturnData];
CFTypeRef result;
sanityCheck = SecItemAdd((__bridge CFDictionaryRef) attributes, &result);
if (sanityCheck == errSecSuccess) {
publicKeyBits = CFBridgingRelease(result);
// Remove from Keychain again:
(void)SecItemDelete((__bridge CFDictionaryRef) queryPublicKey);
}
return publicKeyBits;
}
I know that probably i didn't set the PublicKeyIdentifier and the other attributes (should i had to?).
I am searching into a UITableView using this:
titles = [NSArray arrayWithArray:[datamanager titlesForEntriesBetween:(NSInteger)[slider minSelectedValue] and:(NSInteger)[slider maxSelectedValue]containing:searchText]];
How can I encode array value with NSASCIIStringEncoding during the search process?
(Array contains "tĂȘte" for example.. and when I search "tete" nothing matches.. so I will encode array value just for my search)
I would add change the third parameter to your datamanager function:
- (NSArray*)titlesForEntriesBetween:(NSInteger)startIndex
and:(NSInteger)stopIndex
withFunction:(BOOL(^)(NSString*))block {
NSMutableArray *retVal = [NSMutableArray array];
for(NSInteger i = startIndex; i <= stopIndex; ++i) {
NSString *string = [array_ objectAtIndex:i];
if (block(string)) {
[retVal insertObject:string];
}
}
return retVal;
}
And then I would call the function like this:
titles = [datamanager titlesForEntriesBetween:(NSInteger)[slider minSelectedValue] and:(NSInteger)[slider maxSelectedValue] withFunction:^(BOOL)(NSString *str) {
NSData *data = [str dataUsingEncoding:NSASCIIStringEncoding];
NSString *simpleString = [[[NSString alloc] initWithData:data usingEncoding: NSASCIIStringEncoding] autorelease];
return [simpleString isEqualToString:str];
}]];
Note: I just typed this in, I haven't tried to compile/run this.
I have the following code which I would like to use to check user answers and output a score (out of 5). I use a plist with the answers in and check the textField.text against it. What I'm struggling with is: how to get an output score as a total using this method?
- (IBAction)checkAnswers:(UITextField *)textField
{
NSString *path2 = [[NSBundle mainBundle] pathForResource:#"7A Cells Microscopes 3" ofType:#"plist"];
NSDictionary *dictionary = [[NSDictionary alloc] initWithContentsOfFile:path2];
NSString *tester = [NSString stringWithFormat:#"%i", textField.tag];
// NSDictionary *secondDict = [dictionary valueForKey:tester];
// NSString *answer = [secondDict valueForKey:#"Answer"];
// if ([textField.text isEqualToString:[[dictionary valueForKey:tester] valueForKey:#"Answer"]]) {
// NSLog(#"YAY");
// }
NSArray *allTextFields = [[NSArray alloc] initWithObjects:eyepiece, objectiveLens, focussingKnobs, stage, mirror, nil];
for (textField in allTextFields) {
int x = 0;
if ([textField.text isEqualToString:[[dictionary valueForKey:tester] valueForKey:#"Answer"]]) {
x++;
NSLog(#"%i", x);
}
}
Any help would be much appreciated!
Many thanks.
Assuming the rest of your code is good, just move int x = 0; outside the for loop. The way you have it coded x is reset to 0 on every loop... so it never counts.
I'm unsure how to correctly use [NSDictionary dictionaryWithObjects:forKeys:count:] together with ARC (automatic reference counting). The C arrays require some special modifier, otherwise they receive warning right away. What is a correct example?
Or, asked the other way around, is this safe usage?
#implementation NSArray (CreateDictionaryUsingBlock)
- (NSDictionary *)dictionaryWithKeysUsing:(id (^)(id obj))block
{
NSUInteger n = [self count];
__autoreleasing id *keys = (__autoreleasing id *)malloc(n*sizeof(id));
__autoreleasing id *objects = (__autoreleasing id *)malloc(n*sizeof(id));
for(int i = 0; i<n; i++) {
id object = [self objectAtIndex:i];
keys[i] = block(object);
objects[i] = object;
}
NSDictionary *dictionary = [NSDictionary dictionaryWithObjects:objects
forKeys:keys
count:n];
free(keys);
free(objects);
return dictionary;
}
#end