Parcourir la source

simplify API for password creation

pull/342/head
Guillaume Vincent il y a 8 ans
Parent
révision
f8250016dc
15 fichiers modifiés avec 530 ajouts et 308 suppressions
  1. +2
    -1
      .gitignore
  2. +0
    -13
      lesspass.js
  3. +42
    -10
      package.json
  4. +0
    -44
      password-generator.js
  5. +27
    -13
      readme.md
  6. +58
    -0
      src/encryption.js
  7. +7
    -0
      src/lesspass.js
  8. +60
    -0
      src/render.js
  9. +82
    -0
      tests/encryption.tests.js
  10. +50
    -0
      tests/legacy.tests.js
  11. +142
    -50
      tests/lesspass.tests.js
  12. +0
    -98
      tests/password-generator.tests.js
  13. +60
    -0
      tests/render.tests.js
  14. +0
    -34
      tests/text.tests.js
  15. +0
    -45
      text.js

+ 2
- 1
.gitignore Voir le fichier

@@ -1 +1,2 @@
dist
lib
node_modules

+ 0
- 13
lesspass.js Voir le fichier

@@ -1,13 +0,0 @@
var text = require('./text');
var passwordGenerator = require('./password-generator');

module.exports = {
createPassword: createPassword,
createMasterPassword: passwordGenerator.createMasterPassword
};

function createPassword(masterPassword, entry) {
var hash = passwordGenerator._createHash(masterPassword, entry);
var template = passwordGenerator._getTemplate(entry.password.settings);
return text._encode(hash, template);
}

+ 42
- 10
package.json Voir le fichier

@@ -2,11 +2,10 @@
"name": "lesspass",
"version": "1.1.1",
"description": "node.js stateless password management solution",
"main": "dist/lesspass.js",
"main": "lib/lesspass.js",
"scripts": {
"test": "mocha --compilers js:babel-core/register tests",
"test:watch": "npm run test -- -w",
"build": "babel lesspass.js text.js password-generator.js --presets babel-preset-es2015 --out-dir dist",
"test": "ava --require babel-core/register && xo",
"build": "babel src --out-dir lib",
"prepublish": "npm test && npm run build"
},
"keywords": [
@@ -17,22 +16,55 @@
"type": "git",
"url": "git+ssh://git@github.com:oslab-fr/lesspass-npm.git"
},
"author": "Guillaume Vincent",
"author": {
"name": "Guillaume Vincent",
"email": "guillaume@oslab.fr",
"url": "guillaumevincent.com"
},
"engines": {
"node": ">=4.2.6"
},
"license": "MIT",
"bugs": {
"url": "https://github.com/oslab-fr/lesspass-npm/issues"
},
"homepage": "https://github.com/oslab-fr/lesspass-npm#readme",
"devDependencies": {
"babel-cli": "^6.5.1",
"babel-core": "^6.5.2",
"babel-preset-es2015": "^6.5.0",
"mocha": "^2.4.5",
"webpack": "^1.12.13"
"ava": "^0.14.0",
"babel-cli": "^6.9.0",
"babel-core": "^6.9.0",
"babel-preset-es2015": "^6.9.0",
"xo": "^0.15.1"
},
"babel": {
"presets": [
"es2015"
]
},
"browserify": {
"transform": [
"babelify"
]
},
"xo": {
"esnext": true,
"space": true,
"envs": [
"browser",
"webextensions",
"shared-node-browser",
"es6"
],
"ignores": [
"lib/**"
]
},
"ava": {
"files": [
"tests/*.js"
],
"source": [
"src/*.js"
]
}
}

+ 0
- 44
password-generator.js Voir le fichier

@@ -1,44 +0,0 @@
var crypto = require('crypto');

module.exports = {
createMasterPassword: createMasterPassword,
_getTemplate: _getTemplate,
_createHash:_createHash
};


