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