Fixing Keychain – Look Ma, No Code!
November 3rd, 2005While waiting for Apple to fix the many bugs that I described in my recent posting, I thought I’d hack in with Interface Builder and fix some of my gripes myself. For the benefit of anybody who shares my grievances, I describe the process here for fixing several of the problematic behaviors.
Think of the instructions below as a sort of entertainment fiction. You like to watch movies and read books where the characters steal, pillage, murder, take dangerous drugs, etc. Enjoy the thrill of my dangerous activities vicariously. And if you decide to mimic these bad habits in the privacy of your own house, don’t tell us about it! (Unless you have a really good idea).
Preparing to Hack
As with all modifications of Apple-provided applications, it’s a good idea to start by making a backup for safety’s sake. In the case of Keychain Access, you’ll discovery quickly that it’s not as simple as making a copy of the application in the Finder. It will warn you that “special permissions” prevent everything from being copied. There are two things at work here. First, the Keychain Access application and everything inside it is owned by root. Second, there are files inside the package with a “setuid” bit set, meaning that when they run, they get to inherit the privileges of root. To make this easy, I suggest in this case only backing up the “Resources” portion of the bundle, because that’s all I’m going to be modifying. You might get some complaints from Interface Builder that the nibs are “read only.” I just saved a copy and then copied the new nib into the English.lproj directory of Keychain Access.
Applying the Changes
Alleviating the broken “next responder” loop in the main Keychain window was as simple as defining an “initial first responder” for the window, and setting up an appropriate chain of “nextKeyView” connections. It seems that the responder chain as it ships from Apple is simply the default “emergency chain” fabricated by Cocoa when a developer doesn’t specify a particular chain. I decided to make mine start with the search field, and advance clockwise through the main table, “Category table” and “Keychain” table. The MasterView nib file contains the window whose contents can be fixed in this way.
While poking around in the MasterView nib, I also decided to change the keyboard shortcut for the “Info” button from Cmd-I to simply return. This has the effect of making the return key always open the item selected in the main table, which is fine because the return key doesn’t do anything special in the other tables in the window that can receive focus.
To give a keyboard shortcut to the “Show Secure Note” and “Show Password” items, I located the corresponding UI elements in the NoteEditor and PasswordEditor nibs. I gave them each the shortcut “Cmd-T” (for “Show Text”).
To alleviate the headaches of the “Save Changes” dialog’s missing keyboard shortcut for “No,” I only had to change the Localizable.strings value for that key from “No” to “Don’t Save,” which is probably what it should have been in the first place! Keychain Access uses NSBeginCriticalAlertSheet to display the Save Changes dialog, and as advertised, it will automatically accept Cmd-D as a synonym for clicking on the Don’t Save button. Sometimes “doing the standard thing” also means “doing the right thing,” and adds up to less work for a better product.
Now for the The Big Kahuna. The all-powerful “Allow Acccess” keychain authorization dialog. This bad boy’s unresponsiveness to keystrokes makes it the weak link in not only Keychain Access, but every other application that asks the user to approve a keychain fetch. Where does the Big Kahuna live? By running the command-line tool “fs_usage” while invoking the dialog, it’s easy to locate the nib in question. It looks like /System/Library/CoreServices/SecurityAgent.app/Contents/Resources/English.lproj/ConfirmAccess.nib is what we’re interested in. Again, the sensitive nature of this application means that I have to be careful to leave most of the existing app in place, while only backing up and modifying the resources.
Since I’m usually more interested in giving applications access “forever,” I not only added keyboard shortcuts, but moved things around a bit. I renamed the “Always Allow” item to “Allow Forever,” made it the default button, and moved it to the far-right. I gave the “Allow Once” button the simple shortcut of the “O” key. For some reason I was unable to give it a shortcut that requires the Cmd key to be held down. I’ll take what I can get! The resulting dialog looks like this:
And hallelujah! I can just “hit return” when it pops up.
The only item in my list of gripes which I haven’t been able to address in one way or another is the “Close All Windows” function. If Keychain Access were scriptable, it would be easy to write a script to workaround the problem, similarly to how I solved the problem in Terminal. As it is, I don’t expect to open up 500+ info winodws in Keychain Access in the near future, so I think I can live with that shortcoming.
November 3rd, 2005 at 6:13 pm
Here’s a script that will close all but the main window in Keychain Access. It’s a UI script so it requires that “Enable access for assistive devices” be enabled in the Universal Access pref pane.
—
tell application “System Events”
tell process “Keychain Access”
set w_names to name of windows
repeat with i in w_names
if (i as text) is not “Keychain Access” then ¬
perform action “AXPress” of button 1 of window i
end repeat
end tell
end tell
—
Tested with OS X 10.4.3
November 4th, 2005 at 4:43 pm
Thanks, Rob! I hadn’t considered using UI Scripting. Keychain Access is one of those rare applications *so* unscriptable that it doesn’t even include a “core events” dictionary. I guess I let that get my spirits down about any chance of scripting it.