Core/Source/GrowlBrowserEntry.m
author evands
Mon Jul 28 21:53:02 2008 +0000 (2008-07-28)
changeset 4153 899d3019a60a
parent 3510 1cb27a4b0a9a
child 4154 a2dbe798edf8
permissions -rw-r--r--
* We now store passwords for network servers securely instead of storing them in plain text in the Growl preferences. Heh.
* Remove unneeded code related to resolving Bonjour clients immediately, since we want to resolve them as-needed rather than storing a static IP/port.
     1 //
     2 //  GrowlBrowserEntry.m
     3 //  Growl
     4 //
     5 //  Created by Ingmar Stein on 16.04.05.
     6 //  Copyright 2005-2006 The Growl Project. All rights reserved.
     7 //
     8 
     9 #import "GrowlBrowserEntry.h"
    10 #import "GrowlPreferencePane.h"
    11 #include "CFDictionaryAdditions.h"
    12 #include "CFMutableDictionaryAdditions.h"
    13 #include <Security/SecKeychain.h>
    14 #include <Security/SecKeychainItem.h>
    15 
    16 #define GrowlBrowserEntryKeychainServiceName "GrowlOutgoingNetworkConnection"
    17 
    18 @implementation GrowlBrowserEntry
    19 
    20 - (id) initWithDictionary:(NSDictionary *)dict {
    21 	if ((self = [self init])) {
    22 		properties = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, (CFDictionaryRef)dict);
    23 	}
    24 
    25 	return self;
    26 }
    27 
    28 - (id) initWithComputerName:(NSString *)name {
    29 	if ((self = [self init])) {
    30 		properties = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
    31 		CFDictionarySetValue(properties, CFSTR("computer"), name);
    32 		CFDictionarySetValue(properties, CFSTR("use"), kCFBooleanFalse);
    33 		CFDictionarySetValue(properties, CFSTR("active"), kCFBooleanTrue);
    34 	}
    35 
    36 	return self;
    37 }
    38 
    39 - (BOOL) use {
    40 	return getBooleanForKey((NSDictionary *)properties, @"use");
    41 }
    42 
    43 - (void) setUse:(BOOL)flag {
    44 	setBooleanForKey((NSMutableDictionary *)properties, @"use", flag);
    45 	[owner writeForwardDestinations];
    46 }
    47 
    48 - (BOOL) active {
    49 	return getBooleanForKey((NSDictionary *)properties, @"active");
    50 }
    51 
    52 - (void) setActive:(BOOL)flag {
    53 	setBooleanForKey((NSMutableDictionary *)properties, @"active", flag);
    54 	[owner writeForwardDestinations];
    55 }
    56 
    57 - (NSString *) computerName {
    58 	return (NSString *)CFDictionaryGetValue(properties, CFSTR("computer"));
    59 }
    60 
    61 - (void) setComputerName:(NSString *)name {
    62 	CFDictionarySetValue(properties, CFSTR("computer"), name);
    63 	[owner writeForwardDestinations];
    64 }
    65 
    66 - (NSString *) password {
    67 	if (!didPasswordLookup) {
    68 		unsigned char *passwordChars;
    69 		UInt32 passwordLength;
    70 		OSStatus status;
    71 		const char *computerNameChars = [[self computerName] UTF8String];
    72 		status = SecKeychainFindGenericPassword(NULL,
    73 												strlen(GrowlBrowserEntryKeychainServiceName), GrowlBrowserEntryKeychainServiceName,
    74 												strlen(computerNameChars), computerNameChars,
    75 												&passwordLength, (void **)&passwordChars, NULL);		
    76 		if (status == noErr) {
    77 			password = [[NSString alloc] initWithBytes:passwordChars
    78 												length:passwordLength
    79 											  encoding:NSUTF8StringEncoding];
    80 			SecKeychainItemFreeContent(NULL, password);
    81 		} else {
    82 			if (status != errSecItemNotFound)
    83 				NSLog(@"Failed to retrieve password for %@ from keychain. Error: %d", status);
    84 			password = nil;
    85 		}
    86 		
    87 		didPasswordLookup = YES;
    88 	}
    89 
    90 	
    91 	return password;
    92 }
    93 
    94 - (void) setPassword:(NSString *)inPassword {
    95 	if (password != inPassword) {
    96 		[password release];
    97 		password = [inPassword copy];
    98 	}
    99 
   100 	// Store the password to the keychain
   101 	// XXX TODO Use AIKeychain
   102 	const char *passwordChars = password ? [password UTF8String] : "";
   103 	OSStatus status;
   104 	SecKeychainItemRef itemRef = nil;
   105 	const char *computerNameChars = [[self computerName] UTF8String];
   106 	status = SecKeychainFindGenericPassword(NULL,
   107 											strlen(GrowlBrowserEntryKeychainServiceName), GrowlBrowserEntryKeychainServiceName,
   108 											strlen(computerNameChars), computerNameChars,
   109 											NULL, NULL, &itemRef);
   110 	if (status == errSecItemNotFound) {
   111 		// add new item
   112 		status = SecKeychainAddGenericPassword(NULL,
   113 											   strlen(GrowlBrowserEntryKeychainServiceName), GrowlBrowserEntryKeychainServiceName,
   114 											   strlen(computerNameChars), computerNameChars,
   115 											   strlen(passwordChars), passwordChars, NULL);
   116 		if (status)
   117 			NSLog(@"Failed to add password to keychain.");
   118 	} else {
   119 		// change existing password
   120 		SecKeychainAttribute attrs[] = {
   121 			{ kSecAccountItemAttr, strlen(computerNameChars), (char *)computerNameChars },
   122 			{ kSecServiceItemAttr, strlen(GrowlBrowserEntryKeychainServiceName), (char *)GrowlBrowserEntryKeychainServiceName }
   123 		};
   124 		const SecKeychainAttributeList attributes = { sizeof(attrs) / sizeof(attrs[0]), attrs };
   125 		status = SecKeychainItemModifyAttributesAndData(itemRef,		// the item reference
   126 														&attributes,	// no change to attributes
   127 														strlen(passwordChars),			// length of password
   128 														passwordChars		// pointer to password data
   129 														);
   130 		if (itemRef)
   131 			CFRelease(itemRef);
   132 		if (status)
   133 			NSLog(@"Failed to change password in keychain.");
   134 	}
   135 	
   136 	[owner writeForwardDestinations];
   137 }
   138 
   139 - (void) setOwner:(GrowlPreferencePane *)pref {
   140 	owner = pref;
   141 }
   142 
   143 - (NSDictionary *) properties {
   144 	return (NSDictionary *)properties;
   145 }
   146 
   147 - (void) dealloc {
   148 	[password release];
   149 
   150 	CFRelease(properties);
   151 	[super dealloc];
   152 }
   153 
   154 @end