Ver código fonte

use lesspass as a npm module

pull/44/head
Guillaume Vincent 8 anos atrás
pai
commit
8877f19e11
11 arquivos alterados com 23 adições e 503 exclusões
  1. +0
    -3
      .travis.yml
  2. +2
    -16
      README.md
  3. +0
    -38
      app/app.old.vue
  4. +0
    -29
      app/components/index.old.vue
  5. +3
    -3
      app/components/password-generator.vue
  6. +0
    -84
      app/lesspass.js
  7. +0
    -51
      app/main.old.js
  8. +3
    -4
      package.json
  9. +0
    -176
      tests/lesspass.tests.js
  10. +15
    -13
      webpack.config.js
  11. +0
    -86
      webpack.config.old.js

+ 0
- 3
.travis.yml Ver arquivo

@@ -1,3 +0,0 @@
language: node_js
node_js:
- 4

+ 2
- 16
README.md Ver arquivo

@@ -1,7 +1,6 @@
[![Build Status](https://travis-ci.org/oslab-fr/lesspass.svg?branch=master)](https://travis-ci.org/oslab-fr/lesspass)
# lesspass
lesspass is like keepass without the need to persist passwords
lesspass single page app for https://lesspass.com
## requirements
@@ -23,19 +22,6 @@ start application
open the application in a browser: [http://localhost:8080](http://localhost:8080)
## run tests
install dependencies
npm install
run tests
npm run test
run test in watch mode
npm run test:watch
## run production mode

+ 0
- 38
app/app.old.vue Ver arquivo

@@ -1,38 +0,0 @@
<style>
#toast-container > div {
opacity: 1;
-ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=100);
filter: alpha(opacity=100);
}

body {
font-family: "Roboto", "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 14px;
line-height: 1.4;
background: #D3D8E8;
color: #252830;
}

.blue {
color: #0275D8;
}
</style>

<template>
<div>
<lesspass-header></lesspass-header>
<router-view></router-view>
</div>
</template>
<script>
import LesspassHeader from './components/header.vue';

export default {
data: function () {
return {}
},
components: {
LesspassHeader
}
}
</script>

+ 0
- 29
app/components/index.old.vue Ver arquivo

@@ -1,29 +0,0 @@
<template>
<lesspass-headlines></lesspass-headlines>
<password-generator></password-generator>
<lesspass-features></lesspass-features>
<lesspass-faq></lesspass-faq>
<lesspass-footer></lesspass-footer>
</template>


<script>
import LesspassHeadlines from './headlines.vue';
import PasswordGenerator from './password-generator.vue';
import LesspassFeatures from './features.vue';
import LesspassFaq from './faq.vue';
import LesspassFooter from './footer.vue';

export default {
data: function () {
return {}
},
components: {
LesspassHeadlines,
PasswordGenerator,
LesspassFeatures,
LesspassFaq,
LesspassFooter
}
}
</script>

+ 3
- 3
app/components/password-generator.vue Ver arquivo

@@ -140,7 +140,7 @@
</template>

<script>
import Lesspass from '../lesspass'
import lesspass from 'lesspass'
import Clipboard from 'clipboard';

export default {
@@ -163,7 +163,7 @@
var email = this.email;
var password = this.password;
if (email && password) {
Lesspass.createMasterPassword(email, password).then(function (masterPassword) {
lesspass.createMasterPassword(email, password).then(function (masterPassword) {
self.$set('masterPassword', masterPassword);
});
}
@@ -185,7 +185,7 @@
site: site,
password: this.passwordInfo
};
return Lesspass.createPassword(masterPassword, entry);
return lesspass.createPassword(masterPassword, entry);
}
}
}


+ 0
- 84
app/lesspass.js Ver arquivo

@@ -1,84 +0,0 @@
import crypto from 'crypto';
export default class lesspass {
static createPassword(masterPassword, entry) {
var hash = lesspass._createHash(masterPassword, entry);
var template = lesspass._getTemplate(entry.password.settings);
return lesspass._encode(hash, template);
}
static 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'));
}
});
});
}
static _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);
}
static _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('');
}
static _string2charCodes(text) {
var charCodes = [];
for (let i = 0; i < text.length; i++) {
charCodes.push(text.charCodeAt(i));
}
return charCodes;
}
static _getCharType(template, index) {
return template[index % template.length];
}
static _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];
}
static _encode(hash, template) {
var password = '';
this._string2charCodes(hash).map(
(charCode, index) => {
let charType = this._getCharType(template, index);
password += this._getPasswordChar(charType, charCode);
}
);
return password;
}
}

+ 0
- 51
app/main.old.js Ver arquivo

