@@ -32,8 +32,7 @@ | |||
}, | |||
"dependencies": { | |||
"big-integer": "^1.6.22", | |||
"es6-promise": "^4.1.0", | |||
"lodash.assign": "^4.2.0", | |||
"lodash.merge": "^4.6.0", | |||
"unibabel": "^2.1.4" | |||
}, | |||
"devDependencies": { | |||
@@ -1,5 +1,4 @@ | |||
var crypto = require("crypto"); | |||
var Promise = require("es6-promise").Promise; | |||
module.exports = function(digest, string, salt) { | |||
return new Promise(function(resolve) { | |||
@@ -1,15 +1,157 @@ | |||
var v1 = require("./v1"); | |||
var v2 = require("./v2"); | |||
var hmac = require("./hmac"); | |||
var pbkdf2 = require("./pbkdf2"); | |||
var bigInt = require("big-integer"); | |||
var merge = require("lodash.merge"); | |||
module.exports = { | |||
generatePassword: function(site, login, masterPassword, options) { | |||
if (typeof options !== "undefined" && options.version === 1) { | |||
return v1.generatePassword(site, login, masterPassword, options); | |||
} | |||
return v2.generatePassword(site, login, masterPassword, options); | |||
var defaultProfile = { | |||
site: '', | |||
login: '', | |||
options: { | |||
uppercase: true, | |||
lowercase: true, | |||
digits: true, | |||
symbols: true, | |||
length: 16, | |||
counter: 1 | |||
}, | |||
createFingerprint: function(str) { | |||
return hmac("sha256", str); | |||
crypto: { | |||
method: 'pbkdf2', | |||
iterations: 100000, | |||
keylen: 32, | |||
digest: "sha256" | |||
} | |||
}; | |||
module.exports = { | |||
generatePassword: generatePassword, | |||
createFingerprint: createFingerprint, | |||
isSupported: isSupported, | |||
_calcEntropy: calcEntropy, | |||
_consumeEntropy: consumeEntropy, | |||
_getSetOfCharacters: getSetOfCharacters, | |||
_getConfiguredRules: getConfiguredRules, | |||
_insertStringPseudoRandomly: insertStringPseudoRandomly, | |||
_getOneCharPerRule: getOneCharPerRule, | |||
_renderPassword: renderPassword | |||
}; | |||
function generatePassword(profile, masterPassword) { | |||
var _profile = merge({}, defaultProfile, profile); | |||
return calcEntropy(_profile, masterPassword) | |||
.then(function(entropy) { | |||
return renderPassword(entropy, _profile.options); | |||
}); | |||
} | |||
function createFingerprint(str) { | |||
return hmac("sha256", str); | |||
} | |||
function isSupported() { | |||
try { | |||
var simpleProfile = merge({}, defaultProfile, {crypto: {iterations: 1}}); | |||
return generatePassword(simpleProfile, 'LessPass') | |||
.then(function(generatedPassword) { | |||
return generatedPassword == "n'LTsjPA#3E$e*2'"; | |||
}); | |||
} catch (e) { | |||
console.error(e); | |||
return Promise.resolve(false); | |||
} | |||
} | |||
function calcEntropy(profile, masterPassword) { | |||
var salt = profile.site + profile.login + profile.options.counter.toString(16); | |||
return pbkdf2( | |||
masterPassword, | |||
salt, | |||
profile.crypto.iterations, | |||
profile.crypto.keylen, | |||
profile.crypto.digest | |||
); | |||
} | |||
var characterSubsets = { | |||
lowercase: "abcdefghijklmnopqrstuvwxyz", | |||
uppercase: "ABCDEFGHIJKLMNOPQRSTUVWXYZ", | |||
digits: "0123456789", | |||
symbols: "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~" | |||
}; | |||
function getSetOfCharacters(rules) { | |||
if (typeof rules === "undefined") { | |||
return ( | |||
characterSubsets.lowercase + | |||
characterSubsets.uppercase + | |||
characterSubsets.digits + | |||
characterSubsets.symbols | |||
); | |||
} | |||
var setOfChars = ""; | |||
rules.forEach(function(rule) { | |||
setOfChars += characterSubsets[rule]; | |||
}); | |||
return setOfChars; | |||
} | |||
function consumeEntropy(generatedPassword, | |||
quotient, | |||
setOfCharacters, | |||
maxLength) { | |||
if (generatedPassword.length >= maxLength) { | |||
return {value: generatedPassword, entropy: quotient}; | |||
} | |||
var longDivision = quotient.divmod(setOfCharacters.length); | |||
generatedPassword += setOfCharacters[longDivision.remainder]; | |||
return consumeEntropy( | |||
generatedPassword, | |||
longDivision.quotient, | |||
setOfCharacters, | |||
maxLength | |||
); | |||
} | |||
function insertStringPseudoRandomly(generatedPassword, entropy, string) { | |||
for (var i = 0; i < string.length; i++) { | |||
var longDivision = entropy.divmod(generatedPassword.length); | |||
generatedPassword = | |||
generatedPassword.slice(0, longDivision.remainder) + | |||
string[i] + | |||
generatedPassword.slice(longDivision.remainder); | |||
entropy = longDivision.quotient; | |||
} | |||
return generatedPassword; | |||
} | |||
function getOneCharPerRule(entropy, rules) { | |||
var oneCharPerRules = ""; | |||
rules.forEach(function(rule) { | |||
var password = consumeEntropy("", entropy, characterSubsets[rule], 1); | |||
oneCharPerRules += password.value; | |||
entropy = password.entropy; | |||
}); | |||
return {value: oneCharPerRules, entropy: entropy}; | |||
} | |||
function getConfiguredRules(passwordProfile) { | |||
return ["lowercase", "uppercase", "digits", "symbols"].filter(function(rule) { | |||
return passwordProfile[rule]; | |||
}); | |||
} | |||
function renderPassword(entropy, passwordProfile) { | |||
var rules = getConfiguredRules(passwordProfile); | |||
var setOfCharacters = getSetOfCharacters(rules); | |||
var password = consumeEntropy( | |||
"", | |||
bigInt(entropy, 16), | |||
setOfCharacters, | |||
passwordProfile.length - rules.length | |||
); | |||
var charactersToAdd = getOneCharPerRule(password.entropy, rules); | |||
return insertStringPseudoRandomly( | |||
password.value, | |||
charactersToAdd.entropy, | |||
charactersToAdd.value | |||
); | |||
} |
@@ -1,5 +1,4 @@ | |||
const crypto = require("crypto"); | |||
var Promise = require("es6-promise").Promise; | |||
module.exports = function(password, salt, iterations, keylen, digest) { | |||
return new Promise(function(resolve, reject) { | |||
@@ -1,128 +0,0 @@ | |||
var pbkdf2 = require("./pbkdf2"); | |||
var assign = require("lodash.assign"); | |||
var hmac = require("./hmac"); | |||
module.exports = { | |||
generatePassword: generatePassword, | |||
_renderPassword: renderPassword, | |||
_createHmac: createHmac, | |||
_deriveEncryptedLogin: deriveEncryptedLogin, | |||
_getPasswordTemplate: getPasswordTemplate, | |||
_prettyPrint: prettyPrint, | |||
_string2charCodes: string2charCodes, | |||
_getCharType: getCharType, | |||
_getPasswordChar: getPasswordChar | |||
}; | |||
var defaultOptions = { | |||
version: 1, | |||
lowercase: true, | |||
numbers: true, | |||
uppercase: true, | |||
symbols: true, | |||
keylen: 32, | |||
digest: "sha256", | |||
length: 12, | |||
counter: 1, | |||
iterations: 8192 | |||
}; | |||
function generatePassword(site, login, masterPassword, options) { | |||
var _options = assign({}, defaultOptions, options); | |||
return pbkdf2( | |||
masterPassword, | |||
login, | |||
_options.iterations, | |||
_options.keylen, | |||
"sha256" | |||
).then(function(encryptedLogin) { | |||
return renderPassword(encryptedLogin, site, _options).then(function( | |||
generatedPassword | |||
) { | |||
return generatedPassword; | |||
}); | |||
}); | |||
} | |||
function renderPassword(encryptedLogin, site, passwordOptions) { | |||
return deriveEncryptedLogin( | |||
encryptedLogin, | |||
site, | |||
passwordOptions | |||
).then(function(derivedEncryptedLogin) { | |||
var template = | |||
passwordOptions.template || getPasswordTemplate(passwordOptions); | |||
return prettyPrint(derivedEncryptedLogin, template); | |||
}); | |||
} | |||
function createHmac(encryptedLogin, salt) { | |||
return new Promise(function(resolve) { | |||
resolve(hmac("sha256", encryptedLogin, salt)); | |||
}); | |||
} | |||
function deriveEncryptedLogin(encryptedLogin, site, options) { | |||
var _options = options !== undefined ? options : {}; | |||
var length = _options.length || 12; | |||
var counter = _options.counter || 1; | |||
var salt = site + counter.toString(); | |||
return createHmac(encryptedLogin, salt).then(function(derivedHash) { | |||
return derivedHash.substring(0, length); | |||
}); | |||
} | |||
function getPasswordTemplate(passwordTypes) { | |||
var templates = { | |||
lowercase: "vc", | |||
uppercase: "VC", | |||
numbers: "n", | |||
symbols: "s" | |||
}; | |||
var returnedTemplate = ""; | |||
Object.keys(templates).forEach(function(template) { | |||
if (passwordTypes.hasOwnProperty(template) && passwordTypes[template]) { | |||
returnedTemplate += templates[template]; | |||
} | |||
}); | |||
return returnedTemplate; | |||
} | |||
function prettyPrint(hash, template) { | |||
var password = ""; | |||
string2charCodes(hash).forEach(function(charCode, index) { | |||
var charType = getCharType(template, index); | |||
password += getPasswordChar(charType, charCode); | |||
}); | |||
return password; | |||
} | |||
function string2charCodes(text) { | |||
var charCodes = []; | |||
for (var i = 0; i < text.length; i++) { | |||
charCodes.push(text.charCodeAt(i)); | |||
} | |||
return charCodes; | |||
} | |||
function getCharType(template, index) { | |||
return template[index % template.length]; | |||
} | |||
function getPasswordChar(charType, index) { | |||
var passwordsChars = { | |||
V: "AEIOUY", | |||
C: "BCDFGHJKLMNPQRSTVWXZ", | |||
v: "aeiouy", | |||
c: "bcdfghjklmnpqrstvwxz", | |||
A: "AEIOUYBCDFGHJKLMNPQRSTVWXZ", | |||
a: "AEIOUYaeiouyBCDFGHJKLMNPQRSTVWXZbcdfghjklmnpqrstvwxz", | |||
n: "0123456789", | |||
s: "@&%?,=[]_:-+*$#!'^~;()/.", | |||
x: "AEIOUYaeiouyBCDFGHJKLMNPQRSTVWXZbcdfghjklmnpqrstvwxz0123456789@&%?,=[]_:-+*$#!'^~;()/." | |||
}; | |||
var passwordChar = passwordsChars[charType]; | |||
return passwordChar[index % passwordChar.length]; | |||
} |
@@ -1,136 +0,0 @@ | |||
var pbkdf2 = require("./pbkdf2"); | |||
var bigInt = require("big-integer"); | |||
var assign = require("lodash.assign"); | |||
module.exports = { | |||
generatePassword: generatePassword, | |||
_calcEntropy: calcEntropy, | |||
_consumeEntropy: consumeEntropy, | |||
_getSetOfCharacters: getSetOfCharacters, | |||
_getConfiguredRules: getConfiguredRules, | |||
_insertStringPseudoRandomly: insertStringPseudoRandomly, | |||
_getOneCharPerRule: getOneCharPerRule, | |||
_renderPassword: renderPassword | |||
}; | |||
var defaultOptions = { | |||
version: 2, | |||
lowercase: true, | |||
numbers: true, | |||
uppercase: true, | |||
symbols: true, | |||
keylen: 32, | |||
digest: "sha256", | |||
length: 16, | |||
counter: 1, | |||
iterations: 100000 | |||
}; | |||
function generatePassword(site, login, masterPassword, options) { | |||
var _options = assign({}, defaultOptions, options); | |||
return calcEntropy(site, login, masterPassword, _options).then(function( | |||
entropy | |||
) { | |||
return renderPassword(entropy, _options); | |||
}); | |||
} | |||
function calcEntropy(site, login, masterPassword, passwordProfile) { | |||
var salt = site + login + passwordProfile.counter.toString(16); | |||
return pbkdf2( | |||
masterPassword, | |||
salt, | |||
passwordProfile.iterations, | |||
passwordProfile.keylen, | |||
passwordProfile.digest | |||
); | |||
} | |||
var characterSubsets = { | |||
lowercase: "abcdefghijklmnopqrstuvwxyz", | |||
uppercase: "ABCDEFGHIJKLMNOPQRSTUVWXYZ", | |||
numbers: "0123456789", | |||
symbols: "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~" | |||
}; | |||
function getSetOfCharacters(rules) { | |||
if (typeof rules === "undefined") { | |||
return ( | |||
characterSubsets.lowercase + | |||
characterSubsets.uppercase + | |||
characterSubsets.numbers + | |||
characterSubsets.symbols | |||
); | |||
} | |||
var setOfChars = ""; | |||
rules.forEach(function(rule) { | |||
setOfChars += characterSubsets[rule]; | |||
}); | |||
return setOfChars; | |||
} | |||
function consumeEntropy( | |||
generatedPassword, | |||
quotient, | |||
setOfCharacters, | |||
maxLength | |||
) { | |||
if (generatedPassword.length >= maxLength) { | |||
return { value: generatedPassword, entropy: quotient }; | |||
} | |||
var longDivision = quotient.divmod(setOfCharacters.length); | |||
generatedPassword += setOfCharacters[longDivision.remainder]; | |||
return consumeEntropy( | |||
generatedPassword, | |||
longDivision.quotient, | |||
setOfCharacters, | |||
maxLength | |||
); | |||
} | |||
function insertStringPseudoRandomly(generatedPassword, entropy, string) { | |||
for (var i = 0; i < string.length; i++) { | |||
var longDivision = entropy.divmod(generatedPassword.length); | |||
generatedPassword = | |||
generatedPassword.slice(0, longDivision.remainder) + | |||
string[i] + | |||
generatedPassword.slice(longDivision.remainder); | |||
entropy = longDivision.quotient; | |||
} | |||
return generatedPassword; | |||
} | |||
function getOneCharPerRule(entropy, rules) { | |||
var oneCharPerRules = ""; | |||
rules.forEach(function(rule) { | |||
var password = consumeEntropy("", entropy, characterSubsets[rule], 1); | |||
oneCharPerRules += password.value; | |||
entropy = password.entropy; | |||
}); | |||
return { value: oneCharPerRules, entropy: entropy }; | |||
} | |||
function getConfiguredRules(passwordProfile) { | |||
return ["lowercase", "uppercase", "numbers", "symbols"].filter(function( | |||
rule | |||
) { | |||
return passwordProfile[rule]; | |||
}); | |||
} | |||
function renderPassword(entropy, passwordProfile) { | |||
var rules = getConfiguredRules(passwordProfile); | |||
var setOfCharacters = getSetOfCharacters(rules); | |||
var password = consumeEntropy( | |||
"", | |||
bigInt(entropy, 16), | |||
setOfCharacters, | |||
passwordProfile.length - rules.length | |||
); | |||
var charactersToAdd = getOneCharPerRule(password.entropy, rules); | |||
return insertStringPseudoRandomly( | |||
password.value, | |||
charactersToAdd.entropy, | |||
charactersToAdd.value | |||
); | |||
} |
@@ -1,388 +1,98 @@ | |||
var assert = require("assert"); | |||
var LessPass = require("../src/lesspass"); | |||
describe("api", function() { | |||
describe("v1", function() { | |||
it("generatedPassword", function() { | |||
var site = "example.org"; | |||
var login = "contact@example.org"; | |||
var masterPassword = "password"; | |||
var options = { | |||
describe("api", () => { | |||
it("generatePassword", () => { | |||
const profile = { | |||
site: "example.org", | |||
login: "contact@example.org", | |||
options: { | |||
lowercase: true, | |||
uppercase: true, | |||
numbers: true, | |||
symbols: true, | |||
length: 12, | |||
counter: 1, | |||
version: 1 | |||
}; | |||
return LessPass.generatePassword( | |||
site, | |||
login, | |||
masterPassword, | |||
options | |||
).then(function(generatedPassword) { | |||
assert.equal("izIS5@ozYM2?", generatedPassword); | |||
}); | |||
}); | |||
it("generatedPassword", function() { | |||
var site = "lesspass.com"; | |||
var login = "contact@lesspass.com"; | |||
var masterPassword = "password"; | |||
var options = { | |||
lowercase: true, | |||
uppercase: true, | |||
numbers: true, | |||
symbols: true, | |||
length: 12, | |||
counter: 1, | |||
version: 1 | |||
}; | |||
return LessPass.generatePassword( | |||
site, | |||
login, | |||
masterPassword, | |||
options | |||
).then(function(generatedPassword) { | |||
assert.equal("azYS7,olOL2]", generatedPassword); | |||
}); | |||
}); | |||
it("generatedPassword", function() { | |||
var site = "lesspass.com"; | |||
var login = "contact@lesspass.com"; | |||
var masterPassword = "password"; | |||
var options = { | |||
lowercase: true, | |||
uppercase: true, | |||
numbers: true, | |||
symbols: true, | |||
length: 14, | |||
counter: 1, | |||
version: 1 | |||
}; | |||
return LessPass.generatePassword( | |||
site, | |||
login, | |||
masterPassword, | |||
options | |||
).then(function(generatedPassword) { | |||
assert.equal("azYS7,olOL2]iz", generatedPassword); | |||
}); | |||
}); | |||
it("generatedPassword", function() { | |||
var site = "lesspass.com"; | |||
var login = "contact@lesspass.com"; | |||
var masterPassword = "password"; | |||
var options = { | |||
lowercase: true, | |||
uppercase: false, | |||
numbers: false, | |||
symbols: false, | |||
length: 12, | |||
counter: 1, | |||
version: 1 | |||
}; | |||
return LessPass.generatePassword( | |||
site, | |||
login, | |||
masterPassword, | |||
options | |||
).then(function(generatedPassword) { | |||
assert.equal("azyseqololat", generatedPassword); | |||
}); | |||
}); | |||
it("generatedPassword", function() { | |||
var site = "lesspass.com"; | |||
var login = "contact@lesspass.com"; | |||
var masterPassword = "password"; | |||
var options = { | |||
lowercase: false, | |||
uppercase: true, | |||
numbers: true, | |||
symbols: true, | |||
length: 12, | |||
counter: 1, | |||
version: 1 | |||
}; | |||
return LessPass.generatePassword( | |||
site, | |||
login, | |||
masterPassword, | |||
options | |||
).then(function(generatedPassword) { | |||
assert.equal("AZ3[EQ7@OL2]", generatedPassword); | |||
}); | |||
}); | |||
it("generatedPassword", function() { | |||
var site = "lesspass.com"; | |||
var login = "contact@lesspass.com"; | |||
var masterPassword = "password"; | |||
var options = { | |||
lowercase: false, | |||
uppercase: false, | |||
numbers: true, | |||
symbols: true, | |||
length: 12, | |||
counter: 1, | |||
version: 1 | |||
}; | |||
return LessPass.generatePassword( | |||
site, | |||
login, | |||
masterPassword, | |||
options | |||
).then(function(generatedPassword) { | |||
assert.equal("4?3[7,7@7@2]", generatedPassword); | |||
}); | |||
}); | |||
it("generatedPassword", function() { | |||
var site = "lesspass.com"; | |||
var login = "contact@lesspass.com"; | |||
var masterPassword = "password"; | |||
var options = { | |||
lowercase: false, | |||
uppercase: false, | |||
numbers: false, | |||
symbols: true, | |||
length: 12, | |||
counter: 1, | |||
version: 1 | |||
}; | |||
return LessPass.generatePassword( | |||
site, | |||
login, | |||
masterPassword, | |||
options | |||
).then(function(generatedPassword) { | |||
assert.equal("[?=[&,:@:@[]", generatedPassword); | |||
}); | |||
}); | |||
it("generatedPassword", function() { | |||
var site = "lesspass.com"; | |||
var login = "contact@lesspass.com"; | |||
var masterPassword = "password"; | |||
var options = { | |||
lowercase: true, | |||
uppercase: true, | |||
numbers: true, | |||
symbols: false, | |||
length: 12, | |||
counter: 1, | |||
version: 1 | |||
}; | |||
return LessPass.generatePassword( | |||
site, | |||
login, | |||
masterPassword, | |||
options | |||
).then(function(generatedPassword) { | |||
assert.equal("azYS7uwAW8at", generatedPassword); | |||
}); | |||
}); | |||
it("generatedPassword", function() { | |||
var site = "lesspass.com"; | |||
var login = "contact@lesspass.com"; | |||
var masterPassword = "password"; | |||
var options = { | |||
lowercase: true, | |||
uppercase: true, | |||
numbers: false, | |||
symbols: false, | |||
length: 12, | |||
counter: 1, | |||
version: 1 | |||
}; | |||
return LessPass.generatePassword( | |||
site, | |||
login, | |||
masterPassword, | |||
options | |||
).then(function(generatedPassword) { | |||
assert.equal("azYSeqOLolAT", generatedPassword); | |||
}); | |||
}); | |||
it("generatedPassword", function() { | |||
var site = "lesspass.com"; | |||
var login = "contact@lesspass.com"; | |||
var masterPassword = "password"; | |||
var options = { | |||
lowercase: true, | |||
uppercase: true, | |||
numbers: true, | |||
symbols: true, | |||
length: 12, | |||
counter: 2, | |||
version: 1 | |||
}; | |||
return LessPass.generatePassword( | |||
site, | |||
login, | |||
masterPassword, | |||
options | |||
).then(function(generatedPassword) { | |||
assert.equal("obYT2=olOV9=", generatedPassword); | |||
}); | |||
}); | |||
it("generatedPassword", function() { | |||
var site = "lesspass.com"; | |||
var login = "lesspass"; | |||
var masterPassword = "password"; | |||
var options = { | |||
lowercase: true, | |||
uppercase: true, | |||
numbers: true, | |||
symbols: true, | |||
length: 12, | |||
counter: 1, | |||
version: 1 | |||
}; | |||
return LessPass.generatePassword( | |||
site, | |||
login, | |||
masterPassword, | |||
options | |||
).then(function(generatedPassword) { | |||
assert.equal("erOC1%imIW3,", generatedPassword); | |||
}); | |||
}); | |||
it("generatedPassword", function() { | |||
var site = "lesspass.com"; | |||
var login = "contact@lesspass.com"; | |||
var masterPassword = "password2"; | |||
var options = { | |||
lowercase: true, | |||
uppercase: true, | |||
numbers: true, | |||
symbols: true, | |||
length: 12, | |||
counter: 1, | |||
version: 1 | |||
}; | |||
return LessPass.generatePassword( | |||
site, | |||
login, | |||
masterPassword, | |||
options | |||
).then(function(generatedPassword) { | |||
assert.equal("uvUM5_ucUP5=", generatedPassword); | |||
}); | |||
}); | |||
}); | |||
describe("v2", function() { | |||
it("generatedPassword", function() { | |||
this.timeout(10000); | |||
var site = "example.org"; | |||
var login = "contact@example.org"; | |||
var masterPassword = "password"; | |||
var options = { | |||
lowercase: true, | |||
uppercase: true, | |||
numbers: true, | |||
digits: true, | |||
symbols: true, | |||
length: 16, | |||
counter: 1, | |||
version: 2 | |||
}; | |||
return LessPass.generatePassword( | |||
site, | |||
login, | |||
masterPassword, | |||
options | |||
).then(function(generatedPassword) { | |||
counter: 1 | |||
} | |||
}; | |||
const masterPassword = "password"; | |||
return LessPass | |||
.generatePassword(profile, masterPassword) | |||
.then(generatedPassword => { | |||
assert.equal("WHLpUL)e00[iHR+w", generatedPassword); | |||
}); | |||
}); | |||
it("generatePassword default options", () => { | |||
const profile = { | |||
site: "example.org", | |||
login: "contact@example.org" | |||
}; | |||
const masterPassword = "password"; | |||
return LessPass.generatePassword(profile, masterPassword).then(generatedPassword => { | |||
assert.equal("WHLpUL)e00[iHR+w", generatedPassword); | |||
}); | |||
it("generatedPassword", function() { | |||
this.timeout(10000); | |||
var site = "example.org"; | |||
var login = "contact@example.org"; | |||
var masterPassword = "password"; | |||
var options = { | |||
}); | |||
it("generatedPassword different options", () => { | |||
const profile = { | |||
site: "example.org", | |||
login: "contact@example.org", | |||
options: { | |||
lowercase: true, | |||
uppercase: true, | |||
numbers: true, | |||
digits: true, | |||
symbols: false, | |||
length: 14, | |||
counter: 2, | |||
version: 2 | |||
}; | |||
return LessPass.generatePassword( | |||
site, | |||
login, | |||
masterPassword, | |||
options | |||
).then(function(generatedPassword) { | |||
assert.equal("MBAsB7b1Prt8Sl", generatedPassword); | |||
}); | |||
counter: 2 | |||
} | |||
}; | |||
const masterPassword = "password"; | |||
return LessPass.generatePassword(profile, masterPassword).then(generatedPassword => { | |||
assert.equal("MBAsB7b1Prt8Sl", generatedPassword); | |||
assert.equal(14, generatedPassword.length); | |||
}); | |||
it("generatedPassword", function() { | |||
this.timeout(10000); | |||
var site = "example.org"; | |||
var login = "contact@example.org"; | |||
var masterPassword = "password"; | |||
var options = { | |||
}); | |||
it("generatedPassword only digits", () => { | |||
const profile = { | |||
site: "example.org", | |||
login: "contact@example.org", | |||
options: { | |||
lowercase: false, | |||
uppercase: false, | |||
numbers: true, | |||
digits: true, | |||
symbols: false, | |||
length: 6, | |||
counter: 3, | |||
version: 2 | |||
}; | |||
return LessPass.generatePassword( | |||
site, | |||
login, | |||
masterPassword, | |||
options | |||
).then(function(generatedPassword) { | |||
assert.equal("117843", generatedPassword); | |||
}); | |||
counter: 3 | |||
} | |||
}; | |||
const masterPassword = "password"; | |||
return LessPass.generatePassword(profile, masterPassword).then(generatedPassword => { | |||
assert.equal("117843", generatedPassword); | |||
}); | |||
it("generatedPassword", function() { | |||
this.timeout(10000); | |||
var site = "example.org"; | |||
var login = "contact@example.org"; | |||
var masterPassword = "password"; | |||
var options = { | |||
lowercase: true, | |||
uppercase: true, | |||
numbers: false, | |||
symbols: true, | |||
length: 14, | |||
counter: 1, | |||
version: 2 | |||
}; | |||
return LessPass.generatePassword( | |||
site, | |||
login, | |||
masterPassword, | |||
options | |||
).then(function(generatedPassword) { | |||
assert.equal("sB>{qF}wN%/-fm", generatedPassword); | |||
}); | |||
}); | |||
it("generatedPassword no digit", () => { | |||
const profile = { | |||
site: "example.org", | |||
login: "contact@example.org", | |||
options: { | |||
digits: false | |||
} | |||
}; | |||
const masterPassword = "password"; | |||
return LessPass.generatePassword(profile, masterPassword).then(generatedPassword => { | |||
assert.equal("s>{F}RwkN/-fmM.X", generatedPassword); | |||
}); | |||
it("generatedPassword", function() { | |||
this.timeout(10000); | |||
var site = "example.org"; | |||
var login = "contact@example.org"; | |||
var masterPassword = "password"; | |||
return LessPass.generatePassword( | |||
site, | |||
login, | |||
masterPassword | |||
).then(function(generatedPassword) { | |||
assert.equal("WHLpUL)e00[iHR+w", generatedPassword); | |||
}); | |||
}); | |||
it("createFingerprint", () => { | |||
return LessPass.createFingerprint("password").then(function(fingerprint) { | |||
assert.equal( | |||
"e56a207acd1e6714735487c199c6f095844b7cc8e5971d86c003a7b6f36ef51e", | |||
fingerprint | |||
); | |||
}); | |||
}); | |||
describe("fingerprint", function() { | |||
it("createFingerprint", function() { | |||
return LessPass.createFingerprint("password").then(function(fingerprint) { | |||
assert.equal( | |||
"e56a207acd1e6714735487c199c6f095844b7cc8e5971d86c003a7b6f36ef51e", | |||
fingerprint | |||
); | |||
}); | |||
it("isSupported", () => { | |||
return LessPass.isSupported("password").then(function(isSupported) { | |||
assert(isSupported); | |||
}); | |||
}); | |||
}); |
@@ -0,0 +1,89 @@ | |||
var assert = require("assert"); | |||
var LessPass = require("../src/lesspass"); | |||
var bigInt = require("big-integer"); | |||
describe("entropy", function() { | |||
it("calc entropy pbkdf2 with default params (100000 iterations, 32 bytes length, sha256 digest)", function() { | |||
const profile = { | |||
site: "example.org", | |||
login: "contact@example.org", | |||
options: { | |||
counter: 1 | |||
}, | |||
crypto: { | |||
method: 'pbkdf2', | |||
iterations: 100000, | |||
keylen: 32, | |||
digest: "sha256" | |||
} | |||
}; | |||
const masterPassword = "password"; | |||
return LessPass._calcEntropy(profile, masterPassword) | |||
.then(function(entropy) { | |||
assert.equal( | |||
"dc33d431bce2b01182c613382483ccdb0e2f66482cbba5e9d07dab34acc7eb1e", | |||
entropy | |||
); | |||
}); | |||
}); | |||
it("calc entropy with different options (8192 iterations, 16 bytes length, sha512 digest)", function() { | |||
const profile = { | |||
site: "example.org", | |||
login: "contact@example.org", | |||
options: { | |||
counter: 1 | |||
}, | |||
crypto: { | |||
method: 'pbkdf2', | |||
iterations: 8192, | |||
keylen: 16, | |||
digest: "sha512" | |||
} | |||
}; | |||
const masterPassword = "password"; | |||
return LessPass._calcEntropy(profile, masterPassword) | |||
.then(function(entropy) { | |||
assert.equal("fff211c16a4e776b3574c6a5c91fd252", entropy); | |||
}); | |||
}); | |||
it("calc entropy different if counter different 1", function() { | |||
const profile = { | |||
site: "example.org", | |||
login: "contact@example.org", | |||
options: { | |||
counter: 1 | |||
}, | |||
crypto: { | |||
method: 'pbkdf2', | |||
iterations: 100000, | |||
keylen: 32, | |||
digest: "sha256" | |||
} | |||
}; | |||
const profile2 = { | |||
site: "example.org", | |||
login: "contact@example.org", | |||
options: { | |||
counter: 2 | |||
}, | |||
crypto: { | |||
method: 'pbkdf2', | |||
iterations: 100000, | |||
keylen: 32, | |||
digest: "sha256" | |||
} | |||
}; | |||
const promises = [ | |||
LessPass._calcEntropy(profile, "password"), | |||
LessPass._calcEntropy(profile2, "password"), | |||
]; | |||
Promise.all(promises).then(values => { | |||
assert.notEqual(values[0], values[1]); | |||
}); | |||
}); | |||
it("consume entropy", function() { | |||
var password = LessPass._consumeEntropy("", bigInt(4 * 4 + 2), "abcd", 2); | |||
assert.equal("ca", password.value); | |||
assert.equal(1, password.entropy); | |||
}); | |||
}); |
@@ -1,47 +1,47 @@ | |||
var assert = require("assert"); | |||
var v2 = require("../../src/v2"); | |||
var bigInt = require("big-integer"); | |||
const assert = require("assert"); | |||
const LessPass = require("../src/lesspass"); | |||
const bigInt = require("big-integer"); | |||
describe("LessPass v2", function() { | |||
var defaultPasswordProfile = { | |||
describe("LessPass LessPass", function() { | |||
const defaultPasswordProfile = { | |||
length: 16, | |||
lowercase: true, | |||
uppercase: true, | |||
numbers: true, | |||
digits: true, | |||
symbols: true | |||
}; | |||
it("render password use remainder of long division beetween entropy and set of chars length as an index", function() { | |||
var entropy = | |||
const entropy = | |||
"dc33d431bce2b01182c613382483ccdb0e2f66482cbba5e9d07dab34acc7eb1e"; | |||
assert.equal("W", v2._renderPassword(entropy, defaultPasswordProfile)[0]); | |||
assert.equal("W", LessPass._renderPassword(entropy, defaultPasswordProfile)[0]); | |||
}); | |||
it("render password use quotient as second entropy recursively", function() { | |||
var entropy = | |||
const entropy = | |||
"dc33d431bce2b01182c613382483ccdb0e2f66482cbba5e9d07dab34acc7eb1e"; | |||
assert.equal("H", v2._renderPassword(entropy, defaultPasswordProfile)[1]); | |||
assert.equal("H", LessPass._renderPassword(entropy, defaultPasswordProfile)[1]); | |||
}); | |||
it("render password has default length of 16", function() { | |||
var entropy = | |||
const entropy = | |||
"dc33d431bce2b01182c613382483ccdb0e2f66482cbba5e9d07dab34acc7eb1e"; | |||
assert.equal( | |||
16, | |||
v2._renderPassword(entropy, defaultPasswordProfile).length | |||
LessPass._renderPassword(entropy, defaultPasswordProfile).length | |||
); | |||
}); | |||
it("render password can specify length", function() { | |||
var entropy = | |||
const entropy = | |||
"dc33d431bce2b01182c613382483ccdb0e2f66482cbba5e9d07dab34acc7eb1e"; | |||
var passwordProfile = { | |||
const passwordProfile = { | |||
length: 20, | |||
lowercase: true, | |||
uppercase: true, | |||
numbers: true, | |||
digits: true, | |||
symbols: true | |||
}; | |||
assert.equal(20, v2._renderPassword(entropy, passwordProfile).length); | |||
assert.equal(20, LessPass._renderPassword(entropy, passwordProfile).length); | |||
}); | |||
it("include one char per set of characters", function() { | |||
var password = v2._insertStringPseudoRandomly( | |||
const password = LessPass._insertStringPseudoRandomly( | |||
"123456", | |||
bigInt(7 * 6 + 2), | |||
"uT" | |||
@@ -49,21 +49,21 @@ describe("LessPass v2", function() { | |||
assert.equal("T12u3456", password); | |||
}); | |||
it("render password return at least one char in every characters set", function() { | |||
var entropy = | |||
const entropy = | |||
"dc33d431bce2b01182c613382483ccdb0e2f66482cbba5e9d07dab34acc7eb1e"; | |||
var passwordProfile = { | |||
const passwordProfile = { | |||
length: 6, | |||
lowercase: true, | |||
uppercase: true, | |||
numbers: true, | |||
digits: true, | |||
symbols: true | |||
}; | |||
var generatedPassword = v2._renderPassword(entropy, passwordProfile); | |||
var passwordLength = generatedPassword.length; | |||
var lowercaseOk = false; | |||
var uppercaseOk = false; | |||
var numbersOk = false; | |||
var symbolsOk = false; | |||
const generatedPassword = LessPass._renderPassword(entropy, passwordProfile); | |||
let passwordLength = generatedPassword.length; | |||
let lowercaseOk = false; | |||
let uppercaseOk = false; | |||
let digitsOk = false; | |||
let symbolsOk = false; | |||
while (passwordLength--) { | |||
if ( | |||
"abcdefghijklmnopqrstuvwxyz".indexOf( | |||
@@ -80,7 +80,7 @@ describe("LessPass v2", function() { | |||
uppercaseOk = true; | |||
} | |||
if ("0123456789".indexOf(generatedPassword[passwordLength]) !== -1) { | |||
numbersOk = true; | |||
digitsOk = true; | |||
} | |||
if ( | |||
"!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~".indexOf( | |||
@@ -92,7 +92,7 @@ describe("LessPass v2", function() { | |||
} | |||
assert.equal(6, generatedPassword.length); | |||
assert( | |||
lowercaseOk && uppercaseOk && numbersOk && symbolsOk, | |||
lowercaseOk && uppercaseOk && digitsOk && symbolsOk, | |||
"there is no at least one char in every characters set" | |||
); | |||
}); |
@@ -1,10 +1,10 @@ | |||
var assert = require("assert"); | |||
var v2 = require("../../src/v2"); | |||
var LessPass = require("../src/lesspass"); | |||
var bigInt = require("big-integer"); | |||
describe("set of characters", function() { | |||
it("get default set of characters", function() { | |||
var setOfCharacters = v2._getSetOfCharacters(); | |||
var setOfCharacters = LessPass._getSetOfCharacters(); | |||
assert.equal( | |||
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", | |||
setOfCharacters | |||
@@ -12,10 +12,10 @@ describe("set of characters", function() { | |||
assert.equal(26 * 2 + 10 + 32, setOfCharacters.length); | |||
}); | |||
it("get default set of characters concat rules in order", function() { | |||
var setOfCharacters = v2._getSetOfCharacters([ | |||
var setOfCharacters = LessPass._getSetOfCharacters([ | |||
"lowercase", | |||
"uppercase", | |||
"numbers" | |||
"digits" | |||
]); | |||
assert.equal( | |||
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", | |||
@@ -24,27 +24,27 @@ describe("set of characters", function() { | |||
assert.equal(26 * 2 + 10, setOfCharacters.length); | |||
}); | |||
it("get set of characters only lowercase", function() { | |||
var setOfCharacters = v2._getSetOfCharacters(["lowercase"]); | |||
var setOfCharacters = LessPass._getSetOfCharacters(["lowercase"]); | |||
assert.equal("abcdefghijklmnopqrstuvwxyz", setOfCharacters); | |||
assert.equal(26, setOfCharacters.length); | |||
}); | |||
it("get set of characters only uppercase", function() { | |||
var setOfCharacters = v2._getSetOfCharacters(["uppercase"]); | |||
var setOfCharacters = LessPass._getSetOfCharacters(["uppercase"]); | |||
assert.equal("ABCDEFGHIJKLMNOPQRSTUVWXYZ", setOfCharacters); | |||
assert.equal(26, setOfCharacters.length); | |||
}); | |||
it("get set of characters only numbers", function() { | |||
var setOfCharacters = v2._getSetOfCharacters(["numbers"]); | |||
it("get set of characters only digits", function() { | |||
var setOfCharacters = LessPass._getSetOfCharacters(["digits"]); | |||
assert.equal("0123456789", setOfCharacters); | |||
assert.equal(10, setOfCharacters.length); | |||
}); | |||
it("get set of characters only symbols", function() { | |||
var setOfCharacters = v2._getSetOfCharacters(["symbols"]); | |||
var setOfCharacters = LessPass._getSetOfCharacters(["symbols"]); | |||
assert.equal("!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", setOfCharacters); | |||
assert.equal(32, setOfCharacters.length); | |||
}); | |||
it("generate one char per rules", function() { | |||
var oneCharPerSetOfCharacters = v2._getOneCharPerRule(bigInt(26 * 26), [ | |||
var oneCharPerSetOfCharacters = LessPass._getOneCharPerRule(bigInt(26 * 26), [ | |||
"lowercase", | |||
"uppercase" | |||
]); | |||
@@ -55,23 +55,23 @@ describe("set of characters", function() { | |||
it("configured rules", function() { | |||
assert.deepEqual( | |||
["uppercase"], | |||
v2._getConfiguredRules({ uppercase: true }) | |||
LessPass._getConfiguredRules({ uppercase: true }) | |||
); | |||
assert.deepEqual( | |||
["lowercase", "uppercase"], | |||
v2._getConfiguredRules({ uppercase: true, lowercase: true }) | |||
LessPass._getConfiguredRules({ uppercase: true, lowercase: true }) | |||
); | |||
assert.deepEqual( | |||
["lowercase"], | |||
v2._getConfiguredRules({ lowercase: true, symbols: false }) | |||
LessPass._getConfiguredRules({ lowercase: true, symbols: false }) | |||
); | |||
assert.deepEqual( | |||
["lowercase", "uppercase", "numbers", "symbols"], | |||
v2._getConfiguredRules({ | |||
["lowercase", "uppercase", "digits", "symbols"], | |||
LessPass._getConfiguredRules({ | |||
lowercase: true, | |||
uppercase: true, | |||
symbols: true, | |||
numbers: true | |||
digits: true | |||
}) | |||
); | |||
}); |
@@ -1,110 +0,0 @@ | |||
var assert = require("assert"); | |||
var v1 = require("../../src/v1"); | |||
describe("deriveEncryptedLogin", function() { | |||
it("should createHmac", function() { | |||
var encryptedLogin = | |||
"9f505f3a95fe0485da3242cb81c9fe25c2f400d8399737655a8dad2b52778d88"; | |||
var salt = "lesspass.com1"; | |||
return v1._createHmac(encryptedLogin, salt).then(function(hmac) { | |||
assert.equal( | |||
"be00f942fc8aa67d8e76fc2456862b9d66d166ebfdd3dc2f0116e278209532ed", | |||
hmac | |||
); | |||
}); | |||
}); | |||
it("should derive encrypted login with default options 1", function() { | |||
const encryptedLogin = | |||
"90cff82b8847525370a8f29a59ecf45db62c719a535788ad0df58d32304e925d"; | |||
const site = "lesspass.com"; | |||
return v1 | |||
._deriveEncryptedLogin(encryptedLogin, site) | |||
.then(function(generatedPassword) { | |||
assert.equal("ecd16aefc7e5", generatedPassword); | |||
}); | |||
}); | |||
it("should derive encrypted login with default options 2", function() { | |||
const encryptedLogin = | |||
"90cff82b8847525370a8f29a59ecf45db62c719a535788ad0df58d32304e925d"; | |||
const site = "lesspass.com"; | |||
const option = { | |||
counter: 1, | |||
length: 12, | |||
lowercase: true, | |||
uppercase: true, | |||
numbers: true, | |||
symbols: true | |||
}; | |||
return v1 | |||
._deriveEncryptedLogin(encryptedLogin, site, option) | |||
.then(function(generatedPassword) { | |||
assert.equal("ecd16aefc7e5", generatedPassword); | |||
}); | |||
}); | |||
it("should derive encrypted login with defined length", function() { | |||
var encryptedLogin = | |||
"d79d8482f708122288af7b259393a58fe05840f4555cc935cdd3f062b9aa75ed"; | |||
var site = "lesspass.com"; | |||
var option = { | |||
counter: 1, | |||
length: 10 | |||
}; | |||
return v1 | |||
._deriveEncryptedLogin(encryptedLogin, site, option) | |||
.then(function(generatedPassword) { | |||
assert.equal(10, generatedPassword.length); | |||
}); | |||
}); | |||
it("should return two different passwords if site different 1", function() { | |||
const encryptedLogin = | |||
"f4fd3885fb70085f2285c3382e2d9adb4c2553285fc45dd896791aa5e79070a9"; | |||
const site = "google.com"; | |||
return v1 | |||
._deriveEncryptedLogin(encryptedLogin, site) | |||
.then(function(derivedEncryptedLogin) { | |||
assert.equal("a957c3a459ec", derivedEncryptedLogin); | |||
}); | |||
}); | |||
it("should return two different passwords if site different 2", function() { | |||
const encryptedLogin = | |||
"f4fd3885fb70085f2285c3382e2d9adb4c2553285fc45dd896791aa5e79070a9"; | |||
const site = "facebook.com"; | |||
return v1 | |||
._deriveEncryptedLogin(encryptedLogin, site) | |||
.then(function(derivedEncryptedLogin) { | |||
assert.equal("d9f3a918c34b", derivedEncryptedLogin); | |||
}); | |||
}); | |||
it("should return two different passwords if counter different 1", function() { | |||
const encryptedLogin = | |||
"dfba06278c9aa24d992bc2d390a53efef482788859455875f72015335d085fcd"; | |||
const site = "lesspass.com"; | |||
const option = { counter: 1 }; | |||
return v1 | |||
._deriveEncryptedLogin(encryptedLogin, site, option) | |||
.then(function(derivedEncryptedLogins) { | |||
assert.equal("bb2e0b34036d", derivedEncryptedLogins); | |||
}); | |||
}); | |||
it("should return two different passwords if counter different 2", function() { | |||
const encryptedLogin = | |||
"dfba06278c9aa24d992bc2d390a53efef482788859455875f72015335d085fcd"; | |||
const site = "lesspass.com"; | |||
const option2 = { counter: 2 }; | |||
return v1 | |||
._deriveEncryptedLogin(encryptedLogin, site, option2) | |||
.then(function(derivedEncryptedLogins) { | |||
assert.equal("67fe8c05a248", derivedEncryptedLogins); | |||
}); | |||
}); | |||
it("should derive encrypted login with sha 256", function() { | |||
const encryptedLogin = | |||
"9f505f3a95fe0485da3242cb81c9fe25c2f400d8399737655a8dad2b52778d88"; | |||
const site = "lesspass.com"; | |||
v1 | |||
._deriveEncryptedLogin(encryptedLogin, site) | |||
.then(function(encryptedLogin) { | |||
assert.equal("be00f942fc8a", encryptedLogin); | |||
}); | |||
}); | |||
}); |
@@ -1,82 +0,0 @@ | |||
var assert = require("assert"); | |||
var v1 = require("../../src/v1"); | |||
describe("getPasswordTemplate", function() { | |||
it("should get default template", function() { | |||
assert.equal( | |||
"vcVCns", | |||
v1._getPasswordTemplate({ | |||
counter: 1, | |||
length: 12, | |||
lowercase: true, | |||
uppercase: true, | |||
numbers: true, | |||
symbols: true | |||
}) | |||
); | |||
}); | |||
it("should get lowercase template", function() { | |||
assert.equal( | |||
"vc", | |||
v1._getPasswordTemplate({ | |||
lowercase: true, | |||
uppercase: false, | |||
numbers: false, | |||
symbols: false | |||
}) | |||
); | |||
}); | |||
it("should get uppercase template", function() { | |||
assert.equal( | |||
"VC", | |||
v1._getPasswordTemplate({ | |||
lowercase: false, | |||
uppercase: true, | |||
numbers: false, | |||
symbols: false | |||
}) | |||
); | |||
}); | |||
it("should get numbers template", function() { | |||
assert.equal( | |||
"n", | |||
v1._getPasswordTemplate({ | |||
lowercase: false, | |||
uppercase: false, | |||
numbers: true, | |||
symbols: false | |||
}) | |||
); | |||
}); | |||
it("should get symbols template", function() { | |||
assert.equal( | |||
"s", | |||
v1._getPasswordTemplate({ | |||
lowercase: false, | |||
uppercase: false, | |||
numbers: false, | |||
symbols: true | |||
}) | |||
); | |||
}); | |||
it("should concatenate template if two password settings", function() { | |||
assert.equal( | |||
"vcVC", | |||
v1._getPasswordTemplate({ | |||
lowercase: true, | |||
uppercase: true, | |||
numbers: false, | |||
symbols: false | |||
}) | |||
); | |||
assert.equal( | |||
"vcns", | |||
v1._getPasswordTemplate({ | |||
lowercase: true, | |||
uppercase: false, | |||
numbers: true, | |||
symbols: true | |||
}) | |||
); | |||
}); | |||
}); |
@@ -1,39 +0,0 @@ | |||
var assert = require("assert"); | |||
var v1 = require("../../src/v1"); | |||
describe("prettyPrint", function() { | |||
it("should print different password if templates different", function() { | |||
var encryptedLogin = | |||
"78ae5892055ab59fdd54489ae30928d322841a27590b65cf875fcfdd083f7c32"; | |||
assert.notEqual( | |||
v1._prettyPrint(encryptedLogin, "cv"), | |||
v1._prettyPrint(encryptedLogin, "vc") | |||
); | |||
}); | |||
it("must return a string of the same length as the input", function() { | |||
var hash = | |||
"f5785e569ab5d38b02e2248c798ac17df90f57a85f34a9d5382408c2f0d9532d"; | |||
assert.equal(hash.length, v1._prettyPrint(hash, "cv").length); | |||
}); | |||
it("should return char inside a string based on modulo of the index", function() { | |||
var template = "cv"; | |||
assert.equal("c", v1._getCharType(template, 0)); | |||
assert.equal("v", v1._getCharType(template, 1)); | |||
assert.equal("c", v1._getCharType(template, 10)); | |||
}); | |||
it("should convert a string into an array of char code", function() { | |||
var charCodes = v1._string2charCodes("ab40f6ee71"); | |||
assert.equal(97, charCodes[0]); | |||
assert.equal(98, charCodes[1]); | |||
assert.equal(10, charCodes.length); | |||
}); | |||
it("should get password char based on its type and index", function() { | |||
var typeVowel = "V"; | |||
assert.equal("A", v1._getPasswordChar(typeVowel, 0)); | |||
}); | |||
it("should modulo if overflow", function() { | |||
var typeVowel = "V"; | |||
assert.equal("E", v1._getPasswordChar(typeVowel, 1)); | |||
assert.equal("E", v1._getPasswordChar(typeVowel, 7)); | |||
}); | |||
}); |
@@ -1,281 +0,0 @@ | |||
var assert = require("assert"); | |||
var v1 = require("../../src/v1"); | |||
describe("renderPassword", function() { | |||
it("renderPassword", function() { | |||
var site = "lesspass.com"; | |||
var encryptedLogin = | |||
"63d850713d0b2f7f2c4396fe93f4ac0c6bc7485f9e7473c4b8c4a33ec12199c0"; | |||
var passwordOptions = { | |||
counter: 1, | |||
length: 12, | |||
lowercase: true, | |||
uppercase: true, | |||
numbers: true, | |||
symbols: true | |||
}; | |||
return v1 | |||
._renderPassword(encryptedLogin, site, passwordOptions) | |||
.then(function(generatedPassword) { | |||
assert.equal("azYS7,olOL2]", generatedPassword); | |||
}); | |||
}); | |||
it("renderPassword with a custom template", function() { | |||
var site = "lesspass.com"; | |||
var encryptedLogin = | |||
"63d850713d0b2f7f2c4396fe93f4ac0c6bc7485f9e7473c4b8c4a33ec12199c0"; | |||
var passwordOptions = { | |||
counter: 1, | |||
length: 12, | |||
lowercase: true, | |||
uppercase: true, | |||
numbers: true, | |||
symbols: true, | |||
template: "n" | |||
}; | |||
return v1 | |||
._renderPassword(encryptedLogin, site, passwordOptions) | |||
.then(function(generatedPassword) { | |||
var i = generatedPassword.length; | |||
while (i--) { | |||
assert("0123456789".indexOf(generatedPassword[i]) !== -1); | |||
} | |||
}); | |||
}); | |||
it("renderPassword with a custom template too short", function() { | |||
var site = "lesspass.com"; | |||
var encryptedLogin = | |||
"63d850713d0b2f7f2c4396fe93f4ac0c6bc7485f9e7473c4b8c4a33ec12199c0"; | |||
var passwordOptions = { | |||
counter: 1, | |||
length: 12, | |||
lowercase: true, | |||
uppercase: true, | |||
numbers: true, | |||
symbols: true, | |||
template: "CvcnCVsn" | |||
}; | |||
return v1 | |||
._renderPassword(encryptedLogin, site, passwordOptions) | |||
.then(function(generatedPassword) { | |||
assert.equal("Sor4WU:8Wad5", generatedPassword); | |||
}); | |||
}); | |||
it("renderPassword with a custom template too long", function() { | |||
var site = "lesspass.com"; | |||
var encryptedLogin = | |||
"63d850713d0b2f7f2c4396fe93f4ac0c6bc7485f9e7473c4b8c4a33ec12199c0"; | |||
var passwordOptions = { | |||
counter: 1, | |||
length: 6, | |||
lowercase: true, | |||
uppercase: true, | |||
numbers: true, | |||
symbols: true, | |||
template: "CvcnCVsn" | |||
}; | |||
return v1 | |||
._renderPassword(encryptedLogin, site, passwordOptions) | |||
.then(function(generatedPassword) { | |||
assert.equal("Sor4WU", generatedPassword); | |||
}); | |||
}); | |||
it("renderPassword auto generated 0", function() { | |||
var site = "lesspass.com"; | |||
var encryptedLogin = | |||
"63d850713d0b2f7f2c4396fe93f4ac0c6bc7485f9e7473c4b8c4a33ec12199c0"; | |||
var passwordOptions = { | |||
counter: 1, | |||
length: 12, | |||
lowercase: true, | |||
uppercase: true, | |||
numbers: true, | |||
symbols: true | |||
}; | |||
return v1 | |||
._renderPassword(encryptedLogin, site, passwordOptions) | |||
.then(function(generatedPassword) { | |||
assert.equal("azYS7,olOL2]", generatedPassword); | |||
}); | |||
}); | |||
it("renderPassword auto generated 1", function() { | |||
var site = "lesspass.com"; | |||
var encryptedLogin = | |||
"63d850713d0b2f7f2c4396fe93f4ac0c6bc7485f9e7473c4b8c4a33ec12199c0"; | |||
var passwordOptions = { | |||
counter: 1, | |||
length: 14, | |||
lowercase: true, | |||
uppercase: true, | |||
numbers: true, | |||
symbols: true | |||
}; | |||
return v1 | |||
._renderPassword(encryptedLogin, site, passwordOptions) | |||
.then(function(generatedPassword) { | |||
assert.equal("azYS7,olOL2]iz", generatedPassword); | |||
}); | |||
}); | |||
it("renderPassword auto generated 2", function() { | |||
var site = "lesspass.com"; | |||
var encryptedLogin = | |||
"63d850713d0b2f7f2c4396fe93f4ac0c6bc7485f9e7473c4b8c4a33ec12199c0"; | |||
var passwordOptions = { | |||
counter: 1, | |||
length: 12, | |||
lowercase: true, | |||
uppercase: false, | |||
numbers: false, | |||
symbols: false | |||
}; | |||
return v1 | |||
._renderPassword(encryptedLogin, site, passwordOptions) | |||
.then(function(generatedPassword) { | |||
assert.equal("azyseqololat", generatedPassword); | |||
}); | |||
}); | |||
it("renderPassword auto generated 3", function() { | |||
var site = "lesspass.com"; | |||
var encryptedLogin = | |||
"63d850713d0b2f7f2c4396fe93f4ac0c6bc7485f9e7473c4b8c4a33ec12199c0"; | |||
var passwordOptions = { | |||
counter: 1, | |||
length: 12, | |||
lowercase: false, | |||
uppercase: true, | |||
numbers: true, | |||
symbols: true | |||
}; | |||
return v1 | |||
._renderPassword(encryptedLogin, site, passwordOptions) | |||
.then(function(generatedPassword) { | |||
assert.equal("AZ3[EQ7@OL2]", generatedPassword); | |||
}); | |||
}); | |||
it("renderPassword auto generated 4", function() { | |||
var site = "lesspass.com"; | |||
var encryptedLogin = | |||
"63d850713d0b2f7f2c4396fe93f4ac0c6bc7485f9e7473c4b8c4a33ec12199c0"; | |||
var passwordOptions = { | |||
counter: 1, | |||
length: 12, | |||
lowercase: false, | |||
uppercase: false, | |||
numbers: true, | |||
symbols: true | |||
}; | |||
return v1 | |||
._renderPassword(encryptedLogin, site, passwordOptions) | |||
.then(function(generatedPassword) { | |||
assert.equal("4?3[7,7@7@2]", generatedPassword); | |||
}); | |||
}); | |||
it("renderPassword auto generated 5", function() { | |||
var site = "lesspass.com"; | |||
var encryptedLogin = | |||
"63d850713d0b2f7f2c4396fe93f4ac0c6bc7485f9e7473c4b8c4a33ec12199c0"; | |||
var passwordOptions = { | |||
counter: 1, | |||
length: 12, | |||
lowercase: false, | |||
uppercase: false, | |||
numbers: false, | |||
symbols: true | |||
}; | |||
return v1 | |||
._renderPassword(encryptedLogin, site, passwordOptions) | |||
.then(function(generatedPassword) { | |||
assert.equal("[?=[&,:@:@[]", generatedPassword); | |||
}); | |||
}); | |||
it("renderPassword auto generated 6", function() { | |||
var site = "lesspass.com"; | |||
var encryptedLogin = | |||
"63d850713d0b2f7f2c4396fe93f4ac0c6bc7485f9e7473c4b8c4a33ec12199c0"; | |||
var passwordOptions = { | |||
counter: 1, | |||
length: 12, | |||
lowercase: true, | |||
uppercase: true, | |||
numbers: true, | |||
symbols: false | |||
}; | |||
return v1 | |||
._renderPassword(encryptedLogin, site, passwordOptions) | |||
.then(function(generatedPassword) { | |||
assert.equal("azYS7uwAW8at", generatedPassword); | |||
}); | |||
}); | |||
it("renderPassword auto generated 7", function() { | |||
var site = "lesspass.com"; | |||
var encryptedLogin = | |||
"63d850713d0b2f7f2c4396fe93f4ac0c6bc7485f9e7473c4b8c4a33ec12199c0"; | |||
var passwordOptions = { | |||
counter: 1, | |||
length: 12, | |||
lowercase: true, | |||
uppercase: true, | |||
numbers: false, | |||
symbols: false | |||
}; | |||
return v1 | |||
._renderPassword(encryptedLogin, site, passwordOptions) | |||
.then(function(generatedPassword) { | |||
assert.equal("azYSeqOLolAT", generatedPassword); | |||
}); | |||
}); | |||
it("renderPassword auto generated 8", function() { | |||
var site = "lesspass.com"; | |||
var encryptedLogin = | |||
"63d850713d0b2f7f2c4396fe93f4ac0c6bc7485f9e7473c4b8c4a33ec12199c0"; | |||
var passwordOptions = { | |||
counter: 2, | |||
length: 12, | |||
lowercase: true, | |||
uppercase: true, | |||
numbers: true, | |||
symbols: true | |||
}; | |||
return v1 | |||
._renderPassword(encryptedLogin, site, passwordOptions) | |||
.then(function(generatedPassword) { | |||
assert.equal("obYT2=olOV9=", generatedPassword); | |||
}); | |||
}); | |||
it("renderPassword auto generated 9", function() { | |||
var site = "lesspass.com"; | |||
var encryptedLogin = | |||
"7d05ee25597dcc3ac16d082aa910e7707f75be620ed8db5bef7245e2a8579116"; | |||
var passwordOptions = { | |||
counter: 1, | |||
length: 12, | |||
lowercase: true, | |||
uppercase: true, | |||
numbers: true, | |||
symbols: true | |||
}; | |||
return v1 | |||
._renderPassword(encryptedLogin, site, passwordOptions) | |||
.then(function(generatedPassword) { | |||
assert.equal("erOC1%imIW3,", generatedPassword); | |||
}); | |||
}); | |||
it("renderPassword auto generated 10", function() { | |||
var site = "lesspass.com"; | |||
var encryptedLogin = | |||
"ce853092fc54fe88c281e38df97bd5826d64e6bee315dc94939cbba8930df0e4"; | |||
var passwordOptions = { | |||
counter: 1, | |||
length: 12, | |||
lowercase: true, | |||
uppercase: true, | |||
numbers: true, | |||
symbols: true | |||
}; | |||
return v1 | |||
._renderPassword(encryptedLogin, site, passwordOptions) | |||
.then(function(generatedPassword) { | |||
assert.equal("uvUM5_ucUP5=", generatedPassword); | |||
}); | |||
}); | |||
}); |
@@ -1,79 +0,0 @@ | |||
var assert = require("assert"); | |||
var v2 = require("../../src/v2"); | |||
var bigInt = require("big-integer"); | |||
describe("entropy", function() { | |||
it("calc entropy pbkdf2 with default params (100000 iterations, 32 bytes length, sha256 digest)", function() { | |||
this.timeout(10000); | |||
var site = "example.org"; | |||
var login = "contact@example.org"; | |||
var masterPassword = "password"; | |||
var passwordProfile = { | |||
iterations: 100000, | |||
keylen: 32, | |||
digest: "sha256", | |||
counter: 1 | |||
}; | |||
return v2 | |||
._calcEntropy(site, login, masterPassword, passwordProfile) | |||
.then(function(entropy) { | |||
assert.equal( | |||
"dc33d431bce2b01182c613382483ccdb0e2f66482cbba5e9d07dab34acc7eb1e", | |||
entropy | |||
); | |||
}); | |||
}); | |||
it("calc entropy with different options (8192 iterations, 16 bytes length, sha512 digest)", function() { | |||
var site = "example.org"; | |||
var login = "contact@example.org"; | |||
var masterPassword = "password"; | |||
var passwordProfile = { | |||
iterations: 8192, | |||
keylen: 16, | |||
digest: "sha512", | |||
counter: 1 | |||
}; | |||
return v2 | |||
._calcEntropy(site, login, masterPassword, passwordProfile) | |||
.then(function(entropy) { | |||
assert.equal("fff211c16a4e776b3574c6a5c91fd252", entropy); | |||
}); | |||
}); | |||
it("calc entropy different if counter different 1", function() { | |||
var site = "example.org"; | |||
var login = "contact@example.org"; | |||
var masterPassword = "password"; | |||
var passwordProfile1 = { | |||
iterations: 1, | |||
keylen: 16, | |||
digest: "sha256", | |||
counter: 1 | |||
}; | |||
return v2 | |||
._calcEntropy(site, login, masterPassword, passwordProfile1) | |||
.then(function(entropy) { | |||
assert.equal("d3ec1e988dd0b3640c7491cd2c2a88b5", entropy); | |||
}); | |||
}); | |||
it("calc entropy different if counter different 2", function() { | |||
var site = "example.org"; | |||
var login = "contact@example.org"; | |||
var masterPassword = "password"; | |||
var passwordProfile2 = { | |||
iterations: 1, | |||
keylen: 16, | |||
digest: "sha256", | |||
counter: 2 | |||
}; | |||
return v2 | |||
._calcEntropy(site, login, masterPassword, passwordProfile2) | |||
.then(function(entropy) { | |||
assert.equal("ddfb1136260f930c21f6d72f6eddbd40", entropy); | |||
}); | |||
}); | |||
it("consume entropy", function() { | |||
var password = v2._consumeEntropy("", bigInt(4 * 4 + 2), "abcd", 2); | |||
assert.equal("ca", password.value); | |||
assert.equal(1, password.entropy); | |||
}); | |||
}); |