@@ -0,0 +1,11 @@ | |||
import Vue from 'vue'; | |||
import PasswordGenerator from './components/password-generator.vue'; | |||
import BootstrapHr from './components/bootstrap-hr.vue'; | |||
new Vue({ | |||
el: 'body', | |||
components: { | |||
passwordGenerator: PasswordGenerator, | |||
bootstrapHr: BootstrapHr | |||
} | |||
}); |
@@ -1,72 +0,0 @@ | |||
import lesspass from '../app/lesspass'; | |||
import angular from 'angular'; | |||
import Clipboard from 'clipboard'; | |||
window.jQuery = $ = require('jquery'); | |||
var bootstrap = require('bootstrap/dist/js/bootstrap'); | |||
class lesspassController { | |||
constructor($scope) { | |||
var vm = this; | |||
this.password = ''; | |||
this.site = { | |||
site_name: '', | |||
password_length: 12, | |||
password_types: ['lowercase', 'uppercase', 'numbers', 'symbols'], | |||
counter: 1 | |||
}; | |||
$scope.$watch(function () { | |||
return vm.password; | |||
}, function () { | |||
vm.updatePassword(); | |||
}); | |||
$scope.$watchCollection(function () { | |||
return vm.site; | |||
}, function () { | |||
vm.updatePassword(); | |||
}); | |||
var clipboard = new Clipboard('#copy-btn'); | |||
clipboard.on('success', function (e) { | |||
if (vm.password && vm.site.site_name) { | |||
var t = $('#copy-btn').tooltip({title: 'Copié'}); | |||
t.tooltip('show'); | |||
e.clearSelection(); | |||
} | |||
}); | |||
clipboard.on('error', function (e) { | |||
var passwordGenerated = document.getElementById("password_generated"); | |||
var t = $(passwordGenerated).tooltip({title: 'Cmd + C pour copier le mot de passe'}); | |||
t.tooltip('show'); | |||
}); | |||
this.displayHelp = false; | |||
} | |||
updatePasswordTypes(type) { | |||
var passwordTypes = this.site.password_types; | |||
var indexOfId = passwordTypes.indexOf(type); | |||
if (indexOfId == -1) { | |||
passwordTypes.push(type) | |||
} else { | |||
passwordTypes.splice(indexOfId, 1) | |||
} | |||
this.updatePassword(); | |||
} | |||
updatePassword() { | |||
if (this.password && this.site.site_name) { | |||
this.generatedPassword = lesspass.create_password(this.password, this.site); | |||
} | |||
} | |||
} | |||
angular | |||
.module('app', []) | |||
.controller('lesspassController', lesspassController); |
@@ -0,0 +1,20 @@ | |||
<style> | |||
hr { | |||
margin-top: 1em; | |||
margin-bottom: 3em; | |||
border: 0 none -moz-use-text-color; | |||
border-top: 1px solid #434857; | |||
-moz-border-top-colors: none; | |||
-moz-border-right-colors: none; | |||
-moz-border-bottom-colors: none; | |||
-moz-border-left-colors: none; | |||
border-image: none; | |||
} | |||
</style> | |||
<template> | |||
<div class="container"> | |||
<div class="col-md-6 col-md-offset-3"> | |||
<hr> | |||
</div> | |||
</div> | |||
</template> |
@@ -0,0 +1,126 @@ | |||
<style> | |||
#passwordGenerator input { | |||
background-color: #434857; | |||
color: white; | |||
border: 1px solid #434857; | |||
} | |||
</style> | |||
<template> | |||
<div class="container"> | |||
<form class="form-inline" id="passwordGenerator"> | |||
<div class="m-t-1"> | |||
<div class="form-group"> | |||
<label class="sr-only" for="email">Adresse email</label> | |||
<input type="email" class="form-control" id="email" placeholder="Email" v-model="email"> | |||
</div> | |||
<div class="form-group"> | |||
<label class="sr-only" for="password">Mot de passe</label> | |||
<input type="password" class="form-control" id="password" placeholder="Mot de passe" | |||
v-model="password"> | |||
</div> | |||
<div class="form-group"> | |||
<label class="sr-only" for="site">Site</label> | |||
<input type="text" class="form-control" id="site" placeholder="Site (ex: Facebook)" | |||
v-model="site"> | |||
</div> | |||
<div class="form-group"> | |||
<label class="sr-only" for="generatedPassword">Mot de passe unique</label> | |||
<div class="input-group"> | |||
<input type="text" id="generatedPassword" class="form-control" v-model="generatedPassword"> | |||
<span class="input-group-btn"> | |||
<button id="copyBtn" data-clipboard-target="#generatedPassword" | |||
class="btn btn-primary" type="button"> | |||
Copier | |||
</button> | |||
</span> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="m-t-1"> | |||
<div class="checkbox"> | |||
<label> | |||
<input type="checkbox" v-model="showAdvancedOptions"> Options avancées | |||
</label> | |||
</div> | |||
</div> | |||
<div class="m-t-1" v-if="showAdvancedOptions"> | |||
<div class="form-group"> | |||
<label class="checkbox-inline"> | |||
<input type="checkbox" id="lowercaseCheckbox" value="lowercase" v-model="passwordTypes" checked> | |||
minuscules (a-z) | |||
</label> | |||
<label class="checkbox-inline"> | |||
<input type="checkbox" id="uppercaseCheckbox" value="uppercase" v-model="passwordTypes" checked> | |||
MAJUSCULES (A-Z) | |||
</label> | |||
<label class="checkbox-inline"> | |||
<input type="checkbox" id="numbersCheckbox" value="numbers" v-model="passwordTypes" checked> | |||
nombres (0-9) | |||
</label> | |||
<label class="checkbox-inline"> | |||
<input type="checkbox" id="symbolsCheckbox" value="symbols" v-model="passwordTypes" checked> | |||
caractères spéciaux (@&%?) | |||
</label> | |||
</div> | |||
</div> | |||
<div class="m-t-1" v-if="showAdvancedOptions"> | |||
<div class="form-group"> | |||
<label for="passwordLength">Longueur</label> | |||
<input id="passwordLength" type="range" value="12" min="6" max="64" v-model="length" | |||
class="form-control"> {{ length }} | |||
</div> | |||
</div> | |||
</form> | |||
</div> | |||
</template> | |||
<script lang="babel"> | |||
import crypto from 'crypto'; | |||
import lesspass from '../lesspass'; | |||
import Clipboard from 'clipboard'; | |||
export default { | |||
data: function () { | |||
return { | |||
email: '', | |||
password: '', | |||
site: '', | |||
length: 12, | |||
counter: 1, | |||
passwordTypes: ["lowercase", "uppercase", "numbers", "symbols"], | |||
showAdvancedOptions: false | |||
} | |||
}, | |||
computed: { | |||
generatedPassword: function () { | |||
var generatedPassword; | |||
if (this.email && this.password && this.site) { | |||
var masterPassword = crypto.pbkdf2Sync(this.email, this.password, 10, 64, 'sha256').toString('hex'); | |||
generatedPassword = lesspass.create_password(masterPassword, { | |||
site_name: this.site, | |||
password_length: this.length, | |||
password_types: this.passwordTypes, | |||
counter: this.counter | |||
}); | |||
} | |||
return generatedPassword; | |||
} | |||
} | |||
} | |||
var cb = new Clipboard('#copyBtn'); | |||
cb.on('success', function (e) { | |||
e.clearSelection(); | |||
}); | |||
cb.on('error', function (e) { | |||
}); | |||
</script> |
@@ -10,8 +10,9 @@ | |||
"build:production": "npm prune && npm install && npm run lint && npm test && npm run build", | |||
"build": "npm-run-all clean build:static build:app", | |||
"clean": "rimraf dist && mkdir dist", | |||
"build:static": "npm-run-all copy:html build:css", | |||
"build:static": "npm-run-all copy:html copy:images build:css", | |||
"copy:html": "cpy 'static/*.html' dist", | |||
"copy:images": "cpy 'static/images/*.png' dist/images/", | |||
"build:css": "node-sass static/css/styles.scss dist/css/styles.css", | |||
"build:app": "browserify -e ./app/app.js -o ./dist/app.js", | |||
"prestart": "npm run build", | |||
@@ -35,14 +36,14 @@ | |||
}, | |||
"homepage": "https://github.com/guillaumevincent/lesspass#readme", | |||
"dependencies": { | |||
"angular": "^1.4.8", | |||
"bootstrap": "^4.0.0-alpha.2", | |||
"clipboard": "^1.5.5", | |||
"jquery": "^2.1.4" | |||
"clipboard": "^1.5.5" | |||
}, | |||
"devDependencies": { | |||
"babel-core": "latest", | |||
"babel-preset-es2015": "latest", | |||
"babel-core": "^6.3.26", | |||
"babel-plugin-transform-runtime": "^6.3.13", | |||
"babel-preset-es2015": "^6.3.13", | |||
"babel-runtime": "^5.8.34", | |||
"babelify": "latest", | |||
"browserify": "latest", | |||
"cpy": "latest", | |||
@@ -53,6 +54,10 @@ | |||
"nodemon": "latest", | |||
"npm-run-all": "latest", | |||
"rimraf": "latest", | |||
"vue": "^1.0.12", | |||
"vue-hot-reload-api": "^1.2.2", | |||
"vueify": "^8.0.0", | |||
"vueify-insert-css": "^1.0.0", | |||
"watch": "latest", | |||
"watchify": "latest" | |||
}, | |||
@@ -68,6 +73,20 @@ | |||
{ | |||
"presets": [ | |||
"es2015" | |||
], | |||
"plugins": [ | |||
"transform-runtime" | |||
] | |||
} | |||
], | |||
[ | |||
"vueify", | |||
{ | |||
"presets": [ | |||
"es2015" | |||
], | |||
"plugins": [ | |||
"transform-runtime" | |||
] | |||
} | |||
] | |||
@@ -1,3 +1,36 @@ | |||
@import '../../node_modules/bootstrap/scss/bootstrap'; | |||
body { | |||
font-family: "Roboto", "Helvetica Neue", Helvetica, Arial, sans-serif; | |||
font-size: 14px; | |||
line-height: 1.5; | |||
color: #CFD2DA; | |||
background-color: #252830; | |||
padding-bottom: 2em; | |||
} | |||
#header { | |||
#logo-link { | |||
margin: 0 auto; | |||
width: 200px; | |||
height: 45px; | |||
#logo { | |||
width: inherit; | |||
height: inherit; | |||
} | |||
} | |||
} | |||
#headlines { | |||
padding-top: 2em; | |||
padding-bottom: 1em; | |||
} | |||
.blue { | |||
color: #0275D8; | |||
} | |||
.jumbotron { | |||
color: black; | |||
} |
@@ -9,16 +9,16 @@ | |||
xmlns="http://www.w3.org/2000/svg" | |||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | |||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | |||
width="180" | |||
height="37" | |||
viewBox="0 0 180 37" | |||
width="200" | |||
height="45" | |||
viewBox="0 0 200 45" | |||
id="svg2" | |||
version="1.1" | |||
inkscape:version="0.91 r13725" | |||
inkscape:version="0.48.4 r9939" | |||
sodipodi:docname="logo.svg" | |||
inkscape:export-filename="C:\Users\19011246\workspace\lesspass\static\images\logo.png" | |||
inkscape:export-xdpi="90" | |||
inkscape:export-ydpi="90"> | |||
inkscape:export-filename="/home/guillaume/workspace/lesspass/static/images/logo.png" | |||
inkscape:export-xdpi="180" | |||
inkscape:export-ydpi="180"> | |||
<defs | |||
id="defs4" /> | |||
<sodipodi:namedview | |||
@@ -29,15 +29,15 @@ | |||
inkscape:pageopacity="0.0" | |||
inkscape:pageshadow="2" | |||
inkscape:zoom="5.6568543" | |||
inkscape:cx="80.784639" | |||
inkscape:cx="56.566232" | |||
inkscape:cy="2.3568043" | |||
inkscape:document-units="px" | |||
inkscape:current-layer="layer1" | |||
showgrid="false" | |||
inkscape:window-width="1680" | |||
inkscape:window-height="988" | |||
inkscape:window-x="-8" | |||
inkscape:window-y="-8" | |||
inkscape:window-width="1366" | |||
inkscape:window-height="744" | |||
inkscape:window-x="0" | |||
inkscape:window-y="24" | |||
inkscape:window-maximized="1" | |||
units="px" /> | |||
<metadata | |||
@@ -56,23 +56,28 @@ | |||
inkscape:label="Calque 1" | |||
inkscape:groupmode="layer" | |||
id="layer1" | |||
transform="translate(0,-1015.3622)"> | |||
transform="translate(0,-1007.3622)"> | |||
<path | |||
style="fill:#f9f9f9" | |||
d="m 3.5355339,1040.233 c 0,-4.2478 0,-8.4938 0,-12.7415 1.2566829,0 2.5133651,0 3.7700482,0 0,2.6815 0,5.3616 0,8.042 9.6713189,0 19.3426549,0 29.0139809,0 0,-2.6804 0,-5.3605 0,-8.042 1.282485,0 2.564912,0 3.847367,0 0,4.2476 0,8.4937 0,12.7415 -12.210478,0 -24.420921,0 -36.6313961,0 z" | |||
style="fill:#cfd2da;fill-opacity:1" | |||
d="m 2,1036.233 c 0,-4.2478 0,-8.4938 0,-12.7416 1.2566829,0 2.5133651,0 3.7700482,0 0,2.6816 0,5.3617 0,8.0421 9.6713188,0 19.3426548,0 29.0139808,0 0,-2.6804 0,-5.3605 0,-8.0421 1.282485,0 2.564912,0 3.847367,0 0,4.2477 0,8.4938 0,12.7416 -12.210478,0 -24.420921,0 -36.631396,0 z" | |||
id="path3347" | |||
inkscape:connector-curvature="0" /> | |||
inkscape:connector-curvature="0" | |||
inkscape:export-xdpi="179.79413" | |||
inkscape:export-ydpi="179.79413" /> | |||
<text | |||
xml:space="preserve" | |||
style="font-style:normal;font-weight:normal;font-size:20px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#f9f9f9;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;" | |||
x="54.947002" | |||
y="1041.6552" | |||
style="font-size:20px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#cfd2da;fill-opacity:1;stroke:none;font-family:sans-serif" | |||
x="47.091797" | |||
y="1040.5848" | |||
id="text3356" | |||
sodipodi:linespacing="125%"><tspan | |||
sodipodi:linespacing="125%" | |||
inkscape:export-filename="/home/guillaume/workspace/lesspass/static/images/path3347.png" | |||
inkscape:export-xdpi="179.79413" | |||
inkscape:export-ydpi="179.79413"><tspan | |||
sodipodi:role="line" | |||
id="tspan3358" | |||
x="54.947002" | |||
y="1041.6552" | |||
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:30px;font-family:'Open Sans';-inkscape-font-specification:'Open Sans Bold';fill:#f9f9f9;">lesspass</tspan></text> | |||
x="47.091797" | |||
y="1040.5848" | |||
style="font-size:30px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#cfd2da;fill-opacity:1;font-family:Open Sans;-inkscape-font-specification:Open Sans Bold">LessPass</tspan></text> | |||
</g> | |||
</svg> |
@@ -8,6 +8,38 @@ | |||
<link rel="icon" type="image/png" href="https://lesspass.com/images/favicon.png"> | |||
</head> | |||
<body> | |||
<div id="header"> | |||
<div class="container text-xs-center"> | |||
<div id="logo-link"> | |||
<a href="http://lesspass.com"> | |||
<img id="logo" alt="lesspass" class="img-fluid" src="images/logo.png"> | |||
</a> | |||
</div> | |||
</div> | |||
</div> | |||
<div id="headlines" class="container text-xs-center"> | |||
<h1 class="blue">Gérez vos mots de passe en toute confiance</h1> | |||
<h2>LessPass ne mémorise pas vos mots de passe, et vous non plus !</h2> | |||
</div> | |||
<bootstrap-hr></bootstrap-hr> | |||
<div class="container"> | |||
<div class="jumbotron"> | |||
<div class="row"> | |||
<div class="col-lg-12"> | |||
<p class="lead"> | |||
<a href="https://lesspass.com/">LessPass</a> ne sauvegarde pas vos mots de passe, il les regénère à | |||
chaque fois que vous en avez besoin. Chaque mot de passe est unique et propre à chaque site. Tout ce | |||
dont vous avez besoin c'est de vous souvenir d'un seul mot de passe, et LessPass fait le reste. | |||
</p> | |||
<p class="lead"> | |||
Comme LessPass ne sauvegarde pas vos mots de passe, il n'y a rien à voler. | |||
</p> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
<bootstrap-hr></bootstrap-hr> | |||
<password-generator></password-generator> | |||
<script src="app.js"></script> | |||
</body> | |||
</html> |