@@ -52,6 +52,7 @@ | |||||
"optimize-css-assets-webpack-plugin": "^1.3.0", | "optimize-css-assets-webpack-plugin": "^1.3.0", | ||||
"sass-loader": "^4.1.1", | "sass-loader": "^4.1.1", | ||||
"style-loader": "^0.13.1", | "style-loader": "^0.13.1", | ||||
"timekeeper": "^1.0.0", | |||||
"url-loader": "^0.5.7", | "url-loader": "^0.5.7", | ||||
"vue-loader": "^10.1.0", | "vue-loader": "^10.1.0", | ||||
"vue-template-compiler": "^2.1.10", | "vue-template-compiler": "^2.1.10", | ||||
@@ -1,6 +1,19 @@ | |||||
export const passwords = state => state.passwords; | export const passwords = state => state.passwords; | ||||
export const password = state => state.password; | export const password = state => state.password; | ||||
export const isAuthenticated = state => state.authenticated; | export const isAuthenticated = state => state.authenticated; | ||||
export const isGuest = state => !state.authenticated; | export const isGuest = state => !state.authenticated; | ||||
export const passwordStatus = state => state.passwordStatus; | export const passwordStatus = state => state.passwordStatus; | ||||
export const version = state => state.version; | export const version = state => state.version; | ||||
export const getCurrentPassword = state => { | |||||
const tenMinutesAgo = new Date().getTime() - 10 * 60 * 1000; | |||||
if (state.lastUse < tenMinutesAgo) { | |||||
return Object.assign({}, state.defaultPassword); | |||||
} | |||||
return Object.assign({}, state.defaultPassword, state.currentPassword); | |||||
}; |
@@ -9,7 +9,9 @@ Vue.use(Vuex); | |||||
const state = { | const state = { | ||||
currentPassword: null, | currentPassword: null, | ||||
passwords: {}, | passwords: {}, | ||||
defaultOptions: { | |||||
defaultPassword: { | |||||
login: '', | |||||
site: '', | |||||
uppercase: true, | uppercase: true, | ||||
lowercase: true, | lowercase: true, | ||||
numbers: true, | numbers: true, | ||||
@@ -18,6 +20,7 @@ const state = { | |||||
counter: 1, | counter: 1, | ||||
version: 2 | version: 2 | ||||
}, | }, | ||||
lastUse: new Date().getTime(), | |||||
baseURL: 'https://lesspass.com', | baseURL: 'https://lesspass.com', | ||||
}; | }; | ||||
@@ -1,4 +1,4 @@ | |||||
export const LOGOUT = 'LOGOUT'; | export const LOGOUT = 'LOGOUT'; | ||||
export const LOGIN = 'LOGIN'; | export const LOGIN = 'LOGIN'; | ||||
export const SET_CURRENT_PASSWORD = 'SET_CURRENT_PASSWORD'; | export const SET_CURRENT_PASSWORD = 'SET_CURRENT_PASSWORD'; | ||||
export const SET_DEFAULT_OPTIONS = 'SET_DEFAULT_OPTIONS'; | |||||
export const SET_DEFAULT_PASSWORD = 'SET_DEFAULT_PASSWORD'; |
@@ -5,7 +5,7 @@ function setState(state, id, object) { | |||||
set(state, id, Object.assign({}, object)); | set(state, id, Object.assign({}, object)); | ||||
} | } | ||||
export default { | |||||
export const mutations = { | |||||
[types.LOGIN](state){ | [types.LOGIN](state){ | ||||
state.authenticated = true; | state.authenticated = true; | ||||
}, | }, | ||||
@@ -15,7 +15,7 @@ export default { | |||||
[types.SET_CURRENT_PASSWORD](state, {password}){ | [types.SET_CURRENT_PASSWORD](state, {password}){ | ||||
setState(state, 'currentPassword', password); | setState(state, 'currentPassword', password); | ||||
}, | }, | ||||
[types.SET_DEFAULT_OPTIONS](state, {options}){ | |||||
setState(state, 'defaultOptions', options); | |||||
[types.SET_DEFAULT_PASSWORD](state, {options}){ | |||||
setState(state, 'defaultPassword', options); | |||||
} | } | ||||
}; | }; |
@@ -1,5 +1,9 @@ | |||||
import test from 'ava'; | import test from 'ava'; | ||||
import timekeeper from 'timekeeper'; | |||||
import {mutations} from '../src/store/mutations'; | import {mutations} from '../src/store/mutations'; | ||||
import * as getters from '../src/store/getters'; | |||||
test('LOGOUT', t => { | test('LOGOUT', t => { | ||||
const {LOGOUT} = mutations; | const {LOGOUT} = mutations; | ||||
@@ -32,10 +36,69 @@ test('SET_CURRENT_PASSWORD immutable', t => { | |||||
t.is(state.currentPassword.version, 2); | t.is(state.currentPassword.version, 2); | ||||
}); | }); | ||||
test('SET_DEFAULT_OPTIONS', t => { | |||||
const {SET_DEFAULT_OPTIONS} = mutations; | |||||
test('SET_DEFAULT_PASSWORD', t => { | |||||
const {SET_DEFAULT_PASSWORD} = mutations; | |||||
const state = { | |||||
defaultPassword: { | |||||
site: '', | |||||
login: '', | |||||
uppercase: true, | |||||
lowercase: true, | |||||
numbers: true, | |||||
symbols: true, | |||||
length: 16, | |||||
counter: 1, | |||||
version: 2 | |||||
} | |||||
}; | |||||
SET_DEFAULT_PASSWORD(state, {options: {symbols: false, length: 30}}); | |||||
t.is(state.defaultPassword.length, 30); | |||||
t.false(state.defaultPassword.symbols); | |||||
}); | |||||
test('store getter: get password 5 minutes after last use', t => { | |||||
var now = 1485989236; | |||||
var time = new Date(now * 1000); | |||||
timekeeper.freeze(time); | |||||
var fiveMinutesBefore = (now - 5 * 60) * 1000; | |||||
const state = { | |||||
lastUse: fiveMinutesBefore, | |||||
currentPassword: { | |||||
login: 'test@example.org', | |||||
length: 30 | |||||
}, | |||||
defaultPassword: { | |||||
site: '', | |||||
login: '', | |||||
uppercase: true, | |||||
lowercase: true, | |||||
numbers: true, | |||||
symbols: true, | |||||
length: 16, | |||||
counter: 1, | |||||
version: 2 | |||||
} | |||||
}; | |||||
const password = getters.getCurrentPassword(state); | |||||
t.is('test@example.org', password.login); | |||||
t.is(30, password.length); | |||||
timekeeper.reset(); | |||||
}); | |||||
test('store getter: get password more than 10 minutes after last use', t => { | |||||
var now = 1485989236; | |||||
var time = new Date(now * 1000); | |||||
timekeeper.freeze(time); | |||||
var fifteenMinutesBefore = (now - 15 * 60) * 1000; | |||||
const state = { | const state = { | ||||
defaultOptions: { | |||||
lastUse: fifteenMinutesBefore, | |||||
currentPassword: { | |||||
login: 'test@example.org', | |||||
length: 30 | |||||
}, | |||||
defaultPassword: { | |||||
site: '', | |||||
login: '', | |||||
uppercase: true, | uppercase: true, | ||||
lowercase: true, | lowercase: true, | ||||
numbers: true, | numbers: true, | ||||
@@ -45,7 +108,9 @@ test('SET_DEFAULT_OPTIONS', t => { | |||||
version: 2 | version: 2 | ||||
} | } | ||||
}; | }; | ||||
SET_DEFAULT_OPTIONS(state, {options: {symbols: false, length: 30}}); | |||||
t.is(state.defaultOptions.length, 30); | |||||
t.false(state.defaultOptions.symbols); | |||||
const password = getters.getCurrentPassword(state); | |||||
t.is('', password.login); | |||||
t.is('', password.site); | |||||
t.is(16, password.length); | |||||
timekeeper.reset(); | |||||
}); | }); |