Aiming for elegance, one thought at a time

Wiring up basic Angular front-end for authentication (SPA Part 4)

Posted: May 10th, 2013 | Author: | Filed under: Uncategorized | No Comments »

This is the third part of a series of blog posts that will walk step-by-step through the process of creating a secure Single Page App (SPA) using node.js, passport.js, and Angular.

If you’re new here, you should start at Part 1, where we set up Passport.js. Today, we’re continuing on with Angular, and wiring up our basic authentication to the passport.js backend.

The changes required are pretty minimal, so let’s dive right in!

Front end

For login, we just need to update the login function in the security service to post the username and password to the backend:

Similarly, for signup, we post the new user’s details to the backend:

Backend

In the backend, all that’s required is updating the routes to return JSON instead of redirecting. For login:

exports.postlogin = function(req, res, next) {
  passport.authenticate('local', function(err, user, info) {
    if (err) { return next(err) }
    if (!user) {
      return res.json(403, {message: info.message});
    }
    req.logIn(user, function(err) {
      if (err) { return next(err); }
      return res.json({user: user});
    });
  })(req, res, next);
};

And for signup:

You can grab the complete code for this example at https://github.com/studds/secure-spa-part-4.git

Up next

Next week, we’ll have a couple of posts on verifying user’s email addresses.


Basic Angular front-end for authentication (SPA Part 3)

Posted: May 7th, 2013 | Author: | Filed under: Uncategorized | No Comments »

This is the third part of a series of blog posts that will walk step-by-step through the process of creating a secure Single Page App (SPA) using node.js, passport.js, and Angular.

If you’re new here, you should start at Part 1, where we set up Passport.js. Today, we’re going to get started with Angular. We’re just going to ease in to it: this is deliberately simplified. We’ll cover creating a simple security service and some of the directives we’ll need. Later, we’ll wire the service up to the backend, and make some improvements to how the front end works.

The complete series of posts will cover:

  • Getting started with passport.js
  • Adding in users
  • Handling login, logout, and registration from a single page app
  • Adding in robust remember-me functionality
  • Protecting against CSRF
  • Protecting against XSS
  • Adding a reasonably robust remember-me to passport js
  • Enhancing security by adding some simple HTTP headers
  • Setting up to always redirect to SSL
  • Pushing our app to Heroku
  • Throttling login attempts

Let’s get started

The code for this part is at:

git clone https://github.com/studds/secure-spa-part-3.git

Unlike previous examples, for today we won’t be hitting the database, so you can start the server right away:

node app.js

New home page:
Secure-SPA-Part-3-Home

Login page:
Secure-SPA-Part-3-Login

Signup page:
Secure-SPA-Part-3-Signup

Home page after login:
Secure-SPA-Part-3-Logged-In

Right now, these pages aren’t wired up to the backend. We’ll handle that later in the week. So feel free to try it out and enter whatever information you choose.

The code

The action is all happening in public/scripts/app.js, which is the main file for the new Angular js app.

We’ve only got a few routes here, as the login and signup pages will be “popups”. You’ll have your own preferred way to implement popups, so for this example, I’ve just used simple directives and ng-show. (If I can work out a more elegant way of doing this without assuming what libraries will be used, I’ll build that in to future posts. Suggestions welcome!) The MainCtrl simply maps in the Security service, which we’ll look at next.

'use strict';

var javascriptApp = angular.module('javascriptApp', [])
    .config(function ($routeProvider, $locationProvider) {
        $routeProvider
            .when('/', {
                templateUrl: 'views/main.html',
                controller: 'MainCtrl'
            })
            .when('/account', {
                templateUrl: 'views/account.html',
                controller: 'MainCtrl'
            })
            .otherwise({
                redirectTo: '/'
            });
        $locationProvider.html5Mode(true);
    })
    .controller('MainCtrl', function ($scope, Security) {
        $scope.security = Security;
    })

This simple Security service is just an outline to get us started. It allows us to show and hide the login and signup forms, as well as managing the current logged in user. Ideally, we’d be deferring to a dialog service to display the login popup, but again, I didn’t want to assume too many libraries at this point. For now, it should be pretty simple to modify this to suit your needs.

javascriptApp.factory('Security', function ($location) {
    return {
        showLogin: function () {
            this.isSignupShown = false;
            this.isLoginShown = true;
        },
        isLoginShown: false,
        showSignup: function () {
            this.isLoginShown = false;
            this.isSignupShown = true;
        },
        isSignupShown: false,
        login: function (username, password) {
            this.currentUser = {username: username, email: username+"@example.com" };
            this.isLoginShown = false;
        },
        signup: function (username, email, password1, password2) {
            this.currentUser = {username: username, email: email};
            this.isSignupShown = false;
        },
        logout: function () {
            delete this.currentUser;
        },
        isAuthenticated: function () {
            return !!this.currentUser;
        }
    };
});

