fix https://github.com/lesspass/lesspass/issues/142pull/342/head
@@ -27,6 +27,9 @@ | |||||
<span v-on:click="saveOrUpdatePassword" class="white-link" v-else> | <span v-on:click="saveOrUpdatePassword" class="white-link" v-else> | ||||
<i class="fa fa-lg fa-save fa-clickable"></i> | <i class="fa fa-lg fa-save fa-clickable"></i> | ||||
</span> | </span> | ||||
<router-link class="white-link pl-2" :to="{ name: 'configureOptions'}"> | |||||
<i class="fa fa-lg fa-cog" aria-hidden="true"></i> | |||||
</router-link> | |||||
<router-link class="white-link pl-2" :to="{ name: 'passwords'}"> | <router-link class="white-link pl-2" :to="{ name: 'passwords'}"> | ||||
<i class="fa fa-lg fa-key" aria-hidden="true"></i> | <i class="fa fa-lg fa-key" aria-hidden="true"></i> | ||||
</router-link> | </router-link> | ||||
@@ -43,6 +46,9 @@ | |||||
<router-link class="white-link" :to="{ name: 'home'}">LessPass</router-link> | <router-link class="white-link" :to="{ name: 'home'}">LessPass</router-link> | ||||
</div> | </div> | ||||
<div class="col-6 text-right"> | <div class="col-6 text-right"> | ||||
<router-link class="white-link pl-2" :to="{ name: 'configureOptions'}"> | |||||
<i class="fa fa-lg fa-cog" aria-hidden="true"></i> | |||||
</router-link> | |||||
<router-link class="white-link pl-1" :to="{ name: 'login'}"> | <router-link class="white-link pl-1" :to="{ name: 'login'}"> | ||||
<i class="fa fa-lg fa-user-secret fa-clickable" aria-hidden="true"></i> | <i class="fa fa-lg fa-user-secret fa-clickable" aria-hidden="true"></i> | ||||
</router-link> | </router-link> | ||||
@@ -0,0 +1,98 @@ | |||||
<template> | |||||
<div> | |||||
<div class="form-group row no-gutters pt-3"> | |||||
<div class="col col-sm-2"> | |||||
<label class="custom-control custom-checkbox mr-0"> | |||||
<input type="checkbox" class="custom-control-input" id="lowercase" v-model="options.lowercase"> | |||||
<span class="custom-control-indicator"></span> | |||||
<span class="custom-control-description">abc</span> | |||||
</label> | |||||
</div> | |||||
<div class="col col-sm-2 text-center"> | |||||
<label class="custom-control custom-checkbox mr-0"> | |||||
<input type="checkbox" class="custom-control-input" id="uppercase" v-model="options.uppercase"> | |||||
<span class="custom-control-indicator"></span> | |||||
<span class="custom-control-description">ABC</span> | |||||
</label> | |||||
</div> | |||||
<div class="col col-sm-2 text-center"> | |||||
<label class="custom-control custom-checkbox mr-0"> | |||||
<input type="checkbox" class="custom-control-input" id="numbers" v-model="options.numbers"> | |||||
<span class="custom-control-indicator"></span> | |||||
<span class="custom-control-description">123</span> | |||||
</label> | |||||
</div> | |||||
<div class="col col-sm-2 text-right"> | |||||
<label class="custom-control custom-checkbox mr-0"> | |||||
<input type="checkbox" class="custom-control-input" id="symbols" v-model="options.symbols"> | |||||
<span class="custom-control-indicator"></span> | |||||
<span class="custom-control-description">%!@</span> | |||||
</label> | |||||
</div> | |||||
</div> | |||||
<div class="form-group row"> | |||||
<div class="col-4"> | |||||
<label for="passwordLength"> | |||||
Length | |||||
</label> | |||||
<input id="passwordLength" class="form-control form-control-sm" type="number" | |||||
v-model="options.length" min="5" max="35"> | |||||
</div> | |||||
<div class="col-4 text-center text-sm-left"> | |||||
<label for="passwordCounter"> | |||||
Counter | |||||
</label> | |||||
<input id="passwordCounter" class="form-control form-control-sm" type="number" | |||||
v-model="options.counter" min="1"> | |||||
</div> | |||||
<div class="col-4 text-sm-left text-right"> | |||||
<label>Version</label> | |||||
<br> | |||||
<div class="btn-group btn-group-sm"> | |||||
<button type="button" class="btn" | |||||
v-bind:class="{'btn-primary':options.version===2,'btn-secondary':options.version!==2}" | |||||
v-on:click="setVersion(2)"> | |||||
v2 | |||||
</button> | |||||
<button type="button" class="btn" | |||||
v-bind:class="{'btn-warning':options.version===1,'btn-secondary':options.version!==1}" | |||||
v-on:click="setVersion(1)"> | |||||
v1 | |||||
</button> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</template> | |||||
<script type="text/ecmascript-6"> | |||||
export default { | |||||
name: 'options', | |||||
props: { | |||||
password: { | |||||
type: Object, | |||||
required: true | |||||
} | |||||
}, | |||||
data() { | |||||
return { | |||||
options: this.password | |||||
}; | |||||
}, | |||||
watch: { | |||||
options: { | |||||
handler: function (newOptions) { | |||||
this.$emit('optionsUpdated', newOptions) | |||||
}, | |||||
deep: true | |||||
} | |||||
}, | |||||
methods: { | |||||
setVersion(value){ | |||||
this.options.version = value; | |||||
this.$store.dispatch('saveVersion', {version: value}); | |||||
} | |||||
} | |||||
} | |||||
</script> |
@@ -1,36 +0,0 @@ | |||||
<template> | |||||
<div> | |||||
<label>Version</label> | |||||
<br> | |||||
<div class="btn-group" v-bind:class="{'btn-group-sm':small}"> | |||||
<button type="button" class="btn" | |||||
v-bind:class="{'btn-primary':version===2,'btn-secondary':version!==2}" v-on:click="setVersion(2)"> | |||||
v2 | |||||
</button> | |||||
<button type="button" class="btn" | |||||
v-bind:class="{'btn-warning':version===1,'btn-secondary':version!==1}" v-on:click="setVersion(1)"> | |||||
v1 | |||||
</button> | |||||
</div> | |||||
</div> | |||||
</template> | |||||
<script type="text/ecmascript-6"> | |||||
import {mapGetters} from 'vuex'; | |||||
export default { | |||||
props: { | |||||
small: { | |||||
type: Boolean, | |||||
default: true | |||||
} | |||||
}, | |||||
computed: { | |||||
...mapGetters(['version']) | |||||
}, | |||||
methods: { | |||||
setVersion(value){ | |||||
this.$store.dispatch('saveVersion', {version: value}); | |||||
} | |||||
} | |||||
} | |||||
</script> | |||||
@@ -1,8 +1,9 @@ | |||||
import Vue from 'vue'; | import Vue from 'vue'; | ||||
import VueRouter from 'vue-router'; | import VueRouter from 'vue-router'; | ||||
import PasswordGenerator from './views/PasswordGenerator.vue'; | |||||
import ConfigureOptions from './views/ConfigureOptions.vue'; | |||||
import Login from './views/Login.vue'; | import Login from './views/Login.vue'; | ||||
import PasswordGenerator from './views/PasswordGenerator.vue'; | |||||
import PasswordReset from './views/PasswordReset.vue'; | import PasswordReset from './views/PasswordReset.vue'; | ||||
import PasswordResetConfirm from './views/PasswordResetConfirm.vue'; | import PasswordResetConfirm from './views/PasswordResetConfirm.vue'; | ||||
import Passwords from './views/Passwords.vue'; | import Passwords from './views/Passwords.vue'; | ||||
@@ -13,6 +14,7 @@ const routes = [ | |||||
{path: '/', name: 'home', component: PasswordGenerator}, | {path: '/', name: 'home', component: PasswordGenerator}, | ||||
{path: '/login', name: 'login', component: Login}, | {path: '/login', name: 'login', component: Login}, | ||||
{path: '/passwords/', name: 'passwords', component: Passwords}, | {path: '/passwords/', name: 'passwords', component: Passwords}, | ||||
{path: '/options/default/', name: 'configureOptions', component: ConfigureOptions}, | |||||
{path: '/passwords/:id', name: 'password', component: PasswordGenerator}, | {path: '/passwords/:id', name: 'password', component: PasswordGenerator}, | ||||
{path: '/password/reset', name: 'passwordReset', component: PasswordReset}, | {path: '/password/reset', name: 'passwordReset', component: PasswordReset}, | ||||
{path: '/password/reset/confirm/:uid/:token', name: 'passwordResetConfirm', component: PasswordResetConfirm}, | {path: '/password/reset/confirm/:uid/:token', name: 'passwordResetConfirm', component: PasswordResetConfirm}, | ||||
@@ -0,0 +1,51 @@ | |||||
<template> | |||||
<div> | |||||
<h4>Default Options</h4> | |||||
<small class="help-text">default options are saved locally</small> | |||||
<options v-bind:password="defaultPassword" v-on:optionsUpdated="updatePassword"></options> | |||||
<div class="form-group"> | |||||
<button type="button" class="btn btn-primary" v-on:click="saveDefault"> | |||||
<span v-if="optionsSaved"> | |||||
<i class="fa fa-check" aria-hidden="true"></i> saved | |||||
</span> | |||||
<span v-else> | |||||
save as default options | |||||
</span> | |||||
</button> | |||||
</div> | |||||
</div> | |||||
</template> | |||||
<script type="text/ecmascript-6"> | |||||
import {mapGetters} from 'vuex'; | |||||
import Options from '../components/Options.vue'; | |||||
export default { | |||||
name: 'configure-options-view', | |||||
components: { | |||||
Options | |||||
}, | |||||
computed: mapGetters(['defaultPassword']), | |||||
data(){ | |||||
return { | |||||
options: null, | |||||
optionsSaved: false | |||||
} | |||||
}, | |||||
methods: { | |||||
saveDefault(){ | |||||
if (this.options !== null) { | |||||
this.$store.dispatch('saveDefaultPassword', {password: this.options}); | |||||
} | |||||
this.optionsSaved = true; | |||||
setTimeout(() => { | |||||
this.optionsSaved = false; | |||||
}, 3000); | |||||
}, | |||||
updatePassword(password){ | |||||
console.log(password); | |||||
this.options = password; | |||||
} | |||||
} | |||||
} | |||||
</script> |
@@ -64,9 +64,6 @@ | |||||
</small> | </small> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
<div class="col-sm-4 col mt-3"> | |||||
<version-button :small="false"></version-button> | |||||
</div> | |||||
</div> | </div> | ||||
<div class="form-group my-0"> | <div class="form-group my-0"> | ||||
<router-link :to="{ name: 'passwordReset'}"> | <router-link :to="{ name: 'passwordReset'}"> | ||||
@@ -82,7 +79,6 @@ | |||||
import {mapGetters} from 'vuex'; | import {mapGetters} from 'vuex'; | ||||
import MasterPassword from '../components/MasterPassword.vue'; | import MasterPassword from '../components/MasterPassword.vue'; | ||||
import OptionsButton from '../components/OptionsButton.vue'; | import OptionsButton from '../components/OptionsButton.vue'; | ||||
import VersionButton from '../components/VersionButton.vue'; | |||||
const defaultErrors = { | const defaultErrors = { | ||||
userNameAlreadyExist: false, | userNameAlreadyExist: false, | ||||
@@ -111,8 +107,7 @@ | |||||
}, | }, | ||||
components: { | components: { | ||||
MasterPassword, | MasterPassword, | ||||
OptionsButton, | |||||
VersionButton | |||||
OptionsButton | |||||
}, | }, | ||||
computed: { | computed: { | ||||
...mapGetters(['version']) | ...mapGetters(['version']) | ||||
@@ -130,9 +125,9 @@ | |||||
uppercase: true, | uppercase: true, | ||||
numbers: true, | numbers: true, | ||||
symbols: true, | symbols: true, | ||||
length: this.version == 2 ? 16 : 12, | |||||
length: 16, | |||||
counter: 1, | counter: 1, | ||||
version: this.version, | |||||
version: 2, | |||||
}; | }; | ||||
return LessPass.generatePassword('lesspass.com', this.email, this.password, defaultPasswordProfile).then(generatedPassword => { | return LessPass.generatePassword('lesspass.com', this.email, this.password, defaultPasswordProfile).then(generatedPassword => { | ||||
this.password = generatedPassword; | this.password = generatedPassword; | ||||
@@ -113,75 +113,17 @@ | |||||
<options-button v-on:click.native="showOptions=!showOptions"></options-button> | <options-button v-on:click.native="showOptions=!showOptions"></options-button> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
<div class="form-group row no-gutters pt-3" v-if="showOptions"> | |||||
<div class="col col-sm-2"> | |||||
<label class="custom-control custom-checkbox mr-0"> | |||||
<input type="checkbox" class="custom-control-input" id="lowercase" v-model="password.lowercase"> | |||||
<span class="custom-control-indicator"></span> | |||||
<span class="custom-control-description">abc</span> | |||||
</label> | |||||
</div> | |||||
<div class="col col-sm-2 text-center"> | |||||
<label class="custom-control custom-checkbox mr-0"> | |||||
<input type="checkbox" class="custom-control-input" id="uppercase" v-model="password.uppercase"> | |||||
<span class="custom-control-indicator"></span> | |||||
<span class="custom-control-description">ABC</span> | |||||
</label> | |||||
</div> | |||||
<div class="col col-sm-2 text-center"> | |||||
<label class="custom-control custom-checkbox mr-0"> | |||||
<input type="checkbox" class="custom-control-input" id="numbers" v-model="password.numbers"> | |||||
<span class="custom-control-indicator"></span> | |||||
<span class="custom-control-description">123</span> | |||||
</label> | |||||
</div> | |||||
<div class="col col-sm-2 text-right"> | |||||
<label class="custom-control custom-checkbox mr-0"> | |||||
<input type="checkbox" class="custom-control-input" id="symbols" v-model="password.symbols"> | |||||
<span class="custom-control-indicator"></span> | |||||
<span class="custom-control-description">%!@</span> | |||||
</label> | |||||
</div> | |||||
</div> | |||||
<div class="form-group row" v-if="showOptions"> | |||||
<div class="col-4"> | |||||
<label for="passwordLength"> | |||||
Length | |||||
</label> | |||||
<input class="form-control form-control-sm" type="number" id="passwordLength" | |||||
v-model="password.length" min="5" max="35"> | |||||
</div> | |||||
<div class="col-4 text-center text-sm-left"> | |||||
<label for="passwordCounter"> | |||||
Counter | |||||
</label> | |||||
<input class="form-control form-control-sm" type="number" id="passwordCounter" | |||||
v-model="password.counter" min="1"> | |||||
</div> | |||||
<div class="col-4 text-sm-left text-right"> | |||||
<version-button class="mr-1"></version-button> | |||||
</div> | |||||
</div> | |||||
<options :password="password" v-on:optionsUpdated="updatePassword" v-if="showOptions"></options> | |||||
<div class="form-group" v-if="showOptions"> | <div class="form-group" v-if="showOptions"> | ||||
<div class="input-group input-group-sm"> | <div class="input-group input-group-sm"> | ||||
<span class="input-group-btn btn-copy" data-clipboard-target="#passwordURL" > | |||||
<button class="btn btn-secondary"type="button"> | |||||
<span class="input-group-btn btn-copy" data-clipboard-target="#passwordURL"> | |||||
<button class="btn btn-secondary" type="button"> | |||||
<i class="fa fa-share-alt" aria-hidden="true"></i> | <i class="fa fa-share-alt" aria-hidden="true"></i> | ||||
</button> | </button> | ||||
</span> | </span> | ||||
<input id="passwordURL" type="text" class="form-control" v-model="passwordURL"> | <input id="passwordURL" type="text" class="form-control" v-model="passwordURL"> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
<div class="form-group" v-if="showOptions"> | |||||
<button type="button" class="btn btn-secondary btn-sm" v-on:click="saveDefault"> | |||||
<span v-if="optionsSaved" class="text-success"> | |||||
<i class="fa fa-check" aria-hidden="true"></i> saved | |||||
</span> | |||||
<span v-else> | |||||
save as default options | |||||
</span> | |||||
</button> | |||||
</div> | |||||
<div class="form-group mt-3" v-if="showError"> | <div class="form-group mt-3" v-if="showError"> | ||||
<div class="alert alert-danger" role="alert"> | <div class="alert alert-danger" role="alert"> | ||||
site, login and master password fields are mandatory | site, login and master password fields are mandatory | ||||
@@ -197,8 +139,8 @@ | |||||
import {getSite, getPasswordFromUrlQuery} from '../domain/url-parser'; | import {getSite, getPasswordFromUrlQuery} from '../domain/url-parser'; | ||||
import RemoveAutoComplete from '../components/RemoveAutoComplete.vue'; | import RemoveAutoComplete from '../components/RemoveAutoComplete.vue'; | ||||
import MasterPassword from '../components/MasterPassword.vue'; | import MasterPassword from '../components/MasterPassword.vue'; | ||||
import VersionButton from '../components/VersionButton.vue'; | |||||
import OptionsButton from '../components/OptionsButton.vue'; | import OptionsButton from '../components/OptionsButton.vue'; | ||||
import Options from '../components/Options.vue'; | |||||
function fetchPasswords(store) { | function fetchPasswords(store) { | ||||
return store.dispatch('getPasswords') | return store.dispatch('getPasswords') | ||||
@@ -218,7 +160,7 @@ | |||||
components: { | components: { | ||||
RemoveAutoComplete, | RemoveAutoComplete, | ||||
MasterPassword, | MasterPassword, | ||||
VersionButton, | |||||
Options, | |||||
OptionsButton | OptionsButton | ||||
}, | }, | ||||
computed: mapGetters(['passwords', 'password', 'passwordURL']), | computed: mapGetters(['passwords', 'password', 'passwordURL']), | ||||
@@ -268,8 +210,7 @@ | |||||
cleanTimeout: null, | cleanTimeout: null, | ||||
showOptions: false, | showOptions: false, | ||||
showError: false, | showError: false, | ||||
generatingPassword: false, | |||||
optionsSaved: false | |||||
generatingPassword: false | |||||
} | } | ||||
}, | }, | ||||
watch: { | watch: { | ||||
@@ -292,24 +233,6 @@ | |||||
'password.login': function () { | 'password.login': function () { | ||||
this.cleanErrors(); | this.cleanErrors(); | ||||
}, | }, | ||||
'password.uppercase': function () { | |||||
this.cleanErrors(); | |||||
}, | |||||
'password.lowercase': function () { | |||||
this.cleanErrors(); | |||||
}, | |||||
'password.numbers': function () { | |||||
this.cleanErrors(); | |||||
}, | |||||
'password.symbols': function () { | |||||
this.cleanErrors(); | |||||
}, | |||||
'password.length': function () { | |||||
this.cleanErrors(); | |||||
}, | |||||
'password.counter': function () { | |||||
this.cleanErrors(); | |||||
}, | |||||
'generatedPassword': function () { | 'generatedPassword': function () { | ||||
this.cleanFormInSeconds(30); | this.cleanFormInSeconds(30); | ||||
}, | }, | ||||
@@ -370,12 +293,9 @@ | |||||
window.document.getElementById('copyPasswordButton').setAttribute('data-clipboard-text', generatedPassword); | window.document.getElementById('copyPasswordButton').setAttribute('data-clipboard-text', generatedPassword); | ||||
}); | }); | ||||
}, | }, | ||||
saveDefault(){ | |||||
this.$store.dispatch('saveDefaultPassword', {password: this.password}); | |||||
this.optionsSaved = true; | |||||
setTimeout(() => { | |||||
this.optionsSaved = false; | |||||
}, 3000); | |||||
updatePassword(password){ | |||||
this.cleanErrors(); | |||||
this.$store.dispatch('savePassword', {password: password}); | |||||
} | } | ||||
} | } | ||||
} | } | ||||