<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>░░ fzysqr</title>
	<atom:link href="http://fzysqr.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://fzysqr.com</link>
	<description></description>
	<lastBuildDate>Wed, 01 Feb 2012 04:09:28 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>node grinding the crack (between Windows and Linux)</title>
		<link>http://fzysqr.com/2011/11/13/node-grinding-the-crack/</link>
		<comments>http://fzysqr.com/2011/11/13/node-grinding-the-crack/#comments</comments>
		<pubDate>Mon, 14 Nov 2011 05:51:20 +0000</pubDate>
		<dc:creator>jslatts</dc:creator>
				<category><![CDATA[dev]]></category>

		<guid isPermaLink="false">http://fzysqr.com/?p=566</guid>
		<description><![CDATA[Let me apologize up front for the terrible title. I have been recently inspired. I met some fantastic people at the fantastic Keeping It Realtime Conference last week. The speakers were great. The conversations were fantastic. The parties were fun. I will go again next year. There was so much information to consume that I [...]]]></description>
			<content:encoded><![CDATA[<p>Let me apologize up front for the terrible title. I have been recently <em><a href="http://www.youtube.com/watch?v=TWfph3iNC-k">inspired</a>.</em></p>

<p>I met some fantastic people at the <strong>fantastic</strong> <a href="http://krtconf.com/">Keeping It Realtime Conference</a> last week. The speakers were great. The conversations were fantastic. The parties were fun. I will go again next year. There was so much information to consume that I am just now sorting some of it out. In my mind, the experience plays backs like ten thousand snapshots in rapid succession. A blur of events, conversations, people, code, and crappy wifi. A couple of faces stand out: the crew from Microsoft, Paul Batum, Glenn Block, and of course Scott Hanselman. They left a big impression on me. Not because I was in shock that Microsoft was actually represented at this event (though I was), or that these guys were deep behind enemy lines (you should have seen the mac/win ratio), or because they were all wickedly smart (they were). No, it was that Microsoft seems to be genuinely making a go of supporting node on Windows and it actually looks pretty good.</p>

<p>Okay. So what does this have to do with base jumping wingsuit insanity? Well, dear reader, not much. But I&#8217;ll try and tie it back. If you browse back through my archives or follow me on twitter, you will get a lot of Linux and node content. But every so often, something Windowsy slips through. You see, the truth is: I am .NET developer. Or at least I used to be. Now, I manage a team of developers&#8211;a mixed team. We are about 50/50 .NET and Django with a sprinkle of node on top. Our various products have to integrate with each other and I make platform decisions on a daily basis where I am pitting a Windows stack against a Linux one. In short, I &#8220;grind the crack&#8221; between them. But without the wingsuit and inevitable spectacular death.</p>

<p>Back to the conference. At the opening event, I met Glenn and Paul. I had a great discussion with them about where my team is and where we are going. I like node and I see some great use cases for it in our business. At one point, Glenn asked me, &#8220;What would it take to you get you choose windows?&#8221; I answered that it was probably too late for us, &#8220;We have node programs running on Linux. Why would we switch?&#8221; I told him that I wholeheartedly supported node on Windows for the good of the node community, but that we were already past the point of needing it ourselves.</p>

<p>Fast forward two days. I make sure to attend Glenn&#8217;s and Tomasz&#8217;s talk on node for Windows (the main point behind the recent 0.6.X release by the way). I didn&#8217;t expect to hear anything I wasn&#8217;t already aware of. And I was surprised. Floored even. They have actually done a great job creating a Windows &#8220;story&#8221; for node. They want you to run node with IIS. If you do that, you get some <a href="http://tomasz.janczuk.org/2011/08/hosting-nodejs-applications-in-iis-on.html">pretty awesome stuff</a> for free:</p>

<ul>
<li>built-in process management ala <a href="http://blog.nodejitsu.com/keep-a-nodejs-server-up-with-forever">forever</a></li>
<li>load balancing between node processes</li>
<li><em>graceful</em> auto-refresh of the node process when code changes</li>
<li>remote node-inspector (hell yes!)</li>
<li>logs over http </li>
</ul>

<p>Yes, I know you can get all these things on Linux. And, maybe there are arguments to be made about scaling (haven&#8217;t seen benchmarks, so I have no idea). But you know what? I <em>don&#8217;t have</em> scaling issues. We have a modest user base. Our biggest challenges are building a great experience for our users, integrating disparate systems, and maintaining our automated deployment and testing infrastructure. With iisnode, I can just include the node javascript along side our existing .NET app and ship it with the same TeamCity deployment. I won&#8217;t even need to restart IIS!</p>

<p>We were already planning on using node and WebSockets to bring some realtime features to our ASP.NET MVC app and Microsoft just made my life <em>simpler</em>. Glenn: you got me back (at least partly). I am excited to see what you guys do next.</p>

<p>Bravo.</p>
]]></content:encoded>
			<wfw:commentRss>http://fzysqr.com/2011/11/13/node-grinding-the-crack/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Quick vim tip #1 (and I am not dead)</title>
		<link>http://fzysqr.com/2011/09/24/vimtip1/</link>
		<comments>http://fzysqr.com/2011/09/24/vimtip1/#comments</comments>
		<pubDate>Sat, 24 Sep 2011 16:55:41 +0000</pubDate>
		<dc:creator>jslatts</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://fzysqr.com/?p=559</guid>
		<description><![CDATA[Sorry for the summer hiatus. Work, vacation, and mountain biking put a serious squeeze on my free time hacking and blogging activities. I have been working on some cool stuff lately and the cold weather is starting to arrive here in Spokane, so I should have plenty of blog posts coming up. Anyway, quick vim [...]]]></description>
			<content:encoded><![CDATA[<p>Sorry for the summer hiatus. Work, vacation, and mountain biking put a serious squeeze on my free time hacking and blogging activities. I have been working on some cool stuff lately and the cold weather is starting to arrive here in Spokane, so I should have plenty of blog posts coming up.</p>

<p>Anyway, quick vim tip #1. If I have a chunk of a code with a string:</p>

<pre><code>var blah = "Some string that I want to replace" + previouslyDefinedVariable
</code></pre>

<p>I want to replace it with &#8220;new string&#8221;. In vim, do:</p>

<ol>
<li>Put your cursor on the first character inside the quotes of the string you want to end up with, in our case, the <em>n</em> from &#8220;new string&#8221;.</li>
<li>Type yi&#8221; &#8211; yank inbetween quotes</li>
<li>Navigate to the string you want to replace</li>
<li>Type di&#8221; &#8211; delete inbetween quotes</li>
<li>&#8220;0P &#8211; paste content from yank buffer</li>
<li>Marvel at your vim prowess.</li>
</ol>

<p>Got any great vim tips? I would love to here about them. Send them to <a href="mailto:vimtips@fzysqr.com">vimtips@fzysqr.com</a>. Check out my full vim config fork of scrooloose&#8217;s config on github (here)[https://github.com/jslatts/vimfiles].</p>

<p><strong>Updated</strong> Cory Schmitt wrote in with a helpful suggestion that saves two keystrokes!</p>

<ol>
<li>Put your cursor on the first character inside the quotes of the string you want to end up with, in our case, the <em>n</em> from &#8220;new string&#8221;.</li>
<li>Type yi&#8221; &#8211; yank inbetween quotes</li>
<li>Navigate to the string you want to replace</li>
<li>Type vi&#8221;p &#8211; visual mode select inbetween quotes and paste over</li>
<li>Congratulate yourself for being awesome.</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://fzysqr.com/2011/09/24/vimtip1/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Version 0.0.9 of Stalker for node.js is available</title>
		<link>http://fzysqr.com/2011/06/20/version-0-0-9-of-stalker-for-node-js-is-available/</link>
		<comments>http://fzysqr.com/2011/06/20/version-0-0-9-of-stalker-for-node-js-is-available/#comments</comments>
		<pubDate>Tue, 21 Jun 2011 05:38:14 +0000</pubDate>
		<dc:creator>jslatts</dc:creator>
				<category><![CDATA[dev]]></category>

		<guid isPermaLink="false">http://fzysqr.com/2011/06/20/version-0-0-9-of-stalker-for-node-js-is-available/</guid>
		<description><![CDATA[I have just released 0.0.9 of Stalker. Improvements (some from 0.0.7 as well) are: Added batch mode to group callbacks Added second callback for file removal notices (this works in batch mode as well) Switched unit tests to vows.js and added additional coverage Made errors callback immediately in standard node-fashion. Fixed bugs Get it on [...]]]></description>
			<content:encoded><![CDATA[<p>I have just released 0.0.9 of Stalker. Improvements (some from 0.0.7 as well) are:</p>

<ul>
<li>Added batch mode to group callbacks</li>
<li>Added second callback for file removal notices (this works in batch mode as well)</li>
<li>Switched unit tests to vows.js and added additional coverage</li>
<li>Made errors callback immediately in standard node-fashion.</li>
<li>Fixed bugs</li>
</ul>

<p>Get it on npm now or head to <a href="https://github.com/jslatts/stalker">github</a>.</p>

<p>Thank you for all the feedback.</p>
]]></content:encoded>
			<wfw:commentRss>http://fzysqr.com/2011/06/20/version-0-0-9-of-stalker-for-node-js-is-available/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Introducing stalker, a node.js module. Now your files can get restraining orders against you too.</title>
		<link>http://fzysqr.com/2011/06/08/introducing-stalker-a-node-js-module-now-your-files-can-get-restraining-orders-against-you-too/</link>
		<comments>http://fzysqr.com/2011/06/08/introducing-stalker-a-node-js-module-now-your-files-can-get-restraining-orders-against-you-too/#comments</comments>
		<pubDate>Thu, 09 Jun 2011 05:14:00 +0000</pubDate>
		<dc:creator>jslatts</dc:creator>
				<category><![CDATA[dev]]></category>

		<guid isPermaLink="false">http://fzysqr.com/2011/06/08/new-node-js-module/</guid>
		<description><![CDATA[I released my first node.js module today on npm, aptly named stalker. stalker is basically a wrapper around fs.watchFile(). It will watch a directory tree for new files and fire off your callback whenever it finds one. It tries to be smart about entire nested folder/file structures and tricksy add/removal/add type of stuff. Get it [...]]]></description>
			<content:encoded><![CDATA[<p>I released my first node.js module today on npm, aptly named stalker. stalker is basically a wrapper around fs.watchFile(). It will watch a directory tree for new files and fire off your callback whenever it finds one. It tries to be smart about entire nested folder/file structures and tricksy add/removal/add type of stuff.</p>

<p>Get it on npm: <em>npm install stalker</em></p>

<p>You can test it by running <em>node example/test.js</em> and then dropping files and folders in the example directory.</p>

<p>To incorporate it in your program, simply call stalker.watch with your callback:</p>

<pre><code>stalker.watch('/var/foo', function(err, file) {
  console.log('stalker saw file %s', file);
});
</code></pre>

<p>Code is at github: <a href="https://github.com/jslatts/stalker">https://github.com/jslatts/stalker</a></p>
]]></content:encoded>
			<wfw:commentRss>http://fzysqr.com/2011/06/08/introducing-stalker-a-node-js-module-now-your-files-can-get-restraining-orders-against-you-too/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>node-inspector and the missing &#8211;start-brk option</title>
		<link>http://fzysqr.com/2011/05/29/node-inspector-and-the-missing-start-brk-option/</link>
		<comments>http://fzysqr.com/2011/05/29/node-inspector-and-the-missing-start-brk-option/#comments</comments>
		<pubDate>Sun, 29 May 2011 19:47:26 +0000</pubDate>
		<dc:creator>jslatts</dc:creator>
				<category><![CDATA[dev]]></category>
		<category><![CDATA[nodejs]]></category>

		<guid isPermaLink="false">http://fzysqr.com/2011/05/29/node-inspector-and-the-missing-start-brk-option/</guid>
		<description><![CDATA[Quick tip to anyone having trouble finding the right way to start a node-inspector debugging session with an initial break point. Lot&#8217;s of youtubes and how-to&#8217;s mention a &#8211;start-brk=file.js option. If you try and actually use it, it doesn&#8217;t work. The correct way to do this now is: node-inspector &#38; node --debug-brk --debug server.js Head [...]]]></description>
			<content:encoded><![CDATA[<p>Quick tip to anyone having trouble finding the right way to start a node-inspector debugging session with an initial break point. Lot&#8217;s of youtubes and how-to&#8217;s mention a &#8211;start-brk=file.js option. If you try and actually use it, it doesn&#8217;t work. The correct way to do this now is:</p>

<pre><code>node-inspector &amp;
node --debug-brk --debug server.js 
</code></pre>

<p>Head to http://0.0.0.0:8080/debug?port=5858 to find your app nicely stopped on the first line.</p>

<p>Happy noding!</p>
]]></content:encoded>
			<wfw:commentRss>http://fzysqr.com/2011/05/29/node-inspector-and-the-missing-start-brk-option/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Kilnauth Plugin for Mercurial on a Mac</title>
		<link>http://fzysqr.com/2011/05/21/kilnauth-plugin-for-mercurial-on-a-mac/</link>
		<comments>http://fzysqr.com/2011/05/21/kilnauth-plugin-for-mercurial-on-a-mac/#comments</comments>
		<pubDate>Sat, 21 May 2011 16:36:21 +0000</pubDate>
		<dc:creator>jslatts</dc:creator>
				<category><![CDATA[dev]]></category>

		<guid isPermaLink="false">http://fzysqr.com/2011/05/21/kilnauth-plugin-for-mercurial-on-a-mac/</guid>
		<description><![CDATA[Do you use Kiln from FogCreek? Do you use a Mac? Are you having trouble getting the kilnauth plugin to work on your Mac? If so, you probably have a bad hgcookies file. To fix: Find a colleague with Windows who has a properly functioning kiln client (or follow the process in this kiln stackexchange [...]]]></description>
			<content:encoded><![CDATA[<p>Do you use <a href="http://www.fogcreek.com/kiln/">Kiln</a> from <a href="http://www.fogcreek.com/">FogCreek</a>? Do you use a Mac? Are you having trouble getting the kilnauth plugin to work on your Mac? If so, you probably have a bad hgcookies file. To fix:</p>

<ol>
<li>Find a colleague with Windows who has a properly functioning kiln client (or follow the process in this <a href="http://kiln.stackexchange.com/questions/2574/i-have-kilnauth-installed-but-i-keep-getting-prompted-for-my-credentials-whats">kiln stackexchange post</a>).</li>
<li>Have them open up their user profile and look for an _hgookies folder. Open the cookie file inside.</li>
<li>There will be a line that looks something like (DBID&#8217;s have been changed to protect the innocent):
 servername    FALSE    /    FALSE  DBID    o1sev3t3dn01dabdppin90wexczimb</li>
<li>Have them send you the DBID value</li>
<li>On your Mac, open the cookie in your ~/.hgcookies/ and add the missing DBID value.</li>
<li>You might have to hg logout, then try an hg get/in to put your credentials in. After that it should stop prompting you.</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://fzysqr.com/2011/05/21/kilnauth-plugin-for-mercurial-on-a-mac/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Impress your friends with client side updates</title>
		<link>http://fzysqr.com/2011/05/16/impress-your-friends-with-client-side-updates/</link>
		<comments>http://fzysqr.com/2011/05/16/impress-your-friends-with-client-side-updates/#comments</comments>
		<pubDate>Tue, 17 May 2011 02:32:20 +0000</pubDate>
		<dc:creator>jslatts</dc:creator>
				<category><![CDATA[dev]]></category>
		<category><![CDATA[node.js]]></category>
		<category><![CDATA[socket.io]]></category>

		<guid isPermaLink="false">http://fzysqr.com/?p=540</guid>
		<description><![CDATA[Of the many life lessons I have learned creating nodechat.js, one of the most poignant was that people like to leave their browsers (and tabs) open for a long time. This should not have been a surprise to me&#8211;I often have tabs open for weeks in the vain hope that I will get back to [...]]]></description>
			<content:encoded><![CDATA[<p>Of the many life lessons I have learned creating <a href="http://nodechat.no.de/">nodechat.js</a>, one of the most poignant was that people like to leave their browsers (and tabs) open for a <em>long</em> time. This should not have been a surprise to me&#8211;I often have tabs open for weeks in the vain hope that I will get back to whatever I was doing on that page someday. This phenomena meant that users would log into nodechat, click away to another tab (or restart their browser, or suspend their PC), only to revist the nodechat tab later and find that the chat appeared frozen. The same issue occured everytime I pushed a new server update: all clients would be cut off until the user refreshed the page. Clearly this was a subpar user exeperience. This is how I fixed it.</p>

<p><span id="more-540"></span></p>

<p>There are three main parts to my eventual solution:</p>

<ul>
<li>Socket.IO reconnection</li>
<li>client versioning</li>
<li>pushed client updates</li>
</ul>

<p>Using the same techniques used in nodechat.js, we will write a simple node.js + socket.io application that displays it&#8217;s version number and can be remotely updated. If you are unfamiliar with <a href="http://nodejs.org/">Node.js</a> or <a href="http://socket.io/">Socket.IO</a>, you might want to checkout the <a href="http://fzysqr.com/2011/02/28/nodechat-js-using-node-js-backbone-js-socket-io-and-redis-to-make-a-real-time-chat-app/">original nodechat tutorial</a> first.</p>

<h2>Setup</h2>

<p>Before the fun starts, we need to perform a little setup. I tried to keep this project as simple as possible, so please excuse any and all bad practices you see.</p>

<p>First, create a project directory. Within it, install these modules using npm:</p>

<pre><code>npm install express
npm install socket.io
npm install jade
</code></pre>

<p>Then create the following directory structure and empty files:</p>

<pre><code>project/
-server.js
-views/
--index.jade
-public/
--js/
---jquery-1.5.1.js
</code></pre>

<p><em>server.js</em> will contain all of our server-side application code. <em>index.jade</em> will server up the client-side application code and the minimal layout. jQuery is included to make our life easier.</p>

<p>The contents of <em><a href="https://github.com/jslatts/fzysqr_demo_client_version_updates/blob/initial/server.js">server.js</a></em> should be as follows. Explanations are in-line:</p>

<pre><code>//Include our various dependencies for this demo and set up socket.io to work with express
var express = require('express')
    , app = express.createServer()
    , io = require('socket.io')
    , socket = io.listen(app)
    , version = '1.1.awesome';

//Tell express where to find our jQuery library
app.use(express.static('./public'));

//Setup express to render index.jade to any client requesting '/'. 
app.get('/', function (req, res) {
    res.render('index.jade', { 
        locals: { version: version } //Send the version variable we defined above to the template
        , layout: false              //Tells jade we aren't going to use a layout.jade base template
    });
});

//Make express hang out and listen for incoming connections
app.listen(8000);
</code></pre>

<p>The contents of <em><a href="https://github.com/jslatts/fzysqr_demo_client_version_updates/blob/initial/views/index.jade">index.jade</a></em> should be as follows:</p>

<pre><code>!!! 5
html(lang='en')
  head
    title fzysqr.com client updating demo
    script(type='text/javascript', src='/js/jquery-1.5.1.js')
    script(type='text/javascript', src='/socket.io/socket.io.js')
    script
      $(document).ready(function () { 
        //Crockford compliance! Define all the need variables here
        var socket;

        //- Setup the socket library. The rememberTransport and tryTransportsOnConnectTimeout 
        //- are neccessary because the defaults will cause some browsers to degrade to 
        //- crappy transports when they are disconnected (think suspended laptop) and will 
        //- subsequently stick on said crappy transport even after the network is up again.
        socket = new io.Socket(null, {
            rememberTransport: false
            , tryTransportsOnConnectTimeout: false 
        });

        //- Simple connect event so we can see that we are connecting
        socket.on('connect', function () { 
            console.log('Connected! Oh hai!');
        }); 

        //- Start the connection
        socket.connect();
      });
  body
    p Hello fzysqr.com reader! 
      br
      br
      | This is version:
    //- Render the version variable
    h1 #{version}
</code></pre>

<p>Once you have all the pieces in place, run <em>node server.js</em> and point your browser to http://localhost:8000/. You should see something like:</p>

<p><img src="http://fzysqr.com/wp-content/uploads/2011/05/screen1.png" alt="Example screenshot" title="Example sceenshot" /></p>

<p>Now we are ready to have some fun!</p>

<h2>Reconnectionism</h2>

<p>As web applications have become richer, user expectations of a traditional thick client software like experience has increased. You simply expect Gmail to reconnect when you open your laptop. Likewise, if nodechat detects that a connection is disrupted, it will display a notice to the user and attempt to reconnect every 30 seconds until it succeeds (or the user closes the tab). Let&#8217;s modify our new app to do the same.</p>

<p>All of the required changes are in <em><a href="https://github.com/jslatts/fzysqr_demo_client_version_updates/blob/reconnection/views/index.jade">index.jade</a></em>. Here are the deltas:</p>

<pre><code>....

//Crockford compliance! Define all the need variables here
var socket, connected, trying, tryConnect;

....

//- Log our connection even and hide the disconnectMessage element in case 
//- we are reconnecting after an interuption
socket.on('connect', function () { 
    console.log('Connected! Oh hai!');
    $('#disconnectMessage').hide();
}); 

//- This method checks to see if we are connected, if not, tell socket.io to connect 
//- and reset a timeout to check again in 30 seconds.
tryConnect = function () {
    if (!connected) {
        console.log('Trying to reconnect...');
        socket.connect();
        clearTimeout(trying);
        trying = setTimeout(tryConnect, 30000);
    }
};

//- Handle disconnection by displaying a notice to the user and
//- setting a timer to try connecting in 500ms. 
socket.on('disconnect', function () {
    console.log('Disconnected. Oh noes!');
    connected = false;
    trying = setTimeout(tryConnect, 500);
    $('#disconnectMessage').show();
});

....
</code></pre>

<p>We define a handler for the <em>disconnect</em> event from the socket object (which is an <a href="http://nodejs.org/docs/v0.4.7/api/events.html#events">EventEmitter</a>) and use a timer to try to reconnect the socket.io connection repeatedly until it succeeds. Go ahead and fire it up again (<em>node server.js</em>) and go back to http://localhost:8000/. Initially, you should see the same thing as before:</p>

<p><img src="http://fzysqr.com/wp-content/uploads/2011/05/screen1.png" alt="Initial connection screenshot" title="Initial connection sceenshot" /></p>

<p>Then if you kill the node server with ctrl-c, you should see this:</p>

<p><img src="http://fzysqr.com/wp-content/uploads/2011/05/screen2.png" alt="Disconnected screenshot" title="Disconnected sceenshot" /></p>

<p>Then if you restart the node server and wait patiently (up to 30 seconds), the client should reconnect again and you should see this again:</p>

<p><img src="http://fzysqr.com/wp-content/uploads/2011/05/screen1.png" alt="Initial connection screenshot" title="Initial connection sceenshot" /></p>

<h2>Client updates</h2>

<p>Once nodechat was able to reconnect clients, I noticed a big spike in channel retention. People were able to stay connected/reconnected for weeks at a time. They were also able to reconnect after I shipped a new version of nodechat. This introduce a whole new problem. What happens if we deploy a breaking change to the code? The clients reconnect and promptly crash. Not good UX. Even if I am careful to maintain backwards compatibility, I still want to make sure that long running clients see improvements and bug fixes in the client-side code. To handle this, clients listen for a special upgrade message from the server and react accordingly.</p>

<p>This time we have some changes in <em><a href="https://github.com/jslatts/fzysqr_demo_client_version_updates/blob/version_update/server.js">server.js</a></em>. Once again, deltas only:</p>

<pre><code>//Handle the connect event for the socket.io server in order to send out the 
//current codebase version to any connecting clients.
socket.on('connection', function(client) {
    client.send({
        event: 'version'
        , data: version
    });
});
</code></pre>

<p>Then, in <em><a href="https://github.com/jslatts/fzysqr_demo_client_version_updates/blob/version_update/views/index.jade">index.jade</a></em>, we add a new variable to track the version and a handler for incoming socket messages on the client. If we received the version update message, we force a refresh:</p>

<pre><code>....

//Crockford compliance! Define all the need variables here
var socket, connected, trying, tryConnect
    , version = '#{version}';       //Keep track of the code version at the time this page was rendered

....

//- Handle the message event to see if we are getting a version message from the server
//- If we do, check it's contents to make sure we are on the latest and greatest. If we
//- are out of date, force a reload to get the latest code.
socket.on('message', function (msg) {
    if (msg &amp;&amp; msg.event === 'version' &amp;&amp; version !== msg.data) {
        setTimeout(function() {
            window.location.reload();
        }, 5000);
    }
});

....
</code></pre>

<p>That&#8217;s it! All the pieces are in place. Fire up the server and try it out. When we first connect to http://localhost:8000/, you expect to see the same screen as before:</p>

<p><img src="http://fzysqr.com/wp-content/uploads/2011/05/screen1.png" alt="Initial connection screenshot" title="Initial connection sceenshot" /></p>

<p>Then kill the node server and you should see this:</p>

<p><img src="http://fzysqr.com/wp-content/uploads/2011/05/screen2.png" alt="Disconnected screenshot" title="Disconnected sceenshot" /></p>

<p>Now, go into <em>server.js</em> and update the version to something else:</p>

<pre><code>, version = '1.2.awesomer';
</code></pre>

<p>Save the file and start up the node server again. Switch back to the web browser and <strong>wait</strong>. Do <em>NOT</em> reload the browser. You should first see the 1.1 version reconnect:</p>

<p><img src="http://fzysqr.com/wp-content/uploads/2011/05/screen1.png" alt="Reconnection screenshot" title="Reconnection sceenshot" /></p>

<p>Then, after another view seconds, the browser should reload the whole page and display:</p>

<p><img src="http://fzysqr.com/wp-content/uploads/2011/05/screen3.png" alt="New version screenshot" title="New version sceenshot" /></p>

<h2>Wrapping up</h2>

<p>The full source for this tutorial can be found <a href="https://github.com/jslatts/fzysqr_demo_client_version_updates">here</a> on github. The three different tags represent the three different stages in this tutorial.</p>

<p>This type of client versioning is going to be old hat for anyone who has done serious work in real time web applications, but it was not immediately obvious to me when I first dove into node.js and Socket.IO. Having the ability to pull all my clients along when I deploy a new version has made it easier to push bug fixes and feature to nodechat without dropping the whole channel off-line every time.</p>

<p>As always, I welcome any comments, questions, or suggestions. Find me on twitter (<a href="https://twitter.com/#!/jdslatts">@jdslatts</a>) or drop by <a href="http://nodechat.no.de/">nodechat</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://fzysqr.com/2011/05/16/impress-your-friends-with-client-side-updates/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Sending your clients to purgatory (a node.js/socket.io tutorial)</title>
		<link>http://fzysqr.com/2011/04/11/sending-your-clients-to-purgatory-a-node-jssocket-io-tutorial/</link>
		<comments>http://fzysqr.com/2011/04/11/sending-your-clients-to-purgatory-a-node-jssocket-io-tutorial/#comments</comments>
		<pubDate>Mon, 11 Apr 2011 13:48:42 +0000</pubDate>
		<dc:creator>jslatts</dc:creator>
				<category><![CDATA[dev]]></category>
		<category><![CDATA[nodejs]]></category>
		<category><![CDATA[socketio]]></category>

		<guid isPermaLink="false">http://fzysqr.com/?p=518</guid>
		<description><![CDATA[Updated As has been pointed out, sending the username and password hash over to the client is not the most secure thing you can do. I wholeheartedly agree. Please do not do this on anything for real-ish. Treat this tutorial as a simple demo of how to isolate a connection until you give it some [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Updated</strong> As has been pointed out, sending the username and password hash over to the client is not the most secure thing you can do. I wholeheartedly agree. Please do not do this on anything <em>for real</em>-ish. Treat this tutorial as a simple demo of how to isolate a connection until you give it some sort of approval. A much better approach would be to use a one-time throw away key or create a salted hash using the incoming client&#8217;s IP address. Or probably a million other things. The concept of isolating a connection to socket.io within a closure still applies.</p>

<p>Now back to your regularly scheduled programming:</p>

<p>One of the problems I have had with <a href="http://nodechat.no.de/">nodechat.js</a> is that using sessions to handle the transition of authenticated users between express and socket.io has always been somewhat finicky.</p>

<p>Nodechat.js and the previous nodechat-tutorials have used sessions to manage this transition by storing a username and password in the session after initial login and making it available to the socket.io listener on new connections and during each message. While adequate most of the time, this method never worked correctly with all the various socket.io transports and it seemed like clients would frequently get <em>stuck</em> when reconnecting, requiring them to reload the page to get back into nodechat.js.</p>

<p>I now have a pretty decent way to address this issue and I am going to share it with you. A little technique I came up with that I call Purgatory&#8230;</p>

<p><span id="more-518"></span></p>

<p>The goal of this tutorial is to set up nodechat to authenticate clients initially through connect/express and then to pass that authentication along to a subsequent socket.io connection without relying on the session.</p>

<p>Before we get started, a few notes:</p>

<ul>
<li>The code can be found on the <a href="https://github.com/jslatts/nodechat-tutorial/tree/v0.3">v0.3 tag on github</a> if you want to follow along. </li>
<li>This tutorial was written with npm 1.0RC, so I have been able to include all dependencies in the source code. </li>
<li>I am going to assume you are comfortable with node/socket or have at least worked through the <a href="http://fzysqr.com/2011/02/28/nodechat-js-using-node-js-backbone-js-socket-io-and-redis-to-make-a-real-time-chat-app/">previous</a> <a href="http://fzysqr.com/2011/03/27/nodechat-js-continued-authentication-profiles-ponies-and-a-meaner-socket-io/">two</a> nodechat tutorials.</li>
</ul>

<p>In standard fzysqr tutorial style, we will just march through the important bits of code, explaining as we go.</p>

<h2>Views</h2>

<p>We start off by making a few views. First up, our login page:</p>

<p><strong>login.jade</strong></p>

<p>Crate views/login.jade as follows:</p>

<pre><code>!!! 5
html(lang="en")
  head
    title nodechat login
  body
    #heading
      h1 nodechat login
    #content
      p
        | please login 
      form(method="post", action="/")
        div(style='width:200px; text-align:right')
          label username:
            input(type='text', name='username')
          br
          label password:
            input(type='password', name='password')
          br
          input(type='submit', value='login')
      p
        | or create an account 
      form(method="post", action="/")
        div(style='width:200px; text-align:right')
          label username:  
            input(type='text', name='username')
          br
          label password:  
            input(type='text', name='password')
          br
          label email:  
            input(type='text', name='email')
          br
          input(type='submit', value='signup &amp; login')
</code></pre>

<p>We have a single login/signup page that uses two different forms to handle their respective duties. The password is not hidden when signing up for a new account. Both forms post to the same URI, and we use the existence of the email field to tell which one was used.</p>

<p><strong>index.jade</strong></p>

<p>Next make views/index.jade as follows:</p>

<pre><code>!!! 5
html(lang="en")
  head
    title nodechat
    script(type="text/javascript", src="/lib/jquery-1.5.1.js")
    script(type="text/javascript", src="/lib/underscore.js")
    script(type="text/javascript", src="/lib/backbone.js")
    script(type="text/javascript", src="/socket.io/socket.io.js")
    script(type="text/javascript", src="/models/models.js")
    script(type="text/javascript", src="/controllers/controllers.js")
    script(type="text/javascript", src="/views/views.js")
    script
      //Fake out FF and IE8
      function log() {
          if (typeof console == 'undefined') {
              return;
          }
          console.log.apply(console, arguments);
      }

      $(document).ready(function () { 
          window.app = NodeChatController.init({hashpassword: !{locals.hashpassword}, userName: '!{locals.name}'}); 
      });
  body
    #heading
      h1 nodechat
    #content
      p 
        | connected clients
        span#client_count 0
      p 
        a(href='/logout') logout

      p
        label You are logged in as: 
          = locals.name 
      p
        | Fun Chat Messages
        ul#chat_list

      form(method="post", action="#", onsubmit="return false")#messageForm
        p
          label Message:
            input(type='text', name='message')
            input(type='submit', value='send')
</code></pre>

<p>This page serves up the actual chat UI. It includes the necessary dependencies, sets up the console logging and initializes the controller. The username and hashpassword are stored in the locals collection and replaced by express when the template is rendered. In turn, the parameters are passed to the controller for use later.</p>

<p><strong>views.js and models.js</strong></p>

<p>The backbone views are defined in the views/views.js folder. I won&#8217;t go over each view, as they are largely unchanged from the previous tutorials. Just <a href="https://github.com/jslatts/nodechat-tutorial/blob/v0.3/views/views.js">pull the file from github</a> and place in views.</p>

<p>We have the same story with models.js. It is basically the same as previous tutorials. Just <a href="https://github.com/jslatts/nodechat-tutorial/blob/v0.3/models/models.js">pull the file from github</a> and place in models.</p>

<p><strong>clientauthrequest</strong></p>

<p>We have seen how the username/hashpassword are passed into the controller during instantiation. Now let&#8217;s look at the controller:</p>

<pre><code>var NodeChatController = {
    init: function(options) {
        var mySocket, user, view, hashpassword;

        this.socket = new io.Socket(null, {port: 8001});
        mySocket = this.socket;
        user = this.userName = options.userName;
        hashpassword = this.hashpassword = options.hashpassword

        this.model = new models.NodeChatModel();
        this.view = new NodeChatView({model: this.model, socket: this.socket, el: $('#content')});
        view = this.view;

        this.socket.on('connect', function () { 

            mySocket.send({
                event: 'clientauthrequest'
                , user: user
                , hashpassword: hashpassword
            });

            log('Connected! Oh hai!');
        }); 

        this.socket.on('message', function(msg) {view.msgReceived(msg)});
        this.socket.connect();

        this.view.render();

        return this;
    }
};
</code></pre>

<p>The controller stores the username and hashpassword and sets up an <em>on connect</em> event handler to send them back to the server as a &#8220;clientauthrequest&#8221; message.</p>

<p>Which brings us to <em>Purgatory</em>.</p>

<h2>Purgatory</h2>

<p>Previously, our session based authentication went something like:</p>

<ol>
<li>[server] User submits username/password to login form.</li>
<li>[server] Check username/password by calculating the hash and comparing the information to what has been stored.</li>
<li>[server] If it matches, store a user object in the session.</li>
<li>[server] Redirect to &#8216;/&#8217; and load the client-side code.</li>
<li>[client] The client fires up and connects back to the server.</li>
<li>[server] On incoming connection, the server checks the session for a valid user object and allows the connection.</li>
<li>[server] On incoming messages, the server checks the session for a valid user object and allows the message.</li>
</ol>

<p>The process relies on the socket transport having access to the session cookie and that is what makes it unreliable.</p>

<p>The new, session-less process is:</p>

<ol>
<li>[server] User submits username/password to login form.</li>
<li>[server] Check username/password by calculating the hash and comparing the information to what has been stored.</li>
<li>[server] If it matches, send the rendered index.jade template to the client with the username/hashpassword as part of the rendered html.</li>
<li>[client] The client fires up and connects back to the server.</li>
<li>[server] The server places client connection in purgatory.</li>
<li>[client] The client sends a &#8220;clientauthrequest&#8221; message back to the server.</li>
<li>[server] On incoming message, the server checks to see if the client is in purgatory. It is, so the credentials are verified.</li>
<li>[server] The authentication passes, so the client connection is removed from purgatory.</li>
<li>[server] On future incoming messages, the messages are known to be from an authenticated client and are allowed to pass.</li>
</ol>

<h2>Core.js</h2>

<p>Let&#8217;s look at the pieces that make this happen in core.js:</p>

<p><strong>routes</strong></p>

<pre><code>app.get('/', function (req, res) {
    res.render('login');
});

app.post('/', function (req, res) {
    signInAccount(req, res)
});
</code></pre>

<p>We only need to handle two routes: GET &#8216;/&#8217; and POST &#8216;/&#8217;. For get, render <em>login.jade</em>. For POST, call signInAccount().</p>

<p><strong>signInAccount</strong></p>

<pre><code>function signInAccount(req, res) {
    if (req.body.email) {
        auth.createNewUserAccount(req.body.username, req.body.password, req.body.email, function (err, user) {
            if ((err) || (!user)) {
                es.redirect('back');
            }
            else if (user) {
                res.render('index', {
                    locals: { name: user.name, hashpassword: JSON.stringify(user.hashpassword) }
                });
            }
        });
    }
    else {
        auth.authenticateUser(req.body.username, req.body.password, function (err, user) {
            if (err) {
                winston.error('[signInAccount][authenticateUser][fn] Error: ' + err);
            }

            if (user) {
                res.render('index', {
                    locals: { name: user.name, hashpassword: JSON.stringify(user.hashPass) }
                });
            } 
            else {
                res.redirect('back');
            }
        });
    }
}
</code></pre>

<p>signInAccount() determines whether we are logging in, or creating a new account by checking the request object for an email form field. Upon successful authentication or account creation, the username and hashed password are passed to express in the local variables collection and rendered into the index template.</p>

<p><strong>socket event handler</strong></p>

<pre><code>socket.on('connection', function (client) {
    var clientPurgatory = purgatory();

    client.on('message', function(message) {
        if (clientPurgatory.stillInPurgatory()) {
            if(message.event === 'clientauthrequest') {
                //If we can get out of purgatory, set up the client for pubsub
                clientPurgatory.tryToGetOut(message, client, function () {
                    activeClients += 1;
                    winston.info('clients: ' + activeClients);
                    socket.broadcast({
                        event: 'update'
                        , data: activeClients
                    });

                    client.on('disconnect', function () {
                        clientDisconnect(client);
                    });
                });
            }
        }
        else {
            //If this is called, we are not in purgatory, so handle it normally
            chatMessage(client, socket, message);
        }
    });
});
</code></pre>

<p>The <em>connection</em> event handler creates a closure with a new instance of the purgatory() function. It then sets up an anonymous function to handle client <em>message</em> events. Each time a message is received from this client, stillInPurgatory() is called. If it returns true, check to see if a <em>clientauthrequest</em> message was received and call tryToGetOut(). We pass tryToGetOut() a callback to call if the client successfully gets out of purgatory.</p>

<p>If stillInPurgatory() returns false, then handle the message as a regular chat message.</p>

<p><strong>purgatory</strong></p>

<p><em>Note: if you don&#8217;t understand Javascript closures, <a href="http://stackoverflow.com/questions/111102/how-do-javascript-closures-work">read up a bit on them</a>.</em></p>

<pre><code>function purgatory() {
    var inPurgatory = true;
    return {
        tryToGetOut: function (message, client, cb) {
            if (!message || !message.user || !message.hashpassword) {
                winston.info('[purgatory][tryToGetOut] Client with no user/hash attempting message. Client still in purgatory');
                return;
            }
            auth.authenticateUserByHash(message.user, message.hashpassword, function(err, data) {
                if (err) {
                    winston.info('[purgatory] Bad auth. Client still in purgatory');
                    inPurgatory = true;
                }
                else {
                    winston.info('[purgatory] out of purgatory');
                    inPurgatory = false;

                    //Once we are sure the client is who s/he claims to be, attach name and hash for future use.
                    client.user = message.user;
                    client.hashpassword = message.hashpassword;

                    cb &amp;&amp; cb();
                }
            });
        }
        , stillInPurgatory: function() {
            winston.info('[purgatory] status ' + inPurgatory);
            return inPurgatory;
        }
    }
}
</code></pre>

<p>The purgatory function returns a function that generates a closure for each client connection in order to keep track of whether the client has escaped purgatory or not. Subsequent calls to tryToGetOut() and stillInPurgatory() can reference the inPurgatory variable generated by the closure.</p>

<p>tryToGetOut() looks for a username and hashed password in the message. If it is found, it attempts to authenticate them. If authentication passes, the inPurgatory variable is set to false and the passed in callback is fired.</p>

<p>stillInPurgatory() returns the inPurgatory variable.</p>

<h2>Wrapping it up</h2>

<p>New clients are sent to purgatory. They stay in purgatory until they <em>earn</em> their release by successfully authenticating. Using the purgatory strategy gains us better compatibility with socket.io&#8217;s various transports and allows us to quit worrying about cookies and session expiration. Production nodechat has been running this code for the last week and I have already seen a big decrease in connection/reconnection issues.</p>

<p>You can get the code for this tutorial at the <a href="https://github.com/jslatts/nodechat-tutorial/tree/v0.3">v0.3 tag at github</a>. If you want to see how this is used in a more fully featured application, check out the production <a href="https://github.com/jslatts/nodechat">nodechat.js code-base on github</a>.</p>

<p>If you have questions, comments, or suggestions, you can get a hold of me on twitter @jdslatts, at comments@fzysqr.com, or by stopping in at <a href="http://nodechat.no.de/">nodechat.no.de</a>.</p>

<p>-jslatts</p>
]]></content:encoded>
			<wfw:commentRss>http://fzysqr.com/2011/04/11/sending-your-clients-to-purgatory-a-node-jssocket-io-tutorial/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Nodechat.js continued &#8211; authentication, profiles, ponies, and a meaner socket.io</title>
		<link>http://fzysqr.com/2011/03/27/nodechat-js-continued-authentication-profiles-ponies-and-a-meaner-socket-io/</link>
		<comments>http://fzysqr.com/2011/03/27/nodechat-js-continued-authentication-profiles-ponies-and-a-meaner-socket-io/#comments</comments>
		<pubDate>Mon, 28 Mar 2011 02:36:57 +0000</pubDate>
		<dc:creator>jslatts</dc:creator>
				<category><![CDATA[dev]]></category>

		<guid isPermaLink="false">http://fzysqr.com/?p=459</guid>
		<description><![CDATA[As promised, here is a follow up tutorial on the node.js/socket.io/backbone.js/express/connect/jade/redis stack that powers nodechat.js. The first nodechat.js tutorial introduced some fancy ideas, like using backbone.js on the server and streaming models over socket.io which is all well and great, but it left some of the more practical questions unanswered. Issues like coordinating authentication between [...]]]></description>
			<content:encoded><![CDATA[<p>As promised, here is a follow up tutorial on the node.js/socket.io/backbone.js/express/connect/jade/redis stack that powers <a href="http://nodechat.no.de">nodechat.js</a>.</p>

<p>The first <a href="http://fzysqr.com/2011/02/28/nodechat-js-using-node-js-backbone-js-socket-io-and-redis-to-make-a-real-time-chat-app/">nodechat.js tutorial</a> introduced some fancy ideas, like using backbone.js on the server and streaming models over socket.io which is all well and great, but it left some of the more practical questions unanswered. Issues like coordinating authentication between express/connect and socket.io and creating, storing, and retrieving user profiles, are less sexy, but still quite important for real world use. So that is what the next this tutorial will look at. Practical stuff. Besides, everything is more fun when you do it in node, right?</p>

<p>I will also sprinkle you with some other neat <em>wisdom nuggets</em> along the way. If you want.</p>

<p><span id="more-459"></span></p>

<h1>Overview</h1>

<p>First off, nodechat.js has advanced well passed the point that it is clean and clear enough to be used as a tutorial. I have decided to create a new nodechat project that will be used strictly for tutorials. It lives at <a href="https://github.com/jslatts/nodechat-tutorial">github also</a>. The code for this tutorial is at the <a href="https://github.com/jslatts/nodechat-tutorial/tree/v0.2">v0.2 tag</a>. nodechat.js and nodechat-tutorial share same underlying design, so if you want to see a demo, come visit <a href="http://nodechat.no.de/">nodechat.no.de</a>. There will probably even be someone there to chat with.</p>

<p>Our goal for this tutorial is to put nodechat behind a simple login page, provide a way to sign up new accounts, and make sure that socket.io verifies the accounts before accepting traffic.</p>

<h2>Install Stuff</h2>

<p>Any good node.js adventure starts off with npm powerups. For this adventure, we will need everything from <a href="http://fzysqr.com/2011/02/28/nodechat-js-using-node-js-backbone-js-socket-io-and-redis-to-make-a-real-time-chat-app/">part one</a> of this tutorial and:</p>

<ul>
<li>sudo npm install connect-redis</li>
<li>sudo npm install joose</li>
<li>sudo npm install joosex-namespace-depended </li>
<li>sudo npm install hash</li>
</ul>

<p>And just for fun, let&#8217;s do: sudo npm update</p>

<p>We will be using <a href="https://github.com/visionmedia/connect-redis">connect-redis</a> as our connect session store and <a href="https://github.com/michaelsbradleyjr/Hash/">hash</a> as our hashing library. The joose modules are there because hash requires them.</p>

<h2>Authentication</h2>

<p>To authenticate users and retrieve bits of information about them, we will need to:</p>

<ol>
<li>Create user accounts</li>
<li>Check login information</li>
<li>Retrieve the profile if successful</li>
<li>Kick them out if we are not successful</li>
<li>Do something with the profile information</li>
</ol>

<p>Let&#8217;s start with the easy stuff. We will need a login page and an account creation page. Create the following jade template files in the <em>views/</em> directory:</p>

<h3>login.jade</h3>

<pre><code>!!! 5
html(lang="en")
  head
    title nodechat login
  body
    #heading
      h1 nodechat login
    #content
      p
        | Please login or go 
        a(href='/signup') here
        |  to create a new account.
      form(method="post", action="/login")
        p
          label Username:
            input(type='text', name='username')
        p
          label Password:
            input(type='password', name='password')
        P
          input(type='submit', value='send')
</code></pre>

<p>Not much to this page. Just a simple login form with a link to our signup page.</p>

<h3>signup.jade</h3>

<pre><code>!!! 5
html(lang="en")
  head
    title nodechat new user
  body
    #heading
      h1 nodechat new user
    #content
      p
      form(method="post", action="/signup")
        div(style='width:350px; text-align:right')
          label Username:  
            input(type='text', name='username')
          br
          label Password:  
            input(type='text', name='password1')
          br
          label Password (again):  
            input(type='text', name='password2')
          br
          label Email:  
            input(type='text', name='email')
          br
          label Favorite thing about ponies:  
            input(type='text', name='ponies')
          br
          input(type='submit', value='signup')
</code></pre>

<p>Again, pretty simple. Just collect the signup information and whatever special information we may <strong>&#42;ahem&#42;</strong> require from our users.</p>

<h2>Routes</h2>

<p>Now we need to set up routes to serve our new pages. In <em>core.js</em>, after we have set up express, we want to include several routes.</p>

<pre><code>app.get('/login', function(req, res){
    res.render('login');
});

app.post('/login', function(req, res){
    auth.authenticateUser(req.body.username, req.body.password, function(err, user){
        if (user) {
            req.session.regenerate(function(){
                req.session.cookie.maxAge = 100 * 24 * 60 * 60 * 1000; //Force longer cookie age
                req.session.cookie.httpOnly = false;
                req.session.user = user;

                res.redirect('/');
            });
        } else {
            req.session.error = 'Authentication failed, please check your username and password.';
            res.redirect('back');
        }
    });
});
</code></pre>

<p>Setup the routes for GET and POST /login.</p>

<ul>
<li>GET returns the login.jade template</li>
<li>POST calls the authentication module to verify login details.

<ul>
<li>Failures are redirected back to the login page.</li>
</ul></li>
</ul>

<p><em>&#42;We will cover the authentication module in a minute. For now, just know that it does what it sounds like it might do :)</em></p>

<p>If the authentication module gives us a user object back, we ask connect to regenerate the session and send the client back to index. Note: we specify a <em>long</em> cookie age so users won&#8217;t have to log in frequently. We also set the httpOnly flag to false (I know, not so secure) to make the cookie available over <a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/net/Socket.html">Flash Sockets</a>.</p>

<pre><code>app.get('/signup', function(req, res){
    res.render('signup');
});

app.post('/signup', function(req, res) {
    auth.createNewUserAccount(req.body.username, req.body.password1, req.body.password2, req.body.email, req.body.ponies, function(err, user){
        if ((err) || (!user)) {
            req.session.error = 'New user failed, please check your username and password.';
            res.redirect('back');
        }
        else if(user) {
            res.redirect('/login');
        }
    });

});
</code></pre>

<p>Setup routes for GET and POST &#8216;/signup&#8217;:</p>

<ul>
<li>GET returns signup.jade</li>
<li>POST calls createNewUserAccount() in the auth module.

<ul>
<li>Failures redirect to the same page</li>
<li>Success redirects back to /login for the user to formally log in</li>
</ul></li>
</ul>

<p>Next &#8216;/logout&#8217;:</p>

<pre><code>app.get('/logout', function(req, res){
    req.session.destroy(function(){
        res.redirect('home');
    });
});
</code></pre>

<p>This route tells connect to destroy the session, which will cause nodechat to require the user to login again if they access the &#8216;/&#8217; route.</p>

<pre><code>app.get('/*.(js|css)', function(req, res){
    res.sendfile('./'+req.url);
});

app.get('/', restrictAccess, function(req, res){
    res.render('index', {
        locals: { name: req.session.user.name, hashPass: JSON.stringify(req.session.user.hashPass) }
    });
});

function restrictAccess(req, res, next) {
    if (req.session.user) {
        next();
    } else {
        req.session.error = 'Access denied!';
        res.redirect('/login');
    }
};
</code></pre>

<p>These last two routes already exist in nodechat v0.1. The only difference here is the reference to <em>restrictAcess</em> in the &#8216;/&#8217; route. restrictAccess() is an express <a href="http://expressjs.com/guide.html#route-middleware">route middleware</a>. Control is passed to the middleware function before the route function is called. We use restrictAccess() to verify that we have a valid user key in the session (implying that authentication has succeeded) before we send the client the requested route.</p>

<p>If we do not have a valid user object in the session, then we redirect the client to the &#8216;/login&#8217; route. This effectively locks down our &#8216;/&#8217; route from unauthenticated access. You could add the restrictAccess() to any route you want to protect.</p>

<h2>model</h2>

<p>That covers our new routes. Next we will need a backbone.js model for user accounts (well we don&#8217;t <em>need</em> a model, but nodechat is backbone.js on the server right?). Add a simple empty model to our <em>models/models.js</em>:</p>

<p>models.User = Backbone.Model.extend({});</p>

<p>That was easy.</p>

<h2>auth.js</h2>

<p>Let&#8217;s turn our attention to the authentication module touched on earlier. Create a new file, <em>lib/auth.js</em>. This module will handle the creation, verification, and profile loading of user accounts. It exposes two public methods: authenticateUser() and createNewUserAccount().</p>

<p>This will be a <a href="http://www.commonjs.org/">CommonJS module</a> so we need to start off with some set up:</p>

<pre><code>(function () {
    if (typeof exports !== 'undefined') {
        redis = require('redis');
        rc = redis.createClient();
        models = require('../models/models');

        //joose is required to support the hash lib we are using
        require('joose');
        require('joosex-namespace-depended');
        require('hash');
    } 
    else {
        throw new Error('auth.js must be loaded as a module.');
    }
</code></pre>

<p>Here we are checking to see if this code is included as a module. If it is, we go ahead and include our dependencies (in this case, our models lib, redis, and hash + friends). If we are not a module, we may as well explode because the rest of the code won&#8217;t run without redis and hash.</p>

<pre><code>exports.authenticateUser = function(name, pass, fn) {
    console.log('[authenticate] Starting auth for ' + name + ' with password ' + pass);

    var rKey = 'user:' + name;
    rc.get(rKey, function(err, data){
        if(err) return fn(new Error('[authenticateUser] SET failed for key: ' + rKey + ' for value: ' + name));

        if (!data) {
            fn(new Error('[authenticateUser] invalid password'));
        }
        else {
            console.log('[authenticateUser] user: ' + name + ' found in store. Verifying password.');
            verifyUserAccount(data, pass, fn);
        }
    });
};
</code></pre>

<p>authenticateUser() takes a name, password, and callback. It checks to see if the user exists in redis. If it does, it calls verifyUserAccount().</p>

<p><strong>CommonJS Modules</strong></p>

<p>An aside: if you are unfamiliar with the CommonJS module specification, the basic idea is that you encapsulate your reusable methods and objects in a anonymous function that assigns its &#8220;public&#8221; methods to the global exports variable. This allows us to have private variables and methods, like verifyUserAccount() below, and to easily reuse our code through require() statements throughout our application. This is a pattern you will see constantly in node.js-world.</p>

<pre><code>var verifyUserAccount = function(foundUserName, pass, fn) {
    var rKey = 'user:' + foundUserName;

    rc.get(rKey + '.salt', function(err, data){
        if(err) return fn(new Error('[verifyUserAccount] GET failed for key: ' + rKey + '.salt')); 

        if(data) {
            var calculatedHash = Hash.sha512(data + '_' + pass);
            rc.get(rKey + '.hashPass', function(err, data) {
                if(err) return fn(new Error('[verifyUserAccount] GET failed for key: ' + rKey + '.hashPass'));

                if (calculatedHash === data) {
                    console.log('[verifyUserAccount] Auth succeeded for ' + foundUserName + ' with password ' + pass);

                    rc.get(rKey + '.profile', function(err, data) {
                        if(err) return fn(new Error('[verifyUserAccount] GET failed for key: ' + rKey + '.profile' + ' for user profile'));

                        var foundUser = new models.User();
                        foundUser.mport(data);
                        foundUser.set({'hashPass': calculatedHash});

                        return fn(null, foundUser);
                    });
                }
                else {
                    return fn(new Error('[verifyUserAccount] invalid password'));
                }
            });
        }
        else {
            return fn(new Error('[verifyUserAccount] salt not found'));
        }
    });
}
</code></pre>

<p>verifyUserAccount() takes the same parameters as authenticateUser(). It assumes the passed in user exists in redis (remember, it is only accessible within the module, so that is a safe assumption to make) and then steps through the process of retrieving the salt, calculating the hash of the passed in password, then comparing it to the stored hash in redis. If the comparison is successful, create a new user model and pass it to the callback. Otherwise, any failure along the way means we callback with an error.</p>

<pre><code>exports.createNewUserAccount = function(name, pass1, pass2, email, ponies, fn) {
    if (pass1 !== pass2) return fn(new Error('[createNewUserAccount] Passwords do not match'));

    var newUser = new models.User({name: name, email: email, ponies: ponies});

    var rKey = 'user:' + name;

    rc.set(rKey, name, function(err, data){
        if(err) return fn(new Error('[createNewUserAccount] SET failed for key: ' + rKey + ' for value: ' + name));

        var salt = new Date().getTime();
        rc.set(rKey + '.salt', salt, function(err, data) {
            if(err) return fn(new Error('[createNewUserAccount] SET failed for key: ' + rKey + '.salt' + ' for value: ' + salt));

            var hashPass = Hash.sha512(salt + '_' + pass1);
            rc.set(rKey + '.hashPass', hashPass, function(err, data) {
                if(err) return fn(new Error('[createNewUserAccount] SET failed for key: ' + rKey + '.hashPass' + ' for value: ' + hashPass));

                rc.set(rKey + '.profile', newUser.xport(), function(err, data) {
                    if(err) return fn(new Error('[createNewUserAccount] SET failed for key: ' + rKey + '.profile' + ' for user profile'));

                    newUser.set({'hashPass': hashPass});
                    return fn(null, newUser);
                });

            }); 
        }); 
    }); 
}
</code></pre>

<p>createNewUserAccount() verifies that the two passwords match, then uses the current timestamp to salt a hash of the password. It stores the hashed password and the passed in information about email and ponies in a user model which we will save as a poor man&#8217;s profile&#8211;if everything succeeds. Any failure along the way means we callback with an error. We are using SHA512 which has to be good, because it was invented by the <a href="http://en.wikipedia.org/wiki/Comparison_of_cryptographic_hash_functions">NSA</a>.</p>

<pre><code>})()
</code></pre>

<p>If you have actually been cutting and pasting, you will need to end your file with this little snippet per the CommonJS spec.</p>

<p><strong>Salting and Hashing</strong></p>

<p>Another aside: if you are like me, you probably do not often mess around with actually storing usernames and passwords. Most frameworks will handle this for you quite nicely. I had to do some google-fu to figure out a decent way of doing this. Crypto experts: Please don&#8217;t email me telling me how the NSA could crack this in 5 minutes. It&#8217;s a chat program. I am also aware that there are probably five thousand node modules on npm that will do this for you as well. This is supposed to be fun dammit! Leave me alone.</p>

<p>The basic concept behind <a href="http://en.wikipedia.org/wiki/Cryptographic_hash_function">cryptographic hashing</a> is to take a string of any length, in our case a password, and map it into a fixed length string, using an algorithm. This computation is inexpensive if you <em>know</em> the password up front, but doing the reverse&#8211;finding all the possible passwords that can map to the hash value&#8211;is computationally very expensive. Since we only store the hash, if our redis instance is ever compromised, an attacker would have to compute an enormous number potential passwords (and try each one) to figure out which one is the <strong>real</strong> password.</p>

<p>Hashing on its own can be susceptible to <a href="http://en.wikipedia.org/wiki/Rainbow_table">rainbow tables</a>&#8211;precomputed reverse hash values. The attacker simply looks up the hash in the table and finds the list of corresponding possible passwords. The tables can be precomputed in advance and are easily obtained online by those who may be so inclined. This is where the salt comes in. The salt is a randomly generated string (I am just using a timestamp, but close enough) that is attached to the password before the cryptographic hash computation. We store the hash in the database as well; we will need it to verify passwords later on.</p>

<p>The salt mitigates the ability of an attacker to pre-compute the hash space. Since each user has a different salt, the attacker would have to compute the entire hash space for each user, and that is assuming the know the salt! If they don&#8217;t have the salt, the task becomes insurmountable.</p>

<p>nodechat.js uses the following salt/hash algorithm:</p>

<p>Account Creation</p>

<ol>
<li>On account set up, get the current time in milliseconds. This is our salt.</li>
<li>Prepend the salt to the password separated by an underscore: salt_password.</li>
<li>Calculate the SHA512 hash of the salt_password string. This is our password hash.</li>
<li>Store the salt and the password hash for the user.</li>
</ol>

<p>Account Verification</p>

<ol>
<li>On an attempt to login to an existing account, retrieve the salt for the requested user.</li>
<li>Prepend the salt to the attempted password, separated by an underscore: salt_attemptedpassword.</li>
<li>Calculate the SHA512 hash of the salt_attemptedpassword string. This is our attempted password hash.</li>
<li>Retrieve the stored password hash and compare it to the attempted password hash. If both hash values match, then assume the passwords match. Otherwise, they do not.</li>
</ol>

<p>Enough crypto for today. Back to node stuff.</p>

<h2>Making it work with socket.io</h2>

<p>We now have all the pieces in place to lock down our express routes and if we were not using socket.io, we would be done. But we are using socket.io, so we&#8217;re not. We need to be able to protect socket.io connections the same way we protect our routes. socket.io is not aware of the session and will not have access to the session store the same way express does, so we have to improvise.</p>

<p>Back in <em>core.js</em> we want to add some more code:</p>

<pre><code>function disconnectAndRedirectClient(client, fn) {
    console.log('Disconnecting unauthenticated user');
    client.send({ event: 'disconnect' });
    client.connection.end();
    fn();
    return;
}
</code></pre>

<p>First we are going to give socket.io some teeth (get it, meaner socket.io? it bites? yes I am funny). When we have a client that shouldn&#8217;t be connected, <strong>kick &#8216;em off!</strong>. disconnectAndRedirectClient() takes a client socket.io object and a callback.</p>

<pre><code>socket.on('connection', function(client){
    client.connectSession = function(fn) {
        if (!client.request || !client.request.headers || !client.request.headers.cookie) {
            disconnectAndRedirectClient(client,function() {
               console.log('Null request/header/cookie!');
            });
            return;
        }

        var match = client.request.headers.cookie.match(/connect\.sid=([^;]+)/);
        if (!match || match.length &lt; 2) {
            disconnectAndRedirectClient(client,function() {
                console.log('Failed to find connect.sid in cookie');
            });
            return;
        }

        var sid = unescape(match[1]);

        rc.get(sid, function(err, data) {
            fn(err, JSON.parse(data));
        });
    };

    client.connectSession(function(err, data) {
        if(err) {
            console.log('Error on connectionSession: ' + err);
            return;
        }

        client.user = data.user;

        activeClients += 1;
        client.on('disconnect', function(){clientDisconnect(client)});
        client.on('message', function(msg){chatMessage(client, socket, msg)});

        socket.broadcast({
            event: 'update',
            clients: activeClients
        });

        var ponyWelcome = new models.ChatEntry({name: 'PonyBot', text: 'Hello ' + data.user.name + '. I also feel that ponies ' + data.user.ponies + '. Welcome to nodechat.js'});

        socket.broadcast({
            event: 'chat',
            data: ponyWelcome.xport()
        });
    });
});
</code></pre>

<p>There is a lot going on here, but much of this code is unchanged from v0.1. First, we are defining a helper method, connectSession, that will verify a client&#8217;s validity by checking for a cookie in the request header, then, if we find it,  <em>pulling their session out of redis!</em> We then use the helper method in the &#8216;connection&#8217; handler for our socket listener. Now instead of just accepting any old user connection, we are going to check that the client has a valid session (meaning they logged in). If they don&#8217;t, give them the boot! If they do, then we store a copy of the session data (yay we have access!) in the client object and then set up the rest of the socket events. Finally, send them a welcome message just to prove that we remembered their profile.</p>

<p><strong>connect-redis</strong></p>

<p>One last aside: <a href="https://github.com/visionmedia/connect-redis">connect-redis</a> by visionmedia (I love his stuff!) is a connect session store the is backed by redis. It sets a cookie to track the session id, but it stores all other data in redis. This is really nice because a) we don&#8217;t have to worry about leaving cookies with critical data on the client, and b) we can grab the session data straight out of redis and give it to socket.io. We still have to parse the cookie to get the session id, but at least that is all we have to worry about.</p>

<pre><code>function chatMessage(client, socket, msg){
    var chat = new models.ChatEntry();
    chat.mport(msg);

    rc.incr('next.chatentry.id', function(err, newId) {
        chat.set({id: newId});
        nodeChatModel.chats.add(chat);

        var expandedMsg = chat.get('id') + ' ' + client.user.name + ': ' + chat.get('text');

        rc.rpush('chatentries', chat.xport(), redis.print);

        socket.broadcast({
            event: 'chat',
            data:chat.xport()
        }); 
    }); 
}
</code></pre>

<p>The only material difference in chatMessage() is that we no longer simply believe the client when they tell us their name. Instead we use our newly found session power to tell <em>them</em> what their name is. And prevent fraud and stuff. Oh, and I also removed the call to rc.bgSave(). Because it was crashing during concurrent saves. If you want to persist your chats permanently, use the snapshotting method described by redis <a href="http://redis.io/topics/persistence">here</a>.</p>

<h2>Wrapping it up</h2>

<p>That is about it. There may be some minor changes in some of the other files, so it never hurts to get the code from the <a href="https://github.com/jslatts/nodechat-tutorial/tree/v0.2">v0.2 tag at github</a>.</p>

<p>I want to close by saying that this method of authentication works and it has worked well enough to run in &#8220;production&#8221; on <a href="http://nodechat.no.de/">nodechat.no.de</a> for several weeks. We do experience some funky issues once clients start falling back to xhr-polling and jsonp-polling, so be warned. This is the bleeding edge folks. Treat it as such.</p>

<p>My plan is to follow up with a different take on the authentication issue, one in which we ditch sessions altogether and use a shared key (like the hash) to <em>sign</em> each message over the socket. I&#8217;ll write it up if it works.</p>

<p>Finally, I want to say thanks to everyone who sent me email, tweets, or stopped by nodechat to&#8230; chat. It has been fantastic meeting you all and I look forward to seeing all the cool stuff you guys are cranking out.</p>

<p>Follow me on twitter @jdslatts, email me at <a href="mailto://comments@fzysqr.com">comments@fzysqr.com</a>, or stop by <a href="http://nodechat.no.de">nodechat.no.de</a> and say hi!</p>

<p>-jslatts</p>
]]></content:encoded>
			<wfw:commentRss>http://fzysqr.com/2011/03/27/nodechat-js-continued-authentication-profiles-ponies-and-a-meaner-socket-io/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>nodechat achieves glorious internet notoriety</title>
		<link>http://fzysqr.com/2011/03/14/nodechat-achieves-glorious-internet-notoriety/</link>
		<comments>http://fzysqr.com/2011/03/14/nodechat-achieves-glorious-internet-notoriety/#comments</comments>
		<pubDate>Tue, 15 Mar 2011 05:47:09 +0000</pubDate>
		<dc:creator>jslatts</dc:creator>
				<category><![CDATA[dev]]></category>

		<guid isPermaLink="false">http://fzysqr.com/2011/03/14/nodechat-acheives-glorious-internet-notoriety/</guid>
		<description><![CDATA[Two weeks ago, I released a tutorial on using node.js, backbone.js, socket.io, and redis to make a simple realtime chat app. Someone posted it to Hacker News and it made it the front page. fzysqr.com enjoyed brief fame and notoriety. The number one complaint (other than my awesome user interface) was that there was no [...]]]></description>
			<content:encoded><![CDATA[<p>Two weeks ago, I released <a href="http://fzysqr.com/2011/02/28/nodechat-js-using-node-js-backbone-js-socket-io-and-redis-to-make-a-real-time-chat-app/">a tutorial</a> on using node.js, backbone.js, socket.io, and redis to make a simple realtime chat app. Someone posted it to <a href="http://news.ycombinator.com/news">Hacker News</a> and it made it the front page. fzysqr.com enjoyed brief fame and notoriety. The number one complaint (other than my <em>awesome</em> user interface) was that there was no demo. So without thinking (at all) I threw the code up on a <a href="http://no.de/">Joyent no.de</a> (Joyent are a bunch of node-ninjas and no.de is the best thing since ponies, check them out) and posted the link on HN and on fzysqr.com. Whups.</p>

<p>I have learned a few things over the last couple weeks. Good &#8220;lessons&#8221; I will share with you now:</p>

<ol>
<li>Don&#8217;t actually put your crappy code online, publicly, for abuse. It will crash.</li>
<li>Sanitize inputs for your crappy demo code before you try to run it (in violation of rule number 1). XSS attacks  will <em>significantly lessen</em> the quality of the experience you are trying to provide your audience.</li>
<li>Check for nulls. Everywhere. The internet is a cruel place and people are mean. They will look through your crappy demo code and figure out how to crash your crappy demo.</li>
<li>Running production-ish code on node.js requires a different mindset. If anything takes the process down, it is down for <em>everyone</em>. Coming from a typical web-development background, it took much crashing before I realized this. <em>Writing robust, fault tolerant code is CRITICAL if you are hosting it on node.js</em></li>
<li>If you write a silly chat room and hang out it in all day, you will meet many interesting people.</li>
<li>There is a ton of interest in node.js. People are really excited to work with this stack. </li>
</ol>

<p>People seemed to enjoy <a href="http://nodechat.no.de/">nodechat.js</a> so I have been hacking out new features as fast as I can. Things that have changed since the demo:</p>

<ul>
<li>Authentication: reserve your username now, before they are all gone!</li>
<li>Rightside up chat</li>
<li>Mashtags: like #hashtags but #mashier</li>
<li>Users online: now people are more than numbers</li>
<li>Direct messages: now you can tell @jslatts how much you hate the UI in private</li>
<li>Notifications: blinky tab thingies</li>
<li>Linkify URLS / <em>em</em> / <strong>bold</strong> </li>
<li>Flood control (yes, that one guy who knows who he is, I am thinking of you)</li>
<li>Works in Firefox (sorry FF, I don&#8217;t test in you)</li>
<li>Still Fun Chat Messages only</li>
</ul>

<p>As always, you can find the latest code at <a href="https://github.com/jslatts/nodechat">github</a>.</p>

<p>I am working on a follow up tutorial to cover authentication and some other fun tidbits I have discovered in the last couple weeks. Stay tuned.</p>
]]></content:encoded>
			<wfw:commentRss>http://fzysqr.com/2011/03/14/nodechat-achieves-glorious-internet-notoriety/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

