0

I am writing a Mac OS X Dashboard Widget for Pastebin.com and it stores the user's password (my code does not encrypt it) using widget.setPreferenceForKey.

Is it safe and good practice to do it this way?

Thilina Chamath Hewagama
  • 9,039
  • 3
  • 32
  • 45

2 Answers2

1

I know this is an old question, but I'm trying to develop a Dashboard widget myself at the moment, and I've run up against the same question. I'll share what I've learned.

First of all, the good news is that you don't necessarily need a plugin; all you need is to give your widget access to the command line.

OS X actually includes a command-line utility called security, which lets you do all sorts of things involving the Keychain. You can read up about it by entering info security in Terminal. I haven't reached the point where I can test this from within the widget itself yet (only in Terminal), but from what I've gleaned, I think this is what you do. Anyone who knows better, please don't hesitate to make changes.

Storing the Password in the Keychain

Assuming username and password are variables we've already set up:

widget.system("/usr/bin/security add-generic-password -a \""+username+"\" -s \"My Awesome Widget\" -w \""+password+"\" -T \"/usr/bin/security\" -U);

Command Breakdown

/usr/bin/security: the widget.system() method requires the full path to the command we're executing. This particular command lives in /usr/bin.

add-generic-password: one of security's many commands. There are other kinds of password items that can be added to the Keychain, like Internet passwords, but I think the generic type is best for this case.

-a: the "account name", or username, which goes with the password we want to store. The Keychain probably won't be the primary place you store the username, since we need it to look up the password later, but if a user has multiple instances of our widget open, each with a different user/pass combo, including the username here will let us specifically look up that password when the time comes. Quotes aren't strictly necessary, but you should include them if usernames for your widget are allowed to have spaces.

-s: the "service name" for the Keychain item we're creating — in other words, the verbose, human-readable name. Your widget's name would probably be most appropriate here.

-w: the password. Again, quotes recommended if your passwords might have spaces.

-T: the path(s) to any application(s) which are allowed to access this Keychain item without question. Without this flag, any attempt to retrieve the password later will result in the user seeing one of those "security wants to use your confidential information stored in "My Awesome Widget" in your keychain" prompts, and chances are they won't know what it means and it'll freak them out. I'm assuming here that because the widget uses security to request the password, security (and not, say, DashboardClient) is the program which needs to be granted access.

-U: tells security to update this Keychain item if it already exists, instead of just failing.

Getting the Password Back from the Keychain

This involves an extra step after you get the password, but it still shouldn't be too bad.

var messyPassword = widget.system("/usr/bin/security 2>&1 >/dev/null find-generic-password -ga \""+username+"\" -s \"My Awesome Widget\"").outputString;
scrubPassword(messyPassword);

Command Breakdown

/usr/bin/security: hello again, officer. Some weather we're having, eh?

2>&1 >/dev/null: the output of find-generic-password includes reams of crap otherwise potentially useful information that we don't need in this case. Fortunately, it outputs the password separately from all that, so it can be captured on its own using this extra bit. (Thanks to Allan Odgaard of Macromates Ltd. for his blog post detailing this trick.)

find-generic-password: the counterpart of add-generic-password. The arguments which follow are used as search criteria.

-g: tells security to actually, y'know, output the password. Otherwise, I guess it just...acknowledges the fact that the item exists, then quits?

-a: the username which goes with the password we want to retrieve.

-s: the human-readable name we picked for the widget when we wrote the add-generic-password command.

Wait, what's scrubPassword()?

Well, the catch is that even after all the other stuff is stripped out of security's reply, the string you get back isn't just the password. It's more like:

password: "nobodywilleverguessthis"

As far as I know, we have to use regular expressions to crack open that string and get at the shiny, password-y pearl within. I don't know about you, but regular expressions are the stuff of nightmares for me, so I was very relieved and excited to find txt2re, an online tool that lets you reverse-engineer a regular expression out of the string you want manipulated. You can literally just paste security's output into txt2re and grab a chunk of JavaScript that'll extract the password from it.

Note: widget.system() also allows for a handler function to be used as a second argument, so it's possible that you could call your scrubPassword() function right there and skip the whole part with the messyPassword variable. As I said, I've only tried calling security from Terminal so far, so I don't have any experience actually working with widget.system().

Removing the Password from the Keychain

When an instance of the widget is closed, we probably don't want to leave the associated password cluttering up the user's Keychain, so we'll do the responsible thing and pick up our litter. This one is a bit simpler than the other two commands, since we don't need to create anything or get anything in response.

widget.system("/usr/bin/security delete-generic-password -a \""+username+"\" -s \"My Awesome Widget\"");

Command Breakdown

/usr/bin/security: the usual.

delete-generic-password: does what it says on the box, using the following arguments as search (or, rather, search-and-destroy) criteria.

-a: the username corresponding to the password you want to take out.

-s: the human-readable name of the widget.

Hope this helps!

Evenio
  • 31
  • 5
  • The -w flag to security find-generic-password will cause it to output just the password. – noah Feb 11 '14 at 18:39
0

No. The password would be stored unencrypted in a property list. As far as I know, there is no direct way to securely store information from a widget. The only thing I can think of would be to use a plugin to store the password in the user's keychain. See the Widget Plugin Interface and the Keychain Services Reference.

ughoavgfhw
  • 39,734
  • 6
  • 101
  • 123