@@ -1,51 +0,0 @@
import Vue from 'vue'
import Router from 'vue-router';
import Resource from 'vue-resource';
import i18n from 'vue-i18n';

import locales from './locales/locales';
import App from './app.vue';
import IndexView from './components/index.vue';
import Dashboard from './components/dashboard.vue';
import auth from './services/auth';
Vue.use(Resource);
Vue.use(Router);


var browserLanguage = (navigator.language || navigator.browserLanguage).split('-')[0];
var lang = browserLanguage in locales ? browserLanguage : 'en';
Vue.use(i18n, {
lang: lang,
locales: locales
});


Vue.http.headers.common['Authorization'] = 'Bearer ' + localStorage.getItem('token');

auth.checkAuth();

export var router = new Router();

router.map({
'/': {
auth: true,
component: Dashboard
},
'/presentation/': {
component: IndexView
}
});

router.redirect({
'*': '/'
});

router.start(App, '#app');

router.beforeEach(function (transition) {
if (transition.to.auth && !auth.user.authenticated) {
transition.redirect('/presentation/')
} else {
transition.next()
}
});

+ 3
- 4
package.json Ver arquivo

@@ -1,11 +1,9 @@
{
"name": "lesspass",
"name": "lesspass.com",
"version": "1.0.0",
"description": "lesspass is like keepass without the need to persist passwords",
"description": "lesspass single page app for https://lesspass.com",
"main": "app/app.js",
"scripts": {
"test": "mocha --compilers js:babel-core/register tests",
"test:watch": "npm run test -- -w",
"predev": "npm install",
"dev": "webpack-dev-server --inline --hot --host 0.0.0.0",
"prebuild": "rimraf dist && npm prune && npm install",
@@ -32,6 +30,7 @@
"express": "^4.13.4",
"font-awesome": "^4.5.0",
"jquery": "^2.2.0",
"lesspass": "^1.1.1",
"tether": "^1.1.1",
"toastr": "^2.1.2",
"vue": "^1.0.16",


+ 0
- 176
tests/lesspass.tests.js Ver arquivo

@@ -1,176 +0,0 @@
import assert from 'assert';
import Lesspass from '../app/lesspass';

describe('LessPass', ()=> {
describe('public api', ()=> {
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)
);
});
it('should create master password with pbkdf2 (8192 iterations and sha 256)', (done)=> {
var email = 'test@lesspass.com';
var password = "password";

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

Lesspass.createMasterPassword(email, password).then((masterPassword) => {
assert.equal("90cff82b8847525370a8f29a59ecf45db62c719a535788ad0df58d32304e925d", masterPassword);
assert.equal(64, masterPassword.length);
done();
});
});
});
describe('hash', ()=> {
it('should have default length of 12', ()=> {
var masterPassword = 'password';
var entry = {'site': 'facebook'};
assert.equal(12, Lesspass._createHash(masterPassword, entry).length);
});
it('should be able to create hash with defined length', ()=> {
var masterPassword = 'password';
var entry = {
site: 'facebook',
password: {
length: 10,
counter: 1
}
};
assert.equal(10, Lesspass._createHash(masterPassword, entry).length);
});
it('should return two different passwords if site different', ()=> {
var masterPassword = 'password';
var entry = {site: 'facebook'};
var entry2 = {site: 'google'};
assert.notEqual(
Lesspass._createHash(masterPassword, entry),
Lesspass._createHash(masterPassword, entry2)
);
});
it('should return two different passwords if counter different', ()=> {
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._createHash(masterPassword, entry),
Lesspass._createHash(masterPassword, entry2)
);
});
});
describe('password templates', ()=> {
it('should get default template from password type', ()=> {
assert.equal('Cvcvns', Lesspass._getTemplate());
});
it('should get template from password type', ()=> {
assert.equal('vc', Lesspass._getTemplate(['lowercase']));
assert.equal('VC', Lesspass._getTemplate(['uppercase']));
assert.equal('n', Lesspass._getTemplate(['numbers']));
assert.equal('s', Lesspass._getTemplate(['symbols']));
});
it('should concatenate template if two password password_types', ()=> {
assert.equal('vcVC', Lesspass._getTemplate(['lowercase', 'uppercase']));
assert.equal('vcns', Lesspass._getTemplate(['lowercase', 'numbers', 'symbols']));
});
it('should not care about order of type in password password_types', ()=> {
assert.equal(
Lesspass._getTemplate(['uppercase', 'lowercase']),
Lesspass._getTemplate(['lowercase', 'uppercase'])
);
});
it('should return char inside template based on modulo of the index', function () {
var template = 'cv';
assert.equal('c', Lesspass._getCharType(template, 0));
assert.equal('v', Lesspass._getCharType(template, 1));
assert.equal('c', Lesspass._getCharType(template, 10));
});
});
describe('crypto', ()=> {
it('should convert a string into a char code table', ()=> {
var charCodes = Lesspass._string2charCodes('ab40f6ee71');
assert.equal(97, charCodes[0]);
assert.equal(98, charCodes[1]);
assert.equal(10, charCodes.length);
});
it('should return password size same size of hash given', function () {
var hash = 'Y2Vi2a112A';
assert.equal(10, Lesspass._encode(hash, 'cv').length);
});
it('should return different values if templates are different', function () {
var hash = 'a';
assert.notEqual(Lesspass._encode(hash, 'cv'), Lesspass._encode(hash, 'vc'));
});
it('should get password char based on its type and index', function () {
var typeVowel = 'V';
assert.equal('A', Lesspass._getPasswordChar(typeVowel, 0));
});
it('should modulo if overflow', function () {
var typeVowel = 'V';
assert.equal('E', Lesspass._getPasswordChar(typeVowel, 1));
assert.equal('E', Lesspass._getPasswordChar(typeVowel, 7));
});
});
});

