@@ -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:production": "npm prune && npm install && npm run lint && npm test && npm run build", | ||||
"build": "npm-run-all clean build:static build:app", | "build": "npm-run-all clean build:static build:app", | ||||
"clean": "rimraf dist && mkdir dist", | "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: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:css": "node-sass static/css/styles.scss dist/css/styles.css", | ||||
"build:app": "browserify -e ./app/app.js -o ./dist/app.js", | "build:app": "browserify -e ./app/app.js -o ./dist/app.js", | ||||
"prestart": "npm run build", | "prestart": "npm run build", | ||||
@@ -35,14 +36,14 @@ | |||||
}, | }, | ||||
"homepage": "https://github.com/guillaumevincent/lesspass#readme", | "homepage": "https://github.com/guillaumevincent/lesspass#readme", | ||||
"dependencies": { | "dependencies": { | ||||
"angular": "^1.4.8", | |||||
"bootstrap": "^4.0.0-alpha.2", | "bootstrap": "^4.0.0-alpha.2", | ||||
"clipboard": "^1.5.5", | |||||
"jquery": "^2.1.4" | |||||
"clipboard": "^1.5.5" | |||||
}, | }, | ||||
"devDependencies": { | "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", | "babelify": "latest", | ||||
"browserify": "latest", | "browserify": "latest", | ||||
"cpy": "latest", | "cpy": "latest", | ||||
@@ -53,6 +54,10 @@ | |||||
"nodemon": "latest", | "nodemon": "latest", | ||||
"npm-run-all": "latest", | "npm-run-all": "latest", | ||||
"rimraf": "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", | "watch": "latest", | ||||
"watchify": "latest" | "watchify": "latest" | ||||
}, | }, | ||||
@@ -68,6 +73,20 @@ | |||||
{ | { | ||||
"presets": [ | "presets": [ | ||||
"es2015" | "es2015" | ||||
], | |||||
"plugins": [ | |||||
"transform-runtime" | |||||
] | |||||
} | |||||
], | |||||
[ | |||||
"vueify", | |||||
{ | |||||
"presets": [ | |||||
"es2015" | |||||
], | |||||
"plugins": [ | |||||
"transform-runtime" | |||||
] | ] | ||||
} | } | ||||
] | ] | ||||
@@ -1,3 +1,36 @@ | |||||
@import '../../node_modules/bootstrap/scss/bootstrap'; | @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="http://www.w3.org/2000/svg" | ||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | 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" | id="svg2" | ||||
version="1.1" | version="1.1" | ||||
inkscape:version="0.91 r13725" | |||||
inkscape:version="0.48.4 r9939" | |||||
sodipodi:docname="logo.svg" | 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 | <defs | ||||
id="defs4" /> | id="defs4" /> | ||||
<sodipodi:namedview | <sodipodi:namedview | ||||
@@ -29,15 +29,15 @@ | |||||
inkscape:pageopacity="0.0" | inkscape:pageopacity="0.0" | ||||
inkscape:pageshadow="2" | inkscape:pageshadow="2" | ||||
inkscape:zoom="5.6568543" | inkscape:zoom="5.6568543" | ||||
inkscape:cx="80.784639" | |||||
inkscape:cx="56.566232" | |||||
inkscape:cy="2.3568043" | inkscape:cy="2.3568043" | ||||
inkscape:document-units="px" | inkscape:document-units="px" | ||||
inkscape:current-layer="layer1" | inkscape:current-layer="layer1" | ||||
showgrid="false" | 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" | inkscape:window-maximized="1" | ||||
units="px" /> | units="px" /> | ||||
<metadata | <metadata | ||||
@@ -56,23 +56,28 @@ | |||||
inkscape:label="Calque 1" | inkscape:label="Calque 1" | ||||
inkscape:groupmode="layer" | inkscape:groupmode="layer" | ||||
id="layer1" | id="layer1" | ||||
transform="translate(0,-1015.3622)"> | |||||
transform="translate(0,-1007.3622)"> | |||||
<path | <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" | id="path3347" | ||||
inkscape:connector-curvature="0" /> | |||||
inkscape:connector-curvature="0" | |||||
inkscape:export-xdpi="179.79413" | |||||
inkscape:export-ydpi="179.79413" /> | |||||
<text | <text | ||||
xml:space="preserve" | 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" | 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" | sodipodi:role="line" | ||||
id="tspan3358" | 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> | </g> | ||||
</svg> | </svg> |
@@ -8,6 +8,38 @@ | |||||
<link rel="icon" type="image/png" href="https://lesspass.com/images/favicon.png"> | <link rel="icon" type="image/png" href="https://lesspass.com/images/favicon.png"> | ||||
</head> | </head> | ||||
<body> | <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> | <script src="app.js"></script> | ||||
</body> | </body> | ||||
</html> | </html> |