@@ -48,7 +48,7 @@ | |||
"vue-router": "^3.5.1", | |||
"vuejs-paginate": "^2.1.0", | |||
"vuex": "^3.6.2", | |||
"vuex-persistedstate": "^4.0.0-beta.3", | |||
"vuex-persistedstate": "^3.2.0", | |||
"vuex-router-sync": "^5.0.0" | |||
}, | |||
"devDependencies": { | |||
@@ -5,7 +5,6 @@ | |||
.lesspass--full-width #lesspass { | |||
max-width: none !important; | |||
max-height: 480px; | |||
overflow: auto; | |||
} | |||
@@ -161,8 +160,7 @@ button, | |||
</div> | |||
</template> | |||
<script> | |||
import axios from "axios"; | |||
import { getBaseURL } from "./api/baseURL"; | |||
import http from "./api/http"; | |||
import Menu from "./components/Menu.vue"; | |||
import Message from "./components/Message.vue"; | |||
@@ -181,11 +179,10 @@ export default { | |||
const refresh = localStorage.getItem("refresh_token"); | |||
if (refresh) { | |||
this.isLoading = true; | |||
axios | |||
.post("/api/auth/jwt/refresh/", { refresh }, { baseURL: getBaseURL() }) | |||
http | |||
.post("/auth/jwt/refresh/", { refresh }) | |||
.then(response => { | |||
this.$store.dispatch("login", response.data); | |||
return this.$store.dispatch("getPasswords"); | |||
return this.$store.dispatch("login", response.data); | |||
}) | |||
.finally(() => { | |||
this.isLoading = false; | |||
@@ -1,5 +1,11 @@ | |||
export const defaultBaseURL = "https://lesspass.com"; | |||
import { key } from "../services/localStore"; | |||
export const defaultBaseURL = "https://api.lesspass.com"; | |||
export function getBaseURL() { | |||
return localStorage.getItem("baseURL") || defaultBaseURL; | |||
const lesspass = localStorage.getItem(key); | |||
if (lesspass) { | |||
return JSON.parse(lesspass).settings.baseURL; | |||
} | |||
return defaultBaseURL; | |||
} |
@@ -2,18 +2,18 @@ import http from "./http"; | |||
export default { | |||
all() { | |||
return http.get("/api/passwords/"); | |||
return http.get("/passwords/"); | |||
}, | |||
create(resource) { | |||
return http.post("/api/passwords/", resource); | |||
return http.post("/passwords/", resource); | |||
}, | |||
read(resource) { | |||
return http.get(`/api/passwords/${resource.id}/`); | |||
return http.get(`/passwords/${resource.id}/`); | |||
}, | |||
update(resource) { | |||
return http.put(`/api/passwords/${resource.id}/`, resource); | |||
return http.put(`/passwords/${resource.id}/`, resource); | |||
}, | |||
delete(resource) { | |||
return http.delete(`/api/passwords/${resource.id}/`); | |||
return http.delete(`/passwords/${resource.id}/`); | |||
} | |||
}; |
@@ -15,7 +15,7 @@ test("Passwords.create", () => { | |||
}); | |||
test("Passwords.all", () => { | |||
mock.onGet("https://lesspass.com/api/passwords/").reply(200, {}); | |||
mock.onGet("https://api.lesspass.com/passwords/").reply(200, {}); | |||
return Passwords.all().then(response => { | |||
expect(response.status).toBe(200); | |||
}); | |||
@@ -24,7 +24,7 @@ test("Passwords.all", () => { | |||
test("Passwords.get", () => { | |||
mock | |||
.onGet( | |||
"https://lesspass.com/api/passwords/c8e4f983-8ffe-b705-4064-d3b7aa4a4782/" | |||
"https://api.lesspass.com/passwords/c8e4f983-8ffe-b705-4064-d3b7aa4a4782/" | |||
) | |||
.reply(200, {}); | |||
return Passwords.read({ id: "c8e4f983-8ffe-b705-4064-d3b7aa4a4782" }).then( | |||
@@ -41,7 +41,7 @@ test("Passwords.update", () => { | |||
}; | |||
mock | |||
.onPut( | |||
"https://lesspass.com/api/passwords/c8e4f983-4064-8ffe-b705-d3b7aa4a4782/", | |||
"https://api.lesspass.com/passwords/c8e4f983-4064-8ffe-b705-d3b7aa4a4782/", | |||
password | |||
) | |||
.reply(200, {}); | |||
@@ -53,7 +53,7 @@ test("Passwords.update", () => { | |||
test("Passwords.delete", () => { | |||
mock | |||
.onDelete( | |||
"https://lesspass.com/api/passwords/c8e4f983-8ffe-4064-b705-d3b7aa4a4782/" | |||
"https://api.lesspass.com/passwords/c8e4f983-8ffe-4064-b705-d3b7aa4a4782/" | |||
) | |||
.reply(204); | |||
return Passwords.delete({ id: "c8e4f983-8ffe-4064-b705-d3b7aa4a4782" }).then( | |||
@@ -2,16 +2,16 @@ import http from "./http"; | |||
export default { | |||
login({ email, password }) { | |||
return http.post("/api/auth/jwt/create/", { email, password }); | |||
return http.post("/auth/jwt/create/", { email, password }); | |||
}, | |||
register({ email, password }) { | |||
return http.post("/api/auth/users/", { email, password }); | |||
return http.post("/auth/users/", { email, password }); | |||
}, | |||
resetPassword({ email }) { | |||
return http.post("/api/auth/users/reset_password/", { email }); | |||
return http.post("/auth/users/reset_password/", { email }); | |||
}, | |||
confirmResetPassword({ uid, token, password }) { | |||
return http.post("/api/auth/users/reset_password_confirm/", { | |||
return http.post("/auth/users/reset_password_confirm/", { | |||
uid, | |||
token, | |||
new_password: password, | |||
@@ -19,7 +19,7 @@ export default { | |||
}); | |||
}, | |||
changePassword({ current_password, new_password }) { | |||
return http.post("/api/auth/users/set_password/", { | |||
return http.post("/auth/users/set_password/", { | |||
current_password: current_password, | |||
new_password: new_password, | |||
re_new_password: new_password | |||
@@ -19,7 +19,6 @@ | |||
"Length": "Länge", | |||
"LengthDeprecationWarning": "Die maximale Länge eines Passwortes beträgt 35 Zeichen.", | |||
"LessPass Database Url": "LessPass Datenbank Url", | |||
"LoginFormInvalid": "LessPass URL, email-Adresse und Passwort sind obligatorisch", | |||
"LoginIncorrectError": "Die email-Adresse und das Passwort, die Sie eingegeben haben, entsprechen nicht unseren Daten. Bitte überprüfen Sie sie und versuchen es nochmal.", | |||
"Master Password": "Masterpasswort", | |||
"MasterPasswordsEqualsNoNeedToChange": "Altes Hauptkennwort und neues Hauptkennwort sind identisch. Keine Notwendigkeit, es zu ändern!", | |||
@@ -48,7 +47,6 @@ | |||
"Settings": "Einstellungen", | |||
"Sign In": "Anmelden", | |||
"Sign out": "Ausloggen", | |||
"SignInInstead": "Sie haben bereits ein Konto? Melden Sie sich stattdessen an", | |||
"Site": "Seite", | |||
"SiteLoginMasterPasswordMandatory": "Die Felder für Seite, Anmeldename und Masterpasswort sind obligatorisch.", | |||
"SorryCopy": "Es tut uns leid, dass die Kopie nur auf modernen Browsern funktioniert", | |||
@@ -19,7 +19,6 @@ | |||
"Length": "Length", | |||
"LengthDeprecationWarning": "The maximum length of a password is 35 characters.", | |||
"LessPass Database Url": "LessPass Database Url", | |||
"LoginFormInvalid": "LessPass URL, email, and password are mandatory", | |||
"LoginIncorrectError": "The email and password you entered did not match our records. Please double-check and try again.", | |||
"Master Password": "Master Password", | |||
"MasterPasswordsEqualsNoNeedToChange": "Old master password and new master password are the same. No need to change it!", | |||
@@ -48,7 +47,6 @@ | |||
"Settings": "Settings", | |||
"Sign In": "Sign In", | |||
"Sign out": "Sign out", | |||
"SignInInstead": "Already have an account? Sign In instead", | |||
"Site": "Site", | |||
"SiteLoginMasterPasswordMandatory": "Site, login, and master password fields are mandatory.", | |||
"SorryCopy": "Sorry, copying only works in modern browsers.", | |||
@@ -19,7 +19,6 @@ | |||
"Length": "Tamaño", | |||
"LengthDeprecationWarning": "La longitud máxima de una contraseña es de 35 caracteres.", | |||
"LessPass Database Url": "URL de la base de datos LessPass", | |||
"LoginFormInvalid": "URL, correo electrónico y contraseña de LessPass URL son obligatorios", | |||
"LoginIncorrectError": "El correo electrónico y la contraseña que ingresó no concuerdan con nuestros registros. Revíselos de nuevo.", | |||
"Master Password": "Contraseña maestra", | |||
"MasterPasswordsEqualsNoNeedToChange": "La contraseña maestra anterior y la contraseña maestra nueva son iguales. ¡No es necesario cambiarlo!", | |||
@@ -48,7 +47,6 @@ | |||
"Settings": "Configuraciones", | |||
"Sign In": "Ingresar", | |||
"Sign out": "Desconectar", | |||
"SignInInstead": "¿Ya tienes una cuenta? Iniciar sesión en su lugar", | |||
"Site": "Sitio", | |||
"SiteLoginMasterPasswordMandatory": "Los campos sitio, usuario y contraseña maestra son obligatorios.", | |||
"SorryCopy": "Lamentamos que la copia sólo funcione en navegadores modernos", | |||
@@ -19,7 +19,6 @@ | |||
"Length": "Longueur", | |||
"LengthDeprecationWarning": "La longueur maximale d'un mot de passe est de 35 caractères.", | |||
"LessPass Database Url": "URL de la base de données LessPass", | |||
"LoginFormInvalid": "L'URL LessPass, l'email et le mot de passe sont obligatoires.", | |||
"LoginIncorrectError": "L'email et le mot de passe ne sont pas dans notre base de données. Vérifiez une nouvelle fois et réessayez.", | |||
"Master Password": "Mot de passe principal", | |||
"MasterPasswordsEqualsNoNeedToChange": "L'ancien mot de passe principal et le nouveau mot de passe principal sont identiques. Pas besoin de le changer!", | |||
@@ -48,7 +47,6 @@ | |||
"Settings": "Paramètres", | |||
"Sign In": "Se connecter", | |||
"Sign out": "Se déconnecter", | |||
"SignInInstead": "Vous avez déjà un compte? Connectez-vous à la place", | |||
"Site": "Site", | |||
"SiteLoginMasterPasswordMandatory": "Les champs site, login et mot de passe principal sont obligatoires.", | |||
"SorryCopy": "Nous sommes désolés, la copie ne fonctionne que sur les navigateurs modernes", | |||
@@ -19,7 +19,6 @@ | |||
"Length": "Długość", | |||
"LengthDeprecationWarning": "Maksymalna długość hasła wynosi 35 znaków.", | |||
"LessPass Database Url": "Link do bazy profili LessPass", | |||
"LoginFormInvalid": "Link do bazy LessPass, adres i hasło są wymagane", | |||
"LoginIncorrectError": "Podany adres i hasło nie pasują do zapisanych danych. Sprawdź je dokładnie i spróbuj ponownie.", | |||
"Master Password": "Hasło główne", | |||
"MasterPasswordsEqualsNoNeedToChange": "Stare hasło główne i nowe hasło główne są takie same. Nie musisz tego zmieniać!", | |||
@@ -48,7 +47,6 @@ | |||
"Settings": "Ustawienia", | |||
"Sign In": "Zaloguj się", | |||
"Sign out": "Wyloguj się", | |||
"SignInInstead": "Posiadasz już konto? Zaloguj się zamiast tego", | |||
"Site": "Serwis", | |||
"SiteLoginMasterPasswordMandatory": "Nazwa serwisu, adres i hasło są wymagane.", | |||
"SorryCopy": "Niestety, kopiowanie działa tylko w nowszych przeglądarkach", | |||
@@ -19,7 +19,6 @@ | |||
"Length": "Comprimento", | |||
"LengthDeprecationWarning": "O comprimento máximo de uma senha é de 35 caracteres.", | |||
"LessPass Database Url": "URL do banco de dados LessPass", | |||
"LoginFormInvalid": "URL, email, e senha do LessPass são obrigatórios", | |||
"LoginIncorrectError": "O email e senha que você digitou não estão de acordo com os nossos registros. Por favor verifique seus dados e tente novamente.", | |||
"Master Password": "Senha mestre", | |||
"MasterPasswordsEqualsNoNeedToChange": "A senha mestra antiga e a nova senha mestra são iguais. Não há necessidade de mudar isso!", | |||
@@ -48,7 +47,6 @@ | |||
"Settings": "Configurações", | |||
"Sign In": "Se autenticar", | |||
"Sign out": "Sair", | |||
"SignInInstead": "já tem uma conta? Entrar", | |||
"Site": "Local", | |||
"SiteLoginMasterPasswordMandatory": "Campos de site e credenciais de autenticação são obrigatórios.", | |||
"SorryCopy": "Infelizmente a cópia somente funciona em navegadores modernos", | |||
@@ -19,7 +19,6 @@ | |||
"Length": "Длина", | |||
"LengthDeprecationWarning": "Максимальная длина пароля 35 символов.", | |||
"LessPass Database Url": "URL-адрес базы данных LessPass", | |||
"LoginFormInvalid": "URL-адрес LessPass, email и пароль являются обязательными", | |||
"LoginIncorrectError": "Введенный вами адрес электронной почты и пароль не соответствуют нашим записям. Пожалуйста, проверьте еще раз и попробуйте снова.", | |||
"Master Password": "Мастер-пароль", | |||
"MasterPasswordsEqualsNoNeedToChange": "Старый мастер-пароль и новый мастер-пароль совпадают. Не нужно его менять!", | |||
@@ -48,7 +47,6 @@ | |||
"Settings": "Настройки", | |||
"Sign In": "Войти", | |||
"Sign out": "выйти", | |||
"SignInInstead": "Уже есть аккаунт? Войдите вместо", | |||
"Site": "Сайт", | |||
"SiteLoginMasterPasswordMandatory": "Поля сайта, логина и мастер-пароля являются обязательными.", | |||
"SorryCopy": "Извините, копирование работает только в современных браузерах.", | |||
@@ -19,7 +19,6 @@ | |||
"Length": "长度", | |||
"LengthDeprecationWarning": "密码的最大长度是35个字符。", | |||
"LessPass Database Url": "LessPass 数据库网址", | |||
"LoginFormInvalid": "LessPass 网址、电子邮件地址以及密码均为必填信息。", | |||
"LoginIncorrectError": "我们没找到符合您输入的电子邮件地址及密码的记录。请核验后再试。", | |||
"Master Password": "主密码", | |||
"MasterPasswordsEqualsNoNeedToChange": "旧的主密码和新的主密码相同。无需更改!", | |||
@@ -48,7 +47,6 @@ | |||
"Settings": "设置", | |||
"Sign In": "登录", | |||
"Sign out": "登出", | |||
"SignInInstead": "已经有帐号了?而是登录", | |||
"Site": "网站名", | |||
"SiteLoginMasterPasswordMandatory": "网站名、登录名以及主密码均为必填信息。", | |||
"SorryCopy": "很抱歉,但复制功能仅适用于现代浏览器", | |||
@@ -19,7 +19,6 @@ | |||
"Length": "長度", | |||
"LengthDeprecationWarning": "密碼的最大長度是 35 個字元。", | |||
"LessPass Database Url": "LessPass 資料庫 URL", | |||
"LoginFormInvalid": "LessPass URL、郵件位址、登入密碼皆為必填欄位", | |||
"LoginIncorrectError": "您輸入的郵件位址或登入密碼有誤。請確認後再試一次。", | |||
"Master Password": "主密碼", | |||
"MasterPasswordsEqualsNoNeedToChange": "舊的主密碼和新的主密碼相同。無需更改!", | |||
@@ -48,7 +47,6 @@ | |||
"Settings": "設定", | |||
"Sign In": "登入", | |||
"Sign out": "登出", | |||
"SignInInstead": "已經有帳號了?直接登入", | |||
"Site": "網站位址", | |||
"SiteLoginMasterPasswordMandatory": "網站位址、登入帳號、主密碼皆為必填欄位。", | |||
"SorryCopy": "很抱歉,複製功能僅適用於現代瀏覽器", | |||
@@ -0,0 +1 @@ | |||
export const key = "lesspass-v2" |
@@ -3,10 +3,6 @@ import * as urlParser from "../services/url-parser"; | |||
import * as types from "./mutation-types"; | |||
import defaultPasswordProfile from "./defaultPassword"; | |||
export const saveDefaultOptions = ({ commit }, payload) => { | |||
commit(types.SET_DEFAULT_OPTIONS, payload); | |||
}; | |||
export const loadPasswordProfile = ({ commit }, { site }) => { | |||
commit(types.LOAD_PASSWORD_PROFILE, { site }); | |||
}; | |||
@@ -27,13 +23,11 @@ export const resetPassword = ({ commit }) => { | |||
commit(types.RESET_PASSWORD); | |||
}; | |||
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); | |||
cleanMessage({ commit }); | |||
getPasswords({ commit }); | |||
}; | |||
export const logout = ({ commit }) => { | |||
@@ -58,11 +52,11 @@ export const saveOrUpdatePassword = ({ commit, state }) => { | |||
if (existingPassword) { | |||
const newPassword = Object.assign({}, existingPassword, state.password); | |||
Password.update(newPassword, state).then(() => { | |||
getPasswords({ commit, state }); | |||
getPasswords({ commit }); | |||
}); | |||
} else { | |||
Password.create(state.password, state).then(() => { | |||
getPasswords({ commit, state }); | |||
getPasswords({ commit }); | |||
}); | |||
} | |||
}; | |||
@@ -7,5 +7,5 @@ export const isGuest = state => !state.isAuthenticated; | |||
export const passwordURL = state => { | |||
const base64PasswordProfile = btoa(JSON.stringify(state.password)); | |||
const encodedPasswordProfile = encodeURIComponent(base64PasswordProfile); | |||
return `${state.baseURL}/#/?passwordProfileEncoded=${encodedPasswordProfile}`; | |||
return `${state.settings.baseURL}/#/?passwordProfileEncoded=${encodedPasswordProfile}`; | |||
}; |
@@ -13,11 +13,13 @@ test("passwordURL", () => { | |||
counter: 1, | |||
version: 2 | |||
}, | |||
baseURL: "https://lesspass.com" | |||
settings: { | |||
baseURL: "https://api.lesspass.com" | |||
} | |||
}; | |||
expect(getters.passwordURL(state)).toBe( | |||
"https://lesspass.com/#/?passwordProfileEncoded=eyJsb2dpbiI6InRlc3RAZXhhbXBsZS5vcmciLCJzaXRlIjoiZXhhbXBsZS5vcmciLCJ1cHBlcmNhc2UiOnRydWUsImxvd2VyY2FzZSI6dHJ1ZSwibnVtYmVycyI6dHJ1ZSwic3ltYm9scyI6ZmFsc2UsImxlbmd0aCI6MTYsImNvdW50ZXIiOjEsInZlcnNpb24iOjJ9" | |||
"https://api.lesspass.com/#/?passwordProfileEncoded=eyJsb2dpbiI6InRlc3RAZXhhbXBsZS5vcmciLCJzaXRlIjoiZXhhbXBsZS5vcmciLCJ1cHBlcmNhc2UiOnRydWUsImxvd2VyY2FzZSI6dHJ1ZSwibnVtYmVycyI6dHJ1ZSwic3ltYm9scyI6ZmFsc2UsImxlbmd0aCI6MTYsImNvdW50ZXIiOjEsInZlcnNpb24iOjJ9" | |||
); | |||
}); | |||
@@ -26,11 +28,13 @@ test("passwordURL encode uri component", () => { | |||
password: { | |||
login: "contact@lesspass.com" | |||
}, | |||
baseURL: "https://lesspass.com" | |||
settings: { | |||
baseURL: "https://api.lesspass.com" | |||
} | |||
}; | |||
expect(getters.passwordURL(state)).toBe( | |||
"https://lesspass.com/#/?passwordProfileEncoded=eyJsb2dpbiI6ImNvbnRhY3RAbGVzc3Bhc3MuY29tIn0%3D" | |||
"https://api.lesspass.com/#/?passwordProfileEncoded=eyJsb2dpbiI6ImNvbnRhY3RAbGVzc3Bhc3MuY29tIn0%3D" | |||
); | |||
}); | |||
@@ -5,6 +5,8 @@ import * as getters from "./getters"; | |||
import mutations from "./mutations"; | |||
import createPersistedState from "vuex-persistedstate"; | |||
import defaultPassword from "./defaultPassword"; | |||
import { defaultBaseURL } from "../api/baseURL"; | |||
import { key } from "../services/localStore"; | |||
Vue.use(Vuex); | |||
@@ -13,7 +15,11 @@ const state = { | |||
password: Object.assign({}, defaultPassword), | |||
passwords: [], | |||
message: "", | |||
defaultPassword | |||
defaultPassword, | |||
settings: { | |||
baseURL: defaultBaseURL, | |||
encryptMasterPassword: true | |||
} | |||
}; | |||
export default new Vuex.Store({ | |||
@@ -23,8 +29,8 @@ export default new Vuex.Store({ | |||
mutations, | |||
plugins: [ | |||
createPersistedState({ | |||
key: "lesspass", | |||
paths: ["defaultPassword"] | |||
key, | |||
paths: ["defaultPassword", "settings"] | |||
}) | |||
] | |||
}); |
@@ -1,6 +1,5 @@ | |||
export const LOGOUT = "LOGOUT"; | |||
export const LOGIN = "LOGIN"; | |||
export const SET_BASE_URL = "SET_BASE_URL"; | |||
export const SET_DEFAULT_OPTIONS = "SET_DEFAULT_OPTIONS"; | |||
export const SET_MESSAGE = "SET_MESSAGE"; | |||
export const SET_PASSWORD = "SET_PASSWORD"; | |||
@@ -13,8 +13,6 @@ export default { | |||
state.passwords = []; | |||
localStorage.removeItem("access_token"); | |||
localStorage.removeItem("refresh_token"); | |||
localStorage.removeItem("baseURL"); | |||
localStorage.removeItem("lesspass"); | |||
}, | |||
[types.RESET_PASSWORD](state) { | |||
state.password = { ...state.defaultPassword }; | |||
@@ -36,9 +34,6 @@ export default { | |||
state.password = Object.assign({}, state.defaultPassword); | |||
} | |||
}, | |||
[types.SET_BASE_URL](state, { baseURL }) { | |||
localStorage.setItem("baseURL", baseURL); | |||
}, | |||
[types.SET_SITE](state, { site }) { | |||
state.password.site = site; | |||
}, | |||
@@ -2,19 +2,6 @@ | |||
<form v-on:submit.prevent="signIn"> | |||
<div class="form-group"> | |||
<div class="inner-addon left-addon"> | |||
<i class="fa fa-globe"></i> | |||
<input | |||
id="baseURL" | |||
type="text" | |||
class="form-control" | |||
autocapitalize="none" | |||
v-bind:placeholder="$t('LessPass Database Url')" | |||
v-model="baseURL" | |||
/> | |||
</div> | |||
</div> | |||
<div class="form-group"> | |||
<div class="inner-addon left-addon"> | |||
<i class="fa fa-user"></i> | |||
<input | |||
id="email" | |||
@@ -34,25 +21,7 @@ | |||
v-bind:label="$t('Master Password')" | |||
></master-password> | |||
</div> | |||
<div class="form-check form-switch mb-3"> | |||
<input | |||
id="encryptMasterPassword" | |||
class="form-check-input" | |||
type="checkbox" | |||
v-model="encryptMasterPassword" | |||
/> | |||
<label class="form-check-label" for="encryptMasterPassword"> | |||
<small> | |||
{{ $t("Encrypt my master password") }} | |||
</small> | |||
</label> | |||
</div> | |||
<div class="form-group"> | |||
<button id="signInButton" class="btn btn-primary btn-block"> | |||
{{ $t("Sign In") }} | |||
</button> | |||
</div> | |||
<div class="form-group"> | |||
<div class="form-group text-right"> | |||
<button | |||
id="login__forgot-password-btn" | |||
type="button" | |||
@@ -62,50 +31,46 @@ | |||
<small>{{ $t("ForgotPassword", "Forgot your password?") }}</small> | |||
</button> | |||
</div> | |||
<div class="form-group"> | |||
<button id="signInButton" class="btn btn-primary btn-block"> | |||
{{ $t("Sign In") }} | |||
</button> | |||
</div> | |||
<div class="form-group mb-0"> | |||
<button | |||
id="login__no-account-btn" | |||
type="button" | |||
class="btn btn-light btn-block" | |||
class="btn btn-outline-dark btn-block" | |||
v-on:click="$router.push({ name: 'register' })" | |||
> | |||
<small>{{ | |||
$t( | |||
"NewToLessPassCreateAnAccount", | |||
"New to LessPass? Create an account" | |||
) | |||
}}</small> | |||
{{ $t("NewToLessPass", "New to LessPass? Join now") }} | |||
</button> | |||
</div> | |||
</form> | |||
</template> | |||
<script> | |||
import User from "../api/user"; | |||
import { getBaseURL, defaultBaseURL } from "../api/baseURL"; | |||
import MasterPassword from "../components/MasterPassword.vue"; | |||
import message from "../services/message"; | |||
import { encryptPassword } from "../services/encryption"; | |||
import { mapState } from "vuex"; | |||
export default { | |||
data() { | |||
return { | |||
email: "", | |||
password: "", | |||
encryptMasterPassword: true, | |||
baseURL: getBaseURL() | |||
password: "" | |||
}; | |||
}, | |||
computed: mapState(["settings"]), | |||
components: { | |||
MasterPassword | |||
}, | |||
methods: { | |||
formIsValid() { | |||
if (!this.email || !this.password || !this.baseURL) { | |||
if (!this.email || !this.password) { | |||
message.error( | |||
this.$t( | |||
"LoginFormInvalid", | |||
"LessPass URL, email, and password are mandatory" | |||
) | |||
this.$t("LoginFormInvalid", "Email and password are mandatory") | |||
); | |||
return false; | |||
} | |||
@@ -113,27 +78,17 @@ export default { | |||
}, | |||
signIn() { | |||
if (this.formIsValid()) { | |||
const baseURL = this.baseURL; | |||
this.$store.dispatch("setBaseURL", { baseURL }); | |||
encryptPassword(this.email, this.password).then(encryptedPassword => { | |||
const password = this.encryptMasterPassword | |||
const password = this.settings.encryptMasterPassword | |||
? encryptedPassword | |||
: this.password; | |||
User.login({ email: this.email, password }) | |||
.then(response => { | |||
this.$store.dispatch("login", response.data); | |||
this.$store.dispatch("cleanMessage"); | |||
this.$router.push({ name: "home" }); | |||
}) | |||
.catch(err => { | |||
if (err.response === undefined && baseURL !== defaultBaseURL) { | |||
message.error( | |||
this.$t( | |||
"DBNotRunning", | |||
"Your LessPass Database is not running" | |||
) | |||
); | |||
} else if (err.response && err.response.status === 401) { | |||
if (err.response && err.response.status === 401) { | |||
message.error( | |||
this.$t( | |||
"LoginIncorrectError", | |||
@@ -118,7 +118,7 @@ export default { | |||
this.$store.dispatch("login", response.data); | |||
this.$router.push({ name: "home" }); | |||
}) | |||
.catch(err => message.displayGenericError()); | |||
.catch(() => message.displayGenericError()); | |||
}) | |||
.catch(err => { | |||
message.error( | |||
@@ -75,7 +75,7 @@ export default { | |||
this.$store.dispatch("login", response.data); | |||
this.$router.push({ name: "home" }); | |||
}) | |||
.catch(err => message.displayGenericError()); | |||
.catch(() => message.displayGenericError()); | |||
}) | |||
.catch(err => { | |||
if (err.response.status === 400) { | |||
@@ -1,18 +1,5 @@ | |||
<template> | |||
<form v-on:submit.prevent="signIn"> | |||
<div class="form-group"> | |||
<div class="inner-addon left-addon"> | |||
<i class="fa fa-globe"></i> | |||
<input | |||
id="baseURL" | |||
type="text" | |||
class="form-control" | |||
autocapitalize="none" | |||
v-bind:placeholder="$t('LessPass Database Url')" | |||
v-model="baseURL" | |||
/> | |||
</div> | |||
</div> | |||
<div class="form-group row"> | |||
<div class="col-12"> | |||
<div class="inner-addon left-addon"> | |||
@@ -50,19 +37,16 @@ | |||
<button | |||
id="login__no-account-btn" | |||
type="button" | |||
class="btn btn-light btn-block" | |||
class="btn btn-outline-dark btn-block" | |||
v-on:click="$router.push({ name: 'login' })" | |||
> | |||
<small>{{ | |||
$t("SignInInstead", "Already have an account? Sign In instead") | |||
}}</small> | |||
{{ $t("AlreadyOnLessPass", "Already on LessPass? Sign In") }} | |||
</button> | |||
</div> | |||
</form> | |||
</template> | |||
<script> | |||
import User from "../api/user"; | |||
import { getBaseURL, defaultBaseURL } from "../api/baseURL"; | |||
import MasterPassword from "../components/MasterPassword.vue"; | |||
import message from "../services/message"; | |||
import { encryptPassword } from "../services/encryption"; | |||
@@ -71,8 +55,7 @@ export default { | |||
data() { | |||
return { | |||
email: "", | |||
password: "", | |||
baseURL: getBaseURL() | |||
password: "" | |||
}; | |||
}, | |||
components: { | |||
@@ -80,12 +63,9 @@ export default { | |||
}, | |||
methods: { | |||
formIsValid() { | |||
if (!this.email || !this.password || !this.baseURL) { | |||
if (!this.email || !this.password) { | |||
message.error( | |||
this.$t( | |||
"LoginFormInvalid", | |||
"LessPass URL, email, and password are mandatory" | |||
) | |||
this.$t("LoginFormInvalid", "Email and password are mandatory") | |||
); | |||
return false; | |||
} | |||
@@ -93,9 +73,6 @@ export default { | |||
}, | |||
register() { | |||
if (this.formIsValid()) { | |||
const baseURL = this.baseURL; | |||
this.$store.dispatch("setBaseURL", { baseURL }); | |||
encryptPassword(this.email, this.password).then(encryptedPassword => { | |||
User.register({ email: this.email, password: encryptedPassword }) | |||
.then(() => { | |||
@@ -117,14 +94,7 @@ export default { | |||
.catch(() => message.displayGenericError()); | |||
}) | |||
.catch(err => { | |||
if (err.response === undefined && baseURL !== defaultBaseURL) { | |||
message.error( | |||
this.$t( | |||
"DBNotRunning", | |||
"Your LessPass Database is not running" | |||
) | |||
); | |||
} else if ( | |||
if ( | |||
err.response && | |||
err.response.data && | |||
typeof err.response.data.email !== "undefined" | |||
@@ -1,11 +1,13 @@ | |||
<template> | |||
<div> | |||
<h5>{{ $t("Options by default") }}</h5> | |||
<form | |||
id="lesspass-options-form" | |||
novalidate | |||
v-on:submit.prevent="saveAndExit" | |||
> | |||
<div class="mb-3"> | |||
<h5>{{ $t("Default password profile") }}</h5> | |||
</div> | |||
<div class="form-group"> | |||
<label for="login">{{ $t("Username") }}</label> | |||
<div class="inner-addon left-addon"> | |||
@@ -24,14 +26,61 @@ | |||
/> | |||
</div> | |||
</div> | |||
<options v-bind:options="defaultPassword"></options> | |||
<button | |||
type="submit" | |||
id="btn-submit-settings" | |||
class="btn btn-primary btn-block mt-4" | |||
> | |||
{{ $t("Save") }} | |||
</button> | |||
<div class="mb-5"> | |||
<options v-bind:options="defaultPassword"></options> | |||
</div> | |||
<div class="mb-3"> | |||
<h5>{{ $t("LessPass Database") }}</h5> | |||
</div> | |||
<div class="form-group has-validation"> | |||
<label for="login">{{ $t("LessPass Database Url") }}</label> | |||
<div class="inner-addon left-addon"> | |||
<i class="fa fa-user"></i> | |||
<input | |||
id="login" | |||
type="text" | |||
name="login" | |||
ref="login" | |||
class="form-control" | |||
autocomplete="off" | |||
autocorrect="off" | |||
autocapitalize="none" | |||
v-bind:placeholder="$t('LessPass Database Url')" | |||
v-model="settings.baseURL" | |||
/> | |||
</div> | |||
<div | |||
v-if="settings.baseURL !== defaultBaseURL" | |||
class="text-warning mt-1" | |||
> | |||
<small> | |||
{{ $t("It is not recommended to change the default url.") }} | |||
</small> | |||
</div> | |||
</div> | |||
<label for="encryptMasterPassword">{{ $t("Login") }}</label> | |||
<div class="form-check mb-3"> | |||
<input | |||
id="encryptMasterPassword" | |||
class="form-check-input" | |||
type="checkbox" | |||
v-model="settings.encryptMasterPassword" | |||
/> | |||
<label class="form-check-label" for="encryptMasterPassword"> | |||
<small> | |||
{{ $t("Encrypt my master password") }} | |||
</small> | |||
</label> | |||
</div> | |||
<div class="mt-4 mb-3"> | |||
<button | |||
type="submit" | |||
id="btn-submit-settings" | |||
class="btn btn-primary" | |||
> | |||
{{ $t("Save") }} | |||
</button> | |||
</div> | |||
</form> | |||
</div> | |||
</template> | |||
@@ -39,17 +88,20 @@ | |||
<script> | |||
import Options from "../components/Options.vue"; | |||
import { mapState } from "vuex"; | |||
import { defaultBaseURL } from "../api/baseURL"; | |||
export default { | |||
computed: mapState(["defaultPassword"]), | |||
computed: mapState(["defaultPassword", "settings"]), | |||
components: { | |||
Options | |||
}, | |||
data: () => ({ | |||
defaultBaseURL | |||
}), | |||
methods: { | |||
saveAndExit() { | |||
this.$store | |||
.dispatch("saveDefaultOptions", this.defaultPassword) | |||
.then(this.$store.dispatch("resetPassword")) | |||
.dispatch("resetPassword") | |||
.then(() => this.$router.push({ name: "home" })); | |||
} | |||
} | |||
@@ -10757,10 +10757,10 @@ vuejs-paginate@^2.1.0: | |||
resolved "https://registry.yarnpkg.com/vuejs-paginate/-/vuejs-paginate-2.1.0.tgz#93e1ad1539b713a688c7a2d3080bda60fcc6c77d" | |||
integrity sha512-gnwyXlmCiDOu9MLWxN5UJ4PGijKGNOMpHG8ujsrynCzTJljn/rp7Jq0WiDGDAMi5/u0AHuYIHhced+tUW4jblA== | |||
vuex-persistedstate@^4.0.0-beta.3: | |||
version "4.0.0-beta.3" | |||
resolved "https://registry.yarnpkg.com/vuex-persistedstate/-/vuex-persistedstate-4.0.0-beta.3.tgz#89dd712de72d28e85cc95467d066002c1405f277" | |||
integrity sha512-T4IRD27qoUWh+8qr6T6zVp15xO7x/nPgnU13OD0C2uUwA7U9PhGozrj6lvVmMYDyRgc36J0msMXn3GvwHjkIhA== | |||
vuex-persistedstate@^3.2.0: | |||
version "3.2.0" | |||
resolved "https://registry.yarnpkg.com/vuex-persistedstate/-/vuex-persistedstate-3.2.0.tgz#41d3ea304404769ac653ec020de80c95ce16243d" | |||
integrity sha512-1Q4zV9cNaJtl59jN6rXbndemEtXKywZr0OFZnqgpYdwvdyy+64KNsEltKldQW+i03st5LuDwHsdOEevXIZUgdg== | |||
dependencies: | |||
deepmerge "^4.2.2" | |||
shvl "^2.0.2" | |||