+ 15
- 13
webpack.config.js Ver arquivo

@@ -8,24 +8,17 @@ module.exports = {
publicPath: '/dist/',
filename: "bundle.js"
},

module: {
loaders: [
//{test: /\.js$/, loader: 'babel-loader', query: {presets: ['es2015']}},

{
test: /\.js$/,
exclude: /node_modules|vue\/dist|vue-router\/|vue-loader\/|vue-hot-reload-api\//,
loader: 'babel'
},
{test: /\.js$/, loader: 'babel-loader', query: {presets: ['es2015']}},
{test: /\.css$/, loader: 'style-loader!css-loader'},
{test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192'},
{test: /\.vue$/, loader: 'vue'},
{ test: /\.woff(\?v=\d+\.\d+\.\d+)?$/, loader: "url?limit=10000&mimetype=application/font-woff"},
{ test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/, loader: "url?limit=10000&mimetype=application/font-woff"},
{ test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, loader: "url?limit=10000&mimetype=application/octet-stream"},
{test: /\.woff(\?v=\d+\.\d+\.\d+)?$/, loader: "url?limit=10000&mimetype=application/font-woff"},
{test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/, loader: "url?limit=10000&mimetype=application/font-woff"},
{test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, loader: "url?limit=10000&mimetype=application/octet-stream"},
{test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: "file"},
{ test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: "url?limit=10000&mimetype=image/svg+xml"}
{test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: "url?limit=10000&mimetype=image/svg+xml"}
]
},
plugins: [
@@ -35,4 +28,13 @@ module.exports = {
"window.jQuery": "jquery"
})
]
};
};

if (process.env.NODE_ENV === 'production') {
module.exports.plugins = [
new webpack.DefinePlugin({'process.env': {NODE_ENV: '"production"'}}),
new webpack.optimize.UglifyJsPlugin({compress: {warnings: false}, comments: false}),
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.optimize.DedupePlugin()
]
}

+ 0
- 86
webpack.config.old.js Ver arquivo

@@ -1,86 +0,0 @@
var webpack = require('webpack');

module.exports = {
entry: ['./app/main.js'],
output: {
path: './dist',
publicPath: '/dist/',
filename: 'app.js'
},
devServer: {
port: 8080
},
module: {
loaders: [
{
test: /\.scss$/,
loaders: ['css', 'sass']
},
{
test: /\.js$/,
exclude: /node_modules|vue\/dist|vue-router\/|vue-loader\/|vue-hot-reload-api\//,
loader: 'babel'
},
{
test: /\.vue$/,
loader: 'vue'
},
{
test: /\.(png|jpe?g|gif)$/,
loader: 'url',
query: {
limit: 10000,
name: '[name].[ext]?[hash]'
}
},
{
test: /\.woff(\?v=\d+\.\d+\.\d+)?$/,
loader: "url?limit=10000&mimetype=application/font-woff"
},
{
test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/,
loader: "url?limit=10000&mimetype=application/font-woff"
},
{
test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
loader: "url?limit=10000&mimetype=application/octet-stream"
},
{
test: /\.eot(\?v=\d+\.\d+\.\d+)?$/,
loader: "file"
},
{
test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
loader: "url?limit=10000&mimetype=image/svg+xml"
}
]
},
babel: {
presets: ['es2015'],
plugins: ['transform-runtime']
},
plugins: [
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
"window.jQuery": "jquery"
})
]
};

if (process.env.NODE_ENV === 'production') {
module.exports.plugins = [
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
}),
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
},
comments: false
}),
new webpack.optimize.OccurenceOrderPlugin()
]
}

Carregando…
Cancelar
Salvar