The login directive is for the login form, and is very simple: it simply makes the Security service available to the login template. To keep everything tight, we’re using replace.

javascriptApp.directive("login", function () {
    return {
        restrict: "E",
        scope: {},
        replace: true,
        templateUrl: "views/login.html",
        controller: function ($scope, Security) {
            $scope.security = Security;
        },
        link: function (scope) {
        }
    }
});

The login template will only show if security.isLoginShown is true (our poor-mans popup.) On submit, the username and password entered will be passed to the login function.

<div ng-show="security.isLoginShown"><form ng-submit="security.login(user.username, user.password)">
	<div>
	<label>Username:</label>
	<input type="text" name="username" ng-model="user.username" required/><br/>
	</div>
	<div>
	<label>Password:</label>
	<input type="password" name="password" ng-model="user.password" required/>
	</div>
	<div>
	<input type="submit" value="Log in"/>
	</div>
</form>
<p><small>Hint - bob:secret</small></p></div>

The login toolbar directive is to display the buttons for logging in and logging out, and is also very simple: as above, replace is true, and the controller simply makes the Security service available.

javascriptApp.directive("loginToolbar", function () {
    return {
        restrict: "E",
        scope: {},
        replace: true,
        templateUrl: "views/login-toolbar.html",
        controller: function ($scope, Security) {
            $scope.security = Security;
        },
        link: function (scope) {
        }
    }
});

The toolbar template uses the security service to determine what should (and shouldn’t) be shown to the user.

<ul>
    <li><a href="/">Home</a></li>
    <li ng-show="security.isAuthenticated()"><a href="/account">Account</a></li>
    <li ng-show="!security.isAuthenticated()"><a ng-click="security.showLogin()">Log In</a></li>
    <li ng-show="!security.isAuthenticated()"><a ng-click="security.showSignup()">Sign up</a></li>
    <li ng-show="security.isAuthenticated()"><a ng-click="security.logout()">Log out</a></li>
</ul>

The signup directive does a little bit more that the login and toolbar directives. We’ve wired it up to make sure our password has sufficient complexity, although it’s a bit clunky, and we’re not checking that passwords match. We’ll improve the validation on this page in the next instalment.

javascriptApp.directive("signup", function () {
    return {
        restrict: "E",
        scope: {},
        replace: true,
        templateUrl: "views/signup.html",
        controller: function ($scope, Security) {
            $scope.user = {};
            $scope.security = Security;
        },
        link: function (scope) {
            scope.$watch("user.password", function (value) {
                scope.user.passwordStrength = !value || value.length === 0 ? 0 : typeof zxcvbn !== "undefined" ? zxcvbn(value).score : 0;
            })
        }
    }
});

The signup template will only be shown is isSignupShown is true (again, our poor-mans popup). In the next instalment we’ll be making some improvements to the validation in place here.

