@@ -37,11 +37,7 @@ | |||||
"SorryCopy": "Es tut uns leid, dass die Kopie nur auf modernen Browsern funktioniert", | "SorryCopy": "Es tut uns leid, dass die Kopie nur auf modernen Browsern funktioniert", | ||||
"UNDO": "STORNIEREN", | "UNDO": "STORNIEREN", | ||||
"UpdateYourSearch": "Bitte erweitern Sie Ihre Suche.", | "UpdateYourSearch": "Bitte erweitern Sie Ihre Suche.", | ||||
"Version": "Version", | |||||
"WarningV1Deprecated": "Version 1 ist veraltet und wird bald gelöscht werden. Wir empfehlen Ihnen dringend, Ihre Passwörter auf die Version 2 zu migrieren.", | |||||
"WelcomeRegister": "Willkommen {email}, danke für die Anmeldung.", | "WelcomeRegister": "Willkommen {email}, danke für die Anmeldung.", | ||||
"Your options have been saved successfully": "Ihre Optionen wurden erfolgreich gespeichert", | "Your options have been saved successfully": "Ihre Optionen wurden erfolgreich gespeichert", | ||||
"resetPasswordSuccess": "Wenn die E-Mail-Adresse {email} mit einem LessPass-Konto verknüpft ist, erhalten Sie in Kürze eine E-Mail von LessPass mit Anweisungen zum Zurücksetzen Ihres Passworts.", | |||||
"version": "Version", | |||||
"versionShortcut": "V" | |||||
"resetPasswordSuccess": "Wenn die E-Mail-Adresse {email} mit einem LessPass-Konto verknüpft ist, erhalten Sie in Kürze eine E-Mail von LessPass mit Anweisungen zum Zurücksetzen Ihres Passworts." | |||||
} | } |
@@ -37,11 +37,7 @@ | |||||
"SorryCopy": "We are sorry the copy only works on modern browsers", | "SorryCopy": "We are sorry the copy only works on modern browsers", | ||||
"UNDO": "UNDO", | "UNDO": "UNDO", | ||||
"UpdateYourSearch": "Please try broadening your search.", | "UpdateYourSearch": "Please try broadening your search.", | ||||
"Version": "Version", | |||||
"WarningV1Deprecated": "Version 1 is deprecated and will be deleted soon. We strongly advise you to migrate your passwords to version 2.", | |||||
"WelcomeRegister": "Welcome {email}, thank you for signing up.", | "WelcomeRegister": "Welcome {email}, thank you for signing up.", | ||||
"Your options have been saved successfully": "Your options have been saved successfully", | "Your options have been saved successfully": "Your options have been saved successfully", | ||||
"resetPasswordSuccess": "If the email address {email} is associated with a LessPass account, you will shortly receive an email from LessPass with instructions on how to reset your password.", | |||||
"version": "version", | |||||
"versionShortcut": "v" | |||||
"resetPasswordSuccess": "If the email address {email} is associated with a LessPass account, you will shortly receive an email from LessPass with instructions on how to reset your password." | |||||
} | } |
@@ -37,11 +37,7 @@ | |||||
"SorryCopy": "Lamentamos que la copia sólo funcione en navegadores modernos", | "SorryCopy": "Lamentamos que la copia sólo funcione en navegadores modernos", | ||||
"UNDO": "DESHACER", | "UNDO": "DESHACER", | ||||
"UpdateYourSearch": "Trate de ampliar su búsqueda.", | "UpdateYourSearch": "Trate de ampliar su búsqueda.", | ||||
"Version": "Versión", | |||||
"WarningV1Deprecated": "La versión 1 está obsoleta y será eliminada pronto. Le recomendamos enérgicamente migrar sus contraseñas a la versión 2.", | |||||
"WelcomeRegister": "Bienvenido o bienvenida {email}, gracias por registrarse.", | "WelcomeRegister": "Bienvenido o bienvenida {email}, gracias por registrarse.", | ||||
"Your options have been saved successfully": "Sus opciones se han guardado correctamente", | "Your options have been saved successfully": "Sus opciones se han guardado correctamente", | ||||
"resetPasswordSuccess": "Si la dirección de correo electrónico {email} está asociada a una cuenta LessPass, recibirá un correo electrónico de LessPass con instrucciones sobre cómo restablecer su contraseña.", | |||||
"version": "versión", | |||||
"versionShortcut": "v" | |||||
"resetPasswordSuccess": "Si la dirección de correo electrónico {email} está asociada a una cuenta LessPass, recibirá un correo electrónico de LessPass con instrucciones sobre cómo restablecer su contraseña." | |||||
} | } |
@@ -37,11 +37,7 @@ | |||||
"SorryCopy": "Nous sommes désolés, la copie ne fonctionne que sur les navigateurs modernes", | "SorryCopy": "Nous sommes désolés, la copie ne fonctionne que sur les navigateurs modernes", | ||||
"UNDO": "ANNULER", | "UNDO": "ANNULER", | ||||
"UpdateYourSearch": "Merci de modifier votre recherche.", | "UpdateYourSearch": "Merci de modifier votre recherche.", | ||||
"Version": "Version", | |||||
"WarningV1Deprecated": "La version 1 est déconseillée et sera supprimée bientôt. Nous vous conseillons fortement de migrer vos mots de passe vers la version 2.", | |||||
"WelcomeRegister": "Bienvenue {email}, merci pour vous être enregistré.", | "WelcomeRegister": "Bienvenue {email}, merci pour vous être enregistré.", | ||||
"Your options have been saved successfully": "Vos options ont été enregistrées avec succès", | "Your options have been saved successfully": "Vos options ont été enregistrées avec succès", | ||||
"resetPasswordSuccess": "Si l'adresse email {email} est associée avec un compte LessPass, vous allez recevoir un email de la part de LessPass avec les instructions pour changer votre mot de passe.", | |||||
"version": "version", | |||||
"versionShortcut": "v" | |||||
"resetPasswordSuccess": "Si l'adresse email {email} est associée avec un compte LessPass, vous allez recevoir un email de la part de LessPass avec les instructions pour changer votre mot de passe." | |||||
} | } |
@@ -37,11 +37,7 @@ | |||||
"SorryCopy": "很抱歉,但复制功能仅适用于现代浏览器", | "SorryCopy": "很抱歉,但复制功能仅适用于现代浏览器", | ||||
"UNDO": "解开", | "UNDO": "解开", | ||||
"UpdateYourSearch": "请尝试放宽您的搜索条件。", | "UpdateYourSearch": "请尝试放宽您的搜索条件。", | ||||
"Version": "版本", | |||||
"WarningV1Deprecated": "版本 1 已不再支持,不久后将被删除。我们强烈建议您将密码迁移至版本 2。", | |||||
"WelcomeRegister": "你好 {email},欢迎您的注册。", | "WelcomeRegister": "你好 {email},欢迎您的注册。", | ||||
"Your options have been saved successfully": "您的选项已成功保存", | "Your options have been saved successfully": "您的选项已成功保存", | ||||
"resetPasswordSuccess": "如果电子邮件地址 {email} 与一个 LessPass 账户相关联,您将很快收到 LessPass 的电子邮件,里面提供有重置密码的操作说明。", | |||||
"version": "版本", | |||||
"versionShortcut": "v" | |||||
"resetPasswordSuccess": "如果电子邮件地址 {email} 与一个 LessPass 账户相关联,您将很快收到 LessPass 的电子邮件,里面提供有重置密码的操作说明。" | |||||
} | } |
@@ -37,11 +37,7 @@ | |||||
"SorryCopy": "我們很抱歉,該副本僅適用於現代瀏覽器", | "SorryCopy": "我們很抱歉,該副本僅適用於現代瀏覽器", | ||||
"UNDO": "解開", | "UNDO": "解開", | ||||
"UpdateYourSearch": "請試著放寬您的搜尋條件。", | "UpdateYourSearch": "請試著放寬您的搜尋條件。", | ||||
"Version": "版本", | |||||
"WarningV1Deprecated": "版本 1 已不支援,不久將被刪除。 我們強烈得建議您將密碼換至版本 2。", | |||||
"WelcomeRegister": "歡迎 {email},謝謝您的註冊。", | "WelcomeRegister": "歡迎 {email},謝謝您的註冊。", | ||||
"Your options have been saved successfully": "您的選項已成功保存", | "Your options have been saved successfully": "您的選項已成功保存", | ||||
"resetPasswordSuccess": "如果电子邮件地址 {email} 与LessPass帐户相关联,您将很快收到LessPass的电子邮件,并提供如何重置密码的说明。", | |||||
"version": "版本", | |||||
"versionShortcut": "v" | |||||
"resetPasswordSuccess": "如果电子邮件地址 {email} 与LessPass帐户相关联,您将很快收到LessPass的电子邮件,并提供如何重置密码的说明。" | |||||
} | } |
@@ -26,14 +26,14 @@ | |||||
"dependencies": { | "dependencies": { | ||||
"awesomplete": "^1.1.2", | "awesomplete": "^1.1.2", | ||||
"axios": "^0.16.2", | "axios": "^0.16.2", | ||||
"bootstrap": "4.0.0-alpha.6", | |||||
"bootstrap": "^4.0.0-beta", | |||||
"copy-text-to-clipboard": "^1.0.2", | "copy-text-to-clipboard": "^1.0.2", | ||||
"font-awesome": "^4.7.0", | "font-awesome": "^4.7.0", | ||||
"hint.css": "^2.5.0", | "hint.css": "^2.5.0", | ||||
"jwt-decode": "^2.2.0", | "jwt-decode": "^2.2.0", | ||||
"lesspass": "^6.0.0", | "lesspass": "^6.0.0", | ||||
"lodash.debounce": "^4.0.8", | "lodash.debounce": "^4.0.8", | ||||
"vue": "^2.4.2", | |||||
"vue": "^2.4.4", | |||||
"vue-polyglot": "^0.2.1", | "vue-polyglot": "^0.2.1", | ||||
"vue-router": "^2.7.0", | "vue-router": "^2.7.0", | ||||
"vuejs-paginate": "^1.2.0", | "vuejs-paginate": "^1.2.0", | ||||
@@ -67,7 +67,7 @@ | |||||
"url-loader": "^0.5.9", | "url-loader": "^0.5.9", | ||||
"vue-loader": "^13.0.4", | "vue-loader": "^13.0.4", | ||||
"vue-polyglot-utils": "^0.1.1", | "vue-polyglot-utils": "^0.1.1", | ||||
"vue-template-compiler": "^2.4.2", | |||||
"vue-template-compiler": "^2.4.4", | |||||
"walk": "^2.3.9", | "walk": "^2.3.9", | ||||
"webpack": "^3.5.5", | "webpack": "^3.5.5", | ||||
"webpack-dev-server": "^2.7.1" | "webpack-dev-server": "^2.7.1" | ||||
@@ -1,10 +1,7 @@ | |||||
@import "~bootstrap/scss/functions"; | |||||
@import "~bootstrap/scss/variables"; | @import "~bootstrap/scss/variables"; | ||||
@import "~bootstrap/scss/mixins"; | @import "~bootstrap/scss/mixins"; | ||||
@import "~bootstrap/scss/custom"; | |||||
// Reset and dependencies | |||||
@import "~bootstrap/scss/normalize"; | |||||
//@import "~bootstrap/scss/print"; | //@import "~bootstrap/scss/print"; | ||||
// Core CSS | |||||
@import "~bootstrap/scss/reboot"; | @import "~bootstrap/scss/reboot"; | ||||
@import "~bootstrap/scss/type"; | @import "~bootstrap/scss/type"; | ||||
@import "~bootstrap/scss/images"; | @import "~bootstrap/scss/images"; | ||||
@@ -13,7 +10,6 @@ | |||||
@import "~bootstrap/scss/tables"; | @import "~bootstrap/scss/tables"; | ||||
@import "~bootstrap/scss/forms"; | @import "~bootstrap/scss/forms"; | ||||
@import "~bootstrap/scss/buttons"; | @import "~bootstrap/scss/buttons"; | ||||
// Components | |||||
@import "~bootstrap/scss/transitions"; | @import "~bootstrap/scss/transitions"; | ||||
@import "~bootstrap/scss/dropdown"; | @import "~bootstrap/scss/dropdown"; | ||||
@import "~bootstrap/scss/button-group"; | @import "~bootstrap/scss/button-group"; | ||||
@@ -30,15 +26,13 @@ | |||||
//@import "~bootstrap/scss/progress"; | //@import "~bootstrap/scss/progress"; | ||||
@import "~bootstrap/scss/media"; | @import "~bootstrap/scss/media"; | ||||
@import "~bootstrap/scss/list-group"; | @import "~bootstrap/scss/list-group"; | ||||
@import "~bootstrap/scss/responsive-embed"; | |||||
@import "~bootstrap/scss/close"; | @import "~bootstrap/scss/close"; | ||||
// Components w/ JavaScript | |||||
//@import "~bootstrap/scss/modal"; | //@import "~bootstrap/scss/modal"; | ||||
//@import "~bootstrap/scss/tooltip"; | //@import "~bootstrap/scss/tooltip"; | ||||
//@import "~bootstrap/scss/popover"; | //@import "~bootstrap/scss/popover"; | ||||
//@import "~bootstrap/scss/carousel"; | //@import "~bootstrap/scss/carousel"; | ||||
// Utility classes | |||||
@import "~bootstrap/scss/utilities"; | @import "~bootstrap/scss/utilities"; | ||||
@import '~font-awesome/css/font-awesome.css'; | @import '~font-awesome/css/font-awesome.css'; | ||||
@import '~hint.css/hint.css'; | @import '~hint.css/hint.css'; | ||||
@import '~awesomplete/awesomplete.css'; | @import '~awesomplete/awesomplete.css'; | ||||
@@ -100,3 +94,7 @@ button, .pointer { | |||||
.right-addon input { | .right-addon input { | ||||
padding-right: 30px; | padding-right: 30px; | ||||
} | } | ||||
.border-blue{ | |||||
border-color: $blue !important; | |||||
} |
@@ -2,7 +2,7 @@ | |||||
<div id="lesspass" class="card"> | <div id="lesspass" class="card"> | ||||
<lesspass-menu></lesspass-menu> | <lesspass-menu></lesspass-menu> | ||||
<lesspass-message></lesspass-message> | <lesspass-message></lesspass-message> | ||||
<div class="lesspass__inner-box card-block"> | |||||
<div class="lesspass__inner-box card-body"> | |||||
<router-view></router-view> | <router-view></router-view> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
@@ -11,7 +11,6 @@ | |||||
import './LessPass.scss'; | import './LessPass.scss'; | ||||
import Menu from './components/Menu.vue'; | import Menu from './components/Menu.vue'; | ||||
import Message from './components/Message.vue'; | import Message from './components/Message.vue'; | ||||
import {mapGetters} from 'vuex'; | |||||
export default { | export default { | ||||
name: 'LessPass', | name: 'LessPass', | ||||
@@ -19,7 +18,6 @@ | |||||
'lesspass-menu': Menu, | 'lesspass-menu': Menu, | ||||
'lesspass-message': Message | 'lesspass-message': Message | ||||
}, | }, | ||||
computed: mapGetters(['version']), | |||||
created(){ | created(){ | ||||
this.$store.dispatch('cleanMessage'); | this.$store.dispatch('cleanMessage'); | ||||
this.$store.dispatch('refreshToken'); | this.$store.dispatch('refreshToken'); | ||||
@@ -28,12 +28,13 @@ | |||||
class="form-control" | class="form-control" | ||||
autocorrect="off" | autocorrect="off" | ||||
autocapitalize="off" | autocapitalize="off" | ||||
v-model="password" | |||||
v-bind:value="value" | |||||
v-bind:placeholder="label" | v-bind:placeholder="label" | ||||
v-on:input="updateValue($event.target.value)" | |||||
v-on:keyup.enter="$emit('keyupEnter')" | v-on:keyup.enter="$emit('keyupEnter')" | ||||
v-on:blur="hidePassword($refs.passwordField)"> | v-on:blur="hidePassword($refs.passwordField)"> | ||||
<span class="input-group-btn" | <span class="input-group-btn" | ||||
v-if="fingerprint && password" | |||||
v-if="fingerprint && value" | |||||
v-on:click="togglePasswordType($refs.passwordField)"> | v-on:click="togglePasswordType($refs.passwordField)"> | ||||
<button id="fingerprint" class="btn" type="button" tabindex="-1"> | <button id="fingerprint" class="btn" type="button" tabindex="-1"> | ||||
<small class="hint--left"> | <small class="hint--left"> | ||||
@@ -48,7 +49,7 @@ | |||||
type="button" | type="button" | ||||
class="btn btn-link btn-sm p-0" | class="btn btn-link btn-sm p-0" | ||||
v-if="showEncryptButton" | v-if="showEncryptButton" | ||||
v-on:click="encryptMasterPassword($refs.passwordField.value)" | |||||
v-on:click="encryptMasterPassword()" | |||||
v-bind:class="{'disabled': email === '', 'hint--top hint--medium': email !== ''}"> | v-bind:class="{'disabled': email === '', 'hint--top hint--medium': email !== ''}"> | ||||
<small>{{ EncryptButtonText }}</small> | <small>{{ EncryptButtonText }}</small> | ||||
</button> | </button> | ||||
@@ -57,6 +58,7 @@ | |||||
<script> | <script> | ||||
import LessPass from 'lesspass'; | import LessPass from 'lesspass'; | ||||
import debounce from 'lodash.debounce'; | import debounce from 'lodash.debounce'; | ||||
import defaultPasswordProfile from '../store/defaultPassword'; | |||||
export default { | export default { | ||||
name: 'masterPassword', | name: 'masterPassword', | ||||
@@ -72,7 +74,6 @@ | |||||
}, | }, | ||||
data(){ | data(){ | ||||
return { | return { | ||||
password: this.value, | |||||
fingerprint: '', | fingerprint: '', | ||||
icon1: '', | icon1: '', | ||||
icon2: '', | icon2: '', | ||||
@@ -82,15 +83,14 @@ | |||||
color3: '' | color3: '' | ||||
} | } | ||||
}, | }, | ||||
watch: { | |||||
password(newPassword){ | |||||
methods: { | |||||
updateValue(newPassword){ | |||||
const fakePassword = Math.random().toString(36).substring(7); | const fakePassword = Math.random().toString(36).substring(7); | ||||
this.setFingerprint(fakePassword); | this.setFingerprint(fakePassword); | ||||
this.showRealFingerprint(newPassword); | this.showRealFingerprint(newPassword); | ||||
this.$refs.passwordField.value = newPassword; | |||||
this.$emit('input', newPassword); | this.$emit('input', newPassword); | ||||
} | |||||
}, | |||||
methods: { | |||||
}, | |||||
togglePasswordType(element){ | togglePasswordType(element){ | ||||
if (element.type === 'password') { | if (element.type === 'password') { | ||||
element.type = 'text'; | element.type = 'text'; | ||||
@@ -131,20 +131,12 @@ | |||||
showRealFingerprint: debounce(function(password) { | showRealFingerprint: debounce(function(password) { | ||||
this.setFingerprint(password); | this.setFingerprint(password); | ||||
}, 500), | }, 500), | ||||
encryptMasterPassword(password){ | |||||
const defaultPasswordProfile = { | |||||
lowercase: true, | |||||
uppercase: true, | |||||
numbers: true, | |||||
symbols: true, | |||||
length: 16, | |||||
counter: 1, | |||||
version: 2, | |||||
}; | |||||
encryptMasterPassword(){ | |||||
const password = this.$refs.passwordField.value; | |||||
return LessPass | return LessPass | ||||
.generatePassword('lesspass.com', this.email, password, defaultPasswordProfile) | .generatePassword('lesspass.com', this.email, password, defaultPasswordProfile) | ||||
.then(generatedPassword => { | .then(generatedPassword => { | ||||
this.password = generatedPassword; | |||||
this.updateValue(generatedPassword); | |||||
}); | }); | ||||
} | } | ||||
} | } | ||||
@@ -15,12 +15,12 @@ | |||||
</style> | </style> | ||||
<template> | <template> | ||||
<div id="menu"> | <div id="menu"> | ||||
<div class="card-header" v-bind:class="{ 'card-inverse': isGuest}"> | |||||
<div class="card-header" v-bind:class="{ 'text-white bg-dark': isGuest}"> | |||||
<div class="row"> | <div class="row"> | ||||
<div class="col-3"> | |||||
<div class="col-4"> | |||||
<span id="title" v-on:click="fullReload()" class="white-link pointer">LessPass</span> | <span id="title" v-on:click="fullReload()" class="white-link pointer">LessPass</span> | ||||
</div> | </div> | ||||
<div class="col-9 text-right"> | |||||
<div class="col-8 text-right"> | |||||
<span v-if="saved && isAuthenticated"> | <span v-if="saved && isAuthenticated"> | ||||
<small><i class="fa fa-lg fa-check pl-3"></i> saved</small> | <small><i class="fa fa-lg fa-check pl-3"></i> saved</small> | ||||
</span> | </span> | ||||
@@ -55,7 +55,7 @@ | |||||
}, | }, | ||||
methods: { | methods: { | ||||
fullReload() { | fullReload() { | ||||
this.$store.dispatch('savePassword', {password: this.$store.state.defaultPassword}); | |||||
this.$store.dispatch('resetPassword'); | |||||
this.$router.push({name: 'home'}); | this.$router.push({name: 'home'}); | ||||
}, | }, | ||||
logout() { | logout() { | ||||
@@ -32,7 +32,7 @@ | |||||
<transition name="fade"> | <transition name="fade"> | ||||
<div v-if="message.text"> | <div v-if="message.text"> | ||||
<div class="card-header text-white" | <div class="card-header text-white" | ||||
v-bind:class="{ 'card-warning': message.status==='warning', 'card-danger': message.status==='error', 'card-success': message.status==='success' }"> | |||||
v-bind:class="{ 'bg-warning': message.status==='warning', 'bg-danger': message.status==='error', 'bg-success': message.status==='success' }"> | |||||
<div class="row"> | <div class="row"> | ||||
<div class="col-12"> | <div class="col-12"> | ||||
<small>{{message.text}}</small> | <small>{{message.text}}</small> | ||||
@@ -22,44 +22,44 @@ | |||||
<div class="col-3"> | <div class="col-3"> | ||||
<button id="lowercase__btn" | <button id="lowercase__btn" | ||||
type="button" class="btn btn-block btn-sm px-0" | type="button" class="btn btn-block btn-sm px-0" | ||||
v-bind:class="{'btn-primary':options.lowercase===true && options.version===2,'btn-warning':options.lowercase===true && options.version===1,'btn-secondary':options.lowercase===false}" | |||||
v-on:click="options.lowercase=!options.lowercase"> | |||||
v-bind:class="{'btn-primary':password.lowercase===true, 'btn-light':password.lowercase===false}" | |||||
v-on:click="password.lowercase=!password.lowercase"> | |||||
a-z | a-z | ||||
</button> | </button> | ||||
</div> | </div> | ||||
<div class="col-3"> | <div class="col-3"> | ||||
<button id="uppercase__btn" | <button id="uppercase__btn" | ||||
type="button" class="btn btn-block btn-sm px-0" | type="button" class="btn btn-block btn-sm px-0" | ||||
v-bind:class="{'btn-primary':options.uppercase===true && options.version===2,'btn-warning':options.uppercase===true && options.version===1,'btn-secondary':options.uppercase===false}" | |||||
v-on:click="options.uppercase=!options.uppercase"> | |||||
v-bind:class="{'btn-primary':password.uppercase===true, 'btn-light':password.uppercase===false}" | |||||
v-on:click="password.uppercase=!password.uppercase"> | |||||
A-Z | A-Z | ||||
</button> | </button> | ||||
</div> | </div> | ||||
<div class="col-3"> | <div class="col-3"> | ||||
<button id="numbers__btn" | <button id="numbers__btn" | ||||
type="button" class="btn btn-block btn-sm px-0" | type="button" class="btn btn-block btn-sm px-0" | ||||
v-bind:class="{'btn-primary':options.numbers===true && options.version===2,'btn-warning':options.numbers===true && options.version===1,'btn-secondary':options.numbers===false}" | |||||
v-on:click="options.numbers=!options.numbers"> | |||||
v-bind:class="{'btn-primary':password.numbers===true,'btn-light':password.numbers===false}" | |||||
v-on:click="password.numbers=!password.numbers"> | |||||
0-9 | 0-9 | ||||
</button> | </button> | ||||
</div> | </div> | ||||
<div class="col-3"> | <div class="col-3"> | ||||
<button id="symbols__btn" | <button id="symbols__btn" | ||||
type="button" class="btn btn-block btn-sm px-0" | type="button" class="btn btn-block btn-sm px-0" | ||||
v-bind:class="{'btn-primary':options.symbols===true && options.version===2,'btn-warning':options.symbols===true && options.version===1,'btn-secondary':options.symbols===false}" | |||||
v-on:click="options.symbols=!options.symbols"> | |||||
v-bind:class="{'btn-primary':password.symbols===true,'btn-light':password.symbols===false}" | |||||
v-on:click="password.symbols=!password.symbols"> | |||||
%!@ | %!@ | ||||
</button> | </button> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
<div class="form-group row"> | |||||
<div class="col"> | |||||
<div class="form-group row mb-0"> | |||||
<div class="col-6 col-sm-4"> | |||||
<label for="passwordLength">{{ $t('Length') }}</label> | <label for="passwordLength">{{ $t('Length') }}</label> | ||||
<div class="input-group input-group-sm"> | <div class="input-group input-group-sm"> | ||||
<span class="input-group-btn" v-on:click="options.length=decrement(options.length, {min: 5, max: 35})"> | |||||
<button id="decreaseLength__btn" class="btn btn-secondary p-1" type="button"> | |||||
<span class="input-group-btn" v-on:click="password.length=decrement(password.length, {min: 5, max: 35})"> | |||||
<button id="decreaseLength__btn" class="btn btn-primary border-blue px-2" type="button"> | |||||
<i class="fa fa-minus"></i> | <i class="fa fa-minus"></i> | ||||
</button> | </button> | ||||
</span> | </span> | ||||
@@ -68,16 +68,16 @@ | |||||
type="number" | type="number" | ||||
min="5" | min="5" | ||||
max="35" | max="35" | ||||
v-model.number="options.length"> | |||||
v-model.number="password.length"> | |||||
<span class="input-group-btn" | <span class="input-group-btn" | ||||
v-on:click="options.length=increment(options.length, {min: 5, max: 35})"> | |||||
<button id="increaseLength__btn" class="btn btn-secondary p-1" type="button"> | |||||
v-on:click="password.length=increment(password.length, {min: 5, max: 35})"> | |||||
<button id="increaseLength__btn" class="btn btn-primary border-blue px-2" type="button"> | |||||
<i class="fa fa-plus"></i> | <i class="fa fa-plus"></i> | ||||
</button> | </button> | ||||
</span> | </span> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
<div class="col"> | |||||
<div class="col-6 col-sm-4"> | |||||
<label for="passwordCounter" | <label for="passwordCounter" | ||||
class="hint--top hint--medium" | class="hint--top hint--medium" | ||||
v-bind:aria-label="$t('CounterFieldHelp','Increment this value to change the generated password without changing your master options.')"> | v-bind:aria-label="$t('CounterFieldHelp','Increment this value to change the generated password without changing your master options.')"> | ||||
@@ -85,8 +85,8 @@ | |||||
</label> | </label> | ||||
<div class="input-group input-group-sm"> | <div class="input-group input-group-sm"> | ||||
<span id="decreaseCounter__btn" class="input-group-btn" | <span id="decreaseCounter__btn" class="input-group-btn" | ||||
v-on:click="options.counter=decrement(options.counter, {min: 1})"> | |||||
<button class="btn btn-secondary p-1" type="button"> | |||||
v-on:click="password.counter=decrement(password.counter, {min: 1})"> | |||||
<button class="btn btn-primary border-blue px-2" type="button"> | |||||
<i class="fa fa-minus"></i> | <i class="fa fa-minus"></i> | ||||
</button> | </button> | ||||
</span> | </span> | ||||
@@ -94,52 +94,15 @@ | |||||
class="form-control form-control-sm" | class="form-control form-control-sm" | ||||
type="number" | type="number" | ||||
min="1" | min="1" | ||||
v-model.number="options.counter"> | |||||
v-model.number="password.counter"> | |||||
<span id="increaseCounter__btn" class="input-group-btn" | <span id="increaseCounter__btn" class="input-group-btn" | ||||
v-on:click="options.counter=increment(options.counter, {min: 1})"> | |||||
<button class="btn btn-secondary p-1" type="button"> | |||||
v-on:click="password.counter=increment(password.counter, {min: 1})"> | |||||
<button class="btn btn-primary border-blue px-2" type="button"> | |||||
<i class="fa fa-plus"></i> | <i class="fa fa-plus"></i> | ||||
</button> | </button> | ||||
</span> | </span> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
<div class="col"> | |||||
<div class="row"> | |||||
<div class="col"> | |||||
<label>{{ $t('Version') }}</label> | |||||
</div> | |||||
</div> | |||||
<div class="row no-gutters"> | |||||
<div class="col"> | |||||
<button type="button" class="btn btn-block btn-sm border-right-0" | |||||
v-bind:class="{'btn-primary':options.version===2,'btn-secondary':options.version!==2}" | |||||
v-on:click="setVersion(2)"> | |||||
<span class="hidden-xs-up">{{$t('version')}} </span> | |||||
<span class="hidden-xs-down">{{$t('versionShortcut', 'v')}}</span>2 | |||||
</button> | |||||
</div> | |||||
<div class="col"> | |||||
<button type="button" | |||||
class="btn btn-block btn-sm border-left-0" | |||||
v-bind:class="{'btn-warning':options.version===1,'btn-secondary':options.version!==1}" | |||||
v-on:click="setVersion(1)"> | |||||
<span class="hidden-xs-up">{{$t('version')}} </span> | |||||
<span class="hidden-xs-down">{{$t('versionShortcut', 'v')}}</span>1 | |||||
</button> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
<div class="form-group row mb-0"> | |||||
<div class="col"> | |||||
<button id="saveOptions__btn" | |||||
type="button" class="btn btn-sm hint--top-right hint--medium" | |||||
v-bind:aria-label="$t('DefaultOptionLocalStorage', 'We use local storage to save default options locally. Each time you open the app, these options will be loaded by default.')" | |||||
v-bind:class="{'btn-outline-warning':options.version===1,'btn-outline-primary':options.version!==1}" | |||||
v-on:click="saveDefaultOptions()"> | |||||
<i class="fa fa-floppy-o"></i> {{$t('Save options')}} | |||||
</button> | |||||
</div> | |||||
</div> | </div> | ||||
</div> | </div> | ||||
</template> | </template> | ||||
@@ -147,40 +110,16 @@ | |||||
<script type="text/ecmascript-6"> | <script type="text/ecmascript-6"> | ||||
import message from '../services/message'; | import message from '../services/message'; | ||||
import {increment, decrement} from "../services/form-validator"; | import {increment, decrement} from "../services/form-validator"; | ||||
import { mapState} from 'vuex'; | |||||
export default { | export default { | ||||
name: 'options', | name: 'options', | ||||
props: { | |||||
options: Object | |||||
}, | |||||
watch: { | |||||
'options': { | |||||
handler: function(options) { | |||||
this.$emit('update:options', options) | |||||
}, | |||||
deep: true | |||||
} | |||||
computed: { | |||||
...mapState(['password']), | |||||
}, | }, | ||||
methods: { | methods: { | ||||
decrement, | decrement, | ||||
increment, | |||||
setVersion(value) { | |||||
if (value === 1) { | |||||
message.error(this.$t( | |||||
"WarningV1Deprecated", | |||||
"Version 1 is deprecated and will be deleted soon. We strongly advise you to migrate your passwords to version 2." | |||||
)); | |||||
} | |||||
this.options = Object.assign({}, this.options, { | |||||
length: value === 1 ? 12 : 16, | |||||
version: value | |||||
}); | |||||
this.$store.dispatch('saveVersion', {version: value}); | |||||
}, | |||||
saveDefaultOptions() { | |||||
this.$store.dispatch('saveDefaultOptions', {options: this.options}); | |||||
message.success(this.$t('Your options have been saved successfully')); | |||||
}, | |||||
increment | |||||
} | } | ||||
} | } | ||||
</script> | </script> |
@@ -8,7 +8,7 @@ | |||||
font-weight: 600; | font-weight: 600; | ||||
} | } | ||||
.passwordProfile__site, .passwordProfile__login, .passwordProfile__version { | |||||
.passwordProfile__site, .passwordProfile__login { | |||||
font-size: 0.8rem; | font-size: 0.8rem; | ||||
line-height: 0.8rem; | line-height: 0.8rem; | ||||
} | } | ||||
@@ -37,11 +37,7 @@ | |||||
"SorryCopy": "Es tut uns leid, dass die Kopie nur auf modernen Browsern funktioniert", | "SorryCopy": "Es tut uns leid, dass die Kopie nur auf modernen Browsern funktioniert", | ||||
"UNDO": "STORNIEREN", | "UNDO": "STORNIEREN", | ||||
"UpdateYourSearch": "Bitte erweitern Sie Ihre Suche.", | "UpdateYourSearch": "Bitte erweitern Sie Ihre Suche.", | ||||
"Version": "Version", | |||||
"WarningV1Deprecated": "Version 1 ist veraltet und wird bald gelöscht werden. Wir empfehlen Ihnen dringend, Ihre Passwörter auf die Version 2 zu migrieren.", | |||||
"WelcomeRegister": "Willkommen {email}, danke für die Anmeldung.", | "WelcomeRegister": "Willkommen {email}, danke für die Anmeldung.", | ||||
"Your options have been saved successfully": "Ihre Optionen wurden erfolgreich gespeichert", | "Your options have been saved successfully": "Ihre Optionen wurden erfolgreich gespeichert", | ||||
"resetPasswordSuccess": "Wenn die E-Mail-Adresse {email} mit einem LessPass-Konto verknüpft ist, erhalten Sie in Kürze eine E-Mail von LessPass mit Anweisungen zum Zurücksetzen Ihres Passworts.", | |||||
"version": "Version", | |||||
"versionShortcut": "V" | |||||
"resetPasswordSuccess": "Wenn die E-Mail-Adresse {email} mit einem LessPass-Konto verknüpft ist, erhalten Sie in Kürze eine E-Mail von LessPass mit Anweisungen zum Zurücksetzen Ihres Passworts." | |||||
} | } |
@@ -37,11 +37,7 @@ | |||||
"SorryCopy": "We are sorry the copy only works on modern browsers", | "SorryCopy": "We are sorry the copy only works on modern browsers", | ||||
"UNDO": "UNDO", | "UNDO": "UNDO", | ||||
"UpdateYourSearch": "Please try broadening your search.", | "UpdateYourSearch": "Please try broadening your search.", | ||||
"Version": "Version", | |||||
"WarningV1Deprecated": "Version 1 is deprecated and will be deleted soon. We strongly advise you to migrate your passwords to version 2.", | |||||
"WelcomeRegister": "Welcome {email}, thank you for signing up.", | "WelcomeRegister": "Welcome {email}, thank you for signing up.", | ||||
"Your options have been saved successfully": "Your options have been saved successfully", | "Your options have been saved successfully": "Your options have been saved successfully", | ||||
"resetPasswordSuccess": "If the email address {email} is associated with a LessPass account, you will shortly receive an email from LessPass with instructions on how to reset your password.", | |||||
"version": "version", | |||||
"versionShortcut": "v" | |||||
"resetPasswordSuccess": "If the email address {email} is associated with a LessPass account, you will shortly receive an email from LessPass with instructions on how to reset your password." | |||||
} | } |
@@ -37,11 +37,7 @@ | |||||
"SorryCopy": "Lamentamos que la copia sólo funcione en navegadores modernos", | "SorryCopy": "Lamentamos que la copia sólo funcione en navegadores modernos", | ||||
"UNDO": "DESHACER", | "UNDO": "DESHACER", | ||||
"UpdateYourSearch": "Trate de ampliar su búsqueda.", | "UpdateYourSearch": "Trate de ampliar su búsqueda.", | ||||
"Version": "Versión", | |||||
"WarningV1Deprecated": "La versión 1 está obsoleta y será eliminada pronto. Le recomendamos enérgicamente migrar sus contraseñas a la versión 2.", | |||||
"WelcomeRegister": "Bienvenido o bienvenida {email}, gracias por registrarse.", | "WelcomeRegister": "Bienvenido o bienvenida {email}, gracias por registrarse.", | ||||
"Your options have been saved successfully": "Sus opciones se han guardado correctamente", | "Your options have been saved successfully": "Sus opciones se han guardado correctamente", | ||||
"resetPasswordSuccess": "Si la dirección de correo electrónico {email} está asociada a una cuenta LessPass, recibirá un correo electrónico de LessPass con instrucciones sobre cómo restablecer su contraseña.", | |||||
"version": "versión", | |||||
"versionShortcut": "v" | |||||
"resetPasswordSuccess": "Si la dirección de correo electrónico {email} está asociada a una cuenta LessPass, recibirá un correo electrónico de LessPass con instrucciones sobre cómo restablecer su contraseña." | |||||
} | } |
@@ -37,11 +37,7 @@ | |||||
"SorryCopy": "Nous sommes désolés, la copie ne fonctionne que sur les navigateurs modernes", | "SorryCopy": "Nous sommes désolés, la copie ne fonctionne que sur les navigateurs modernes", | ||||
"UNDO": "ANNULER", | "UNDO": "ANNULER", | ||||
"UpdateYourSearch": "Merci de modifier votre recherche.", | "UpdateYourSearch": "Merci de modifier votre recherche.", | ||||
"Version": "Version", | |||||
"WarningV1Deprecated": "La version 1 est déconseillée et sera supprimée bientôt. Nous vous conseillons fortement de migrer vos mots de passe vers la version 2.", | |||||
"WelcomeRegister": "Bienvenue {email}, merci pour vous être enregistré.", | "WelcomeRegister": "Bienvenue {email}, merci pour vous être enregistré.", | ||||
"Your options have been saved successfully": "Vos options ont été enregistrées avec succès", | "Your options have been saved successfully": "Vos options ont été enregistrées avec succès", | ||||
"resetPasswordSuccess": "Si l'adresse email {email} est associée avec un compte LessPass, vous allez recevoir un email de la part de LessPass avec les instructions pour changer votre mot de passe.", | |||||
"version": "version", | |||||
"versionShortcut": "v" | |||||
"resetPasswordSuccess": "Si l'adresse email {email} est associée avec un compte LessPass, vous allez recevoir un email de la part de LessPass avec les instructions pour changer votre mot de passe." | |||||
} | } |
@@ -37,11 +37,7 @@ | |||||
"SorryCopy": "很抱歉,但复制功能仅适用于现代浏览器", | "SorryCopy": "很抱歉,但复制功能仅适用于现代浏览器", | ||||
"UNDO": "解开", | "UNDO": "解开", | ||||
"UpdateYourSearch": "请尝试放宽您的搜索条件。", | "UpdateYourSearch": "请尝试放宽您的搜索条件。", | ||||
"Version": "版本", | |||||
"WarningV1Deprecated": "版本 1 已不再支持,不久后将被删除。我们强烈建议您将密码迁移至版本 2。", | |||||
"WelcomeRegister": "你好 {email},欢迎您的注册。", | "WelcomeRegister": "你好 {email},欢迎您的注册。", | ||||
"Your options have been saved successfully": "您的选项已成功保存", | "Your options have been saved successfully": "您的选项已成功保存", | ||||
"resetPasswordSuccess": "如果电子邮件地址 {email} 与一个 LessPass 账户相关联,您将很快收到 LessPass 的电子邮件,里面提供有重置密码的操作说明。", | |||||
"version": "版本", | |||||
"versionShortcut": "v" | |||||
"resetPasswordSuccess": "如果电子邮件地址 {email} 与一个 LessPass 账户相关联,您将很快收到 LessPass 的电子邮件,里面提供有重置密码的操作说明。" | |||||
} | } |
@@ -37,11 +37,7 @@ | |||||
"SorryCopy": "我們很抱歉,該副本僅適用於現代瀏覽器", | "SorryCopy": "我們很抱歉,該副本僅適用於現代瀏覽器", | ||||
"UNDO": "解開", | "UNDO": "解開", | ||||
"UpdateYourSearch": "請試著放寬您的搜尋條件。", | "UpdateYourSearch": "請試著放寬您的搜尋條件。", | ||||
"Version": "版本", | |||||
"WarningV1Deprecated": "版本 1 已不支援,不久將被刪除。 我們強烈得建議您將密碼換至版本 2。", | |||||
"WelcomeRegister": "歡迎 {email},謝謝您的註冊。", | "WelcomeRegister": "歡迎 {email},謝謝您的註冊。", | ||||
"Your options have been saved successfully": "您的選項已成功保存", | "Your options have been saved successfully": "您的選項已成功保存", | ||||
"resetPasswordSuccess": "如果电子邮件地址 {email} 与LessPass帐户相关联,您将很快收到LessPass的电子邮件,并提供如何重置密码的说明。", | |||||
"version": "版本", | |||||
"versionShortcut": "v" | |||||
"resetPasswordSuccess": "如果电子邮件地址 {email} 与LessPass帐户相关联,您将很快收到LessPass的电子邮件,并提供如何重置密码的说明。" | |||||
} | } |
@@ -33,8 +33,8 @@ export const savePassword = ({ commit }, payload) => { | |||||
commit(types.SET_PASSWORD, payload); | commit(types.SET_PASSWORD, payload); | ||||
}; | }; | ||||
export const saveVersion = ({ commit }, payload) => { | |||||
commit(types.SET_VERSION, payload); | |||||
export const resetPassword = ({ commit, state }) => { | |||||
commit(types.RESET_PASSWORD); | |||||
}; | }; | ||||
export const getSite = ({ commit }) => { | export const getSite = ({ commit }) => { | ||||
@@ -53,6 +53,7 @@ export const login = ({ commit }, payload) => { | |||||
export const logout = ({ commit }) => { | export const logout = ({ commit }) => { | ||||
commit(types.LOGOUT); | commit(types.LOGOUT); | ||||
commit(types.RESET_PASSWORD); | |||||
}; | }; | ||||
export const getPasswords = ({ commit, state }) => { | export const getPasswords = ({ commit, state }) => { | ||||
@@ -4,13 +4,6 @@ export const isAuthenticated = state => state.authenticated; | |||||
export const isGuest = state => !state.authenticated; | export const isGuest = state => !state.authenticated; | ||||
export const version = state => { | |||||
if (state.password === null) { | |||||
return state.defaultPassword.version; | |||||
} | |||||
return state.password.version; | |||||
}; | |||||
export const passwordURL = state => { | export const passwordURL = state => { | ||||
return `${state.baseURL}/#/?login=${state.password.login}&site=${state | return `${state.baseURL}/#/?login=${state.password.login}&site=${state | ||||
.password.site}&uppercase=${state.password.uppercase}&lowercase=${state | .password.site}&uppercase=${state.password.uppercase}&lowercase=${state | ||||
@@ -6,7 +6,7 @@ export const SET_MESSAGE = "SET_MESSAGE"; | |||||
export const SET_PASSWORD = "SET_PASSWORD"; | export const SET_PASSWORD = "SET_PASSWORD"; | ||||
export const SET_PASSWORDS = "SET_PASSWORDS"; | export const SET_PASSWORDS = "SET_PASSWORDS"; | ||||
export const SET_TOKEN = "SET_TOKEN"; | export const SET_TOKEN = "SET_TOKEN"; | ||||
export const SET_VERSION = "SET_VERSION"; | |||||
export const RESET_PASSWORD = "RESET_PASSWORD"; | |||||
export const SET_SITE = "SET_SITE"; | export const SET_SITE = "SET_SITE"; | ||||
export const LOAD_PASSWORD_PROFILE = "LOAD_PASSWORD_PROFILE"; | export const LOAD_PASSWORD_PROFILE = "LOAD_PASSWORD_PROFILE"; | ||||
export const DELETE_PASSWORD = "DELETE_PASSWORD"; | export const DELETE_PASSWORD = "DELETE_PASSWORD"; | ||||
@@ -11,6 +11,8 @@ export default { | |||||
state.authenticated = false; | state.authenticated = false; | ||||
state.token = null; | state.token = null; | ||||
state.passwords = []; | state.passwords = []; | ||||
}, | |||||
[types.RESET_PASSWORD](state) { | |||||
state.password = { ...state.defaultPassword }; | state.password = { ...state.defaultPassword }; | ||||
}, | }, | ||||
[types.SET_PASSWORD](state, { password }) { | [types.SET_PASSWORD](state, { password }) { | ||||
@@ -33,11 +35,6 @@ export default { | |||||
[types.SET_BASE_URL](state, { baseURL }) { | [types.SET_BASE_URL](state, { baseURL }) { | ||||
state.baseURL = baseURL; | state.baseURL = baseURL; | ||||
}, | }, | ||||
[types.SET_VERSION](state, { version }) { | |||||
const length = version === 1 ? 12 : 16; | |||||
state.password.version = version; | |||||
state.password.length = length; | |||||
}, | |||||
[types.SET_SITE](state, { site }) { | [types.SET_SITE](state, { site }) { | ||||
state.password.site = site; | state.password.site = site; | ||||
}, | }, | ||||
@@ -44,8 +44,7 @@ | |||||
</div> | </div> | ||||
<div class="form-group row no-gutters mb-0"> | <div class="form-group row no-gutters mb-0"> | ||||
<div class="col"> | <div class="col"> | ||||
<button id="signInButton" class="btn btn-block" | |||||
v-bind:class="{ 'btn-warning': version===1, 'btn-primary': version===2 }"> | |||||
<button id="signInButton" class="btn btn-primary btn-block"> | |||||
{{$t('Sign In')}} | {{$t('Sign In')}} | ||||
</button> | </button> | ||||
</div> | </div> | ||||
@@ -67,7 +66,6 @@ | |||||
</template> | </template> | ||||
<script type="text/ecmascript-6"> | <script type="text/ecmascript-6"> | ||||
import User from '../api/user'; | import User from '../api/user'; | ||||
import {mapGetters} from 'vuex'; | |||||
import MasterPassword from '../components/MasterPassword.vue'; | import MasterPassword from '../components/MasterPassword.vue'; | ||||
import message from '../services/message'; | import message from '../services/message'; | ||||
@@ -82,7 +80,6 @@ | |||||
components: { | components: { | ||||
MasterPassword | MasterPassword | ||||
}, | }, | ||||
computed: mapGetters(['version']), | |||||
methods: { | methods: { | ||||
formIsValid(){ | formIsValid(){ | ||||
if (!this.email || !this.password || !this.baseURL) { | if (!this.email || !this.password || !this.baseURL) { | ||||
@@ -1,6 +1,6 @@ | |||||
<style> | <style> | ||||
#generated-password { | #generated-password { | ||||
font-family: Consolas, Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace, sans-serif; | |||||
font-family: Consolas, Menlo, Monaco, Courier New, monospace, sans-serif; | |||||
} | } | ||||
div.awesomplete { | div.awesomplete { | ||||
@@ -44,7 +44,8 @@ | |||||
</div> | </div> | ||||
</div> | </div> | ||||
<div class="form-group"> | <div class="form-group"> | ||||
<master-password ref="masterPassword" v-model="masterPassword" | |||||
<master-password ref="masterPassword" | |||||
v-model="masterPassword" | |||||
v-on:keyupEnter="generatePassword" | v-on:keyupEnter="generatePassword" | ||||
v-bind:label="$t('Master Password')"></master-password> | v-bind:label="$t('Master Password')"></master-password> | ||||
</div> | </div> | ||||
@@ -53,13 +54,12 @@ | |||||
<div v-if="!passwordGenerated"> | <div v-if="!passwordGenerated"> | ||||
<button id="generatePassword__btn" | <button id="generatePassword__btn" | ||||
type="button" | type="button" | ||||
class="btn" | |||||
v-on:click="generatePassword" | |||||
v-bind:class="{ 'btn-warning': password.version===1, 'btn-primary': password.version===2 }"> | |||||
class="btn btn-primary border-blue" | |||||
v-on:click="generatePassword"> | |||||
{{ $t('Generate') }} | {{ $t('Generate') }} | ||||
</button> | </button> | ||||
<button type="button" | <button type="button" | ||||
class="btn btn-secondary pull-right showOptions__btn" | |||||
class="btn btn-light pull-right showOptions__btn" | |||||
v-show="!passwordGenerated" | v-show="!passwordGenerated" | ||||
v-on:click="showOptions =! showOptions"> | v-on:click="showOptions =! showOptions"> | ||||
<i class="fa fa-sliders"></i> | <i class="fa fa-sliders"></i> | ||||
@@ -69,10 +69,9 @@ | |||||
<div class="input-group"> | <div class="input-group"> | ||||
<span class="input-group-btn"> | <span class="input-group-btn"> | ||||
<button id="copyPasswordButton" | <button id="copyPasswordButton" | ||||
class="btn" | |||||
class="btn btn-primary border-blue" | |||||
type="button" | type="button" | ||||
v-on:click="copyPassword()" | |||||
v-bind:class="{ 'btn-warning': password.version===1, 'btn-primary': password.version===2 }"> | |||||
v-on:click="copyPassword()"> | |||||
<i class="fa fa-clipboard"></i> | <i class="fa fa-clipboard"></i> | ||||
</button> | </button> | ||||
</span> | </span> | ||||
@@ -85,7 +84,7 @@ | |||||
<span class="input-group-btn"> | <span class="input-group-btn"> | ||||
<button id="revealGeneratedPassword" | <button id="revealGeneratedPassword" | ||||
type="button" | type="button" | ||||
class="btn btn-secondary" | |||||
class="btn btn-light" | |||||
v-on:click="togglePasswordType($refs.passwordGenerated)"> | v-on:click="togglePasswordType($refs.passwordGenerated)"> | ||||
<i class="fa fa-eye"></i> | <i class="fa fa-eye"></i> | ||||
</button> | </button> | ||||
@@ -93,14 +92,14 @@ | |||||
<span class="input-group-btn"> | <span class="input-group-btn"> | ||||
<button id="sharePasswordProfileButton" | <button id="sharePasswordProfileButton" | ||||
type="button" | type="button" | ||||
class="btn btn-secondary" | |||||
class="btn btn-light" | |||||
v-on:click="sharePasswordProfile()"> | v-on:click="sharePasswordProfile()"> | ||||
<i class="fa fa-share-alt pointer"></i> | <i class="fa fa-share-alt pointer"></i> | ||||
</button> | </button> | ||||
</span> | </span> | ||||
<span class="input-group-btn"> | <span class="input-group-btn"> | ||||
<button type="button" | <button type="button" | ||||
class="btn btn-secondary showOptions__btn" | |||||
class="btn btn-light showOptions__btn" | |||||
v-on:click="showOptions =! showOptions"> | v-on:click="showOptions =! showOptions"> | ||||
<i class="fa fa-sliders"></i> | <i class="fa fa-sliders"></i> | ||||
</button> | </button> | ||||
@@ -108,7 +107,7 @@ | |||||
</div> | </div> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
<options :options.sync="password" v-if="showOptions || !isDefaultProfile"></options> | |||||
<options v-if="showOptions || !isDefaultProfile"></options> | |||||
</form> | </form> | ||||
</template> | </template> | ||||
<script type="text/ecmascript-6"> | <script type="text/ecmascript-6"> | ||||
@@ -151,7 +150,6 @@ | |||||
return { | return { | ||||
showOptions: false, | showOptions: false, | ||||
masterPassword: '', | masterPassword: '', | ||||
fingerprint: '', | |||||
passwordGenerated: '', | passwordGenerated: '', | ||||
cleanTimeout: null | cleanTimeout: null | ||||
} | } | ||||
@@ -178,13 +176,6 @@ | |||||
this.cleanErrors(); | this.cleanErrors(); | ||||
}, | }, | ||||
deep: true | deep: true | ||||
}, | |||||
'passwordGenerated': function() { | |||||
this.cleanFormInSeconds(30); | |||||
}, | |||||
'masterPassword': function() { | |||||
this.cleanErrors(); | |||||
this.cleanFormInSeconds(30); | |||||
} | } | ||||
}, | }, | ||||
methods: { | methods: { | ||||
@@ -200,26 +191,20 @@ | |||||
this.passwordGenerated = ''; | this.passwordGenerated = ''; | ||||
}, | }, | ||||
cleanFormInSeconds(seconds = 15) { | cleanFormInSeconds(seconds = 15) { | ||||
clearTimeout(this.cleanTimeout); | |||||
this.cleanTimeout = setTimeout(() => { | this.cleanTimeout = setTimeout(() => { | ||||
this.masterPassword = ''; | this.masterPassword = ''; | ||||
this.passwordGenerated = ''; | this.passwordGenerated = ''; | ||||
this.fingerprint = ''; | |||||
}, 1000 * seconds); | }, 1000 * seconds); | ||||
}, | }, | ||||
generatePassword() { | generatePassword() { | ||||
const site = this.password.site; | const site = this.password.site; | ||||
const login = this.password.login; | const login = this.password.login; | ||||
const masterPassword = this.masterPassword; | const masterPassword = this.masterPassword; | ||||
if (!site && !login || !masterPassword) { | if (!site && !login || !masterPassword) { | ||||
message.error(this.$t('SiteLoginMasterPasswordMandatory', 'Site, login, and master password fields are mandatory.')); | message.error(this.$t('SiteLoginMasterPasswordMandatory', 'Site, login, and master password fields are mandatory.')); | ||||
return; | return; | ||||
} | } | ||||
this.cleanErrors(); | this.cleanErrors(); | ||||
this.fingerprint = this.masterPassword; | |||||
const passwordProfile = { | const passwordProfile = { | ||||
lowercase: this.password.lowercase, | lowercase: this.password.lowercase, | ||||
uppercase: this.password.uppercase, | uppercase: this.password.uppercase, | ||||
@@ -231,6 +216,7 @@ | |||||
}; | }; | ||||
return LessPass.generatePassword(site, login, masterPassword, passwordProfile).then(passwordGenerated => { | return LessPass.generatePassword(site, login, masterPassword, passwordProfile).then(passwordGenerated => { | ||||
this.passwordGenerated = passwordGenerated; | this.passwordGenerated = passwordGenerated; | ||||
this.cleanFormInSeconds(30); | |||||
}); | }); | ||||
}, | }, | ||||
focusBestInputField() { | focusBestInputField() { | ||||
@@ -249,9 +235,6 @@ | |||||
const copied = copy(this.passwordGenerated); | const copied = copy(this.passwordGenerated); | ||||
if (copied) { | if (copied) { | ||||
showTooltip(document.getElementById('copyPasswordButton'), this.$t('Copied', 'copied !')); | showTooltip(document.getElementById('copyPasswordButton'), this.$t('Copied', 'copied !')); | ||||
setTimeout(() => { | |||||
this.cleanFormInSeconds(); | |||||
}, 2000); | |||||
} else { | } else { | ||||
message.warning(this.$t('SorryCopy', 'We are sorry the copy only works on modern browsers')) | message.warning(this.$t('SorryCopy', 'We are sorry the copy only works on modern browsers')) | ||||
} | } | ||||
@@ -265,9 +248,6 @@ | |||||
copySuccessMessage, | copySuccessMessage, | ||||
'hint--top-left' | 'hint--top-left' | ||||
); | ); | ||||
setTimeout(() => { | |||||
this.cleanFormInSeconds(); | |||||
}, 2000); | |||||
} | } | ||||
else { | else { | ||||
message.warning(this.$t('SorryCopy', 'We are sorry the copy only works on modern browsers')) | message.warning(this.$t('SorryCopy', 'We are sorry the copy only works on modern browsers')) | ||||
@@ -16,8 +16,7 @@ | |||||
<div class="form-group row"> | <div class="form-group row"> | ||||
<div class="col-12"> | <div class="col-12"> | ||||
<button id="password-reset__reset-password-btn" | <button id="password-reset__reset-password-btn" | ||||
class="btn" | |||||
v-bind:class="{ 'btn-warning': version===1, 'btn-primary': version===2 }"> | |||||
class="btn btn-primary"> | |||||
{{$t('Reset my password')}} | {{$t('Reset my password')}} | ||||
</button> | </button> | ||||
</div> | </div> | ||||
@@ -26,7 +25,7 @@ | |||||
</template> | </template> | ||||
<script type="text/ecmascript-6"> | <script type="text/ecmascript-6"> | ||||
import User from '../api/user'; | import User from '../api/user'; | ||||
import {mapState, mapGetters} from 'vuex'; | |||||
import {mapState} from 'vuex'; | |||||
import message from '../services/message'; | import message from '../services/message'; | ||||
export default { | export default { | ||||
@@ -36,8 +35,7 @@ | |||||
}; | }; | ||||
}, | }, | ||||
computed: { | computed: { | ||||
...mapState(['baseURL']), | |||||
...mapGetters(['version']) | |||||
...mapState(['baseURL']) | |||||
}, | }, | ||||
methods: { | methods: { | ||||
resetPassword() { | resetPassword() { | ||||
@@ -25,8 +25,7 @@ | |||||
</div> | </div> | ||||
<div class="form-group row"> | <div class="form-group row"> | ||||
<div class="col-12"> | <div class="col-12"> | ||||
<button id="loginButton" class="btn" | |||||
v-bind:class="{ 'btn-warning': version===1, 'btn-primary': version===2 }"> | |||||
<button id="loginButton" class="btn btn-primary"> | |||||
{{$t('Reset my password')}} | {{$t('Reset my password')}} | ||||
</button> | </button> | ||||
</div> | </div> | ||||
@@ -35,14 +34,10 @@ | |||||
</template> | </template> | ||||
<script type="text/ecmascript-6"> | <script type="text/ecmascript-6"> | ||||
import User from '../api/user'; | import User from '../api/user'; | ||||
import {mapActions, mapGetters} from 'vuex'; | |||||
import message from '../services/message'; | import message from '../services/message'; | ||||
import MasterPassword from '../components/MasterPassword.vue'; | import MasterPassword from '../components/MasterPassword.vue'; | ||||
export default { | export default { | ||||
computed: { | |||||
...mapGetters(['version']) | |||||
}, | |||||
components: { | components: { | ||||
MasterPassword | MasterPassword | ||||
}, | }, | ||||
@@ -1,20 +0,0 @@ | |||||
var assert = require("assert"); | |||||
module.exports = { | |||||
"Set default options": function(browser) { | |||||
browser | |||||
.url(browser.launch_url) | |||||
.waitForElementVisible("#site") | |||||
.setValue("#site", "lesspass.com") | |||||
.setValue("#login", "test@lesspass.com") | |||||
.click(".showOptions__btn") | |||||
.waitForElementVisible("#saveOptions__btn") | |||||
.click("#saveOptions__btn") | |||||
.click("#title") | |||||
.refresh() | |||||
.assert.value("#site", "lesspass.com") | |||||
.assert.value("#login", "test@lesspass.com"); | |||||
browser.end(); | |||||
} | |||||
}; |
@@ -1,24 +1,6 @@ | |||||
import test from "ava"; | import test from "ava"; | ||||
import * as getters from "../../src/store/getters"; | import * as getters from "../../src/store/getters"; | ||||
test("version", t => { | |||||
const state = { | |||||
password: { version: 1 }, | |||||
defaultPassword: { version: 2 } | |||||
}; | |||||
const version = getters.version(state); | |||||
t.is(version, 1); | |||||
}); | |||||
test("version no password return default password version", t => { | |||||
const state = { | |||||
password: null, | |||||
defaultPassword: { version: 2 } | |||||
}; | |||||
const version = getters.version(state); | |||||
t.is(version, 2); | |||||
}); | |||||
test("passwordURL", t => { | test("passwordURL", t => { | ||||
const state = { | const state = { | ||||
password: { | password: { | ||||
@@ -13,6 +13,16 @@ test("LOGOUT", t => { | |||||
t.false(state.authenticated); | t.false(state.authenticated); | ||||
}); | }); | ||||
test("RESET_PASSWORD set default password", t => { | |||||
const RESET_PASSWORD = mutations[types.RESET_PASSWORD]; | |||||
const state = { | |||||
password: { counter: 2 }, | |||||
defaultPassword: { counter: 1 } | |||||
}; | |||||
RESET_PASSWORD(state); | |||||
t.is(state.password.counter, 1); | |||||
}); | |||||
test("LOGOUT clean user personal info", t => { | test("LOGOUT clean user personal info", t => { | ||||
const LOGOUT = mutations[types.LOGOUT]; | const LOGOUT = mutations[types.LOGOUT]; | ||||
const state = { | const state = { | ||||
@@ -24,7 +34,7 @@ test("LOGOUT clean user personal info", t => { | |||||
LOGOUT(state); | LOGOUT(state); | ||||
t.true(state.token === null); | t.true(state.token === null); | ||||
t.is(state.passwords.length, 0); | t.is(state.passwords.length, 0); | ||||
t.is(state.password.counter, 1); | |||||
t.is(state.password.counter, 2); | |||||
}); | }); | ||||
test("LOGIN", t => { | test("LOGIN", t => { | ||||
@@ -45,18 +55,18 @@ test("SET_TOKEN", t => { | |||||
test("SET_PASSWORD", t => { | test("SET_PASSWORD", t => { | ||||
const SET_PASSWORD = mutations[types.SET_PASSWORD]; | const SET_PASSWORD = mutations[types.SET_PASSWORD]; | ||||
const state = { password: null }; | const state = { password: null }; | ||||
SET_PASSWORD(state, { password: { uppercase: true, version: 2 } }); | |||||
t.is(state.password.version, 2); | |||||
SET_PASSWORD(state, { password: { uppercase: true, counter: 2 } }); | |||||
t.is(state.password.counter, 2); | |||||
t.true(state.password.uppercase); | t.true(state.password.uppercase); | ||||
}); | }); | ||||
test("SET_PASSWORD immutable", t => { | test("SET_PASSWORD immutable", t => { | ||||
const SET_PASSWORD = mutations[types.SET_PASSWORD]; | const SET_PASSWORD = mutations[types.SET_PASSWORD]; | ||||
const state = {}; | const state = {}; | ||||
const password = { version: 2 }; | |||||
const password = { counter: 2 }; | |||||
SET_PASSWORD(state, { password }); | SET_PASSWORD(state, { password }); | ||||
password.version = 1; | |||||
t.is(state.password.version, 2); | |||||
password.counter = 1; | |||||
t.is(state.password.counter, 2); | |||||
}); | }); | ||||
test("SET_DEFAULT_OPTIONS", t => { | test("SET_DEFAULT_OPTIONS", t => { | ||||
@@ -120,33 +130,6 @@ test("SET_BASE_URL", t => { | |||||
t.is(state.baseURL, baseURL); | t.is(state.baseURL, baseURL); | ||||
}); | }); | ||||
test("SET_VERSION", t => { | |||||
const SET_VERSION = mutations[types.SET_VERSION]; | |||||
const state = { | |||||
password: { version: 2 } | |||||
}; | |||||
SET_VERSION(state, { version: 1 }); | |||||
t.is(state.password.version, 1); | |||||
}); | |||||
test("SET_VERSION 1 should modify length to 12", t => { | |||||
const SET_VERSION = mutations[types.SET_VERSION]; | |||||
const state = { | |||||
password: { length: 16, version: 2 } | |||||
}; | |||||
SET_VERSION(state, { version: 1 }); | |||||
t.is(state.password.length, 12); | |||||
}); | |||||
test("SET_VERSION 2 should modify length to 16", t => { | |||||
const SET_VERSION = mutations[types.SET_VERSION]; | |||||
const state = { | |||||
password: { length: 12, version: 1 } | |||||
}; | |||||
SET_VERSION(state, { version: 2 }); | |||||
t.is(state.password.length, 16); | |||||
}); | |||||
test("LOAD_PASSWORD_PROFILE", t => { | test("LOAD_PASSWORD_PROFILE", t => { | ||||
const state = { | const state = { | ||||
password: { | password: { | ||||
@@ -253,7 +236,7 @@ test("LOAD_PASSWORD_PROFILE with no site keep password profile", t => { | |||||
site: "example.org", | site: "example.org", | ||||
login: "contact@example.org", | login: "contact@example.org", | ||||
length: 8, | length: 8, | ||||
version: 1 | |||||
version: 2 | |||||
}, | }, | ||||
defaultPassword: { | defaultPassword: { | ||||
login: "", | login: "", | ||||
@@ -265,7 +248,7 @@ test("LOAD_PASSWORD_PROFILE with no site keep password profile", t => { | |||||
t.is(state.password.site, "example.org"); | t.is(state.password.site, "example.org"); | ||||
t.is(state.password.login, "contact@example.org"); | t.is(state.password.login, "contact@example.org"); | ||||
t.is(state.password.length, 8); | t.is(state.password.length, 8); | ||||
t.is(state.password.version, 1); | |||||
t.is(state.password.version, 2); | |||||
}); | }); | ||||
test("LOAD_PASSWORD_PROFILE no passwords", t => { | test("LOAD_PASSWORD_PROFILE no passwords", t => { | ||||