Psi is a powerful and popular XMPP client which runs on nearly any platform. It recently got features like Jingle Audio which enables peer-to-peer audio calls.
These new features aside, Psi's user interface is lacking in various places, including, but not limited to, the multi-user chat area. This is kind of sad since the project's mission statement includes ease of use.
The second part of my Google Summer of Code project is to improve this area.
Psi's known to be used more by power IM users than by people who are new to IM, and as power user you like auto-join a couple of MUCs and also connect from multiple places to your account. However if you're already logged in and joined all those rooms, a lot MUC software will complain that you are already in the room, when a your second resource tries to auto-join those.
In Psi this situation can be described by a single picture/screenshot. :)
A possible solution to this problem is to handle auto-join of chatrooms on login completely differently compared to manual joins. A long requested feature for Psi is to have chatrooms show up in your contact list. This has already been implemented by the Psi+ project and it's working quite nicely.
For auto-join one couldn't show any dialogs at all and just let the items in the contact list indicate whether a join was successful or an error occurred.
The next MUC section that could need some improvement is manually joining a room. You have to go to different places depending if you already know where to join or not.
- You already know the conference you want to join.
- You have the room already bookmarked.
- You have no clue what conference to go in, still you want to chat with other people.
A possibile solution to this problem is providing a single dialog for the general task of 'Joining a MUC'. More on that is soon to follow.
Here comes another short update on my Google Summer of Code project.
Stanza acknowledgement is finally done, including representation in the GUI. You can see a short demonstration of the feature in the video below where I'm chatting with Matthew Wild, one of Prosody's main developers. He developed a module for Prosody that implements parts of Stream Management. This made my client side implementation much more easier to test.
The idea is simple: the status icon in the top left corner is replaced with a throbber animation, known to users from recent OSes and browsers, as long as there are messages that haven't been acked by the server.
Psi will at least request an ack after half a minute. However only if there's something to acknowledge for the server.
This week is mid-term evaluation of the Google Summer of Code projects. SCRAM support and stanza acknowledgement, which is the most important part of the Stream Management XEP, are both finished including GUI.
Here another short update.
Stanza acknowledgement from client to server is working now and chat dialogs get notified when a message sent by them has been acked by the server. The only thing left here is the visual representation in chat dialogs of unacked and acked messages.
After that is done I'll try to add support for session resumption and hopefully get it done till mid-term evaluation next week. Most of this stuff doesn't sound hard to implement however there is currently only one server implementation of XEP-0198 and that one only supports stanza acknowledgement, so it's a bit hard to test my client side implementation of it. XEP-0198 resulted out of long discussions in the XSF on how to improve reliability and the overall experience of chatting over XMPP. It's important that this extension is implemented so we can test in real life whether these changes help or not.
50% of my end semester exams are taken and the rest is following in the next week. After those I'll have plenty of time to start the second big part of this project, UI improvements in Psi.
Here another short update:
Stanza acknowledgement from the server to the client is now done so acknowledgement requests coming from the server get answered correctly. A couple of days ago I've discussed with Justin how the client to server direction is best implemented and at what layer of Iris it's done best. I've modified the default chat dialog so it can be notified when a stanza which originated from it has been acknowledged by the server. This will be displayed to the end user by special coloring of the message or something similar.
- queueing outgoing stanzas for possible resend and also as container of messages that need to be acknowledged
- request an acknowledgment every minute or when the sending queue is bigger than 10
- mark acknowledged and unacknowledged messages differently in the UI
The next two weeks i'll be taking semester exams so I've less time for GSoC coding. However directly after those two weeks there's a semester break for 6 weeks in which all my time is available for GSoC and Psi coding. YAY.
Here the short but little late update on my GSoC project status.
Acking requests coming from the server is basically implemented in Iris. Psi as a client can tell Iris that the last received stanza has been handled and Iris will take care of the rest.
Next on the list: Sending own acking requests to the server so we know the stanzas Psi's send have successfully been handled by the server.
I've finally begun to start implementing Stream Management in C++ for Iris.
Detecting the stream feature and enabling stream management, while sounding like a quite simple task, was a small adventure on its own.
Iris code that handles the whole XMPP login process (STARTTLS, TLS, compression, binding) dates back to 2004. Back then it has been designed as a state machine you run through during login and end up in a simple proxy state. Altogether this approach means mixing the code of complete distinct features like binding and SASL together in a couple of state handling functions using large if/elseif/elseif/... blocks.
Luckily Justin Karneges, the main author of Iris, was online and he could help me out with some debugging.
So what's next on the list: acknowledge the request of the server and sending own requests.
Finally, now that both the XSF and Google packages are underway, it should give me some extra motivation for coding.
SCRAM is a new mechanism designed to let you sign in into your servers much more securely than with existing mechanisms. It involves applying various algorithms to your password to make it extremely difficult to hack.
The SCRAM-SHA-1 SASL mechanism was added to the XMPP spec, and replaces the legacy DIGEST-MD5 mechanism. Its various security features include hashed passwords being send over the internet, and hash passwords being stored on disk. Attackers which can read the network traffic or the server's password database are unable to do any harm.
I just finished a SCRAM-SHA-1 implementation for Psi as part of my GSoC project. There are test cases to write and wider testing to be done, but we now have a working implementation.
What does this mean for Psi users? Well, usually, when you don't want to enter your password each time you login, you tell Psi to save it. Most clients, if not all, store it in clear text form if you tell them to store it at all. This is fairly insecure, and anyone with access to the computer could get access to your password. It's a common security advice that you shouldn't use the same password for all your accounts on various services on the internet. However, human laziness is a powerful force. So, if you use the same password for various services, and someone malicious gains access to it, she/he can gain access into all the other accounts where you used that password.
Now SCRAM comes into play. If your server supports this, and your client supports this, you can have them store your password in a form not very usable by attackers. Thankfully Prosody got some new authentication backend APIs thanks to Jeff Mitchell. You can read more about that in Jeff's blog post. Effectively this means that if a malicious person gains read access to your network or the server, they can't do anything, and if they gain access to your computer, they can do nothing more than login into your jabber account.
What are the consequences of using a hash to login? It basically comes down to support. It requires support by both the client and the server. Only when both have support do you get the full security SCRAM offers. On client side, since you're clearing your plaintext password you have to login using SCRAM in the future. On the server side, you're storing the iteration count, salt and the and two keys instead of the plaintext password. This reduces your possible login methods to only PLAIN (this should only be done over TLS) and SCRAM-SHA-1.
This is currently only available in a development branch. It'll soon get merged into the main branch. To enable this in Psi, first make sure your server supports SCRAM. Then go to the Misc tab in your Account Properties dialog and check the checkbox labelled “Store password as salted hash...”.
Apply the changes. Reconnect.
Now when you visit your Account Properties dialog, you'll notice that the input box for your password is empty. YAY.
So what's next on the agenda for my Google Summer of Code project? Currently I'm a little behind but I'll get started on implementing stanza acknowledgement and session resumption of XEP-0198 the next couple of days to get back on the track.
So coding time of Google Summer of Code 2010 just began and I wanted to put out some introductory note about what I'm planning to archive this summer.
The project consists of mainly four parts:
- implementing the new SCRAM-SHA-1 SASL authentication mechanism
This should be a rather easy part. Adding SCRAM-SHA-1 to Iris, Psi's core XMPP C++ library based on the Qt framework. Additionally I'll try to introduce the ability to store the password in hashed form, if the user wants to store it at all. However this demands you're using a XMPP server supporting the SCRAM SASL mechanism and it's using a constant salt and iteration count.
- implementing XEP-0198 for a more reliable client-to-server connection
XEP-0198 has been developed in the XMPP community because reliability is still a problem when communication over the internet, even when using TCP. This protocol extension provides features like stanza acknowledgment, session resumption and throttling. Using this XEP clients can tell the user that she/he can be sure that the message reached the server or if there has been a problem. No more strange wondering about messages getting lost.
- implementing XEP-0184; this way you can let your chat partner know you've read a message
The guys from the Psi+ project already wrote a patch for this as I found out a couple of days ago. I'll evaluate the patch, merge it and make it works in a decent way. You don't want to spam people with message receipt requests.
- redesigning the multi-user conference join dialog
Currently you have your bookmarked rooms in a drop-down menu, the recent joined MUC rooms in the join dialog and public rooms available at your server are accessible via the service discovery dialog. I'll try to unify those three use cases in a single MUC dialog which should easy to process of joining MUCs.
That's right DIGEST-MD5, your job is done here. Now it's time for the new kid to take up your place.
Those of you who ever tried to actually implement the DIGEST-MD5 SASL mechanism for authentication know that it suffers from quite a few problems, including but not limited to a variety of different implementations with a variable level of compliance to the DIGEST-MD5 RFC 2831. These interoperability problems make it quite hard to get a new implementation working with most of the already existing implementations.
SASL mechanisms are designed to be protocol-independent. That's basically the whole idea about SASL; to abstract the authentication part out of the application protocols, and standardize it. However DIGEST-MD5 already started off on the wrong foot.
Intending to interoperate with digest authentication used for HTTP, the requirement for ISO 8859-1 encoding support was added. However XMPP for example, designed internationally and using latest developments in the DNS area, supports UTF-8 usernames, passwords and IDNs. This makes it hard to store a hashed version of the password since you need to be prepared for either encoding, ISO 8859-1 and UTF-8.
Here comes SCRAM to the rescue. So far I have implemented the basic parts of it in my SASL library which is written in Lua and is a part of Prosody. In the SCRAM draft you can read about the design considerations which are clearly more modern and focused on more international usage.
- Usernames and password are Unicode and are to be string prepped before usage; a feature DIGEST-MD5 doesn't have.
- You can now easily store the user relevant authentication information in a database which isn't by itself sufficient to impersonate the user; this might be possible somehow with DIGEST-MD5 but it clearly hasn't been made easy for the developers (leading to XMPP servers storing plaintext passwords).
- You can simply swap out the basis, the hashing algorithm used, in SCRAM. This makes the mechanism more future proof and secure, unless design issues are found in the protocol itself.
- SCRAM has been designed to be easier to implement than DIGEST-MD5. I totally agree with this. Message parsing has been made easier by using no quotes on values; DIGEST-MD5 used them but only on some values.
One last note on interoperability: I've continuously tested my implementation against Simon Josefsson's implementation for GSASL, which was quite easy to set up thanks to GSASL's command line interface. Shortly after, I also did interoperability testing against the SCRAM implementation by Paul Aurich for Pidgin, in which we both fixed some bugs. A Prosody instance is still running for interoperability testing at scram-interop.ayena.de. Last but not least, we're working nicely against Swift; however no end-users can be happy about that currently;).
So client and server developers, get ready for SCRAM and implement support for it for a more interoperable future; not to forget its being the MTI mechanism for the next XMPP RFC iterations.
Due to Waqas's asking for months now I've finally got around and made some benchmarks on two string prepping libraries. The one being libidn, as far as I know most XMPP servers use this and the other being ICU by IBM.
libidn is LGPL licensed and ICU is MIT licensed.
Current XMPP standard says that every JID must be string prepped so if you don't want to cache because of memory reasons your string prepping routines are called quite often. It turns out ICU is much faster than libidn. For this benchmark I tested a couple of strings and let them go through nameprep, resourceprep and nodeprep profiles via string prepping.
The result is that ICU is about 60 times faster in string prepping. Version of libidn being 1.15 and of ICU being 220.127.116.11.
The source code package of the benchmark is attached to this node. It falls under GPLv3 license.