<div ng-show="security.isSignupShown">
    <form ng-submit="security.signup(user.username, user.email, user.password, user.password2)">
        <div>
            <label>Username:</label>
            <input type="text" required name="username" ng-model="user.username"/><br/>
        </div>
        <div>
            <label>Email:</label>
            <input type="email" required name="email" ng-model="user.email"/><br/>
        </div>
        <div>
            <label>Password:</label>
            <input type="password" required name="password" ng-model="user.password"/>
            <input type="text" class="password-strength-{{user.passwordStrength}}" disabled/>
        </div>
        <div>
            <label>Repeat password:</label>
            <input type="password" required name="password2" ng-model="user.password2"/>
        </div>
        <div>
            <input id="submit" type="submit" value="Sign up" ng-disabled="user.passwordStrength < 2"/>
        </div>
    </form>
    <p>
        <small>Hint - some strong password are correcthorsebatterystaple, rWibMFACxAUGZmxhVncy,
            Ba9ZyWABu99[BK#6MBgbH88Tofv)vs$w
        </small>
    </p>
</div>

Putting it all together

By using directives for the toolbar, login, and signup, we can easily insert the authentication components where they’re needed.

<login-toolbar></login-toolbar>
<login></login>
<signup></signup>
<h2 ng-show="!security.isAuthenticated()">Welcome. Please log in.</h2>
<h2 ng-show="security.isAuthenticated()">Hello {{security.currentUser.username}}</h2>

Wrapping up

Today we’ve just put the very basics in place for authentication using Angular. Next up, we’ll improve the validation and wire it together with the back end.


Choosing a javascript library to check password entropy (strength) (Secure SPA Aside 1)

Posted: May 3rd, 2013 | Author: | Filed under: Uncategorized | 1 Comment »

I’m writing a series of posts of creating a Single Page App (SPA) using node.js, passport.js, and Angular.

One thing I wanted to do as part of this series is select a javascript library to check and enforce password entropy or strength, ultimately as a way of helping users choose strong passwords. After a few hours of research, I selected zxcvbn.

Why zxcvbn?

But first, a quick note on my zxcvbn. I looked at a few libraries before choosing zxcvbn:

  • node-complexify, the node port of jQuery complexify. I liked this because it had the node & jQuery components. In the end, I decided against it because it considers aaaaaaaaaaaaaaaaaaaaaaaaaaa to be a strong password.
  • Gavel seemed to have a better password strength test, and I can see the appeal of having a dedicated password strength test service. However, the additional setup meant that it definitely wasn’t appropriate for a tutorial (also, I would guess it would be a hassle to push to Heroku or another similar hosting service.)
  • Mellt is definitely getting closer, by basing the strength of the brute-force time and banning common password. Curiously, though, it estimates 717 thousand years to crack Tr0ub4dour&3 – significantly more than expected.
  • So finally zxcvbn was the library of choice. It works on the client and server, and makes a pretty decent estimate of password strength.

Adding a registration form (Secure SPA Part 2)

Posted: May 3rd, 2013 | Author: | Filed under: Uncategorized | 1 Comment »

This is the second part of a series of blog posts that will walk step-by-step through the process of creating a secure Single Page App (SPA) using node.js, passport.js, and Angular. We’ll be enforcing a minimum password strength (entropy) using zxcvbn, with checks on both the server and client.

If you’re new here, you should start at Part 1, where we set up Passport.js. Today we’re going to add in a signup page. We’ll be enforcing a minimum password strength (entropy) using zxcvbn, with checks on both the server and client (why I chose zxcvbn).

The complete series of posts will cover:

  • Getting started with passport.js
  • Adding in users
  • Handling login, logout, and registration from a single page app
  • Adding in robust remember-me functionality
  • Protecting against CSRF
  • Protecting against XSS
  • Adding a reasonably robust remember-me to passport js
  • Enhancing security by adding some simple HTTP headers
  • Setting up to always redirect to SSL
  • Pushing our app to Heroku
  • Throttling login attempts

Let’s get started

The code for this part is at:

git clone https://github.com/studds/secure-spa-part-2.git

Change in to the secure-spa-part-2 directory and run

npm install
grunt dbseed

See Part 1 for a detailed description
Now run:

node app.js

… and take a look at http://localhost:3000/signup
Passport-Local Example-Signup
Here’s out new signup screen. Let’s have a look at the code…

The create user function

A create user function has been added inside of config/pass.js. This function is where we enforce our password rules, and only then create the user in the database. Note that we require password1 and password2 in this function, the idea being that this forces anyone using this function to confirm the password with the user (or at least forces them to knowingly choose not to.)

On line 11, we define the MIN_PASSWORD_SCORE required. This is on a scale of 0 – 4 defined by zxcvbn. 2 here equates to a crack time of between 3 and 300 hours.

On line 18, we’ve got a simple check that the passwords provided are in fact the same, or otherwise we return an error. This error message will be displayed to the user.

On lines 20 and 21, we use zxcvbn to calculate the score. If the score is less than MIN_PASSWORD_SCORE, then we return an error (again, this will be displayed to the user.)

Finally, from line 22 on, we save the user to the database.

var passport = require('passport')
  , LocalStrategy = require('passport-local').Strategy
  , db = require('../config/dbschema')
    , zxcvbn = require("zxcvbn");

// Minimum password score based on scale from zxcvbn:
// [0,1,2,3,4] if crack time (in seconds) is less than
// [10**2, 10**4, 10**6, 10**8, Infinity].
// (useful for implementing a strength bar.)
const MIN_PASSWORD_SCORE = 2;

// snip

// Helper function to create a new user
passport.createUser = function(username, emailaddress, password1, password2, adm, done) {
    // convert adm string to bool

    if (password1 !== password2) return done(new Error("Passwords must match"));

    var result = zxcvbn(password1);
    if (result.score < MIN_PASSWORD_SCORE) return done(new Error("Password is too simple"));
    var user = new db.userModel({ username: username
        , email: emailaddress
        , password: password1
        , admin: adm });

    user.save(function(err) {
        if(err) {
            done(err);
        } else {
            done(null, user);
        }
    });

};

Adding the routes

To get the signup work, we need to add two new routes. Firstly, a simple route to render the signup template (line 3). Secondly, a route to actually create the new user (line 7). At line 9 on, we’re pulling the parameters from the createUser function out of the request body. Note the two separate password fields. At line 15, we’re checking whether the error was a type 11000, which is the MongoDB error for a duplicate key (in this case, duplicate user), or otherwise passing the error message straight through to the user. In a production system, we’d probably want to be more sophisticated in our error handling.

// snip

exports.getsignup = function(req, res) {
    res.render('signup', { user: req.user, message: req.session.messages });
};

exports.signup = function (req, res) {
    var body = req.body;
    pass.createUser(
        body.username,
        body.email,
        body.password,
        body.password2,
        false,
        function (err, user) {
            if (err) return res.render('signup', {user: req.user, message: err.code === 11000 ? "User already exists" : err.message});
            req.login(user, function (err) {
                if (err) return next(err);
                // successful login
                res.redirect('/');
            })
        })
}
1

Then we add these routes to app.js.

1
// snip

app.use('/public/zxcvbn', express.static('node_modules/zxcvbn/zxcvbn'));

// snip

// Signup pages
app.get('/dmz/signup', user_routes.getsignup);
app.post('/dmz/signup', user_routes.signup);

// snip

Note at line 3 that we’re also adding in an additional static middleware to make the zxcvbn scripts available to the front-end. Which brings us to…

Client side password checks

A key goal is using the same code to do both the client and server password strength checks. This is why we’ve exposed the zxcvbn scripts above. At line 5, we’re including zxcvbn-async.js file, which will retrieve the main zxcvbn file – this is the recommended way of including zxcvbn.

<% include header %>
<% if (message) { %>
<p><%= message %></p>
<% } %>
<script src="/public/zxcvbn/zxcvbn-async.js"></script>
<form action="/dmz/signup" method="post">
	<div>
	<label>Username:</label>
	<input type="text" required name="username"/><br/>
	</div>
	<div>
	<label>Email:</label>
	<input type="email" required name="email"/><br/>
	</div>
	<div>
	<label>Password:</label>
	<input id="password" type="password" required name="password"/>
	<input id="strength" class="weak" type="text" value="weak" disabled />
	</div>
	<div>
	<label>Repeat password:</label>
	<input type="password" required name="password2"/>
	</div>
	<div>
	<input id="submit" type="submit" value="Submit" disabled />
	</div>
</form>
<script src="/public/javascript/check-password.js"></script>
<p><small>Hint - some strong password are correcthorsebatterystaple, rWibMFACxAUGZmxhVncy, Ba9ZyWABu99[BK#6MBgbH88Tofv)vs$w</small></p>
<% include footer %>

At line 28, we include check-password.js:

var password = document.getElementById("password"),
    strength = document.getElementById("strength"),
    submit = document.getElementById("submit");
password.addEventListener('keyup', function () {
    var score = zxcvbn(password.value).score;
    if (score < 2) {
        strength.value = strength.className = "weak";
        submit.disabled = true;
    }
    if (score === 2) {
        strength.value = strength.className = "so-so";
        submit.disabled = false;
    }
    if (score > 2) {
        strength.value = strength.className = "strong";
        submit.disabled = false;
    }
})

This defines a simple event listener that enables and disabled to submit button and changed the class and value of the strength indicator.

Wrapping up

Today, we’ve added a user signup page, complete with passport strength tests that are enforced both on the client and the server. Next up, we’ll change the front-end to an Angular SPA.


Setting up passport.js (Secure SPA Part 1)

Posted: April 30th, 2013 | Author: | Filed under: Uncategorized | 3 Comments »

This is the first part of a series of blog posts that will walk step-by-step through the process of creating a secure Single Page App (SPA) using node.js, passport.js, and Angular.

Subsequent parts will cover:

  • Handling login, logout, and registration from a single page app
  • Adding in robust remember-me functionality
  • Protecting against CSRF
  • Protecting against XSS
  • Adding a reasonably robust remember-me to passport js
  • Enhancing security by adding some simple HTTP headers
  • Setting up to always redirect to SSL
  • Pushing our app to Heroku
  • Throttling login attempts

To get started, though, let’s just get Passport up and running using a mongoose backend. This starting point is based heavily off the multiple file example provided with passport-local, so shout out to andr3w321 for providing that example!

Prerequisites

You’ll need Node.js of course! Then make sure you’ve got MongoDB and finally Mongoose. You only need to install Mongoose, but you do need to start mongod – see the MongoDB docs for instructions.

Let’s get started

First off, grab the code:

git clone https://github.com/studds/secure-spa-part-1.git

Change in to the secure-spa-part-1 directory and run

npm install
grunt dbseed

What just happened?

Those commands:

  1. Downloaded the dependencies
  2. Installed jake (javascript make) globally, so we can use it on the command line
  3. Seeded our database (called “secure-spa-part-1″ by default) with some test users.

Now run:

node app.js

… and take a look at http://localhost:3000/
Passport-Local Example-Logged-In

The login page:
Passport-Local Example-Login 

After logged in:
Passport-Local Example-Index
I’ll let you explore the rest of that yourself.

The code

Setting up the database – db/schema.js

// Database connect
var uristring = 
  process.env.MONGOLAB_URI || 
  process.env.MONGOHQ_URL || 
  'mongodb://localhost/secure-spa-part-1';

var mongoOptions = { db: { safe: true }};

mongoose.connect(uristring, mongoOptions, function (err, res) {
  if (err) { 
    console.log ('ERROR connecting to: ' + uristring + '. ' + err);
  } else {
    console.log ('Successfully connected to: ' + uristring);
  }
});

First, we work out the URI to connect to the Mongo DB. The first two options (process.env.MONGOLAB_URI and process.env.MONGOHQ_URL) are included so that (later on) we can push this straight to Heroku 1.

Next, we set that mongo should run in safe mode. This means that we’ll wait for our inserts to succeed before going on. This is important when we’re altering passwords, but comes at a performance cost which might not be right for all apps. This is something we’ll come back to 2.

Then, we connect to the database. Easy.

I’m going to skip over setting up the mongoose schema – there are good docs and tutorials elsewhere that will explain that. Let’s just look at what we’re adding for security:

// Bcrypt middleware
userSchema.pre('save', function(next) {
	var user = this;

	if(!user.isModified('password')) return next();

	bcrypt.genSalt(SALT_WORK_FACTOR, function(err, salt) {
		if(err) return next(err);

		bcrypt.hash(user.password, salt, function(err, hash) {
			if(err) return next(err);
			user.password = hash;
			next();
		});
	});
});

// Password verification
userSchema.methods.comparePassword = function(candidatePassword, cb) {
	bcrypt.compare(candidatePassword, this.password, function(err, isMatch) {
		if(err) return cb(err);
		cb(null, isMatch);
	});
};

The ‘pre’ function will run before we save the model to the database. We need to do it this way because the hash function is asynchronous, and we need to make sure the clear text password is never saved to the database. When comparing the passwords, bcrypt has helpfully embedded the sale into the hash itself, so we don’t need to store that ourselves. For more details on this code, see 3.

Passport setup – config/pass.js

First up, we need to tell passport how it can serialize and deserialize users. The serialise function is called when the user logs in. Whatever it passes as the second parameter to done will be stored in the session 4 Deserialize is called is does just the opposite: it takes the id stored in the session and we use that id to retrieve our user.

passport.serializeUser(function(user, done) {
  done(null, user.id);
});

passport.deserializeUser(function(id, done) {
  db.userModel.findById(id, function (err, user) {
    done(err, user);
  });
});

Next up, we configure passport to use LocalStrategy – this is the middleware that will actually do the authentication. Passport extracts the username and password from the body, and passes them to this function, which then looks the user up in the database, and checks that the passwords match.

passport.use(new LocalStrategy(function(username, password, done) {
  db.userModel.findOne({ username: username }, function(err, user) {
    if (err) { return done(err); }
    if (!user) { return done(null, false, { message: 'Unknown user ' + username }); }
    user.comparePassword(password, function(err, isMatch) {
      if (err) return done(err);
      if(isMatch) {
        return done(null, user);
      } else {
        return done(null, false, { message: 'Invalid password' });
      }
    });
  });
}));

Finally, two simple route middlewares to check that the user is authenticated:

// Simple route middleware to ensure user is authenticated.  Otherwise send to login page.
exports.ensureAuthenticated = function ensureAuthenticated(req, res, next) {
  if (req.isAuthenticated()) { return next(); }
  res.redirect('/login')
};

// Check for admin middleware, this is unrelated to passport.js
// You can delete this if you use different method to check for admins or don't need admins
exports.ensureAdmin = function ensureAdmin(req, res, next) {
        if(req.user && req.user.admin === true)
            next();
        else
            res.send(403);
};

And now for something completely different – app.js

After all that build up, we come to app.js. We’re going to do a few things here that will lay the foundation of our SPA. Most notably, we’re going to establish a few base URLs for different security levels. This will come in handy when we’re creating the REST API that sits behind our app.

/
Everything, including public files – this is unsecured
/public
An explicit directory for public files – this is unsecured
/secure
Secure directory – must be logged in to access this
/secure/admin
Admin directory – must be logged in AND an admin to access this
// use express.session before passport, so that passport session will work
app.use(express.session({ secret: 'keyboard cat' }));
// Initialize Passport!  Also use passport.session() middleware, to support
// persistent login sessions (recommended).
app.use(passport.initialize());
app.use(passport.session());
app.use(app.router);
// clearly denote public content
app.use('/public', express.static('public'));

// set up our security to be enforced on all requests to secure paths
app.all('/secure', pass.ensureAuthenticated);
app.all('/secure/admin', pass.ensureAdmin);

// Basic pages
app.get('/', basic_routes.index);

// Login pages
app.get('/dmz/login', user_routes.getlogin);
app.post('/dmz/login', user_routes.postlogin);
app.get('/dmz/logout', user_routes.logout);

// secure pages
app.get('/secure/account', user_routes.account);

//admin pages
app.get('/secure/admin', user_routes.admin);

Well, that’s our foundation in place. Stay tuned for part 2, where we’ll add in a registration form.


How to create a secure single page app with a node.js backend

Posted: April 29th, 2013 | Author: | Filed under: Uncategorized | No Comments »

Over the weekend, I put my first product online. It’s still a little bit rusty and not ready for the prime time. I’ve broken all the rules:

  • Haven’t identified who my customer is
  • Haven’t really identified that the pain is real
  • Haven’t set up a sales funnel
  • Haven’t set up anything for SEO
  • Spent a few days developing before doing any of the above

So, given the above, I would say that success is far from guaranteed!

I’ve also, though, learnt a lot – and in the scheme of things, a few days developing is not that bad. Over the next month, I’ll be blogging about how to create a secure single page application with a node.js backend. I’ll cover off:

  • Handling login, logout, and registration from a single page app
  • Adding in robust remember-me functionality
  • Protecting against CSRF
  • Protecting against XSS
  • Adding a reasonably robust remember-me to passport js
  • Enhancing security by adding some simple HTTP headers
  • Setting up to always redirect to SSL

Adblock for Chrome

Posted: June 3rd, 2010 | Author: | Filed under: Reviews | No Comments »

I’ve been using Chrome for a while, and I must have missed the memo where they added extension support, so I didn’t know there was an AdBlock extension either.

Thank god for The Age. Browsing through some articles this morning, I noticed that they had a full-motion ad for cough medicine. My first thought was: wow, online ads have really come along. My second thought was: I wonder if I can get AdBlock for Chrome? I can tune out still ads, which is why I’ve been using Chrome without AdBlock for so long. These video ads are really hard to ignore, though.

I have to wonder if these advertising companies are sowing the seeds of their own destruction – if they keep making more annoying ads, more and more people will take the 10 seconds needed to install AdBlock.

Tags: , ,

Javascript Form Validation

Posted: May 23rd, 2010 | Author: | Filed under: IT | No Comments »

This is an incredibly common problem, and there’s really no reason to reinvent the wheel. That said, yesterday I thought of (what I think is) a rather neat way of solving the problem. So I’ve deliberately not looked in-depth at how others have solved this particular problem, and instead made a quick sketch of my solution. When I do look, I think I’ll be looking at the jQuery Validation Plugin.

In short, this model is inspired by jQuery’s ability to chain queries together, to give succinct, powerful syntax. There are two essential things that I want to be able to do:

  1. Check if a condition is present
  2. Assert that something should be so

My aim is to be able to do this with code that looks like this:

vl.ifEqual("detailrequired","Full")
  .assertNotEmpty("If full details are required,"
                  + "contributions must be entered",
                  "contributions");

But let’s start at the beginning. Form validation: there are many levels. Let me enumerate some:

  1. Required fields
  2. Fields having the correct format
  3. Inter-field validation (eg a start date falling before an end date)

In this sketch, I’m particularly thinking of the third level of form validation. In the example of a start and end date, all I want to do is check that the start date falls before the end date, and it it does, throw an error. I can do that with this code (error handling removed for brevity):

var startdate = Date.parse(document.getElementById("startdate").value);
var enddate = Date.parse(document.getElementById("enddate").value);
if (startdate > enddate) {
    alert("Start date must fall before the end date");
}

Simple enough, but rather wordy – particularly when you get in to handling errors and unexpected input. A more complex example might be to check the value of one field, and depending on its value, apply a particular rule. For example, if a field detailsrequired equals full, then a number of other fields are required. This could be achieved with this Javascript:

if (document.getElementById("detailsrequired").value=="Full") {
    if (document.getElementById("contribututions").value=="") {
        alert("If full details are required, "
               + "contributions must be entered");
    }
}

These individual samples aren’t very complex, but once you add code to handle exceptions, then they blow out a little bit. It’s also quite verbose. To achieve the syntax outlined above, where I can chain the checks and assertions together, I need to create an object that returns a reference to itself when you call any of its methods – the same way as jQuery works.

In the following code excerpt, I create two functions, and then bind them to a function object, ValidationLibrary. First a word on the function object: it has a single property, ‘check’, that is set by its single parameter. This parameter is used by the function assertEmpty. If this.check is true, then it will apply the assertion. If not, it doesn’t do anything.

The ifEqual function takes two parameters and compares them. If they are equal, it returns the parent object unaltered. On the other hand, if it they are unequal, it returns a new ValidationLibrary with check set to false – thus disabling any subsequent assertions.

function ifEqual(a, b) {
    if (a!=b) {
        return new ValidationLibrary(false);
    }
    return this;
}

function assertNotEmpty(msg, a) {
    if (this.check) {
        if (a=="") {
            this.error(msg);
        }
    }
    return this;
}

function ValidationLibrary(check) {
     this.check = check;
     this.assertNotEmpty = assertNotEmpty;
     this.ifEqual = ifEqual;
} 

With this framework, the example above becomes:

var vl = new ValidationLibrary(true);
vl.ifEqual(f("detailsrequired"),"Full")
  .assertNotEmpty("If full details only are required, "
                    + " contribution must be provided",
                  f("contribution"));

Note: I’ve created a function f(id) that returns the value of a form field, given a particular ID. If the form field contains a date, a Date object will be returned. If the form field contains a number, a Number object will be returned. Otherwise, a string will be returned.

With this framework, there’s a lot less boilerplate in order to get the same effect, and behind the scenes there is (or is in theory) a lot more error checking.

As above, this is only a rough sketch to capture the idea. I’m still to go and look at how other people have solved this same problem. And to be usable, a lot more would need to be done on this framework: the way assertions are reported in particular would need a lot of work, and even a cursory glance shows the the jQuery Validation plugin does a much better job of simple validations like making a field mandatory.

That said, the main idea I wanted to jot down was a way of handling more complex validations in an elegant way: I’m curious to see what other options are already in use.

In the meantime, please feel free to check out the rough demo and peruse the full javascript files, ValidateLibrary.js and FormValidations.js.

Tags: , , , , , ,

Installing Oracle Instant Client (and connecting to Oracle from Excel)

Posted: May 1st, 2010 | Author: | Filed under: IT | 2 Comments »

‘Instant’ probably overstates it somewhat, but the Oracle Instant Client does let you connect to an Oracle database in a reasonably snappy way. It’s pretty straight-forward too, but there are a few hoops to jump through. Here’s how I got it working.

Installing Instant Client

  1. Download the Instant Client. You’ll need the ‘basic’ or ‘basiclite’ packages, and you’ll probably want one of the add-ons, like the jdbc driver (for Java) or the odbc driver. I grabbed the odbc driver, because I’m going to connect via Excel. You’ll need to sign up to the Oracle website to access the downloads. I’ve been a member for a while, and it seems pretty harmless – no spam that I’ve noticed. Once you’ve downloaded the packages, unzip them to the same directory.
  2. The current packages ship without some necessary DLLs, as detail on the OTN Discussion Forum. The missing DLLs are MFC71.dll, msvcr71.dll and MFC71ENU.dll. I believe they’re part of the Visual Studio install, and I had them on my PC, but I needed to drag them into the install directory. If you don’t have them, you can google them (if you’re feeling lucky.) Update: looks like they’ve updated the packages, and you shouldn’t need to track down these dlls any longer.
  3. Place this directory where you want it and run odbc_install.exe. The install adds some registry settings to register to odbc driver, and it points to the driver in the directory you’re using.
  4. Create an environment variable called TNS_ADMIN. The value should be the path to the directory that contains tnsnames.ora, which lets the Oracle driver know what servers are available. Managing tnsnames.ora can be frustrating, especially for the uninitiated (that is, me), and in a subsequent post, I’ll detail how to connect without tnsnames.ora.
  5. You’ll also need to create an NLS_LANG environmental value. Oracle recommends you set this in the registry, but the instantclient doesn’t create the registry structures needed. You could create them, but it’s easier to create the environmental variable. Oracle provides a list of possible values.
  6. You can now connect to your Oracle DB using Microsoft Query.

Update: The promised post to connect using VBA is on it’s way! In the meantime, to connect with Microsoft Query, there’s a few things to be aware of.

Connecting with Microsoft Query

Firstly, your TNS_ADMIN environment variable must point to a valid file – or this won’t work. If you’re connecting to Oracle Express Edition, then you’re tnsnames.ora will look like this:

XE =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCP)(HOST = 127.0.0.1)(PORT = 1521))
)
(CONNECT_DATA =
(SERVICE_NAME = XE)
)
)

