var hashUtils = require('./hashing.js'); var chai = require('chai'); var chaiAsPromised = require('chai-as-promised'); var expect = chai.expect; chai.use(chaiAsPromised); // // Sample data // const samplePassword = '5678'; const incorrectPassword = '5679'; // // Current max password version // const latestVersion = 2; // // Sample V1 hash: actually just a direct compare // const sampleHashV1 = '5678'; // // Sample V2 values. Calculated indepedently using the Standford Javascript // Crypto Library: http://bitwiseshiftleft.github.io/sjcl/ // const sampleHashV2 = '2::920290ac3bc5f38d78ca46a2e714da6f0e45a080d2a0259e09bc04cfa3d9b081'; const sampleSaltV2 = '1ba8b6f708f075241f3d7cd9d63e0664b62e98f01ca83aafa453896fa49e8f1a'; describe('Hashing utilities', function() { describe('generateHash', function() { it('should give hash+salt', function() { var result = hashUtils.generateHash(2, samplePassword); return expect(result).to.eventually.have.property('hash'); }); it('should match on verify', function() { var hash = hashUtils.generateHash(2, samplePassword); var result = hash.then(function(newHash) { return hashUtils.verifyHash(samplePassword, newHash.hash, newHash.salt, latestVersion); }); return expect(result).to.eventually.be.fulfilled; }); }); describe('valid v1 hash with matching password', function() { var result = null; beforeEach('call verifyHash', function() { result = hashUtils.verifyHash(samplePassword, sampleHashV1, '', latestVersion); }); it('should match a v1 hash', function() { return expect(result).to.eventually.be.fulfilled; }); it('should generate a v2 hash', function() { return expect(result).to.eventually.have.property('hash'); }); it('should generate a new salt', function() { return expect(result).to.eventually.have.property('salt'); }); it('should generate a 64 character salt (32 bytes = 64 hex chars)', function() { return result.then(function(newHash) { expect(newHash.salt).to.have.length(64); }); }); it('should generate a 67 character hash ("2::" + 32 bytes/64 hex chars)', function() { return result.then(function(newHash) { expect(newHash.hash).to.have.length(67); }); }); it('should generate a hash in the right format', function() { return result.then(function(newHash) { expect(newHash.hash).to.match(/^2::[0-9a-z]{64}$/); }); }); }); describe('valid v2 hash with matching password', function() { var result = null; beforeEach('call verifyHash', function() { result = hashUtils.verifyHash(samplePassword, sampleHashV2, sampleSaltV2, latestVersion); }); it('should match a v2 hash', function() { return expect(result).to.eventually.be.fulfilled; }); it('should not generate a new hash/salt (already latest version)', function() { return expect(result).to.eventually.equal(null); }); }); describe('wrong password', function() { it('should not match a v1 hash', function() { var result = hashUtils.verifyHash(incorrectPassword, sampleHashV1, '', latestVersion); return expect(result).to.eventually.be.rejectedWith(hashUtils.ERRORS.NO_MATCH); }); it('should not match a v2 hash', function() { var result = hashUtils.verifyHash(incorrectPassword, sampleHashV2, '', latestVersion); return expect(result).to.eventually.be.rejectedWith(hashUtils.ERRORS.NO_MATCH); }); }); describe('unknown latest version', function() { it('v1 hash should fail to generate a new hash/salt', function() { var result = hashUtils.verifyHash(samplePassword, sampleHashV1, '', latestVersion + 1); return expect(result).to.eventually.be.rejectedWith(hashUtils.ERRORS.UNKNOWN_ALGO); }); it('v2 hash should fail to generate a new hash/salt', function() { var result = hashUtils.verifyHash(samplePassword, sampleHashV2, sampleSaltV2, latestVersion + 1); return expect(result).to.eventually.be.rejectedWith(hashUtils.ERRORS.UNKNOWN_ALGO); }); }); });