Generating UUIDs in Javascript

I was looking for a method of generating UUIDs using Javascript and after a quick search, came across an ExtJS implementation which seemed to do the job quite nicely. However, I don’t use ExtJS so I quickly ported it to MooTools which I’m currently using for most projects.

The code works well but the uniqueness of the UUID may not be sufficient depending on what you intend to use if for, in which case you’d be better off using XHR to return a server-generated identifier which would be of higher entropy.

View demo

// Direct MooTools port of Ext.ux.UUID.js - http://ext.vosandhowden.com/ux/uuid/Ext.ux.UUID.js
// Original version copyright (C) 2006, Erik Giberti (AF-Design), and licensed GNU GPL

var UUID = new Class({
    initialize: function() {
        this.id = '';
        if(Browser.Engine.trident) {
            /* for IE users, we can use a built-in ActiveX object to retrive a GUID and trim it
            to 38 characters to more closely resemble a UUID. */
            try {
                var guid = (new ActiveXObject('Scriptlet.TypeLib').GUID).substr(1, 36).split('-');
                this.id = guid[0] + '-' + guid[1] + '-' + guid[2] + '-' + guid[3] + guid[4];
            }
            catch(e) {this.generateUUID();}
        }
        else
            this.generateUUID();
    },
    generateUUID: function() {
        /* Loose interpretation of the specification DCE 1.1: Remote Procedure Call
        described at http://www.opengroup.org/onlinepubs/009629399/apdxa.htm#tagtcjh_37
        since JavaScript doesn't allow access to internal systems, the last 48 bits
        of the node section is made up using a series of random numbers (6 octets long). */
        var dg = new Date(1582, 10, 15, 0, 0, 0, 0).getTime();
        var dc = new Date().getTime();
        var t = (dg < 0) ? Math.abs(dg) + dc : dc - dg;
        var h = '-';
        var tl = this.getIntegerBits(t, 0, 31);
        var tm = this.getIntegerBits(t, 32, 47);
        var thv = this.getIntegerBits(t, 48, 59) + '1'; // version 1, security version is 2
        var csar = this.getIntegerBits(Math.randRange(0, 4095), 0, 7);
        var csl = this.getIntegerBits(Math.randRange(0, 4095), 0, 7);

        /* since detection of anything about the machine/browser is far too buggy, include
        some more random numbers here if nic or at least an IP can be obtained reliably,
        that should be put in here instead. */
        var n = this.getIntegerBits(Math.randRange(0, 8191), 0, 7) +
                this.getIntegerBits(Math.randRange(0, 8191), 8, 15) +
                this.getIntegerBits(Math.randRange(0, 8191), 0, 7) +
                this.getIntegerBits(Math.randRange(0, 8191), 8, 15) +
                this.getIntegerBits(Math.randRange(0, 8191), 0, 15); // this last number is two octets long
        this.id = tl + h + tm + h + thv + h + csar + csl + n;
    },
    getIntegerBits: function(val, start, end) {
        var quadArray = val.toString(16).toUpperCase().split('');
        var quadString = '';
        for(var i = Math.floor(start / 4); i <= Math.floor(end / 4); i++) {
            if(!quadArray[i] || quadArray[i] == '') quadString += '0';
            else quadString += quadArray[i];
        }
        return quadString;
    }
});


Math.randRange = function(min, max) { 
    return Math.max(Math.min(Math.round(Math.random() * max), max), min);
}

2009-08-14