If you’re connecting to another Oracle database, you’ll need to find the appropriate tnsnames.ora. It might be under a path like C:/oracle/network/admin/. Without TNS_ADMIN pointing to a directory with a valid tnsnames.ora, you won’t be able to connect using this method.

There are two ways of setting up the connection. The first is directly through Microsoft Excel. The second is through ODBC Data Source Administrator. ODBC Data Source Administrator is probably the better way, but I’ll look at setting it up through Excel first.

New connection through excel

  1. In Excel, start Microsoft Query. In Office 2007, go to the Data ribbon and click on Get External Data -> From Other Sources -> Microsoft Query.
    The Choose Data Source dialog shown in Excel when you choose to import external data using Microsoft Query
  2. Leave <New Data Source> selected and click OK. The Create New Data Source dialogue will be displayed. Enter a name for the data source, and the driver drop-down becomes enabled. Select Oracle in instantclient_11_2 (or similar).
    The Create New Data Source window in Microsoft Query
  3. Click connect. The service name must much a valid service name in the tnsnames.ora. If you’re using the Oracle Express example above (and have installed the Oracle Express client with default settings) this will be XE. The username and password will be whatever you or the sysadmin set.
  4. Click OK. If you cannot connect at this point, but you can connect to the database by other means, it most likely means that your tnsnames.ora is wrong or that TNS_ADMIN is not pointing to the right directory (note that if you change the environmental variable, you’ll need to restart Excel for the change to take effect.)
  5. All being well, you will now be able to select a default table (if you choose to) and use Microsoft Query as you normally would.

