Being long time Linux user and doing lot of remote consultancy (you know, VoIP solutions design and implementation using Kamailio and SIP Router), one of the most used application was KeePassX. It fits perfectly for secure storing of my long list of usernames, passwords, IP addresses and web URLs.
Recently I become the owner of a MacBook Pro and fortunately KeePassX is available (natively) for Mac OS X, but with no auto-typing. That is very handy in Linux for authentication on web pages. I tried to play a bit with KeePass (the original Windows version) and Mono, but the results were not very satisfactory (quite tight tied to Windows style), plus that I could not import the KeePassX database (I would need a Windows box).
Checking the web for KeePassX and auto-typing revealed clearly that is not available for Mac OS X out of the box, but folks around gave some good hints, so I started digging in. Pretty soon a plan was sketched:
- AppleScript give the tools for a nicely and easily coding of interactive applications
- KeePassX uses OS URL handlers to start applications when double-clicking the URL field of stored records
- MoreInternet application for Mac OS X offers easy way to manage URL helper applications
Therefore, here we are...
Step 1
Go, download and install MoreInternet:
http://www.monkeyfood.com/software/MoreInternet/
We will be back later to its configuration.
Step 2
Create the application handler for a new URL type. Open the Script Editor and paste following code:
on open location localURL -- kex://proto?username:password:address:port/path set thePath to text 7 thru -1 of localURL if (text 1 thru 4 of thePath) is "ssh?" then -- ssh? set theProto to "ssh" set theData to text 5 thru -1 of thePath else if (text 1 thru 6 of thePath) is "https?" then -- https? set theProto to "https" set theData to text 7 thru -1 of thePath else if (text 1 thru 5 of thePath) is "http?" then -- http? set theProto to "http" set theData to text 6 thru -1 of thePath else -- assume http set theProto to "http" set theData to thePath end if end if end if set theCLPos to offset of ":" in theData if theCLPos = 0 then display dialog "INVALID URL - NO USER" return end if set theUser to text 1 thru (theCLPos - 1) of theData set theData1 to text (theCLPos + 1) thru -1 of theData set theData to theData1 set theCLPos to offset of ":" in theData if theCLPos = 0 then display dialog "INVALID URL - NO PASSWORD" return end if set thePass to text 1 thru (theCLPos - 1) of theData set theAddr to text (theCLPos + 1) thru -1 of theData -- display dialog "URL+: " & theProto & "://" & theUser & ":xyz@" & theAddr if theProto is "ssh" then tell application "Terminal" activate delay 1 set theCLPos to offset of ":" in theAddr if theCLPos = 0 then set theSSHUrl to "ssh " & theUser & "@" & theAddr else set theHost to texts 1 thru (theCLPos - 1) of theAddr set thePort to texts (theCLPos + 1) thru -1 of theAddr set theSSHUrl to "ssh -p " & thePort & " " & theUser & "@" & theHost end if do script with command theSSHUrl set theButton to button returned of (display dialog "Auto type? (" & theAddr & ")" buttons {"No", "Yes"} default button "Yes") if theButton is "Yes" then tell application "System Events" keystroke thePass key code 52 end tell end if end tell else set theHTTPUrl to theProto & "://" & theAddr tell application "Safari" activate delay 1 tell window 1 of application "Safari" to make new tab tell front window of application "Safari" to set current tab to last tab set the URL of document 1 to theHTTPUrl set theButton to button returned of (display dialog "Auto type? (" & theAddr & ")" buttons {"No", "Yes"} default button "Yes") if theButton is "Yes" then tell application "System Events" keystroke theUser keystroke " " keystroke thePass key code 52 end tell end if end tell end if end open location
Save it as Application Bundle, say under 'kpx' name.
Step 3
Update Application bundle meta-data
Edit kpx.app/Contents/PkgInfo and set the content to "APPLokpx" (no double quotes). Edit kpx.app/Contents/Info.plist and set the bundle signature to the last 4 letters of the value in PkgInfo file and add details about 'kpx' URL handling, you should get to something like this:
<key>CFBundleSignature</key> <string>okpx</string> <key>CFBundleURLTypes</key> <array> <dict> <key>CFBundleURLName</key> <string>KeePassX</string> <key>CFBundleURLSchemes</key> <array> <string>kpx</string> </array> </dict> </array>
Note: CFBundleSignature should be there already, just update the string value. CFBundleURLTypes (and the array value) must be added.
Step 4
Set the 'kpx' URL helper application.
Open System Preferences, then More Internet and add a new protocol 'kpx'. Associate the kpx.app (the application bundle built above) with this URL type. Now, all URL starting with 'kpx://' should be opened with kpx application.
Step 5
Add entries to the KeePassX
The format of the kpx URL is kind of special to fit my needs of opening http and ssh URLs:
kpx://proto?username:password:address:port/path
- proto can be http, https or ssh - if it is something else, it assumes http (can be extended or just use the given value and let the OS handle it)
- the rest are more or less self explaining, 'path' is just for HTTP(S) - the part after server address in web URLs
Here are some examples:
kpx://ssh?{USERNAME}:{PASSWORD}:192.168.64.103:14092
kpx://http?test:testpw:192.168.64.103/admin/login.php
As you can see, it is possible to use the KeePassX self expanding variables such as {USERNAME} or {PASSWORD}.
The format is chosen this way to be compliant with URL specs, you can try a different one, which might be nicer from your point of view, but you have to adjust kxp.app accordingly.
Step 6
Save the KeePassX record and double-click on URL field.
The Terminal or Safari should start depending whether is SSH or HTTP/S URL. A dialog prompting if you want auto-type pops up. Wait (this is important) until SSH prompts for password or the web page is completely loaded. Then you can click "Yes". If you don't want auto-type, press "No".
REMARKS:
- do not use real username and passwords until you are sure the kpx application handler starts correctly. If the OS didn't register the URL helper properly, Safari will open and try to guess what site you want to open, so it may result in trying accessing public web sites with your username and password in URL (e.g., kpx.com/username/password/address) which will stay in remote server logs
- you can change the 'kpx' to anything you want, which is recommended anyway. You have to do small adjustment for the parser in kpx.app to skip it, update the metadata URL types and the System Preferences, Internet More records.
- it is my first Apple Script coding, so bare with me if there are other nicer ways to accomplish same goals
- yeah, you get auto-type for SSH which is not possible in Linux
Hopefully I haven't forgotten anything important. I did it about one week ago. I hope some of you will enjoy and contribute back with improvements or comments (which are moderated by the way). Maybe KeePassX will add auto-type feature for Mac OS X soon, that would be great. Being myself an open source developer, I have to congrat the KeePassX coders, a great project.
Some screenshots:
Fantastic, I check keepassx once a month to see if there is any progress.
ReplyDeletecan't seem to get web logins to work. does it only work with http authentication? ie typing into the browser authentication dialog?
Mark Hellier
mark AT hellier dot co dot nz
I haven't tested with http authentication, only with web forms login and should work.
ReplyDeleteCan you describe what you get? No auto-typing at all? Or some missbehavior.
Be sure you have TAB pressed in between double quotes of:
keystroke " "
in the apple script after the auto type of theUSER and not a white space.
I am using version Mac OS X 10.6.3 and get an error message when save the script. Which Mac OS X version is the script? I have to create the script with Apple Script Editor is thies right?
ReplyDeleteRight now I have as well 10.6.3 and works fine. What is the error message?
ReplyDeleteHey Daniel,
ReplyDeletethx for ur post and it works fine!!!
Cheers,
Alex
Daniel
ReplyDeleteThanks for the solution, very ingenuine! Just one quick note, there's a small typo in the code above
set theHost to texts 1 thru (theCLPos - 1) of theAddr
set thePort to texts (theCLPos + 1) thru -1 of theAddr
these lines compiled fine after removing 's' from 'texts'
thanks again!