function createMasterPassword(email, password) {
return new Promise((resolve, reject) => {
var iterations = 8192;
var keylen = 32;
crypto.pbkdf2(password, email, iterations, keylen, 'sha256', function (error, key) {
if (error) {
reject('error in pbkdf2');
} else {
resolve(key.toString('hex'));
}
});
});
}

function _getTemplate(passwordTypes = ['strong']) {
var passwordTypesInfo = {
lowercase: {value: 'vc', order: 1},
uppercase: {value: 'VC', order: 2},
numbers: {value: 'n', order: 3},
symbols: {value: 's', order: 4},
strong: {value: 'Cvcvns', order: 5}
};
return passwordTypes
.map(passwordType => passwordTypesInfo[passwordType])
.sort((passwordType1, passwordType2) => passwordType1.order > passwordType2.order)
.map(passwordType => passwordType.value)
.join('');
}


function _createHash(masterPassword, {site, password={length: 12, counter: 1}}) {
var salt = site + password.counter.toString();
var hash = crypto.createHmac('sha256', masterPassword).update(salt).digest('hex');
return hash.substring(0, password.length);
}

+ 27
- 13
readme.md Voir le fichier

@@ -2,7 +2,11 @@

# LessPass Core

LessPass npm module use to generate unique password
LessPass node module use to generate unique password

# requirements

* node 4.2.x

## Install

@@ -10,21 +14,31 @@ LessPass npm module use to generate unique password

## Usage

