
var crypto = require('crypto');

var hotp = {};

/**
 * Generate a counter based One Time Password
 *
 * @return {String} the one time password
 *
 * Arguments:
 *
 *  args
 *     key - Key for the one time password.  This should be unique and secret for
 *         every user as this is the seed that is used to calculate the HMAC
 *
 *     counter - Counter value.  This should be stored by the application, must
 *         be user specific, and be incremented for each request.
 *
 */
hotp.gen = function(key, opt) {
	key = key || '';
	opt = opt || {};
	var counter = opt.counter || 0;
	var characters = opt.characters || 4;
	var modulo = '1';
	
	for(var x = characters; x--;) modulo = modulo + '0'; 

	// Create the byte array
	var b = new Buffer(intToBytes(counter));

	var hmac = crypto.createHmac('sha1', new Buffer(key));

	// Update the HMAC with the byte array
	var digest = hmac.update(b).digest('hex');

	// Get byte array
	var h = hexToBytes(digest);

	// Truncate
	var offset = h[19] & 0xf;
	var v = (h[offset] & 0x7f) << 24 |
		(h[offset + 1] & 0xff) << 16 |
		(h[offset + 2] & 0xff) << 8  |
		(h[offset + 3] & 0xff);
		console.log(v);
	
	v = (v % parseInt(modulo)) + '';
	
	return Array((characters + 1)-v.length).join('0') + v;
};

/**
 * Check a One Time Password based on a counter.
 *
 * @return {Object} null if failure, { delta: # } on success
 * delta is the time step difference between the client and the server
 *
 * Arguments:
 *
 *  args
 *     key - Key for the one time password.  This should be unique and secret for
 *         every user as it is the seed used to calculate the HMAC
 *
 *     token - Passcode to validate.
 *
 *     window - The allowable margin for the counter.  The function will check
 *         'W' codes in the future against the provided passcode.  Note,
 *         it is the calling applications responsibility to keep track of
 *         'W' and increment it for each password check, and also to adjust
 *         it accordingly in the case where the client and server become
 *         out of sync (second argument returns non zero).
 *         E.g. if W = 100, and C = 5, this function will check the passcode
 *         against all One Time Passcodes between 5 and 105.
 *
 *         Default - 50
 *
 *     counter - Counter value.  This should be stored by the application, must
 *         be user specific, and be incremented for each request.
 *
 */
hotp.verify = function(token, key, opt) {
	opt = opt || {};
	var window = opt.window || 50;
	var counter = opt.counter || 0;

	// Now loop through from C to C + W to determine if there is
	// a correct code
	for(var i = counter - window; i <=  counter + window; ++i) {
		opt.counter = i;
		if(this.gen(key, opt) === token) {
			// We have found a matching code, trigger callback
			// and pass offset
			return { delta: i - counter };
		}
	}

	// If we get to here then no codes have matched, return null
	return null;
};

var totp = {};

/**
 * Generate a time based One Time Password
 *
 * @return {String} the one time password
 *
 * Arguments:
 *
 *  args
 *     key - Key for the one time password.  This should be unique and secret for
 *         every user as it is the seed used to calculate the HMAC
 *
 *     time - The time step of the counter.  This must be the same for
 *         every request and is used to calculat C.
 *
 *         Default - 30
 *
 */
totp.gen = function(key, opt) {
	opt = opt || {};
	var time = opt.time || 30;
	var _t = new Date().getTime();

	// Time has been overwritten.
	if(opt._t) {
		if(process.env.NODE_ENV != 'test') {
			throw new Error('cannot overwrite time in non-test environment!');
		}
		_t = opt._t;
	}

	// Determine the value of the counter, C
	// This is the number of time steps in seconds since T0
	opt.counter = Math.floor((_t / 1000) / time);

	return hotp.gen(key, opt);
};

/**
 * Check a One Time Password based on a timer.
 *
 * @return {Object} null if failure, { delta: # } on success
 * delta is the time step difference between the client and the server
 *
 * Arguments:
 *
 *  args
 *     key - Key for the one time password.  This should be unique and secret for
 *         every user as it is the seed used to calculate the HMAC
 *
 *     token - Passcode to validate.
 *
 *     window - The allowable margin for the counter.  The function will check
 *         'W' codes either side of the provided counter.  Note,
 *         it is the calling applications responsibility to keep track of
 *         'W' and increment it for each password check, and also to adjust
 *         it accordingly in the case where the client and server become
 *         out of sync (second argument returns non zero).
 *         E.g. if W = 5, and C = 1000, this function will check the passcode
 *         against all One Time Passcodes between 995 and 1005.
 *
 *         Default - 6
 *
 *     time - The time step of the counter.  This must be the same for
 *         every request and is used to calculate C.
 *
 *         Default - 30
 *
 */
totp.verify = function(token, key, opt) {
	opt = opt || {};
	var time = opt.time || 30;
	var _t = new Date().getTime();

	// Time has been overwritten.
	if(opt._t) {
		if(process.env.NODE_ENV != 'test') {
			throw new Error('cannot overwrite time in non-test environment!');
		}
		_t = opt._t;
	}

	// Determine the value of the counter, C
	// This is the number of time steps in seconds since T0
	opt.counter = Math.floor((_t / 1000) / time);

	return hotp.verify(token, key, opt);
};

module.exports.hotp = hotp;
module.exports.totp = totp;

/**
 * convert an integer to a byte array
 * @param {Integer} num
 * @return {Array} bytes
 */
var intToBytes = function(num) {
	var bytes = [];

	for(var i=7 ; i>=0 ; --i) {
		bytes[i] = num & (255);
		num = num >> 8;
	}

	return bytes;
};


/**
 * convert a hex value to a byte array
 * @param {String} hex string of hex to convert to a byte array
 * @return {Array} bytes
 */
var hexToBytes = function(hex) {
	var bytes = [];
	for(var c = 0, C = hex.length; c < C; c += 2) {
		bytes.push(parseInt(hex.substr(c, 2), 16));
	}
	return bytes;
};

@@ -1131,26 +1131,8 @@
 f);%0A
-%09%09console.log(v);%0A
 %09%0A%09v

update index.js