argon2-pass
Advanced tools
Comparing version 0.2.1 to 0.2.2
# Changelog | ||
All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). | ||
## [0.2.2] - 2018-09-10 | ||
### Added | ||
- Added convenience functions to test if a VerificationResult is a specific type. These are; `isInvalidOrUnrecognized()`, `isInvalid()`, `isValid()` and `isValidNeedsRehash()`. These functions will return true if the enumeration value matches the tested value. | ||
## [0.2.1] - 2018-09-09 | ||
@@ -11,2 +16,3 @@ ### Removed | ||
### Added | ||
- Added JSDoc comments to all functions and important objects. This was then used with the TypeDoc module to generate a documentation site for the package. | ||
@@ -13,0 +19,0 @@ - Added synchronous versions of hash and verify. `hashPasswordSync()` and `verifyHashSync()`. |
@@ -6,3 +6,3 @@ "use strict"; | ||
describe('bufferFromSafeBase64', () => { | ||
test('Should convert a valid base64 string into a buffer.', () => { | ||
test('Should convert a valid url-safe base64 string into a buffer.', () => { | ||
const expected = Buffer.from('TestString'); | ||
@@ -14,7 +14,9 @@ const buffer = __1.bufferFromSafeBase64('VGVzdFN0cmluZw'); | ||
describe('bufferToSafeBase64', () => { | ||
const expected = 'VGVzdFN0cmluZw'; | ||
const base64 = __1.bufferToSafeBase64(Buffer.from('TestString')); | ||
expect(base64).toEqual(expected); | ||
test('Should convert a buffer into a valid url-safe base64 string.', () => { | ||
const expected = 'VGVzdFN0cmluZw'; | ||
const base64 = __1.bufferToSafeBase64(Buffer.from('TestString')); | ||
expect(base64).toEqual(expected); | ||
}); | ||
}); | ||
}); | ||
//# sourceMappingURL=base64.js.map |
@@ -10,27 +10,14 @@ "use strict"; | ||
}; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const sodium_native_1 = __importDefault(require("sodium-native")); | ||
const __1 = require(".."); | ||
const error_1 = require("../error"); | ||
describe('SecurePass - Constants', () => { | ||
test('PasswordBytes* Constants should be defined.', () => { | ||
describe('SecurePass', () => { | ||
test('static readonly constants should be defined.', () => { | ||
expect(__1.SecurePass.PasswordBytesMin).toBeDefined(); | ||
expect(__1.SecurePass.PasswordBytesMax).toBeDefined(); | ||
expect(__1.SecurePass.PasswordBytesMin).toBeDefined(); | ||
}); | ||
test('HashBytes Constant should be defined.', () => { | ||
expect(__1.SecurePass.HashBytes).toBeDefined(); | ||
}); | ||
test('SaltBytes Constant should be defined', () => { | ||
expect(__1.SecurePass.SaltBytes).toBeDefined(); | ||
}); | ||
test('MacBytes Constant should be defined.', () => { | ||
expect(__1.SecurePass.MacBytes).toBeDefined(); | ||
}); | ||
test('KeyBytes Constant should be defined.', () => { | ||
expect(__1.SecurePass.KeyBytes).toBeDefined(); | ||
}); | ||
test('MemLimit* Constants should be defined.', () => { | ||
// Memory Limit Constants | ||
expect(__1.SecurePass.MemLimitDefault).toBeDefined(); | ||
@@ -42,4 +29,3 @@ expect(__1.SecurePass.MemLimitInteractive).toBeDefined(); | ||
expect(__1.SecurePass.MemLimitMaximum).toBeDefined(); | ||
}); | ||
test('OpsLimit* Constants should be defined.', () => { | ||
// Operations Limit Constants | ||
expect(__1.SecurePass.OpsLimitDefault).toBeDefined(); | ||
@@ -52,144 +38,180 @@ expect(__1.SecurePass.OpsLimitInteractive).toBeDefined(); | ||
}); | ||
test('VerificationResult.* Enum Constants should be defined.', () => { | ||
expect(__1.VerificationResult.InvalidOrUnrecognized).toEqual(0); | ||
expect(__1.VerificationResult.Invalid).toEqual(1); | ||
expect(__1.VerificationResult.Valid).toEqual(2); | ||
expect(__1.VerificationResult.ValidNeedsRehash).toEqual(3); | ||
test('static readonly constants should have the correct values.', () => { | ||
expect(__1.SecurePass.PasswordBytesMin).toEqual(1); | ||
expect(__1.SecurePass.PasswordBytesMax).toEqual(2147483647); | ||
expect(__1.SecurePass.HashBytes).toEqual(128); | ||
expect(__1.SecurePass.SaltBytes).toEqual(16); | ||
expect(__1.SecurePass.MacBytes).toEqual(16); | ||
expect(__1.SecurePass.KeyBytes).toEqual(32); | ||
// Memory Limit Constants | ||
expect(__1.SecurePass.MemLimitDefault).toEqual(67108864); | ||
expect(__1.SecurePass.MemLimitInteractive).toEqual(67108864); | ||
expect(__1.SecurePass.MemLimitModerate).toEqual(268435456); | ||
expect(__1.SecurePass.MemLimitSensitive).toEqual(1073741824); | ||
expect(__1.SecurePass.MemLimitMinimum).toEqual(8192); | ||
expect(__1.SecurePass.MemLimitMaximum).toEqual(4398046510080); | ||
// Operations Limit Constants | ||
expect(__1.SecurePass.OpsLimitDefault).toEqual(2); | ||
expect(__1.SecurePass.OpsLimitInteractive).toEqual(2); | ||
expect(__1.SecurePass.OpsLimitModerate).toEqual(3); | ||
expect(__1.SecurePass.OpsLimitSensitive).toEqual(4); | ||
expect(__1.SecurePass.OpsLimitMinimum).toEqual(1); | ||
expect(__1.SecurePass.OpsLimitMaximum).toEqual(4294967295); | ||
}); | ||
}); | ||
describe('SecurePass - Options', () => { | ||
test('Passing no configuration should create a new instance with the default options.', () => { | ||
const sp = new __1.SecurePass(); | ||
expect(sp.MemLimit).toEqual(sodium_native_1.default.crypto_pwhash_MEMLIMIT_INTERACTIVE); | ||
expect(sp.OpsLimit).toEqual(sodium_native_1.default.crypto_pwhash_OPSLIMIT_INTERACTIVE); | ||
}); | ||
test('Passing in an empty object should create a new instance with the default options.', () => { | ||
const sp = new __1.SecurePass({}); | ||
expect(sp.MemLimit).toEqual(sodium_native_1.default.crypto_pwhash_MEMLIMIT_INTERACTIVE); | ||
expect(sp.OpsLimit).toEqual(sodium_native_1.default.crypto_pwhash_OPSLIMIT_INTERACTIVE); | ||
}); | ||
test('A valid value for memLimit should be set correctly. And opsLimit should be set to the default value.', () => { | ||
const sp = new __1.SecurePass({ | ||
memLimit: 16384 | ||
describe('VerificationResult', () => { | ||
test('VerificationResult enumeration has the right values.', () => { | ||
expect(__1.VerificationResult.InvalidOrUnrecognized).toEqual(0); | ||
expect(__1.VerificationResult.Invalid).toEqual(1); | ||
expect(__1.VerificationResult.Valid).toEqual(2); | ||
expect(__1.VerificationResult.ValidNeedsRehash).toEqual(3); | ||
}); | ||
expect(sp.MemLimit).toEqual(16384); | ||
expect(sp.OpsLimit).toEqual(sodium_native_1.default.crypto_pwhash_OPSLIMIT_INTERACTIVE); | ||
}); | ||
test('A valid value for opsLimit should be set correctly. And memLimit should be set to the default value.', () => { | ||
const sp = new __1.SecurePass({ | ||
opsLimit: 12 | ||
test.each([ | ||
[__1.VerificationResult.InvalidOrUnrecognized, true], | ||
[__1.VerificationResult.Invalid, false], | ||
[__1.VerificationResult.Valid, false], | ||
[__1.VerificationResult.ValidNeedsRehash, false] | ||
])('isInvalidOrUnrecognized should return the correct result when called with %i.', (vr, b) => { | ||
expect(__1.SecurePass.isInvalidOrUnrecognized(vr)).toEqual(b); | ||
}); | ||
expect(sp.MemLimit).toEqual(sodium_native_1.default.crypto_pwhash_MEMLIMIT_INTERACTIVE); | ||
expect(sp.OpsLimit).toEqual(12); | ||
}); | ||
test('A lower bounds value for memLimit should still be considered valid.', () => { | ||
const sp = new __1.SecurePass({ | ||
memLimit: __1.SecurePass.MemLimitMinimum | ||
test.each([ | ||
[__1.VerificationResult.InvalidOrUnrecognized, false], | ||
[__1.VerificationResult.Invalid, true], | ||
[__1.VerificationResult.Valid, false], | ||
[__1.VerificationResult.ValidNeedsRehash, false] | ||
])('isInvalid should return the correct result when called with %i.', (vr, b) => { | ||
expect(__1.SecurePass.isInvalid(vr)).toEqual(b); | ||
}); | ||
expect(sp.MemLimit).toEqual(__1.SecurePass.MemLimitMinimum); | ||
}); | ||
test('An upper bounds value for memLimit should still be considered valid.', () => { | ||
const sp = new __1.SecurePass({ | ||
memLimit: __1.SecurePass.MemLimitMaximum | ||
test.each([ | ||
[__1.VerificationResult.InvalidOrUnrecognized, false], | ||
[__1.VerificationResult.Invalid, false], | ||
[__1.VerificationResult.Valid, true], | ||
[__1.VerificationResult.ValidNeedsRehash, false] | ||
])('isValid should return the correct result when called with %i.', (vr, b) => { | ||
expect(__1.SecurePass.isValid(vr)).toEqual(b); | ||
}); | ||
expect(sp.MemLimit).toEqual(__1.SecurePass.MemLimitMaximum); | ||
}); | ||
test('A lower bounds value for opsLimit should still be considered valid.', () => { | ||
const sp = new __1.SecurePass({ | ||
opsLimit: __1.SecurePass.OpsLimitMinimum | ||
test.each([ | ||
[__1.VerificationResult.InvalidOrUnrecognized, false], | ||
[__1.VerificationResult.Invalid, false], | ||
[__1.VerificationResult.Valid, false], | ||
[__1.VerificationResult.ValidNeedsRehash, true] | ||
])('isValidNeedsRehash should return the correct result when called with %i.', (vr, b) => { | ||
expect(__1.SecurePass.isValidNeedsRehash(vr)).toEqual(b); | ||
}); | ||
expect(sp.OpsLimit).toEqual(__1.SecurePass.OpsLimitMinimum); | ||
}); | ||
test('An upper bounds value for opsLimit should still be considered valid.', () => { | ||
const sp = new __1.SecurePass({ | ||
opsLimit: __1.SecurePass.OpsLimitMaximum | ||
describe('SecurePass MemLimit and OpsLimit Options', () => { | ||
test('Passing no configuration to SecurePass, should create a new instance with the default values', () => { | ||
const sp1 = new __1.SecurePass(); | ||
expect(sp1.MemLimit).toEqual(__1.SecurePass.MemLimitDefault); | ||
expect(sp1.OpsLimit).toEqual(__1.SecurePass.OpsLimitDefault); | ||
const sp2 = new __1.SecurePass({}); | ||
expect(sp2.MemLimit).toEqual(__1.SecurePass.MemLimitDefault); | ||
expect(sp2.OpsLimit).toEqual(__1.SecurePass.OpsLimitDefault); | ||
}); | ||
expect(sp.OpsLimit).toEqual(__1.SecurePass.OpsLimitMaximum); | ||
}); | ||
test('An invalid value for memLimit should throw an error.', () => { | ||
try { | ||
test('Passing no value for memLimit, should result in the default value being set.', () => { | ||
const sp = new __1.SecurePass({ | ||
memLimit: 1 | ||
opsLimit: 6 | ||
}); | ||
} | ||
catch (e) { | ||
expect(e).toBeDefined(); | ||
expect(e instanceof error_1.SecurePassOptionsError).toBeTruthy(); | ||
} | ||
}); | ||
test('An invalid value for opsLimit should throw an error.', () => { | ||
try { | ||
expect(sp.MemLimit).toEqual(__1.SecurePass.MemLimitDefault); | ||
}); | ||
test('Passing no value for opsLimit, should result in the default value being set.', () => { | ||
const sp = new __1.SecurePass({ | ||
opsLimit: __1.SecurePass.OpsLimitMaximum + 1 | ||
memLimit: 16 * 1024 | ||
}); | ||
} | ||
catch (e) { | ||
expect(e).toBeDefined(); | ||
expect(e instanceof error_1.SecurePassOptionsError).toBeTruthy(); | ||
} | ||
}); | ||
describe('get and set - MemLimit', () => { | ||
test('MemLimit should return the currently configured Memory Limit.', () => { | ||
const sp = new __1.SecurePass({ | ||
memLimit: __1.SecurePass.MemLimitSensitive | ||
expect(sp.OpsLimit).toEqual(__1.SecurePass.OpsLimitDefault); | ||
}); | ||
// Test Valid Values for MemLimit, Including Upper and Lower Bounds. | ||
describe.each([__1.SecurePass.MemLimitInteractive, __1.SecurePass.MemLimitMinimum, __1.SecurePass.MemLimitMaximum])('Valid and Edge Case values for MemLimit.', m => { | ||
test(`${m} should be a valid value for MemLimit, when passed in the constructor.`, () => { | ||
const sp = new __1.SecurePass({ | ||
memLimit: m | ||
}); | ||
expect(sp.MemLimit).toEqual(m); | ||
}); | ||
expect(sp.MemLimit).toEqual(__1.SecurePass.MemLimitSensitive); | ||
test(`${m} should be a valid value for MemLimit, when set with the accessor.`, () => { | ||
const sp = new __1.SecurePass(); | ||
sp.MemLimit = m; | ||
expect(sp.MemLimit).toEqual(m); | ||
}); | ||
}); | ||
test('MemLimit should set the configured Memory Limit to the new limit.', () => { | ||
const sp = new __1.SecurePass(); | ||
sp.MemLimit = __1.SecurePass.MemLimitModerate; | ||
expect(sp.MemLimit).toEqual(__1.SecurePass.MemLimitModerate); | ||
// Test Valid Values for OpsLimit, Including Upper and Lower Bounds. | ||
describe.each([__1.SecurePass.OpsLimitInteractive, __1.SecurePass.OpsLimitMinimum, __1.SecurePass.OpsLimitMaximum])('Valid and Edge Case values for OpsLimit.', o => { | ||
test(`${o} should be a valid value for OpsLimit, when passed in the constructor.`, () => { | ||
const sp = new __1.SecurePass({ | ||
opsLimit: o | ||
}); | ||
expect(sp.OpsLimit).toEqual(o); | ||
}); | ||
test(`${o} should be a valid value for OpsLimit, when set with the accessor.`, () => { | ||
const sp = new __1.SecurePass(); | ||
sp.OpsLimit = o; | ||
expect(sp.OpsLimit).toEqual(o); | ||
}); | ||
}); | ||
test('MemLimit should throw an error if set with an invalid memory limit.', () => { | ||
const sp = new __1.SecurePass(); | ||
try { | ||
sp.MemLimit = 1024; | ||
} | ||
catch (e) { | ||
expect(e instanceof error_1.SecurePassOptionsError).toBeTruthy(); | ||
} | ||
// Test Invalid Values for MemLimit. | ||
describe.each([__1.SecurePass.MemLimitMinimum - 1, __1.SecurePass.MemLimitMaximum + 1])('Invalid Values for MemLimit.', m => { | ||
test(`${m} should be an invalid value for MemLimit, when passed in the constructor.`, () => { | ||
try { | ||
const sp = new __1.SecurePass({ | ||
memLimit: m | ||
}); | ||
// Makes sure that the error is thrown. | ||
expect(true).toBeFalsy(); | ||
} | ||
catch (e) { | ||
expect(e instanceof error_1.SecurePassOptionsError).toBeTruthy(); | ||
} | ||
}); | ||
test(`${m} should be an invalid value for MemLimit, when set with the accessor.`, () => { | ||
try { | ||
const sp = new __1.SecurePass(); | ||
sp.MemLimit = m; | ||
// Makes sure that the error is thrown. | ||
expect(true).toBeFalsy(); | ||
} | ||
catch (e) { | ||
expect(e instanceof error_1.SecurePassOptionsError).toBeTruthy(); | ||
} | ||
}); | ||
}); | ||
}); | ||
describe('get and set - OpsLimit', () => { | ||
test('OpsLimit should return the currently configured Memory Limit.', () => { | ||
const sp = new __1.SecurePass({ | ||
opsLimit: __1.SecurePass.OpsLimitSensitive | ||
// Test Invalid Values for OpsLimit. | ||
describe.each([__1.SecurePass.OpsLimitMinimum - 1, __1.SecurePass.OpsLimitMaximum + 1])('Invalid Values for OpsLimit.', o => { | ||
test(`${o} should be an invalid value for OpsLimit, when passed in the constructor.`, () => { | ||
try { | ||
const sp = new __1.SecurePass({ | ||
opsLimit: o | ||
}); | ||
// Makes sure that the error is thrown. | ||
expect(true).toBeFalsy(); | ||
} | ||
catch (e) { | ||
expect(e instanceof error_1.SecurePassOptionsError).toBeTruthy(); | ||
} | ||
}); | ||
expect(sp.OpsLimit).toEqual(__1.SecurePass.OpsLimitSensitive); | ||
test(`${o} should be an invalid value for OpsLimit, when set with the accessor.`, () => { | ||
try { | ||
const sp = new __1.SecurePass(); | ||
sp.OpsLimit = o; | ||
// Makes sure that the error is thrown. | ||
expect(true).toBeFalsy(); | ||
} | ||
catch (e) { | ||
expect(e instanceof error_1.SecurePassOptionsError).toBeTruthy(); | ||
} | ||
}); | ||
}); | ||
test('OpsLimit should set the configured Memory Limit to the new limit.', () => { | ||
const sp = new __1.SecurePass(); | ||
sp.OpsLimit = __1.SecurePass.OpsLimitModerate; | ||
expect(sp.OpsLimit).toEqual(__1.SecurePass.OpsLimitModerate); | ||
}); | ||
test('OpsLimit should throw an error if set with an invalid memory limit.', () => { | ||
const sp = new __1.SecurePass(); | ||
try { | ||
sp.OpsLimit = __1.SecurePass.OpsLimitMaximum + 1; | ||
} | ||
catch (e) { | ||
expect(e instanceof error_1.SecurePassOptionsError).toBeTruthy(); | ||
} | ||
}); | ||
}); | ||
}); | ||
describe('SecurePass - Static Functions', () => { | ||
describe('generateOneTimeAuth()', () => { | ||
test('Should return a mac, key and the original message.', () => { | ||
test('Should return a mac, random key and the original message.', () => { | ||
const message = Buffer.from('ExampleMessage'); | ||
const result = __1.SecurePass.generateOneTimeAuth(message); | ||
expect(result.mac).toBeDefined(); | ||
expect(result.mac.length).toEqual(sodium_native_1.default.crypto_onetimeauth_BYTES); | ||
expect(result.message).toBeDefined(); | ||
expect(result.mac.length).toEqual(__1.SecurePass.MacBytes); | ||
expect(result.message.compare(message)).toEqual(0); | ||
expect(result.key).toBeDefined(); | ||
expect(result.key.length).toEqual(sodium_native_1.default.crypto_onetimeauth_KEYBYTES); | ||
expect(result.key.length).toEqual(__1.SecurePass.KeyBytes); | ||
}); | ||
}); | ||
describe('verifyOneTimeAuth()', () => { | ||
test('Should return true if the message, mac and key match.', () => { | ||
test('Should return true if the message, mac and random key match.', () => { | ||
const message = Buffer.from('ExampleMessage'); | ||
const ota = __1.SecurePass.generateOneTimeAuth(message); | ||
const result = __1.SecurePass.verifyOneTimeAuth(ota.mac, message, ota.key); | ||
expect(result).toBeDefined(); | ||
expect(result).toBeTruthy(); | ||
@@ -200,5 +222,4 @@ }); | ||
const ota = __1.SecurePass.generateOneTimeAuth(message); | ||
const badMessage = Buffer.from('ExampleBad'); | ||
const badMessage = Buffer.from('ExampleMessageBad'); | ||
const result = __1.SecurePass.verifyOneTimeAuth(ota.mac, badMessage, ota.key); | ||
expect(result).toBeDefined(); | ||
expect(result).toBeFalsy(); | ||
@@ -209,13 +230,11 @@ }); | ||
const ota = __1.SecurePass.generateOneTimeAuth(message); | ||
const badMac = Buffer.alloc(sodium_native_1.default.crypto_onetimeauth_BYTES); | ||
const badMac = Buffer.alloc(__1.SecurePass.MacBytes); | ||
const result = __1.SecurePass.verifyOneTimeAuth(badMac, message, ota.key); | ||
expect(result).toBeDefined(); | ||
expect(result).toBeFalsy(); | ||
}); | ||
test('Should return false if the key does not match the message and mac.', () => { | ||
test('Should return false if the random key does not match the message and mac.', () => { | ||
const message = Buffer.from('ExampleMessage'); | ||
const ota = __1.SecurePass.generateOneTimeAuth(message); | ||
const badKey = Buffer.alloc(sodium_native_1.default.crypto_onetimeauth_KEYBYTES); | ||
const badKey = Buffer.alloc(__1.SecurePass.KeyBytes); | ||
const result = __1.SecurePass.verifyOneTimeAuth(ota.mac, message, badKey); | ||
expect(result).toBeDefined(); | ||
expect(result).toBeFalsy(); | ||
@@ -225,31 +244,26 @@ }); | ||
describe('generateOneTimeAuthCode()', () => { | ||
test('Should return a code string and a key buffer.', () => { | ||
test('Should return a valid code and a key buffer.', () => { | ||
const message = Buffer.from('ExampleMessage'); | ||
const result = __1.SecurePass.generateOneTimeAuthCode(message); | ||
expect(typeof result.code).toEqual('string'); | ||
expect(result.code.length > 0).toBeTruthy(); | ||
expect(result.code.indexOf('~')).toBeTruthy(); | ||
expect(result.key instanceof Buffer).toBeTruthy(); | ||
expect(result.key.length).toEqual(sodium_native_1.default.crypto_onetimeauth_KEYBYTES); | ||
const otac = __1.SecurePass.generateOneTimeAuthCode(message); | ||
expect(otac.code.indexOf('~')).not.toEqual(-1); | ||
expect(otac.key.length).toEqual(__1.SecurePass.KeyBytes); | ||
}); | ||
}); | ||
describe('verifyOneTimeAuthCode()', () => { | ||
test('Should return true when used with a valid code and key.', () => { | ||
test('Should return true when called with a valid code and key.', () => { | ||
const message = Buffer.from('ExampleMessage'); | ||
const ota = __1.SecurePass.generateOneTimeAuthCode(message); | ||
const result = __1.SecurePass.verifyOneTimeAuthCode(ota.code, ota.key); | ||
const otac = __1.SecurePass.generateOneTimeAuthCode(message); | ||
const result = __1.SecurePass.verifyOneTimeAuthCode(otac.code, otac.key); | ||
expect(result).toBeTruthy(); | ||
}); | ||
test('Should return false when used with an invalid key.', () => { | ||
test('Should return false if called with an invalid key.', () => { | ||
const message = Buffer.from('ExampleMessage'); | ||
const ota = __1.SecurePass.generateOneTimeAuthCode(message); | ||
const badKey = Buffer.alloc(sodium_native_1.default.crypto_onetimeauth_KEYBYTES); | ||
const result = __1.SecurePass.verifyOneTimeAuthCode(ota.code, badKey); | ||
const otac = __1.SecurePass.generateOneTimeAuthCode(message); | ||
const badKey = Buffer.alloc(__1.SecurePass.KeyBytes); | ||
const result = __1.SecurePass.verifyOneTimeAuthCode(otac.code, badKey); | ||
expect(result).toBeFalsy(); | ||
}); | ||
}); | ||
}); | ||
describe('SecurePass - Functions', () => { | ||
describe('async/promise hashPassword()', () => { | ||
test('Should return a string if given a valid password buffer.', () => __awaiter(this, void 0, void 0, function* () { | ||
test('Should return a hash if given a valid password.', (done) => __awaiter(this, void 0, void 0, function* () { | ||
const sp = new __1.SecurePass(); | ||
@@ -259,14 +273,24 @@ const password = Buffer.from('SecurePass'); | ||
expect(hash.length).toEqual(__1.SecurePass.HashBytes); | ||
expect(hash.toString().length > 0).toBeTruthy(); | ||
expect(hash.indexOf('$argon2id')).toEqual(0); | ||
done(); | ||
})); | ||
test('Should return an error if given a blank password buffer.', () => __awaiter(this, void 0, void 0, function* () { | ||
test.each([__1.SecurePass.PasswordBytesMin, __1.SecurePass.PasswordBytesMax])('Should return a hash if given a password buffer of length %1.', (p, done) => __awaiter(this, void 0, void 0, function* () { | ||
const sp = new __1.SecurePass(); | ||
const password = Buffer.alloc(p, 'f'); | ||
const hash = yield sp.hashPassword(password); | ||
expect(hash.length).toEqual(__1.SecurePass.HashBytes); | ||
expect(hash.indexOf('$argon2id')).toEqual(0); | ||
done(); | ||
})); | ||
test.each([__1.SecurePass.PasswordBytesMin - 1, __1.SecurePass.PasswordBytesMax + 1])('Should throw an error if given a password buffer of length %i.', (p, done) => __awaiter(this, void 0, void 0, function* () { | ||
try { | ||
const password = Buffer.from(''); | ||
const sp = new __1.SecurePass(); | ||
const password = Buffer.alloc(p, 'f'); | ||
const hash = yield sp.hashPassword(password); | ||
expect(false).toBeTruthy(); | ||
done(); | ||
} | ||
catch (e) { | ||
expect(e).toBeDefined(); | ||
expect(e instanceof error_1.SecurePassError).toBeTruthy(); | ||
done(); | ||
} | ||
@@ -276,24 +300,46 @@ })); | ||
describe('callback hashPassword()', () => { | ||
test('Should return a string if given a valid password buffer.', done => { | ||
test('Should return a hash if given a valid password.', done => { | ||
const sp = new __1.SecurePass(); | ||
const password = Buffer.from('SecurePass'); | ||
sp.hashPassword(password, (err, hash) => { | ||
expect(err).toBeNull(); | ||
expect(hash).toBeDefined(); | ||
if (err || hash == undefined) { | ||
expect(false).toBeTruthy(); | ||
return; | ||
} | ||
expect(hash.length).toEqual(__1.SecurePass.HashBytes); | ||
expect(hash.indexOf('$argon2id')).toEqual(0); | ||
done(); | ||
}); | ||
}); | ||
test('Should return an error if given a blank password buffer.', done => { | ||
test.each([__1.SecurePass.PasswordBytesMin, __1.SecurePass.PasswordBytesMax])('Should return a hash if given a password buffer of length %1.', (p, done) => __awaiter(this, void 0, void 0, function* () { | ||
const sp = new __1.SecurePass(); | ||
const password = Buffer.from(''); | ||
const password = Buffer.alloc(p, 'f'); | ||
sp.hashPassword(password, (err, hash) => { | ||
expect(err).toBeDefined(); | ||
expect(err instanceof error_1.SecurePassError).toBeTruthy(); | ||
expect(hash).toBeUndefined(); | ||
if (err || hash == undefined) { | ||
expect(false).toBeTruthy(); | ||
return; | ||
} | ||
expect(hash.length).toEqual(__1.SecurePass.HashBytes); | ||
expect(hash.indexOf('$argon2id')).toEqual(0); | ||
done(); | ||
}); | ||
}); | ||
})); | ||
test.each([__1.SecurePass.PasswordBytesMin - 1, __1.SecurePass.PasswordBytesMax + 1])('Should throw an error if given a password buffer of length %i.', (p, done) => __awaiter(this, void 0, void 0, function* () { | ||
const sp = new __1.SecurePass(); | ||
try { | ||
const password = Buffer.alloc(p, 'f'); | ||
sp.hashPassword(password, (err, hash) => { | ||
expect(err instanceof error_1.SecurePassError).toBeTruthy(); | ||
expect(hash).toBeUndefined(); | ||
done(); | ||
}); | ||
} | ||
catch (e) { | ||
expect(e).toBeDefined(); | ||
done(); | ||
} | ||
})); | ||
}); | ||
describe('hashPasswordSync', () => { | ||
test('Should return a valid hash if given a valid password.', done => { | ||
describe('hashPasswordSync()', () => { | ||
test('Should return a hash if given a valid password.', done => { | ||
const sp = new __1.SecurePass(); | ||
@@ -303,16 +349,25 @@ const password = Buffer.from('SecurePass'); | ||
expect(hash.length).toEqual(__1.SecurePass.HashBytes); | ||
expect(sp.verifyHashSync(password, hash)).toEqual(__1.VerificationResult.Valid); | ||
expect(hash.indexOf('$argon2id')).toEqual(0); | ||
done(); | ||
}); | ||
test('Should throw an error if given a blank password buffer.', done => { | ||
test.each([__1.SecurePass.PasswordBytesMin, __1.SecurePass.PasswordBytesMax])('Should return a hash if given a password buffer of length %1.', (p, done) => { | ||
const sp = new __1.SecurePass(); | ||
const password = Buffer.from(''); | ||
const password = Buffer.alloc(p, 'f'); | ||
const hash = sp.hashPasswordSync(password); | ||
expect(hash.length).toEqual(__1.SecurePass.HashBytes); | ||
expect(hash.indexOf('$argon2id')).toEqual(0); | ||
done(); | ||
}); | ||
test.each([__1.SecurePass.PasswordBytesMin - 1, __1.SecurePass.PasswordBytesMax + 1])('Should throw an error if given a password buffer of length %i.', (p, done) => { | ||
try { | ||
const sp = new __1.SecurePass(); | ||
const password = Buffer.alloc(p, 'f'); | ||
const hash = sp.hashPasswordSync(password); | ||
expect(false).toBeTruthy(); | ||
done(); | ||
} | ||
catch (e) { | ||
expect(e).toBeDefined(); | ||
expect(e instanceof error_1.SecurePassError).toBeTruthy(); | ||
done(); | ||
} | ||
done(); | ||
}); | ||
@@ -319,0 +374,0 @@ }); |
@@ -108,2 +108,3 @@ /** | ||
* Use of this option requires a minimum of 1024 MiB of dedicated RAM. | ||
* @readonly | ||
*/ | ||
@@ -147,2 +148,3 @@ static readonly MemLimitSensitive: number; | ||
* Using this option it takes around 3.5 seconds to derrive a hash on a 2.8Ghz Core i7 CPU. | ||
* @readonly | ||
*/ | ||
@@ -187,2 +189,22 @@ static readonly OpsLimitSensitive: number; | ||
/** | ||
* Tests a VerificationResult enumeration and returns true if the value is InvalidOrUnrecognized. | ||
* @param vr - The VerificationResult to Test. | ||
*/ | ||
static isInvalidOrUnrecognized(vr: VerificationResult): boolean; | ||
/** | ||
* Tests a VerificationResult enumeration and returns true if the value is Invalid. | ||
* @param vr - The VerificationResult to Test. | ||
*/ | ||
static isInvalid(vr: VerificationResult): boolean; | ||
/** | ||
* Tests a VerificationResult enumeration and returns true if the value is Valid. | ||
* @param vr - The VerificationResult to Test. | ||
*/ | ||
static isValid(vr: VerificationResult): boolean; | ||
/** | ||
* Tests a VerificationResult enumeration and returns true if the value is ValidNeedsRehash. | ||
* @param vr - The VerificationResult to Test. | ||
*/ | ||
static isValidNeedsRehash(vr: VerificationResult): boolean; | ||
/** | ||
* Configured memory limit for Argon2ID. | ||
@@ -189,0 +211,0 @@ */ |
@@ -117,2 +117,30 @@ "use strict"; | ||
/** | ||
* Tests a VerificationResult enumeration and returns true if the value is InvalidOrUnrecognized. | ||
* @param vr - The VerificationResult to Test. | ||
*/ | ||
static isInvalidOrUnrecognized(vr) { | ||
return vr == VerificationResult.InvalidOrUnrecognized; | ||
} | ||
/** | ||
* Tests a VerificationResult enumeration and returns true if the value is Invalid. | ||
* @param vr - The VerificationResult to Test. | ||
*/ | ||
static isInvalid(vr) { | ||
return vr == VerificationResult.Invalid; | ||
} | ||
/** | ||
* Tests a VerificationResult enumeration and returns true if the value is Valid. | ||
* @param vr - The VerificationResult to Test. | ||
*/ | ||
static isValid(vr) { | ||
return vr == VerificationResult.Valid; | ||
} | ||
/** | ||
* Tests a VerificationResult enumeration and returns true if the value is ValidNeedsRehash. | ||
* @param vr - The VerificationResult to Test. | ||
*/ | ||
static isValidNeedsRehash(vr) { | ||
return vr == VerificationResult.ValidNeedsRehash; | ||
} | ||
/** | ||
* Returns the currently configured Memory Limit. | ||
@@ -167,3 +195,3 @@ */ | ||
hashPasswordSync(password) { | ||
if (!(password.length >= SecurePass.PasswordBytesMin && password.length < SecurePass.PasswordBytesMax)) { | ||
if (!(password.length >= SecurePass.PasswordBytesMin && password.length <= SecurePass.PasswordBytesMax)) { | ||
throw new error_1.SecurePassError(`Length of Password Buffer must be between ${SecurePass.PasswordBytesMin} and ${SecurePass.PasswordBytesMax}`); | ||
@@ -190,3 +218,3 @@ } | ||
verifyHashSync(password, hash) { | ||
if (!(password.length >= SecurePass.PasswordBytesMin && password.length < SecurePass.PasswordBytesMax)) { | ||
if (!(password.length >= SecurePass.PasswordBytesMin && password.length <= SecurePass.PasswordBytesMax)) { | ||
throw new error_1.SecurePassError(`Length of Password Buffer must be between ${SecurePass.PasswordBytesMin} and ${SecurePass.PasswordBytesMax}`); | ||
@@ -211,3 +239,3 @@ } | ||
return new Promise((resolve, reject) => { | ||
if (!(password.length >= SecurePass.PasswordBytesMin && password.length < SecurePass.PasswordBytesMax)) { | ||
if (!(password.length >= SecurePass.PasswordBytesMin && password.length <= SecurePass.PasswordBytesMax)) { | ||
reject(new error_1.SecurePassError(`Length of Password Buffer must be between ${SecurePass.PasswordBytesMin} and ${SecurePass.PasswordBytesMax}`)); | ||
@@ -231,3 +259,3 @@ } | ||
return new Promise((resolve, reject) => { | ||
if (!(password.length >= SecurePass.PasswordBytesMin && password.length < SecurePass.PasswordBytesMax)) { | ||
if (!(password.length >= SecurePass.PasswordBytesMin && password.length <= SecurePass.PasswordBytesMax)) { | ||
reject(new error_1.SecurePassError(`Length of Password Buffer must be between ${SecurePass.PasswordBytesMin} and ${SecurePass.PasswordBytesMax}`)); | ||
@@ -270,3 +298,3 @@ } | ||
*/ | ||
SecurePass.PasswordBytesMax = 4294967295; | ||
SecurePass.PasswordBytesMax = 2147483647; | ||
/** | ||
@@ -318,2 +346,3 @@ * Length of the Password Hash output buffer. | ||
* Use of this option requires a minimum of 1024 MiB of dedicated RAM. | ||
* @readonly | ||
*/ | ||
@@ -357,2 +386,3 @@ SecurePass.MemLimitSensitive = 1073741824; | ||
* Using this option it takes around 3.5 seconds to derrive a hash on a 2.8Ghz Core i7 CPU. | ||
* @readonly | ||
*/ | ||
@@ -359,0 +389,0 @@ SecurePass.OpsLimitSensitive = 4; |
{ | ||
"name": "argon2-pass", | ||
"version": "0.2.1", | ||
"version": "0.2.2", | ||
"description": "State of the art password hashing and one time password reset token generation module written in TypeScript for nodejs.", | ||
@@ -5,0 +5,0 @@ "main": "./dist/index.js", |
@@ -5,3 +5,3 @@ import { bufferFromSafeBase64, bufferToSafeBase64 } from '..'; | ||
describe('bufferFromSafeBase64', () => { | ||
test('Should convert a valid base64 string into a buffer.', () => { | ||
test('Should convert a valid url-safe base64 string into a buffer.', () => { | ||
const expected = Buffer.from('TestString'); | ||
@@ -14,6 +14,8 @@ const buffer = bufferFromSafeBase64('VGVzdFN0cmluZw'); | ||
describe('bufferToSafeBase64', () => { | ||
const expected = 'VGVzdFN0cmluZw'; | ||
const base64 = bufferToSafeBase64(Buffer.from('TestString')); | ||
expect(base64).toEqual(expected); | ||
test('Should convert a buffer into a valid url-safe base64 string.', () => { | ||
const expected = 'VGVzdFN0cmluZw'; | ||
const base64 = bufferToSafeBase64(Buffer.from('TestString')); | ||
expect(base64).toEqual(expected); | ||
}); | ||
}); | ||
}); |
@@ -5,25 +5,12 @@ import sodium from 'sodium-native'; | ||
describe('SecurePass - Constants', () => { | ||
test('PasswordBytes* Constants should be defined.', () => { | ||
describe('SecurePass', () => { | ||
test('static readonly constants should be defined.', () => { | ||
expect(SecurePass.PasswordBytesMin).toBeDefined(); | ||
expect(SecurePass.PasswordBytesMax).toBeDefined(); | ||
expect(SecurePass.PasswordBytesMin).toBeDefined(); | ||
}); | ||
test('HashBytes Constant should be defined.', () => { | ||
expect(SecurePass.HashBytes).toBeDefined(); | ||
}); | ||
test('SaltBytes Constant should be defined', () => { | ||
expect(SecurePass.SaltBytes).toBeDefined(); | ||
}); | ||
test('MacBytes Constant should be defined.', () => { | ||
expect(SecurePass.MacBytes).toBeDefined(); | ||
}); | ||
test('KeyBytes Constant should be defined.', () => { | ||
expect(SecurePass.KeyBytes).toBeDefined(); | ||
}); | ||
test('MemLimit* Constants should be defined.', () => { | ||
// Memory Limit Constants | ||
expect(SecurePass.MemLimitDefault).toBeDefined(); | ||
@@ -35,5 +22,4 @@ expect(SecurePass.MemLimitInteractive).toBeDefined(); | ||
expect(SecurePass.MemLimitMaximum).toBeDefined(); | ||
}); | ||
test('OpsLimit* Constants should be defined.', () => { | ||
// Operations Limit Constants | ||
expect(SecurePass.OpsLimitDefault).toBeDefined(); | ||
@@ -47,157 +33,206 @@ expect(SecurePass.OpsLimitInteractive).toBeDefined(); | ||
test('VerificationResult.* Enum Constants should be defined.', () => { | ||
expect(VerificationResult.InvalidOrUnrecognized).toEqual(0); | ||
expect(VerificationResult.Invalid).toEqual(1); | ||
expect(VerificationResult.Valid).toEqual(2); | ||
expect(VerificationResult.ValidNeedsRehash).toEqual(3); | ||
}); | ||
}); | ||
test('static readonly constants should have the correct values.', () => { | ||
expect(SecurePass.PasswordBytesMin).toEqual(1); | ||
expect(SecurePass.PasswordBytesMax).toEqual(2147483647); | ||
expect(SecurePass.HashBytes).toEqual(128); | ||
expect(SecurePass.SaltBytes).toEqual(16); | ||
expect(SecurePass.MacBytes).toEqual(16); | ||
expect(SecurePass.KeyBytes).toEqual(32); | ||
describe('SecurePass - Options', () => { | ||
test('Passing no configuration should create a new instance with the default options.', () => { | ||
const sp = new SecurePass(); | ||
expect(sp.MemLimit).toEqual(sodium.crypto_pwhash_MEMLIMIT_INTERACTIVE); | ||
expect(sp.OpsLimit).toEqual(sodium.crypto_pwhash_OPSLIMIT_INTERACTIVE); | ||
}); | ||
// Memory Limit Constants | ||
expect(SecurePass.MemLimitDefault).toEqual(67108864); | ||
expect(SecurePass.MemLimitInteractive).toEqual(67108864); | ||
expect(SecurePass.MemLimitModerate).toEqual(268435456); | ||
expect(SecurePass.MemLimitSensitive).toEqual(1073741824); | ||
expect(SecurePass.MemLimitMinimum).toEqual(8192); | ||
expect(SecurePass.MemLimitMaximum).toEqual(4398046510080); | ||
test('Passing in an empty object should create a new instance with the default options.', () => { | ||
const sp = new SecurePass({}); | ||
expect(sp.MemLimit).toEqual(sodium.crypto_pwhash_MEMLIMIT_INTERACTIVE); | ||
expect(sp.OpsLimit).toEqual(sodium.crypto_pwhash_OPSLIMIT_INTERACTIVE); | ||
// Operations Limit Constants | ||
expect(SecurePass.OpsLimitDefault).toEqual(2); | ||
expect(SecurePass.OpsLimitInteractive).toEqual(2); | ||
expect(SecurePass.OpsLimitModerate).toEqual(3); | ||
expect(SecurePass.OpsLimitSensitive).toEqual(4); | ||
expect(SecurePass.OpsLimitMinimum).toEqual(1); | ||
expect(SecurePass.OpsLimitMaximum).toEqual(4294967295); | ||
}); | ||
test('A valid value for memLimit should be set correctly. And opsLimit should be set to the default value.', () => { | ||
const sp = new SecurePass({ | ||
memLimit: 16384 | ||
describe('VerificationResult', () => { | ||
test('VerificationResult enumeration has the right values.', () => { | ||
expect(VerificationResult.InvalidOrUnrecognized).toEqual(0); | ||
expect(VerificationResult.Invalid).toEqual(1); | ||
expect(VerificationResult.Valid).toEqual(2); | ||
expect(VerificationResult.ValidNeedsRehash).toEqual(3); | ||
}); | ||
expect(sp.MemLimit).toEqual(16384); | ||
expect(sp.OpsLimit).toEqual(sodium.crypto_pwhash_OPSLIMIT_INTERACTIVE); | ||
}); | ||
test('A valid value for opsLimit should be set correctly. And memLimit should be set to the default value.', () => { | ||
const sp = new SecurePass({ | ||
opsLimit: 12 | ||
test.each([ | ||
[VerificationResult.InvalidOrUnrecognized, true], | ||
[VerificationResult.Invalid, false], | ||
[VerificationResult.Valid, false], | ||
[VerificationResult.ValidNeedsRehash, false] | ||
])('isInvalidOrUnrecognized should return the correct result when called with %i.', (vr, b) => { | ||
expect(SecurePass.isInvalidOrUnrecognized(vr)).toEqual(b); | ||
}); | ||
expect(sp.MemLimit).toEqual(sodium.crypto_pwhash_MEMLIMIT_INTERACTIVE); | ||
expect(sp.OpsLimit).toEqual(12); | ||
}); | ||
test('A lower bounds value for memLimit should still be considered valid.', () => { | ||
const sp = new SecurePass({ | ||
memLimit: SecurePass.MemLimitMinimum | ||
test.each([ | ||
[VerificationResult.InvalidOrUnrecognized, false], | ||
[VerificationResult.Invalid, true], | ||
[VerificationResult.Valid, false], | ||
[VerificationResult.ValidNeedsRehash, false] | ||
])('isInvalid should return the correct result when called with %i.', (vr, b) => { | ||
expect(SecurePass.isInvalid(vr)).toEqual(b); | ||
}); | ||
expect(sp.MemLimit).toEqual(SecurePass.MemLimitMinimum); | ||
}); | ||
test('An upper bounds value for memLimit should still be considered valid.', () => { | ||
const sp = new SecurePass({ | ||
memLimit: SecurePass.MemLimitMaximum | ||
test.each([ | ||
[VerificationResult.InvalidOrUnrecognized, false], | ||
[VerificationResult.Invalid, false], | ||
[VerificationResult.Valid, true], | ||
[VerificationResult.ValidNeedsRehash, false] | ||
])('isValid should return the correct result when called with %i.', (vr, b) => { | ||
expect(SecurePass.isValid(vr)).toEqual(b); | ||
}); | ||
expect(sp.MemLimit).toEqual(SecurePass.MemLimitMaximum); | ||
}); | ||
test('A lower bounds value for opsLimit should still be considered valid.', () => { | ||
const sp = new SecurePass({ | ||
opsLimit: SecurePass.OpsLimitMinimum | ||
test.each([ | ||
[VerificationResult.InvalidOrUnrecognized, false], | ||
[VerificationResult.Invalid, false], | ||
[VerificationResult.Valid, false], | ||
[VerificationResult.ValidNeedsRehash, true] | ||
])('isValidNeedsRehash should return the correct result when called with %i.', (vr, b) => { | ||
expect(SecurePass.isValidNeedsRehash(vr)).toEqual(b); | ||
}); | ||
expect(sp.OpsLimit).toEqual(SecurePass.OpsLimitMinimum); | ||
}); | ||
test('An upper bounds value for opsLimit should still be considered valid.', () => { | ||
const sp = new SecurePass({ | ||
opsLimit: SecurePass.OpsLimitMaximum | ||
describe('SecurePass MemLimit and OpsLimit Options', () => { | ||
test('Passing no configuration to SecurePass, should create a new instance with the default values', () => { | ||
const sp1 = new SecurePass(); | ||
expect(sp1.MemLimit).toEqual(SecurePass.MemLimitDefault); | ||
expect(sp1.OpsLimit).toEqual(SecurePass.OpsLimitDefault); | ||
const sp2 = new SecurePass({}); | ||
expect(sp2.MemLimit).toEqual(SecurePass.MemLimitDefault); | ||
expect(sp2.OpsLimit).toEqual(SecurePass.OpsLimitDefault); | ||
}); | ||
expect(sp.OpsLimit).toEqual(SecurePass.OpsLimitMaximum); | ||
}); | ||
test('An invalid value for memLimit should throw an error.', () => { | ||
try { | ||
test('Passing no value for memLimit, should result in the default value being set.', () => { | ||
const sp = new SecurePass({ | ||
memLimit: 1 | ||
opsLimit: 6 | ||
}); | ||
} catch (e) { | ||
expect(e).toBeDefined(); | ||
expect(e instanceof SecurePassOptionsError).toBeTruthy(); | ||
} | ||
}); | ||
expect(sp.MemLimit).toEqual(SecurePass.MemLimitDefault); | ||
}); | ||
test('An invalid value for opsLimit should throw an error.', () => { | ||
try { | ||
test('Passing no value for opsLimit, should result in the default value being set.', () => { | ||
const sp = new SecurePass({ | ||
opsLimit: SecurePass.OpsLimitMaximum + 1 | ||
memLimit: 16 * 1024 | ||
}); | ||
} catch (e) { | ||
expect(e).toBeDefined(); | ||
expect(e instanceof SecurePassOptionsError).toBeTruthy(); | ||
} | ||
}); | ||
describe('get and set - MemLimit', () => { | ||
test('MemLimit should return the currently configured Memory Limit.', () => { | ||
const sp = new SecurePass({ | ||
memLimit: SecurePass.MemLimitSensitive | ||
}); | ||
expect(sp.MemLimit).toEqual(SecurePass.MemLimitSensitive); | ||
expect(sp.OpsLimit).toEqual(SecurePass.OpsLimitDefault); | ||
}); | ||
test('MemLimit should set the configured Memory Limit to the new limit.', () => { | ||
const sp = new SecurePass(); | ||
// Test Valid Values for MemLimit, Including Upper and Lower Bounds. | ||
describe.each([SecurePass.MemLimitInteractive, SecurePass.MemLimitMinimum, SecurePass.MemLimitMaximum])( | ||
'Valid and Edge Case values for MemLimit.', | ||
m => { | ||
test(`${m} should be a valid value for MemLimit, when passed in the constructor.`, () => { | ||
const sp = new SecurePass({ | ||
memLimit: m | ||
}); | ||
expect(sp.MemLimit).toEqual(m); | ||
}); | ||
sp.MemLimit = SecurePass.MemLimitModerate; | ||
test(`${m} should be a valid value for MemLimit, when set with the accessor.`, () => { | ||
const sp = new SecurePass(); | ||
sp.MemLimit = m; | ||
expect(sp.MemLimit).toEqual(m); | ||
}); | ||
} | ||
); | ||
expect(sp.MemLimit).toEqual(SecurePass.MemLimitModerate); | ||
}); | ||
// Test Valid Values for OpsLimit, Including Upper and Lower Bounds. | ||
describe.each([SecurePass.OpsLimitInteractive, SecurePass.OpsLimitMinimum, SecurePass.OpsLimitMaximum])( | ||
'Valid and Edge Case values for OpsLimit.', | ||
o => { | ||
test(`${o} should be a valid value for OpsLimit, when passed in the constructor.`, () => { | ||
const sp = new SecurePass({ | ||
opsLimit: o | ||
}); | ||
expect(sp.OpsLimit).toEqual(o); | ||
}); | ||
test('MemLimit should throw an error if set with an invalid memory limit.', () => { | ||
const sp = new SecurePass(); | ||
try { | ||
sp.MemLimit = 1024; | ||
} catch (e) { | ||
expect(e instanceof SecurePassOptionsError).toBeTruthy(); | ||
test(`${o} should be a valid value for OpsLimit, when set with the accessor.`, () => { | ||
const sp = new SecurePass(); | ||
sp.OpsLimit = o; | ||
expect(sp.OpsLimit).toEqual(o); | ||
}); | ||
} | ||
}); | ||
}); | ||
); | ||
describe('get and set - OpsLimit', () => { | ||
test('OpsLimit should return the currently configured Memory Limit.', () => { | ||
const sp = new SecurePass({ | ||
opsLimit: SecurePass.OpsLimitSensitive | ||
}); | ||
// Test Invalid Values for MemLimit. | ||
describe.each([SecurePass.MemLimitMinimum - 1, SecurePass.MemLimitMaximum + 1])( | ||
'Invalid Values for MemLimit.', | ||
m => { | ||
test(`${m} should be an invalid value for MemLimit, when passed in the constructor.`, () => { | ||
try { | ||
const sp = new SecurePass({ | ||
memLimit: m | ||
}); | ||
expect(sp.OpsLimit).toEqual(SecurePass.OpsLimitSensitive); | ||
}); | ||
// Makes sure that the error is thrown. | ||
expect(true).toBeFalsy(); | ||
} catch (e) { | ||
expect(e instanceof SecurePassOptionsError).toBeTruthy(); | ||
} | ||
}); | ||
test('OpsLimit should set the configured Memory Limit to the new limit.', () => { | ||
const sp = new SecurePass(); | ||
test(`${m} should be an invalid value for MemLimit, when set with the accessor.`, () => { | ||
try { | ||
const sp = new SecurePass(); | ||
sp.MemLimit = m; | ||
sp.OpsLimit = SecurePass.OpsLimitModerate; | ||
// Makes sure that the error is thrown. | ||
expect(true).toBeFalsy(); | ||
} catch (e) { | ||
expect(e instanceof SecurePassOptionsError).toBeTruthy(); | ||
} | ||
}); | ||
} | ||
); | ||
expect(sp.OpsLimit).toEqual(SecurePass.OpsLimitModerate); | ||
}); | ||
// Test Invalid Values for OpsLimit. | ||
describe.each([SecurePass.OpsLimitMinimum - 1, SecurePass.OpsLimitMaximum + 1])( | ||
'Invalid Values for OpsLimit.', | ||
o => { | ||
test(`${o} should be an invalid value for OpsLimit, when passed in the constructor.`, () => { | ||
try { | ||
const sp = new SecurePass({ | ||
opsLimit: o | ||
}); | ||
test('OpsLimit should throw an error if set with an invalid memory limit.', () => { | ||
const sp = new SecurePass(); | ||
// Makes sure that the error is thrown. | ||
expect(true).toBeFalsy(); | ||
} catch (e) { | ||
expect(e instanceof SecurePassOptionsError).toBeTruthy(); | ||
} | ||
}); | ||
try { | ||
sp.OpsLimit = SecurePass.OpsLimitMaximum + 1; | ||
} catch (e) { | ||
expect(e instanceof SecurePassOptionsError).toBeTruthy(); | ||
test(`${o} should be an invalid value for OpsLimit, when set with the accessor.`, () => { | ||
try { | ||
const sp = new SecurePass(); | ||
sp.OpsLimit = o; | ||
// Makes sure that the error is thrown. | ||
expect(true).toBeFalsy(); | ||
} catch (e) { | ||
expect(e instanceof SecurePassOptionsError).toBeTruthy(); | ||
} | ||
}); | ||
} | ||
}); | ||
); | ||
}); | ||
}); | ||
describe('SecurePass - Static Functions', () => { | ||
describe('generateOneTimeAuth()', () => { | ||
test('Should return a mac, key and the original message.', () => { | ||
test('Should return a mac, random key and the original message.', () => { | ||
const message = Buffer.from('ExampleMessage'); | ||
const result = SecurePass.generateOneTimeAuth(message); | ||
expect(result.mac).toBeDefined(); | ||
expect(result.mac.length).toEqual(sodium.crypto_onetimeauth_BYTES); | ||
expect(result.message).toBeDefined(); | ||
expect(result.mac.length).toEqual(SecurePass.MacBytes); | ||
expect(result.message.compare(message)).toEqual(0); | ||
expect(result.key).toBeDefined(); | ||
expect(result.key.length).toEqual(sodium.crypto_onetimeauth_KEYBYTES); | ||
expect(result.key.length).toEqual(SecurePass.KeyBytes); | ||
}); | ||
@@ -207,3 +242,3 @@ }); | ||
describe('verifyOneTimeAuth()', () => { | ||
test('Should return true if the message, mac and key match.', () => { | ||
test('Should return true if the message, mac and random key match.', () => { | ||
const message = Buffer.from('ExampleMessage'); | ||
@@ -213,3 +248,3 @@ const ota = SecurePass.generateOneTimeAuth(message); | ||
const result = SecurePass.verifyOneTimeAuth(ota.mac, message, ota.key); | ||
expect(result).toBeDefined(); | ||
expect(result).toBeTruthy(); | ||
@@ -222,5 +257,5 @@ }); | ||
const badMessage = Buffer.from('ExampleBad'); | ||
const badMessage = Buffer.from('ExampleMessageBad'); | ||
const result = SecurePass.verifyOneTimeAuth(ota.mac, badMessage, ota.key); | ||
expect(result).toBeDefined(); | ||
expect(result).toBeFalsy(); | ||
@@ -233,15 +268,15 @@ }); | ||
const badMac = Buffer.alloc(sodium.crypto_onetimeauth_BYTES); | ||
const badMac = Buffer.alloc(SecurePass.MacBytes); | ||
const result = SecurePass.verifyOneTimeAuth(badMac, message, ota.key); | ||
expect(result).toBeDefined(); | ||
expect(result).toBeFalsy(); | ||
}); | ||
test('Should return false if the key does not match the message and mac.', () => { | ||
test('Should return false if the random key does not match the message and mac.', () => { | ||
const message = Buffer.from('ExampleMessage'); | ||
const ota = SecurePass.generateOneTimeAuth(message); | ||
const badKey = Buffer.alloc(sodium.crypto_onetimeauth_KEYBYTES); | ||
const badKey = Buffer.alloc(SecurePass.KeyBytes); | ||
const result = SecurePass.verifyOneTimeAuth(ota.mac, message, badKey); | ||
expect(result).toBeDefined(); | ||
expect(result).toBeFalsy(); | ||
@@ -252,10 +287,8 @@ }); | ||
describe('generateOneTimeAuthCode()', () => { | ||
test('Should return a code string and a key buffer.', () => { | ||
test('Should return a valid code and a key buffer.', () => { | ||
const message = Buffer.from('ExampleMessage'); | ||
const result = SecurePass.generateOneTimeAuthCode(message); | ||
expect(typeof result.code).toEqual('string'); | ||
expect(result.code.length > 0).toBeTruthy(); | ||
expect(result.code.indexOf('~')).toBeTruthy(); | ||
expect(result.key instanceof Buffer).toBeTruthy(); | ||
expect(result.key.length).toEqual(sodium.crypto_onetimeauth_KEYBYTES); | ||
const otac = SecurePass.generateOneTimeAuthCode(message); | ||
expect(otac.code.indexOf('~')).not.toEqual(-1); | ||
expect(otac.key.length).toEqual(SecurePass.KeyBytes); | ||
}); | ||
@@ -265,24 +298,22 @@ }); | ||
describe('verifyOneTimeAuthCode()', () => { | ||
test('Should return true when used with a valid code and key.', () => { | ||
test('Should return true when called with a valid code and key.', () => { | ||
const message = Buffer.from('ExampleMessage'); | ||
const ota = SecurePass.generateOneTimeAuthCode(message); | ||
const otac = SecurePass.generateOneTimeAuthCode(message); | ||
const result = SecurePass.verifyOneTimeAuthCode(ota.code, ota.key); | ||
const result = SecurePass.verifyOneTimeAuthCode(otac.code, otac.key); | ||
expect(result).toBeTruthy(); | ||
}); | ||
test('Should return false when used with an invalid key.', () => { | ||
test('Should return false if called with an invalid key.', () => { | ||
const message = Buffer.from('ExampleMessage'); | ||
const ota = SecurePass.generateOneTimeAuthCode(message); | ||
const otac = SecurePass.generateOneTimeAuthCode(message); | ||
const badKey = Buffer.alloc(sodium.crypto_onetimeauth_KEYBYTES); | ||
const result = SecurePass.verifyOneTimeAuthCode(ota.code, badKey); | ||
const badKey = Buffer.alloc(SecurePass.KeyBytes); | ||
const result = SecurePass.verifyOneTimeAuthCode(otac.code, badKey); | ||
expect(result).toBeFalsy(); | ||
}); | ||
}); | ||
}); | ||
describe('SecurePass - Functions', () => { | ||
describe('async/promise hashPassword()', () => { | ||
test('Should return a string if given a valid password buffer.', async () => { | ||
test('Should return a hash if given a valid password.', async done => { | ||
const sp = new SecurePass(); | ||
@@ -294,21 +325,41 @@ | ||
expect(hash.length).toEqual(SecurePass.HashBytes); | ||
expect(hash.toString().length > 0).toBeTruthy(); | ||
expect(hash.indexOf('$argon2id')).toEqual(0); | ||
done(); | ||
}); | ||
test('Should return an error if given a blank password buffer.', async () => { | ||
const sp = new SecurePass(); | ||
test.each([SecurePass.PasswordBytesMin, SecurePass.PasswordBytesMax])( | ||
'Should return a hash if given a password buffer of length %1.', | ||
async (p, done) => { | ||
const sp = new SecurePass(); | ||
const password = Buffer.alloc(p, 'f'); | ||
const hash = await sp.hashPassword(password); | ||
try { | ||
const password = Buffer.from(''); | ||
const hash = await sp.hashPassword(password); | ||
} catch (e) { | ||
expect(e).toBeDefined(); | ||
expect(e instanceof SecurePassError).toBeTruthy(); | ||
expect(hash.length).toEqual(SecurePass.HashBytes); | ||
expect(hash.indexOf('$argon2id')).toEqual(0); | ||
done(); | ||
} | ||
}); | ||
); | ||
test.each([SecurePass.PasswordBytesMin - 1, SecurePass.PasswordBytesMax + 1])( | ||
'Should throw an error if given a password buffer of length %i.', | ||
async (p, done) => { | ||
try { | ||
const sp = new SecurePass(); | ||
const password = Buffer.alloc(p, 'f'); | ||
const hash = await sp.hashPassword(password); | ||
expect(false).toBeTruthy(); | ||
done(); | ||
} catch (e) { | ||
expect(e).toBeDefined(); | ||
done(); | ||
} | ||
} | ||
); | ||
}); | ||
describe('callback hashPassword()', () => { | ||
test('Should return a string if given a valid password buffer.', done => { | ||
test('Should return a hash if given a valid password.', done => { | ||
const sp = new SecurePass(); | ||
@@ -318,5 +369,10 @@ | ||
sp.hashPassword(password, (err: SecurePassError | null, hash?: Buffer) => { | ||
expect(err).toBeNull(); | ||
expect(hash).toBeDefined(); | ||
if (err || hash == undefined) { | ||
expect(false).toBeTruthy(); | ||
return; | ||
} | ||
expect(hash.length).toEqual(SecurePass.HashBytes); | ||
expect(hash.indexOf('$argon2id')).toEqual(0); | ||
done(); | ||
@@ -326,18 +382,45 @@ }); | ||
test('Should return an error if given a blank password buffer.', done => { | ||
const sp = new SecurePass(); | ||
test.each([SecurePass.PasswordBytesMin, SecurePass.PasswordBytesMax])( | ||
'Should return a hash if given a password buffer of length %1.', | ||
async (p, done) => { | ||
const sp = new SecurePass(); | ||
const password = Buffer.alloc(p, 'f'); | ||
sp.hashPassword(password, (err: SecurePassError | null, hash?: Buffer) => { | ||
if (err || hash == undefined) { | ||
expect(false).toBeTruthy(); | ||
return; | ||
} | ||
const password = Buffer.from(''); | ||
sp.hashPassword(password, (err: SecurePassError | null, hash?: Buffer) => { | ||
expect(err).toBeDefined(); | ||
expect(err instanceof SecurePassError).toBeTruthy(); | ||
expect(hash).toBeUndefined(); | ||
expect(hash.length).toEqual(SecurePass.HashBytes); | ||
expect(hash.indexOf('$argon2id')).toEqual(0); | ||
done(); | ||
}); | ||
}); | ||
done(); | ||
}); | ||
} | ||
); | ||
test.each([SecurePass.PasswordBytesMin - 1, SecurePass.PasswordBytesMax + 1])( | ||
'Should throw an error if given a password buffer of length %i.', | ||
async (p, done) => { | ||
const sp = new SecurePass(); | ||
try { | ||
const password = Buffer.alloc(p, 'f'); | ||
sp.hashPassword(password, (err: SecurePassError | null, hash?: Buffer) => { | ||
expect(err instanceof SecurePassError).toBeTruthy(); | ||
expect(hash).toBeUndefined(); | ||
done(); | ||
}); | ||
} catch (e) { | ||
expect(e).toBeDefined(); | ||
done(); | ||
} | ||
} | ||
); | ||
}); | ||
describe('hashPasswordSync', () => { | ||
test('Should return a valid hash if given a valid password.', done => { | ||
describe('hashPasswordSync()', () => { | ||
test('Should return a hash if given a valid password.', done => { | ||
const sp = new SecurePass(); | ||
@@ -349,3 +432,3 @@ | ||
expect(hash.length).toEqual(SecurePass.HashBytes); | ||
expect(sp.verifyHashSync(password, hash)).toEqual(VerificationResult.Valid); | ||
expect(hash.indexOf('$argon2id')).toEqual(0); | ||
@@ -355,16 +438,32 @@ done(); | ||
test('Should throw an error if given a blank password buffer.', done => { | ||
const sp = new SecurePass(); | ||
test.each([SecurePass.PasswordBytesMin, SecurePass.PasswordBytesMax])( | ||
'Should return a hash if given a password buffer of length %1.', | ||
(p, done) => { | ||
const sp = new SecurePass(); | ||
const password = Buffer.alloc(p, 'f'); | ||
const hash = sp.hashPasswordSync(password); | ||
const password = Buffer.from(''); | ||
expect(hash.length).toEqual(SecurePass.HashBytes); | ||
expect(hash.indexOf('$argon2id')).toEqual(0); | ||
try { | ||
const hash = sp.hashPasswordSync(password); | ||
} catch (e) { | ||
expect(e).toBeDefined(); | ||
expect(e instanceof SecurePassError).toBeTruthy(); | ||
done(); | ||
} | ||
); | ||
done(); | ||
}); | ||
test.each([SecurePass.PasswordBytesMin - 1, SecurePass.PasswordBytesMax + 1])( | ||
'Should throw an error if given a password buffer of length %i.', | ||
(p, done) => { | ||
try { | ||
const sp = new SecurePass(); | ||
const password = Buffer.alloc(p, 'f'); | ||
const hash = sp.hashPasswordSync(password); | ||
expect(false).toBeTruthy(); | ||
done(); | ||
} catch (e) { | ||
expect(e).toBeDefined(); | ||
done(); | ||
} | ||
} | ||
); | ||
}); | ||
@@ -371,0 +470,0 @@ |
@@ -73,3 +73,3 @@ /** | ||
*/ | ||
public static readonly PasswordBytesMax: number = 4294967295; | ||
public static readonly PasswordBytesMax: number = 2147483647; | ||
@@ -129,2 +129,3 @@ /** | ||
* Use of this option requires a minimum of 1024 MiB of dedicated RAM. | ||
* @readonly | ||
*/ | ||
@@ -174,2 +175,3 @@ public static readonly MemLimitSensitive: number = 1073741824; | ||
* Using this option it takes around 3.5 seconds to derrive a hash on a 2.8Ghz Core i7 CPU. | ||
* @readonly | ||
*/ | ||
@@ -242,2 +244,34 @@ public static readonly OpsLimitSensitive: number = 4; | ||
/** | ||
* Tests a VerificationResult enumeration and returns true if the value is InvalidOrUnrecognized. | ||
* @param vr - The VerificationResult to Test. | ||
*/ | ||
public static isInvalidOrUnrecognized(vr: VerificationResult): boolean { | ||
return vr == VerificationResult.InvalidOrUnrecognized; | ||
} | ||
/** | ||
* Tests a VerificationResult enumeration and returns true if the value is Invalid. | ||
* @param vr - The VerificationResult to Test. | ||
*/ | ||
public static isInvalid(vr: VerificationResult): boolean { | ||
return vr == VerificationResult.Invalid; | ||
} | ||
/** | ||
* Tests a VerificationResult enumeration and returns true if the value is Valid. | ||
* @param vr - The VerificationResult to Test. | ||
*/ | ||
public static isValid(vr: VerificationResult): boolean { | ||
return vr == VerificationResult.Valid; | ||
} | ||
/** | ||
* Tests a VerificationResult enumeration and returns true if the value is ValidNeedsRehash. | ||
* @param vr - The VerificationResult to Test. | ||
*/ | ||
public static isValidNeedsRehash(vr: VerificationResult): boolean { | ||
return vr == VerificationResult.ValidNeedsRehash; | ||
} | ||
/** | ||
* Configured memory limit for Argon2ID. | ||
@@ -363,3 +397,3 @@ */ | ||
public hashPasswordSync(password: Buffer): Buffer { | ||
if (!(password.length >= SecurePass.PasswordBytesMin && password.length < SecurePass.PasswordBytesMax)) { | ||
if (!(password.length >= SecurePass.PasswordBytesMin && password.length <= SecurePass.PasswordBytesMax)) { | ||
throw new SecurePassError( | ||
@@ -399,3 +433,3 @@ `Length of Password Buffer must be between ${SecurePass.PasswordBytesMin} and ${SecurePass.PasswordBytesMax}` | ||
public verifyHashSync(password: Buffer, hash: Buffer): VerificationResult { | ||
if (!(password.length >= SecurePass.PasswordBytesMin && password.length < SecurePass.PasswordBytesMax)) { | ||
if (!(password.length >= SecurePass.PasswordBytesMin && password.length <= SecurePass.PasswordBytesMax)) { | ||
throw new SecurePassError( | ||
@@ -427,3 +461,3 @@ `Length of Password Buffer must be between ${SecurePass.PasswordBytesMin} and ${SecurePass.PasswordBytesMax}` | ||
return new Promise<Buffer>((resolve, reject) => { | ||
if (!(password.length >= SecurePass.PasswordBytesMin && password.length < SecurePass.PasswordBytesMax)) { | ||
if (!(password.length >= SecurePass.PasswordBytesMin && password.length <= SecurePass.PasswordBytesMax)) { | ||
reject( | ||
@@ -452,3 +486,3 @@ new SecurePassError( | ||
return new Promise<VerificationResult>((resolve, reject) => { | ||
if (!(password.length >= SecurePass.PasswordBytesMin && password.length < SecurePass.PasswordBytesMax)) { | ||
if (!(password.length >= SecurePass.PasswordBytesMin && password.length <= SecurePass.PasswordBytesMax)) { | ||
reject( | ||
@@ -455,0 +489,0 @@ new SecurePassError( |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
644886
3749