Day Four: Smart Platform and JavaScript libraries
Now that we have a working tasks application, seems to be the perfect moment to start polishing it a bit with the help of the available JavaScript libraries on the Smart Platform. We’ll add a bit of privacy to our application, requiring user login in order to access our tasks list and learn about application level hooks.
Then, we’ll review how to add our own libraries and, of course, start using them too.
We’ll assume you already added the suggested AJAX activity indicator from the previous article – it’s on the sample application source code anyway – and start thinking about new things our application needs, (apart of an urgent CSS review!).
One obvious thing is: everybody can access our tasks list, reorder them, add new ones, even delete them all!. Let’s prevent lurkers poking around our super important list of things to do by adding user authentication before to be able to access our tasks.
User authentication.
This time, I’ve chosen to commit everything at once so we can give a quick look to all the files together and, then, start dissecting their contents.
We’ve just created 3 new files: web/login.html – which contains our login form – js/auth.js and js/auth/user.js, which contain all the logic to handle authentication.
The first one, web/login.html is merely the login form with a single relevant addition:
[% IF error %]
<p class="error">[% error.message %]</p>
[% END %]
We’re just providing a way to display login errors. We’re using it just by setting the this.error value to whatever the error we catched while processing our logic – common JavaScript errors – so we’ll be able to access it from our template.
Then, we tell our application to load our js/auth.js file by adding the next line to js/bootstrap.js:
system.use("auth");
And, just as another simple demonstration of how system.use works, we’ve loaded our js/auth/user.js from js/auth.js.
This way, if you want to remove user authentication, just dropping out a single line will do the trick.
A Transient User Resource.
First thing you’ll probably notice on the js/auth/user.js file is that the resource is transient, it’s to say, not stored into the DB. This is because we are trying to authenticate a single, hardcoded user so, there’s no need to save it. An important advice regarding this: you cannot use Resource.get neither Resource.search with a transient Resource. Those methods talk to the Data Store and, our resource isn’t there!.
So, you’ll see that we’re just creating a single instance of our User resource every time we need to use it.
Also, on the User constructor, we’re ensuring the user always will have an username:
var User = new Resource('user', {
'@constructor': function( aUsername ) {
if (!aUsername) throw new Error("Username is required");
This is a perfect valid way to ensure that your resources are always created with the required properties: add all of them to the constructor and throw an Error when not present.
Still on this file, we’ve enabled Sessions – literally, indeed, with enable("Sessions"); and populate the session variables with some values during authentication. enable is exactly the same thing than system.use with the difference it will try to load libraries relatives to com.joyent.Sammy.
Having our User resource in place, the real application fun happens on js/auth.js: There are, obviously, 3 new routes: /login (GET), /login (POST) and /logout (GET). Of these, the most important, by far, is the /login (POST) one, which processes the parameters coming from our login form and tries to authenticate our user.
Application level before hooks
But there’s something better there:
before(function () {
// Stuff here ...
});
This is an application level hook. It will be executed always, on each request, so you can perform any duplicated logic there like we’re doing for our authentication library.
In our case, we’re using the before filter to check if we’ve got a logged in user, cleaning up sessions when some exception happens – the username doesn’t match – and redirecting to the login page when, being not authenticated, anybody requests whatever the action in our /tasks resource path.
system.digest
Another suggestion for the day you decide to implement a proper User authentication would be to do not store passwords in the plain. The Smart Platform provides a set of available functions to avoid that using the system.digest libraries.
For example, we’re gonna store our hardcoded password using the SHA1 Hex Digested version, and then, checking that the user provided password matches with our stored one doing the proper transformation:
if ( system.digest.sha1.hex( aPassword ) == User.password )
And this has been the 4th day, less writing, more code. There are other libraries we’re going to cover during the next articles, starting with a bit of XML fun on the next day, using E4X to generate an OPML representation of our tasks list.
Something really cool to try: JavaScript console
Did you know Smart application comes with a bundled version of the Spider Monkey JavaScript Shell?. Well, it does – yours truly was bugging James for a while regarding that ;-).
If you’ve got your local copy of the Smart.app into your applications directory, try this:
cd /Applications/Smart.app/Contents/Resources/Image
./bin/js
and you’ll get a nice js> prompt from where you can play and improve your JavaScript using all the available features of core JavaScript 1.8. What are you waiting for?, play time with JavaScript!.
PS: In order to exit the console, type quit();.