var lesspass = require('lesspass');
var entry = {
site: 'lesspass',
import lesspass from 'lesspass';

const login = 'contact@lesspass.com';
const masterPassword = 'password';
const site = 'lesspass.com';
const options = {
counter: 1,
password: {
length: 14,
settings: ['lowercase', 'uppercase', 'numbers', 'symbols'],
counter: 1
length: 12,
settings: ['lowercase', 'uppercase', 'numbers', 'symbols']
}
};
var masterPassword = '90cff82b8847525370a8f29a59ecf45db62c719a535788ad0df58d32304e925d';
var password = lesspass.createPassword(masterPassword, entry);
console.log(password); // ubUB4[yqAD3?od
lesspass.generatePassword(login, masterPassword, site, options).then(password => {
console.log(password) //azYS7,olOL2]
});

## API

### `generatePassword(login, masterPassword, site, options)`

generate unique password based on login, masterPassword, site and options.


## Test
## Tests

npm run test
npm test

[lesspass submodule](https://github.com/lesspass/lesspass)
see [lesspass](https://github.com/lesspass/lesspass) project

+ 58
- 0
src/encryption.js Voir le fichier

@@ -0,0 +1,58 @@
import crypto from 'crypto';
import render from './render';

module.exports = {
createPassword: _createPassword,
generatePassword: _generatePassword,
encryptLogin: _encryptLogin,
deriveHash: _deriveHash
};

function _encryptLogin(login, masterPassword) {
return new Promise((resolve, reject) => {
if (!login || !masterPassword) {
reject('encryptLogin parameter could not be empty');
}
const iterations = 8192;
const keylen = 32;
crypto.pbkdf2(masterPassword, login, iterations, keylen, 'sha256', (error, key) => {
if (error) {
reject('error in pbkdf2');
} else {
resolve(key.toString('hex'));
}
});
});
}

function _deriveHash(hash, site, {password = {length: 12}, counter = 1} = {}) {
const salt = site + counter.toString();
const derivedHash = crypto.createHmac('sha256', hash).update(salt).digest('hex');
return derivedHash.substring(0, password.length);
}

function _createPassword(hash, entry) {
// createPassword is deprecated use generatePassword instead
const options = {
counter: entry.password.counter || 1,
password: entry.password
};
const site = entry.site;
const derivedHash = _deriveHash(hash, site, options);
const template = render.getTemplate(options.password.settings);
return render.prettyPrint(derivedHash, template);
}

function _generatePassword(login, masterPassword, site, options) {
return new Promise((resolve, reject) => {
if (!login || !masterPassword || !site) {
reject('generatePassword invalid parameter');
}

_encryptLogin(login, masterPassword).then(hash => {
const derivedHash = _deriveHash(hash, site, options);
const template = render.getTemplate(options.password.settings);
resolve(render.prettyPrint(derivedHash, template));
});
});
}

+ 7
- 0
src/lesspass.js Voir le fichier

@@ -0,0 +1,7 @@
import encryption from './encryption';

module.exports = {
generatePassword: encryption.generatePassword,
createPassword: encryption.createPassword,
createMasterPassword: encryption.encryptLogin
};

+ 60
- 0
src/render.js Voir le fichier

@@ -0,0 +1,60 @@
module.exports = {
prettyPrint: _prettyPrint,
getTemplate: _getTemplate,
_getCharType,
_getPasswordChar,
_string2charCodes
};

function _getCharType(template, index) {
return template[index % template.length];
}

function _getPasswordChar(charType, index) {
const passwordsChars = {
V: 'AEIOUY',
C: 'BCDFGHJKLMNPQRSTVWXZ',
v: 'aeiouy',
c: 'bcdfghjklmnpqrstvwxz',
A: 'AEIOUYBCDFGHJKLMNPQRSTVWXZ',
a: 'AEIOUYaeiouyBCDFGHJKLMNPQRSTVWXZbcdfghjklmnpqrstvwxz',
n: '0123456789',
s: '@&%?,=[]_:-+*$#!\'^~;()/.',
x: 'AEIOUYaeiouyBCDFGHJKLMNPQRSTVWXZbcdfghjklmnpqrstvwxz0123456789@&%?,=[]_:-+*$#!\'^~;()/.'
};
const passwordChar = passwordsChars[charType];
return passwordChar[index % passwordChar.length];
}

function _prettyPrint(hash, template) {
let password = '';

_string2charCodes(hash).forEach((charCode, index) => {
const charType = _getCharType(template, index);
password += _getPasswordChar(charType, charCode);
});
return password;
}

function _string2charCodes(text) {
const charCodes = [];
for (let i = 0; i < text.length; i++) {
charCodes.push(text.charCodeAt(i));
}
return charCodes;
}

function _getTemplate(passwordTypes = ['strong']) {
const passwordTypesInfo = {
lowercase: {value: 'vc', order: 1},
uppercase: {value: 'VC', order: 2},
numbers: {value: 'n', order: 3},
symbols: {value: 's', order: 4},
strong: {value: 'Cvcvns', order: 5}
};
return passwordTypes
.map(passwordType => passwordTypesInfo[passwordType])
.sort((passwordType1, passwordType2) => passwordType1.order > passwordType2.order)
.map(passwordType => passwordType.value)
.join('');
}

+ 82
- 0
tests/encryption.tests.js Voir le fichier

@@ -0,0 +1,82 @@
import test from 'ava';
import {encryptLogin, deriveHash} from '../src/encryption';

test('should create encrypted hash with pbkdf2 (8192 iterations and sha 256)', t => {
const login = 'test@lesspass.com';
const masterPassword = 'password';

return encryptLogin(login, masterPassword).then(hash => {
t.is('90cff82b8847525370a8f29a59ecf45db62c719a535788ad0df58d32304e925d', hash);
});
});

test('should create encrypted hash with 64 chars length', t => {
const login = 'test@lesspass.com';
const masterPassword = 'password';

return encryptLogin(login, masterPassword).then(hash => {
t.is(64, hash.length);
});
});

test('should reject promise if no parameter', t => {
t.plan(1);
return encryptLogin('', '').catch(() => {
t.pass('promise rejected with empty parameter');
});
});

test('should derive hash with default length', t => {
const hash = '9f505f3a95fe0485da3242cb81c9fe25c2f400d8399737655a8dad2b52778d88';
const site = 'lesspass.com';
t.is(12, deriveHash(hash, site).length);
});

test('should derive hash with default options', t => {
const hash = '90cff82b8847525370a8f29a59ecf45db62c719a535788ad0df58d32304e925d';
const site = 'lesspass.com';
const option = {
counter: 1,
password: {
length: 12,
settings: ['lowercase', 'uppercase', 'numbers', 'symbols']
}
};
t.is(
deriveHash(hash, site),
deriveHash(hash, site, option)
);
});

test('should derive hash with defined length', t => {
const hash = 'd79d8482f708122288af7b259393a58fe05840f4555cc935cdd3f062b9aa75ed';
const site = 'lesspass.com';
const option = {
counter: 1,
password: {
length: 10
}
};
t.is(10, deriveHash(hash, site, option).length);
});

test('should return two different passwords if site different', t => {
const hash = 'f4fd3885fb70085f2285c3382e2d9adb4c2553285fc45dd896791aa5e79070a9';
const site = 'google.com';
const site2 = 'facebook.com';
t.not(
deriveHash(hash, site),
deriveHash(hash, site2)
);
});

test('should return two different passwords if counter different', t => {
const hash = 'dfba06278c9aa24d992bc2d390a53efef482788859455875f72015335d085fcd';
const site = 'lesspass.com';
const option = {counter: 1};
const option2 = {counter: 2};
t.not(
deriveHash(hash, site, option),
deriveHash(hash, site, option2)
);
});

+ 50
- 0
tests/legacy.tests.js Voir le fichier

@@ -0,0 +1,50 @@
import test from 'ava';
import lesspass from '../src/lesspass';

test('should create password', t => {
const masterPassword = 'password';
const entry = {
site: 'facebook',
password: {
length: 14,
settings: ['lowercase', 'uppercase', 'numbers', 'symbols'],
counter: 1
}
};
t.is('iwIQ8[acYT4&oc', lesspass.createPassword(masterPassword, entry));
});
test('should create password 2', t => {
const masterPassword = 'password';
const entry = {
site: 'facebook',
password: {
length: 12,
settings: ['strong'],
counter: 1
}
};
t.is('Vexu8[Syce4&', lesspass.createPassword(masterPassword, entry));
});
test('should create 2 passwords different if counter different', t => {
const masterPassword = 'password';
const entry = {
site: 'facebook',
password: {
length: 14,
settings: ['lowercase', 'uppercase', 'numbers', 'symbols'],
counter: 1
}
};
const entry2 = {
site: 'facebook',
password: {
length: 14,
settings: ['lowercase', 'uppercase', 'numbers', 'symbols'],
counter: 2
}
};
t.not(
lesspass.createPassword(masterPassword, entry),
lesspass.createPassword(masterPassword, entry2)
);
});

+ 142
- 50
tests/lesspass.tests.js Voir le fichier

@@ -1,52 +1,144 @@
var assert = require('assert');
var lesspass = require('../lesspass');
import test from 'ava';
import lesspass from '../src/lesspass';

describe('lesspass', function () {
it('should create password', function () {
var masterPassword = "password";
var entry = {
site: 'facebook',
password: {
length: 14,
settings: ['lowercase', 'uppercase', 'numbers', 'symbols'],
counter: 1
}
};
assert.equal('iwIQ8[acYT4&oc', lesspass.createPassword(masterPassword, entry));
});
it('should create password 2', function () {
var masterPassword = "password";
var entry = {
site: 'facebook',
password: {
length: 12,
settings: ['strong'],
counter: 1
}
};
assert.equal('Vexu8[Syce4&', lesspass.createPassword(masterPassword, entry));
});
it('should create 2 passwords different if counter different', function () {
var masterPassword = "password";
var entry = {
site: 'facebook',
password: {
length: 14,
settings: ['lowercase', 'uppercase', 'numbers', 'symbols'],
counter: 1
}
};
var entry2 = {
site: 'facebook',
password: {
length: 14,
settings: ['lowercase', 'uppercase', 'numbers', 'symbols'],
counter: 2
}
};
assert.notEqual(
lesspass.createPassword(masterPassword, entry),
lesspass.createPassword(masterPassword, entry2)
);
});
test('generate password', t => {
const login = 'contact@lesspass.com';
const masterPassword = 'password';
const site = 'lesspass.com';
const options = {
counter: 1,
password: {
length: 12,
settings: ['lowercase', 'uppercase', 'numbers', 'symbols']
}
};
return lesspass.generatePassword(login, masterPassword, site, options).then(password => {
t.is(password, 'azYS7,olOL2]');
});
});

test('generate password2', t => {
const login = 'contact@lesspass.com';
const masterPassword = 'password';
const site = 'lesspass.com';
const options = {
counter: 1,
password: {
length: 12,
settings: ['lowercase', 'uppercase', 'numbers', 'symbols']
}
};
return lesspass.generatePassword(login, masterPassword, site, options).then(password => {
t.is(password, 'azYS7,olOL2]');
});
});

test('generate password3', t => {
const login = 'contact@lesspass.com';
const masterPassword = 'password';
const site = 'lesspass.com';
const options = {
counter: 1,
password: {
length: 12,
settings: ['lowercase', 'uppercase', 'numbers', 'symbols']
}
};
return lesspass.generatePassword(login, masterPassword, site, options).then(password => {
t.is(password, 'azYS7,olOL2]');
});
});

test('auto generated password', t => {
const promises = [];
const entries = [
{
login: 'contact@lesspass.com',
masterPassword: 'password',
site: 'lesspass.com',
options: {counter: 1, password: {length: 12, settings: ['lowercase', 'uppercase', 'numbers', 'symbols']}},
generatedPassword: 'azYS7,olOL2]'
},
{
login: 'contact@lesspass.com',
masterPassword: 'password',
site: 'lesspass.com',
options: {counter: 1, password: {length: 14, settings: ['lowercase', 'uppercase', 'numbers', 'symbols']}},
generatedPassword: 'azYS7,olOL2]iz'
},
{
login: 'contact@lesspass.com',
masterPassword: 'password',
site: 'lesspass.com',
options: {counter: 1, password: {length: 12, settings: ['lowercase']}},
generatedPassword: 'azyseqololat'
},
{
login: 'contact@lesspass.com',
masterPassword: 'password',
site: 'lesspass.com',
options: {counter: 1, password: {length: 12, settings: ['uppercase', 'numbers', 'symbols']}},
generatedPassword: 'AZ3[EQ7@OL2]'
},
{
login: 'contact@lesspass.com',
masterPassword: 'password',
site: 'lesspass.com',
options: {counter: 1, password: {length: 12, settings: ['numbers', 'symbols']}},
generatedPassword: '4?3[7,7@7@2]'
},
{
login: 'contact@lesspass.com',
masterPassword: 'password',
site: 'lesspass.com',
options: {counter: 1, password: {length: 12, settings: ['symbols']}},
generatedPassword: '[?=[&,:@:@[]'
},
{
login: 'contact@lesspass.com',
masterPassword: 'password',
site: 'lesspass.com',
options: {counter: 1, password: {length: 12, settings: ['lowercase', 'uppercase', 'numbers']}},
generatedPassword: 'azYS7uwAW8at'
},
{
login: 'contact@lesspass.com',
masterPassword: 'password',
site: 'lesspass.com',
options: {counter: 1, password: {length: 12, settings: ['lowercase', 'uppercase']}},
generatedPassword: 'azYSeqOLolAT'
},
{
login: 'contact@lesspass.com',
masterPassword: 'password',
site: 'lesspass.com',
options: {counter: 2, password: {length: 12, settings: ['lowercase', 'uppercase', 'numbers', 'symbols']}},
generatedPassword: 'obYT2=olOV9='
},
{
login: 'lesspass',
masterPassword: 'password',
site: 'lesspass.com',
options: {counter: 1, password: {length: 12, settings: ['lowercase', 'uppercase', 'numbers', 'symbols']}},
generatedPassword: 'erOC1%imIW3,'
},
{
login: 'contact@lesspass.com',
masterPassword: 'password2',
site: 'lesspass.com',
options: {counter: 1, password: {length: 12, settings: ['lowercase', 'uppercase', 'numbers', 'symbols']}},
generatedPassword: 'uvUM5_ucUP5='
}
];

for (const entry of entries) {
promises.push(lesspass.generatePassword(entry.login, entry.masterPassword, entry.site, entry.options));
}

t.plan(entries.length);
return Promise.all(promises).then(values => {
for (let i = 0; i < values.length; i++) {
t.is(entries[i].generatedPassword, values[i], JSON.stringify(entries[i], null, 2));
}
});
});

+ 0
- 98
tests/password-generator.tests.js Voir le fichier

@@ -1,98 +0,0 @@
var assert = require('assert');
var passwordGenerator = require('../password-generator');
var lesspass = require('../lesspass');

describe('passwordGenerator', function () {
describe('master password', function () {
it('should create master password with pbkdf2 (8192 iterations and sha 256)', function (done) {
var email = 'test@lesspass.com';
var password = "password";

lesspass.createMasterPassword(email, password).then(function (masterPassword) {
assert.equal("90cff82b8847525370a8f29a59ecf45db62c719a535788ad0df58d32304e925d", masterPassword);
done();
});
});
it('should create 64 char length master password', function (done) {
var email = 'test@lesspass.com';
var password = "password";

lesspass.createMasterPassword(email, password).then(function (masterPassword) {
assert.equal(64, masterPassword.length);
done();
});
});
});
describe('password templates password', function () {
it('should get default template from password type', function () {
assert.equal('Cvcvns', passwordGenerator._getTemplate());
});
it('should get template from password type', function () {
assert.equal('vc', passwordGenerator._getTemplate(['lowercase']));
assert.equal('VC', passwordGenerator._getTemplate(['uppercase']));
assert.equal('n', passwordGenerator._getTemplate(['numbers']));
assert.equal('s', passwordGenerator._getTemplate(['symbols']));
});
it('should concatenate template if two password password_types', function () {
assert.equal('vcVC', passwordGenerator._getTemplate(['lowercase', 'uppercase']));
assert.equal('vcns', passwordGenerator._getTemplate(['lowercase', 'numbers', 'symbols']));
});
it('should not care about order of type in password password_types', function () {
assert.equal(
passwordGenerator._getTemplate(['uppercase', 'lowercase']),
passwordGenerator._getTemplate(['lowercase', 'uppercase'])
);
});
});
describe('hash', function () {
it('should have default length of 12', function () {
var masterPassword = 'password';
var entry = {'site': 'facebook'};
assert.equal(12, passwordGenerator._createHash(masterPassword, entry).length);
});
it('should allow to change default length', function () {
var masterPassword = 'password';
var entry = {
site: 'lesspass',
password: {
length: 10,
counter: 1
}
};
assert.equal(10, passwordGenerator._createHash(masterPassword, entry).length);
});
it('should return two different passwords if site different', function () {
var masterPassword = 'password';
var entry = {site: 'facebook'};
var entry2 = {site: 'google'};
assert.notEqual(
passwordGenerator._createHash(masterPassword, entry),
passwordGenerator._createHash(masterPassword, entry2)
);
});
it('should return two different passwords if counter different', function () {
var masterPassword = 'password';
var entry = {
site: 'facebook',
password: {
length: 14,
settings: ['lowercase', 'uppercase', 'numbers', 'symbols'],
counter: 1
}
};
var entry2 = {
site: 'facebook',
password: {
length: 14,
settings: ['lowercase', 'uppercase', 'numbers', 'symbols'],
counter: 2
}
};
assert.notEqual(
passwordGenerator._createHash(masterPassword, entry),
passwordGenerator._createHash(masterPassword, entry2)
);
});
});

});

+ 60
- 0
tests/render.tests.js Voir le fichier

@@ -0,0 +1,60 @@
import test from 'ava';
import render from '../src/render';

test('should print different password if templates different', t => {
const hash = '78ae5892055ab59fdd54489ae30928d322841a27590b65cf875fcfdd083f7c32';
t.not(render.prettyPrint(hash, 'cv'), render.prettyPrint(hash, 'vc'));
});

test('must return a string of the same length as the input', t => {
const hash = 'f5785e569ab5d38b02e2248c798ac17df90f57a85f34a9d5382408c2f0d9532d';
t.is(hash.length, render.prettyPrint(hash, 'cv').length);
});

test('should return char inside a string based on modulo of the index', t => {
const template = 'cv';
t.is('c', render._getCharType(template, 0));
t.is('v', render._getCharType(template, 1));
t.is('c', render._getCharType(template, 10));
});

test('should convert a string into an array of char code', t => {
const charCodes = render._string2charCodes('ab40f6ee71');
t.is(97, charCodes[0]);
t.is(98, charCodes[1]);
t.is(10, charCodes.length);
});

test('should get password char based on its type and index', t => {
const typeVowel = 'V';
t.is('A', render._getPasswordChar(typeVowel, 0));
});

test('should modulo if overflow', t => {
const typeVowel = 'V';
t.is('E', render._getPasswordChar(typeVowel, 1));
t.is('E', render._getPasswordChar(typeVowel, 7));
});

test('should get default template', t => {
t.is('Cvcvns', render.getTemplate());
});

test('should get template from password setting', t => {
t.is('vc', render.getTemplate(['lowercase']));
t.is('VC', render.getTemplate(['uppercase']));
t.is('n', render.getTemplate(['numbers']));
t.is('s', render.getTemplate(['symbols']));
});

test('should concatenate template if two password settings', t => {
t.is('vcVC', render.getTemplate(['lowercase', 'uppercase']));
t.is('vcns', render.getTemplate(['lowercase', 'numbers', 'symbols']));
});

test('should not care about order of password settings', t => {
t.is(
render.getTemplate(['uppercase', 'lowercase']),
render.getTemplate(['lowercase', 'uppercase'])
);
});

+ 0
- 34
tests/text.tests.js Voir le fichier

@@ -1,34 +0,0 @@
var assert = require('assert');
var text = require('../text');

describe('crypto', function () {
it('should return char inside a string based on modulo of the index', function () {
var template = 'cv';
assert.equal('c', text._getCharType(template, 0));
assert.equal('v', text._getCharType(template, 1));
assert.equal('c', text._getCharType(template, 10));
});
it('should convert a string into an array of char code', function () {
var charCodes = text._string2charCodes('ab40f6ee71');
assert.equal(97, charCodes[0]);
assert.equal(98, charCodes[1]);
assert.equal(10, charCodes.length);
});
it('must return a string of the same length as the input', function () {
var hash = 'Y2Vi2a112A';
assert.equal(hash.length, text._encode(hash, 'cv').length);
});
it('should return different values if strings different', function () {
var hash = 'a';
assert.notEqual(text._encode(hash, 'cv'), text._encode(hash, 'vc'));
});
it('should get password char based on its type and index', function () {
var typeVowel = 'V';
assert.equal('A', text._getPasswordChar(typeVowel, 0));
});
it('should modulo if overflow', function () {
var typeVowel = 'V';
assert.equal('E', text._getPasswordChar(typeVowel, 1));
assert.equal('E', text._getPasswordChar(typeVowel, 7));
});
});

+ 0
- 45
text.js Voir le fichier

@@ -1,45 +0,0 @@
module.exports = {
_getCharType: _getCharType,
_getPasswordChar: _getPasswordChar,
_encode: _encode,
_string2charCodes: _string2charCodes
};

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];
}

function _encode(hash, template) {
var password = '';
_string2charCodes(hash).map(
(charCode, index) => {
let charType = _getCharType(template, index);
password += _getPasswordChar(charType, charCode);
}
);
return password;
}

function _string2charCodes(text) {
var charCodes = [];
for (let i = 0; i < text.length; i++) {
charCodes.push(text.charCodeAt(i));
}
return charCodes;
}

Chargement…
Annuler
Enregistrer