Congratulations! You’re now connected to Oracle using Microsoft Query!

Creating the connection in ODBC Data Source Administrator

It’s often easier and more convenient to set up the new data source through the ODBC Data Source Administrator. This way, the new data source will be available whenever you want to use it, rather than needing to recreate it every time.

  1. Open the ODBC Data Source Administrator. This is in Control Panels. Under Windows 7 64bit you’ll need to choose the appropriate version: odbcad32.exe under either system32 or SysWOW64, depending on whether you’re setting up a connection for 32bit or 64 bit applications.
  2. Click Add. The Create New Data Source window appears. Choose the Oracle in instantclient_11_2 driver and click OK.
  3. The Oracle ODBC Driver Configuration page will open. This page gives you far more options and is more intelligent than the equivalent if you create the connection in Excel. The TNS Service Names drop-down box will populate with the databases specified in tnsnames.ora: if no options appear, then either your tnsnames.ora file is invalid, or TNS_ADMIN is not specified correctly. Again, if you change TNS_ADMIN, you’ll need to restart ODBC Data Source Administrator for the change to take effect.
  4. Click ‘Test Connection’. You’ll be prompted to enter a password, and all being well, you’ll get this dialogue:
  5. Click OK in the Data Source Configuration dialogue, and open Microsoft Excel. The new Data Source will appear when you open Microsoft Query.
  6. Click OK and you can use the connection in Microsoft Query as usual.

