* Load loadBestPasswordProfile when not connected * Dont load previous password profile is last used < 1 minute * Load default password profile if site different * Keep existing password profile if no site Fixes: https://github.com/lesspass/lesspass/issues/265pull/342/head
@@ -16,16 +16,9 @@ export const saveDefaultOptions = ({ commit }, payload) => { | |||||
commit(types.SET_DEFAULT_OPTIONS, payload); | commit(types.SET_DEFAULT_OPTIONS, payload); | ||||
}; | }; | ||||
export const passwordGenerated = ({ commit }) => { | |||||
commit(types.PASSWORD_GENERATED); | |||||
}; | |||||
export const loadBestPasswordProfile = ({ commit }) => { | export const loadBestPasswordProfile = ({ commit }) => { | ||||
urlParser.getSite().then(site => { | urlParser.getSite().then(site => { | ||||
if (site) { | |||||
commit(types.SET_SITE, { site }); | |||||
commit(types.LOAD_PASSWORD_PROFILE, { site }); | |||||
} | |||||
commit(types.LOAD_PASSWORD_PROFILE, { site }); | |||||
}); | }); | ||||
}; | }; | ||||
@@ -64,12 +57,13 @@ export const logout = ({ commit }) => { | |||||
export const getPasswords = ({ commit, state }) => { | export const getPasswords = ({ commit, state }) => { | ||||
if (state.authenticated) { | if (state.authenticated) { | ||||
Password.all(state) | |||||
.then(response => { | |||||
commit(types.SET_PASSWORDS, { passwords: response.data.results }); | |||||
}) | |||||
.then(() => loadBestPasswordProfile({ commit })); | |||||
return Password.all(state).then(response => { | |||||
const passwords = response.data.results; | |||||
commit(types.SET_PASSWORDS, { passwords }); | |||||
return passwords; | |||||
}); | |||||
} | } | ||||
return Promise.resolve([]); | |||||
}; | }; | ||||
export const saveOrUpdatePassword = ({ commit, state }) => { | export const saveOrUpdatePassword = ({ commit, state }) => { | ||||
@@ -13,7 +13,6 @@ const state = { | |||||
password: defaultPassword, | password: defaultPassword, | ||||
passwords: [], | passwords: [], | ||||
defaultPassword: defaultPassword, | defaultPassword: defaultPassword, | ||||
lastUse: null, | |||||
showOptions: false, | showOptions: false, | ||||
token: null, | token: null, | ||||
baseURL: "https://lesspass.com" | baseURL: "https://lesspass.com" | ||||
@@ -1,6 +1,5 @@ | |||||
export const LOGOUT = "LOGOUT"; | export const LOGOUT = "LOGOUT"; | ||||
export const LOGIN = "LOGIN"; | export const LOGIN = "LOGIN"; | ||||
export const PASSWORD_GENERATED = "PASSWORD_GENERATED"; | |||||
export const SET_BASE_URL = "SET_BASE_URL"; | export const SET_BASE_URL = "SET_BASE_URL"; | ||||
export const SET_DEFAULT_OPTIONS = "SET_DEFAULT_OPTIONS"; | export const SET_DEFAULT_OPTIONS = "SET_DEFAULT_OPTIONS"; | ||||
export const SET_MESSAGE = "SET_MESSAGE"; | export const SET_MESSAGE = "SET_MESSAGE"; | ||||
@@ -16,9 +16,6 @@ export default { | |||||
[types.SET_PASSWORD](state, { password }) { | [types.SET_PASSWORD](state, { password }) { | ||||
state.password = { ...password }; | state.password = { ...password }; | ||||
}, | }, | ||||
[types.PASSWORD_GENERATED](state) { | |||||
state.lastUse = new Date().getTime(); | |||||
}, | |||||
[types.SET_DEFAULT_OPTIONS](state, { options }) { | [types.SET_DEFAULT_OPTIONS](state, { options }) { | ||||
state.defaultPassword = Object.assign({}, state.defaultPassword, options); | state.defaultPassword = Object.assign({}, state.defaultPassword, options); | ||||
}, | }, | ||||
@@ -45,9 +42,8 @@ export default { | |||||
state.password.site = site; | state.password.site = site; | ||||
}, | }, | ||||
[types.LOAD_PASSWORD_PROFILE](state, { site }) { | [types.LOAD_PASSWORD_PROFILE](state, { site }) { | ||||
const oneMinuteAgo = new Date().getTime() - 60 * 1000; | |||||
const siteDontMatch = !(site && site.endsWith(state.password.site)); | |||||
if (state.lastUse < oneMinuteAgo || siteDontMatch) { | |||||
const siteDontMatch = site && !site.endsWith(state.password.site); | |||||
if (siteDontMatch) { | |||||
state.password = { ...state.defaultPassword }; | state.password = { ...state.defaultPassword }; | ||||
} | } | ||||
const passwords = state.passwords || []; | const passwords = state.passwords || []; | ||||
@@ -45,7 +45,7 @@ | |||||
</div> | </div> | ||||
<div class="form-group"> | <div class="form-group"> | ||||
<master-password ref="masterPassword" v-model="masterPassword" | <master-password ref="masterPassword" v-model="masterPassword" | ||||
:keyupEnter="generatePassword" | |||||
v-on:keyupEnter="generatePassword" | |||||
v-bind:label="$t('Master Password')"></master-password> | v-bind:label="$t('Master Password')"></master-password> | ||||
</div> | </div> | ||||
<div class="form-group" | <div class="form-group" | ||||
@@ -111,7 +111,6 @@ | |||||
<options :options.sync="password" v-if="showOptions || !isDefaultProfile"></options> | <options :options.sync="password" v-if="showOptions || !isDefaultProfile"></options> | ||||
</form> | </form> | ||||
</template> | </template> | ||||
<script type="text/ecmascript-6"> | <script type="text/ecmascript-6"> | ||||
import LessPass from 'lesspass'; | import LessPass from 'lesspass'; | ||||
import {mapGetters, mapState} from 'vuex'; | import {mapGetters, mapState} from 'vuex'; | ||||
@@ -135,9 +134,13 @@ | |||||
...mapGetters(['passwordURL', 'isDefaultProfile']) | ...mapGetters(['passwordURL', 'isDefaultProfile']) | ||||
}, | }, | ||||
beforeMount() { | beforeMount() { | ||||
this.$store.dispatch('getPasswords'); | |||||
this.$store.dispatch('getSite'); | |||||
this.$store.dispatch('getPasswordFromUrlQuery', {query: this.$route.query}); | |||||
this.$store | |||||
.dispatch('getPasswords') | |||||
.then(() => { | |||||
this.$store.dispatch('loadBestPasswordProfile'); | |||||
this.$store.dispatch('getSite'); | |||||
this.$store.dispatch('getPasswordFromUrlQuery', {query: this.$route.query}); | |||||
}); | |||||
}, | }, | ||||
mounted() { | mounted() { | ||||
setTimeout(() => { | setTimeout(() => { | ||||
@@ -228,7 +231,6 @@ | |||||
}; | }; | ||||
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.$store.dispatch('passwordGenerated'); | |||||
}); | }); | ||||
}, | }, | ||||
focusBestInputField() { | focusBestInputField() { | ||||
@@ -50,28 +50,6 @@ test("SET_PASSWORD", t => { | |||||
t.true(state.password.uppercase); | t.true(state.password.uppercase); | ||||
}); | }); | ||||
test("SET_PASSWORD dont change lastUse date", t => { | |||||
const SET_PASSWORD = mutations[types.SET_PASSWORD]; | |||||
const now = 1485989236000; | |||||
const time = new Date(now); | |||||
timekeeper.freeze(time); | |||||
const state = { lastUse: null, password: null }; | |||||
SET_PASSWORD(state, { password: {} }); | |||||
t.true(state.lastUse === null); | |||||
timekeeper.reset(); | |||||
}); | |||||
test("PASSWORD_GENERATED change lastUse date", t => { | |||||
const PASSWORD_GENERATED = mutations[types.PASSWORD_GENERATED]; | |||||
const now = 1485989236000; | |||||
const time = new Date(now); | |||||
timekeeper.freeze(time); | |||||
const state = { lastUse: null }; | |||||
PASSWORD_GENERATED(state); | |||||
t.is(now, state.lastUse); | |||||
timekeeper.reset(); | |||||
}); | |||||
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 = {}; | ||||
@@ -238,98 +216,19 @@ test("LOAD_PASSWORD_PROFILE", t => { | |||||
t.deepEqual(state.password, state.passwords[1]); | t.deepEqual(state.password, state.passwords[1]); | ||||
}); | }); | ||||
test("LOAD_PASSWORD_PROFILE 30 seconds after last use", t => { | |||||
const now = 1485989236000; | |||||
const time = new Date(now); | |||||
timekeeper.freeze(time); | |||||
const thirtySecondBefore = now - 30 * 1000; | |||||
const state = { | |||||
lastUse: thirtySecondBefore, | |||||
password: { | |||||
site: "example.org", | |||||
login: "test@example.org", | |||||
length: 30 | |||||
}, | |||||
defaultPassword: { | |||||
login: "", | |||||
length: 16 | |||||
} | |||||
}; | |||||
const LOAD_PASSWORD_PROFILE = mutations[types.LOAD_PASSWORD_PROFILE]; | |||||
LOAD_PASSWORD_PROFILE(state, { site: "example.org" }); | |||||
t.is(state.password.login, "test@example.org"); | |||||
t.is(state.password.length, 30); | |||||
timekeeper.reset(); | |||||
}); | |||||
test("LOAD_PASSWORD_PROFILE 30 seconds after last use on different site #242", t => { | |||||
const now = 1485989236000; | |||||
const time = new Date(now); | |||||
timekeeper.freeze(time); | |||||
const thirtySecondBefore = now - 30 * 1000; | |||||
test("LOAD_PASSWORD_PROFILE on different site", t => { | |||||
const state = { | const state = { | ||||
lastUse: thirtySecondBefore, | |||||
password: { | password: { | ||||
site: "example.org", | site: "example.org", | ||||
login: "test@example.org", | |||||
length: 30 | |||||
login: "test@example.org" | |||||
}, | }, | ||||
defaultPassword: { | defaultPassword: { | ||||
login: "", | |||||
length: 16 | |||||
login: "" | |||||
} | } | ||||
}; | }; | ||||
const LOAD_PASSWORD_PROFILE = mutations[types.LOAD_PASSWORD_PROFILE]; | const LOAD_PASSWORD_PROFILE = mutations[types.LOAD_PASSWORD_PROFILE]; | ||||
LOAD_PASSWORD_PROFILE(state, { site: "lesspass.com" }); | LOAD_PASSWORD_PROFILE(state, { site: "lesspass.com" }); | ||||
t.is(state.password.login, ""); | t.is(state.password.login, ""); | ||||
t.is(state.password.length, 16); | |||||
timekeeper.reset(); | |||||
}); | |||||
test("LOAD_PASSWORD_PROFILE more than 1 minute after last use", t => { | |||||
const now = 1485989236000; | |||||
const time = new Date(now); | |||||
timekeeper.freeze(time); | |||||
const oneMinuteAndOneSecond = now - 61 * 1000; | |||||
const state = { | |||||
lastUse: oneMinuteAndOneSecond, | |||||
password: { | |||||
site: "example.org", | |||||
login: "test@example.org", | |||||
length: 30 | |||||
}, | |||||
defaultPassword: { | |||||
login: "", | |||||
length: 16 | |||||
} | |||||
}; | |||||
const LOAD_PASSWORD_PROFILE = mutations[types.LOAD_PASSWORD_PROFILE]; | |||||
LOAD_PASSWORD_PROFILE(state, { site: "example.org" }); | |||||
t.is(state.password.login, ""); | |||||
t.is(state.password.length, 16); | |||||
timekeeper.reset(); | |||||
}); | |||||
test("LOAD_PASSWORD_PROFILE empty login", t => { | |||||
const state = { | |||||
lastUse: null, | |||||
password: { | |||||
site: "", | |||||
login: "", | |||||
version: 1 | |||||
}, | |||||
passwords: [], | |||||
defaultPassword: { | |||||
site: "", | |||||
login: "", | |||||
version: 2 | |||||
} | |||||
}; | |||||
const LOAD_PASSWORD_PROFILE = mutations[types.LOAD_PASSWORD_PROFILE]; | |||||
LOAD_PASSWORD_PROFILE(state, { site: "example.org" }); | |||||
t.is(state.password.login, ""); | |||||
t.is(state.password.version, 2); | |||||
timekeeper.reset(); | |||||
}); | }); | ||||
test("LOAD_PASSWORD_PROFILE with passwords", t => { | test("LOAD_PASSWORD_PROFILE with passwords", t => { | ||||
@@ -348,7 +247,7 @@ test("LOAD_PASSWORD_PROFILE with passwords", t => { | |||||
t.is(state.password.site, "www.google.com"); | t.is(state.password.site, "www.google.com"); | ||||
}); | }); | ||||
test("LOAD_PASSWORD_PROFILE with no site reset default", t => { | |||||
test("LOAD_PASSWORD_PROFILE with no site keep password profile", t => { | |||||
const state = { | const state = { | ||||
password: { | password: { | ||||
site: "example.org", | site: "example.org", | ||||
@@ -363,8 +262,10 @@ test("LOAD_PASSWORD_PROFILE with no site reset default", t => { | |||||
}; | }; | ||||
const LOAD_PASSWORD_PROFILE = mutations[types.LOAD_PASSWORD_PROFILE]; | const LOAD_PASSWORD_PROFILE = mutations[types.LOAD_PASSWORD_PROFILE]; | ||||
LOAD_PASSWORD_PROFILE(state, { site: "" }); | LOAD_PASSWORD_PROFILE(state, { site: "" }); | ||||
t.is(state.password.login, ""); | |||||
t.is(state.password.length, 16); | |||||
t.is(state.password.site, "example.org"); | |||||
t.is(state.password.login, "contact@example.org"); | |||||
t.is(state.password.length, 8); | |||||
t.is(state.password.version, 1); | |||||
}); | }); | ||||
test("LOAD_PASSWORD_PROFILE no passwords", t => { | test("LOAD_PASSWORD_PROFILE no passwords", t => { | ||||