@@ -1,6 +1,6 @@ | |||||
{ | { | ||||
"name": "lesspass-pure", | "name": "lesspass-pure", | ||||
"version": "9.1.9", | |||||
"version": "9.1.10", | |||||
"description": "LessPass web component", | "description": "LessPass web component", | ||||
"license": "GPL-3.0", | "license": "GPL-3.0", | ||||
"author": "Guillaume Vincent <guillaume@oslab.fr>", | "author": "Guillaume Vincent <guillaume@oslab.fr>", | ||||
@@ -80,7 +80,6 @@ export default { | |||||
}, | }, | ||||
created() { | created() { | ||||
this.$store.dispatch("cleanMessage"); | this.$store.dispatch("cleanMessage"); | ||||
this.$store.dispatch("refreshToken"); | |||||
this.$store.dispatch("resetPassword"); | this.$store.dispatch("resetPassword"); | ||||
} | } | ||||
}; | }; | ||||
@@ -4,7 +4,7 @@ export default { | |||||
addAuthorizationHeader(config) { | addAuthorizationHeader(config) { | ||||
return { | return { | ||||
...config, | ...config, | ||||
headers: { Authorization: `JWT ${config.token}` } | |||||
headers: { Authorization: `Bearer ${config.access_token}` } | |||||
}; | }; | ||||
}, | }, | ||||
all(config) { | all(config) { | ||||
@@ -4,7 +4,7 @@ import Passwords from "./password"; | |||||
const mock = new MockAdapter(axios); | const mock = new MockAdapter(axios); | ||||
const config = { baseURL: "https://lesspass.com", token: "abc" }; | |||||
const config = { baseURL: "https://lesspass.com", access_token: "abc" }; | |||||
test("Passwords.create", () => { | test("Passwords.create", () => { | ||||
const password = { login: "text@example.org" }; | const password = { login: "text@example.org" }; | ||||
@@ -1,25 +1,25 @@ | |||||
import axios from "axios"; | import axios from "axios"; | ||||
export default { | export default { | ||||
login(user, config) { | |||||
return axios.post("/api/tokens/auth/", user, config).then(response => { | |||||
return response.data; | |||||
}); | |||||
login({ email, password }, config) { | |||||
return axios.post("/api/auth/jwt/create/", { email, password }, config); | |||||
}, | }, | ||||
register(user, config) { | |||||
return axios.post("/api/auth/register/", user, config).then(response => { | |||||
return response.data; | |||||
}); | |||||
register({ email, password }, config) { | |||||
return axios.post("/api/auth/users/", { email, password }, config); | |||||
}, | }, | ||||
resetPassword(email, config) { | |||||
return axios.post("/api/auth/password/reset/", email, config); | |||||
resetPassword({ email }, config) { | |||||
return axios.post("/api/auth/users/reset_password/", { email }, config); | |||||
}, | }, | ||||
confirmResetPassword(password, config) { | |||||
return axios.post("/api/auth/password/reset/confirm/", password, config); | |||||
}, | |||||
requestNewToken(token, config) { | |||||
return axios.post("/api/tokens/refresh/", token, config).then(response => { | |||||
return response.data.token; | |||||
}); | |||||
confirmResetPassword({ uid, token, password }, config) { | |||||
return axios.post( | |||||
"/api/auth/users/reset_password_confirm/", | |||||
{ | |||||
uid, | |||||
token, | |||||
new_password: password, | |||||
re_new_password: password | |||||
}, | |||||
config | |||||
); | |||||
} | } | ||||
}; | }; |
@@ -5,40 +5,42 @@ import User from "./user"; | |||||
const mock = new MockAdapter(axios); | const mock = new MockAdapter(axios); | ||||
test("login", () => { | test("login", () => { | ||||
const token = "5e0651"; | |||||
const access = "12345"; | |||||
const refresh = "67890" | |||||
const user = { email: "test@example.org", password: "password" }; | const user = { email: "test@example.org", password: "password" }; | ||||
mock | mock | ||||
.onPost("/api/tokens/auth/", user) | |||||
.reply(201, { token }); | |||||
.onPost("/api/auth/jwt/create/", user) | |||||
.reply(201, { access, refresh }); | |||||
return User.login(user, { | return User.login(user, { | ||||
baseURL: "https://lesspass.com" | baseURL: "https://lesspass.com" | ||||
}).then(response => { | }).then(response => { | ||||
expect(response.token).toBe(token); | |||||
expect(response.data.access).toBe(access); | |||||
expect(response.data.refresh).toBe(refresh); | |||||
}); | }); | ||||
}); | }); | ||||
test("register", () => { | test("register", () => { | ||||
const user = { email: "test@example.org", password: "password" }; | const user = { email: "test@example.org", password: "password" }; | ||||
mock | mock | ||||
.onPost("/api/auth/register/", user) | |||||
.onPost("/api/auth/users/", user) | |||||
.reply(201, { email: user.email, pk: 1 }); | .reply(201, { email: user.email, pk: 1 }); | ||||
return User.register(user, { | return User.register(user, { | ||||
baseURL: "https://lesspass.com" | baseURL: "https://lesspass.com" | ||||
}).then(response => { | }).then(response => { | ||||
expect(response.email).toBe(user.email); | |||||
expect(response.data.email).toBe(user.email); | |||||
}); | }); | ||||
}); | }); | ||||
test("resetPassword", () => { | test("resetPassword", () => { | ||||
var email = "test@lesspass.com"; | var email = "test@lesspass.com"; | ||||
mock | mock | ||||
.onPost("/api/auth/password/reset/", { email }) | |||||
.onPost("/api/auth/users/reset_password/", { email }) | |||||
.reply(204); | .reply(204); | ||||
return User.resetPassword( | return User.resetPassword( | ||||
{ email }, | { email }, | ||||
{ baseURL: "https://lesspass.com" } | { baseURL: "https://lesspass.com" } | ||||
).then(data => { | |||||
expect(data.status).toBe(204); | |||||
).then(response => { | |||||
expect(response.status).toBe(204); | |||||
}); | }); | ||||
}); | }); | ||||
@@ -46,29 +48,19 @@ test("confirmResetPassword", () => { | |||||
var newPassword = { | var newPassword = { | ||||
uid: "MQ", | uid: "MQ", | ||||
token: "5g1-2bd69bd6f6dcd73f8124", | token: "5g1-2bd69bd6f6dcd73f8124", | ||||
new_password: "password1" | |||||
new_password: "password1", | |||||
re_new_password: "password1", | |||||
}; | }; | ||||
mock | mock | ||||
.onPost("/api/auth/password/reset/confirm/", newPassword) | |||||
.onPost("/api/auth/users/reset_password_confirm/", newPassword) | |||||
.reply(204); | .reply(204); | ||||
return User.confirmResetPassword(newPassword, { | |||||
return User.confirmResetPassword({ | |||||
uid: "MQ", | |||||
token: "5g1-2bd69bd6f6dcd73f8124", | |||||
password: "password1", | |||||
}, { | |||||
baseURL: "https://lesspass.com" | baseURL: "https://lesspass.com" | ||||
}).then(data => { | |||||
expect(data.status).toBe(204); | |||||
}); | |||||
}); | |||||
test("refresh token", () => { | |||||
const token = "3e3231"; | |||||
const newToken = | |||||
"wibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9eyJzdWIiOiIxMjM0NTY3ODkwIi"; | |||||
mock | |||||
.onPost("/api/tokens/refresh/", { token }) | |||||
.reply(200, { token: newToken }); | |||||
return User.requestNewToken( | |||||
{ token }, | |||||
{ baseURL: "https://lesspass.com" } | |||||
).then(refreshedToken => { | |||||
expect(refreshedToken).toBe(newToken); | |||||
}).then(response => { | |||||
expect(response.status).toBe(204); | |||||
}); | }); | ||||
}); | }); |
@@ -59,11 +59,11 @@ | |||||
methods: { | methods: { | ||||
fullReload() { | fullReload() { | ||||
this.$store.dispatch('resetPassword'); | this.$store.dispatch('resetPassword'); | ||||
this.$router.push({name: 'home'}); | |||||
this.$router.push({name: 'home'}).catch(e => {}); | |||||
}, | }, | ||||
logout() { | logout() { | ||||
this.$store.dispatch('logout'); | this.$store.dispatch('logout'); | ||||
this.$router.push({name: 'home'}); | |||||
this.$router.push({name: 'home'}).catch(e => {}); | |||||
}, | }, | ||||
saveOrUpdatePassword() { | saveOrUpdatePassword() { | ||||
this.$store.dispatch('saveOrUpdatePassword'); | this.$store.dispatch('saveOrUpdatePassword'); | ||||
@@ -1,18 +1,8 @@ | |||||
import Password from "../api/password"; | import Password from "../api/password"; | ||||
import User from "../api/user"; | |||||
import * as urlParser from "../services/url-parser"; | import * as urlParser from "../services/url-parser"; | ||||
import * as types from "./mutation-types"; | import * as types from "./mutation-types"; | ||||
import defaultPasswordProfile from "./defaultPassword"; | import defaultPasswordProfile from "./defaultPassword"; | ||||
export const refreshToken = ({ commit, state }) => { | |||||
const token = state.token; | |||||
if (token) { | |||||
User.requestNewToken({ token }, { baseURL: state.baseURL }) | |||||
.then(newToken => commit(types.SET_TOKEN, { token: newToken })) | |||||
.catch(() => commit(types.LOGOUT)); | |||||
} | |||||
}; | |||||
export const saveDefaultOptions = ({ commit }, payload) => { | export const saveDefaultOptions = ({ commit }, payload) => { | ||||
commit(types.SET_DEFAULT_OPTIONS, payload); | commit(types.SET_DEFAULT_OPTIONS, payload); | ||||
}; | }; | ||||
@@ -37,9 +27,12 @@ export const resetPassword = ({ commit }) => { | |||||
commit(types.RESET_PASSWORD); | commit(types.RESET_PASSWORD); | ||||
}; | }; | ||||
export const login = ({ commit }, payload) => { | |||||
commit(types.SET_BASE_URL, payload); | |||||
commit(types.SET_TOKEN, payload); | |||||
export const setBaseURL = ({ commit }, { baseURL }) => { | |||||
commit(types.SET_BASE_URL, { baseURL }); | |||||
}; | |||||
export const login = ({ commit }, { access, refresh }) => { | |||||
commit(types.SET_TOKENS, { access_token: access, refresh_token: refresh }); | |||||
commit(types.LOGIN); | commit(types.LOGIN); | ||||
}; | }; | ||||
@@ -15,7 +15,8 @@ const state = { | |||||
message: "", | message: "", | ||||
defaultPassword: defaultPassword, | defaultPassword: defaultPassword, | ||||
showOptions: false, | showOptions: false, | ||||
token: null, | |||||
access_token: null, | |||||
refresh_token: null, | |||||
baseURL: "https://lesspass.com" | baseURL: "https://lesspass.com" | ||||
}; | }; | ||||
@@ -27,7 +28,7 @@ export default new Vuex.Store({ | |||||
plugins: [ | plugins: [ | ||||
createPersistedState({ | createPersistedState({ | ||||
key: "lesspass", | key: "lesspass", | ||||
paths: ["token", "baseURL", "authenticated", "defaultPassword"] | |||||
paths: ["access_token", "refresh_token", "baseURL", "authenticated", "defaultPassword"] | |||||
}) | }) | ||||
] | ] | ||||
}); | }); |
@@ -5,7 +5,7 @@ export const SET_DEFAULT_OPTIONS = "SET_DEFAULT_OPTIONS"; | |||||
export const SET_MESSAGE = "SET_MESSAGE"; | 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_TOKENS = "SET_TOKENS"; | |||||
export const RESET_PASSWORD = "RESET_PASSWORD"; | 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"; | ||||
@@ -4,8 +4,9 @@ export default { | |||||
[types.LOGIN](state) { | [types.LOGIN](state) { | ||||
state.authenticated = true; | state.authenticated = true; | ||||
}, | }, | ||||
[types.SET_TOKEN](state, { token }) { | |||||
state.token = token; | |||||
[types.SET_TOKENS](state, { refresh_token, access_token }) { | |||||
state.refresh_token = refresh_token; | |||||
state.access_token = access_token | |||||
}, | }, | ||||
[types.LOGOUT](state) { | [types.LOGOUT](state) { | ||||
state.authenticated = false; | state.authenticated = false; | ||||
@@ -43,12 +43,14 @@ test("LOGIN", () => { | |||||
expect(state.authenticated).toBe(true); | expect(state.authenticated).toBe(true); | ||||
}); | }); | ||||
test("SET_TOKEN", () => { | |||||
const token = "123456"; | |||||
const SET_TOKEN = mutations[types.SET_TOKEN]; | |||||
test("SET_TOKENS", () => { | |||||
const access_token = "123456"; | |||||
const refresh_token = "7890" | |||||
const SET_TOKENS = mutations[types.SET_TOKENS]; | |||||
const state = { token: null }; | const state = { token: null }; | ||||
SET_TOKEN(state, { token }); | |||||
expect(state.token).toBe(token); | |||||
SET_TOKENS(state, { access_token, refresh_token }); | |||||
expect(state.access_token).toBe(access_token); | |||||
expect(state.refresh_token).toBe(refresh_token); | |||||
}); | }); | ||||
test("SET_PASSWORD", () => { | test("SET_PASSWORD", () => { | ||||
@@ -107,7 +107,8 @@ export default { | |||||
const baseURL = this.baseURL; | const baseURL = this.baseURL; | ||||
User.login({ email: this.email, password: this.password }, { baseURL }) | User.login({ email: this.email, password: this.password }, { baseURL }) | ||||
.then(response => { | .then(response => { | ||||
this.$store.dispatch("login", { token: response.token, baseURL }); | |||||
this.$store.dispatch("login", response.data); | |||||
this.$store.dispatch("setBaseURL", { baseURL }); | |||||
this.$router.push({ name: "home" }); | this.$router.push({ name: "home" }); | ||||
}) | }) | ||||
.catch(err => { | .catch(err => { | ||||
@@ -4,12 +4,14 @@ | |||||
<div class="col-12"> | <div class="col-12"> | ||||
<div class="inner-addon left-addon"> | <div class="inner-addon left-addon"> | ||||
<i class="fa fa-user"></i> | <i class="fa fa-user"></i> | ||||
<input id="email" | |||||
class="form-control" | |||||
name="email" | |||||
type="email" | |||||
placeholder="Email" | |||||
v-model="email"> | |||||
<input | |||||
id="email" | |||||
class="form-control" | |||||
name="email" | |||||
type="email" | |||||
placeholder="Email" | |||||
v-model="email" | |||||
/> | |||||
</div> | </div> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
@@ -20,56 +22,73 @@ | |||||
v-bind:label="$t('Master Password')" | v-bind:label="$t('Master Password')" | ||||
v-bind:email="email" | v-bind:email="email" | ||||
v-bind:showEncryptButton="true" | v-bind:showEncryptButton="true" | ||||
v-bind:EncryptButtonText="$t('Encrypt my master password')"></master-password> | |||||
v-bind:EncryptButtonText="$t('Encrypt my master password')" | |||||
></master-password> | |||||
</div> | </div> | ||||
</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 btn-primary"> | <button id="loginButton" class="btn btn-primary"> | ||||
{{$t('Reset my password')}} | |||||
{{ $t("Reset my password") }} | |||||
</button> | </button> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
</form> | </form> | ||||
</template> | </template> | ||||
<script type="text/ecmascript-6"> | <script type="text/ecmascript-6"> | ||||
import User from '../api/user'; | |||||
import message from '../services/message'; | |||||
import MasterPassword from '../components/MasterPassword.vue'; | |||||
import User from '../api/user'; | |||||
import message from '../services/message'; | |||||
import MasterPassword from '../components/MasterPassword.vue'; | |||||
import { mapState } from "vuex"; | |||||
export default { | |||||
components: { | |||||
MasterPassword | |||||
}, | |||||
data() { | |||||
return { | |||||
email: '', | |||||
password: '' | |||||
}; | |||||
}, | |||||
methods: { | |||||
resetPasswordConfirm(){ | |||||
if (!this.password) { | |||||
message.error(this.$t('PasswordResetRequired', 'A password is required')); | |||||
return; | |||||
} | |||||
User | |||||
.confirmResetPassword({ | |||||
export default { | |||||
components: { | |||||
MasterPassword | |||||
}, | |||||
data() { | |||||
return { | |||||
email: '', | |||||
password: '' | |||||
}; | |||||
}, | |||||
computed: mapState([ | |||||
'baseURL' | |||||
]), | |||||
methods: { | |||||
resetPasswordConfirm(){ | |||||
if (!this.password) { | |||||
message.error(this.$t('PasswordResetRequired', 'A password is required')); | |||||
return; | |||||
} | |||||
User | |||||
.confirmResetPassword( | |||||
{ | |||||
uid: this.$route.params.uid, | uid: this.$route.params.uid, | ||||
token: this.$route.params.token, | token: this.$route.params.token, | ||||
new_password: this.password | |||||
}) | |||||
.then(() => { | |||||
message.success(this.$t('PasswordResetSuccessful', 'Your password was reset successfully.')); | |||||
}) | |||||
.catch(err => { | |||||
if (err.response.status === 400) { | |||||
message.error(this.$t('ResetLinkExpired', 'This password reset link has expired.')); | |||||
} else { | |||||
message.displayGenericError(); | |||||
} | |||||
}); | |||||
} | |||||
password: this.password | |||||
}, | |||||
{ | |||||
baseURL: this.baseURL | |||||
} | |||||
) | |||||
.then(() => { | |||||
message.success(this.$t('PasswordResetSuccessful', 'Your password was reset successfully.')); | |||||
User | |||||
.login({ email: this.email, password: this.password }, { baseURL: this.baseURL }) | |||||
.then(response => { | |||||
this.$store.dispatch("login", response.data); | |||||
this.$router.push({ name: "home" }); | |||||
}) | |||||
.catch(err => message.displayGenericError()); | |||||
}) | |||||
.catch(err => { | |||||
if (err.response.status === 400) { | |||||
message.error(this.$t('ResetLinkExpired', 'This password reset link has expired.')); | |||||
} else { | |||||
message.displayGenericError(); | |||||
} | |||||
}); | |||||
} | } | ||||
} | } | ||||
} | |||||
</script> | </script> |