Still to come…

So that’s two different ways to connect to Oracle in Excel using Microsoft Query. As soon as I have time, I’ll be posting a sample workbook and instructions on how to connect to Oracle using VBA instead of Microsoft Query, which is especially handy if you want to distribute the workbook.

Tags: , , , ,

Barefooting

Posted: April 25th, 2010 | Author: | Filed under: Health | No Comments »

A couple of weeks ago I bought a pair of Vibram Five Fingers Sprint.

Vibram Five Fingers Sprint Grey

Vibram Five Fingers Sprint Grey

The idea of these shoes is to let your foot work the way it evolved to. The human foot is the most complex piece of anatomy that we have, but most of the time it’s hidden away in inflexible shoes that prevent it from moving the way it should. We walk and run like cows, when we should be running like foxes. It’s foxier, and better for your body.

When you land first on your heel when walking or running, the impact is absorbed first by your cushy shoe, but then mostly by your skeleton. Needless to say, that’s not what your skeleton was designed for. Enter joint problems and shin pain.

On the other hand, when you land on the ball of your foot, the impact is smoothed by your foot and absorbed by muscles, leading to beautifully toned calves. I know which I prefer.

I must admit, I was at first sceptical about running the balls of my feet, and even more sceptical about walking on the balls of my feet. Now that I’ve tried it for the past two weeks, though, it does feel far more natural – and far more enjoyable.

The only problem with these shoes is that they look quite ridiculous. Already I dread putting on my traditional shoes, especially the dress shoes I wear to work. It’s impossible to walk properly in them because of the heal, and I’m much more conscious of the way they crush my feet. Even so, there’s no way I could wear Five Fingers to work.

I’m on the lookout for a softer, kinder shoe that could pass for a dress shoe, but I haven’t found any good matches to date.

Any other barefooters out there? Has anyone found a better compromise between corporate dress and walking right?

Tags: , , , , ,