Browse Source

Move master password encryption and baseURL on settings page

pull/612/head
Guillaume Vincent 3 years ago
parent
commit
0f5d2fbd19
28 changed files with 141 additions and 180 deletions
  1. +1
    -1
      packages/lesspass-pure/package.json
  2. +4
    -7
      packages/lesspass-pure/src/LessPass.vue
  3. +8
    -2
      packages/lesspass-pure/src/api/baseURL.js
  4. +5
    -5
      packages/lesspass-pure/src/api/password.js
  5. +4
    -4
      packages/lesspass-pure/src/api/password.test.js
  6. +5
    -5
      packages/lesspass-pure/src/api/user.js
  7. +0
    -2
      packages/lesspass-pure/src/i18n/de.json
  8. +0
    -2
      packages/lesspass-pure/src/i18n/en.json
  9. +0
    -2
      packages/lesspass-pure/src/i18n/es.json
  10. +0
    -2
      packages/lesspass-pure/src/i18n/fr.json
  11. +0
    -2
      packages/lesspass-pure/src/i18n/pl.json
  12. +0
    -2
      packages/lesspass-pure/src/i18n/pt.json
  13. +0
    -2
      packages/lesspass-pure/src/i18n/ru.json
  14. +0
    -2
      packages/lesspass-pure/src/i18n/zh-CN.json
  15. +0
    -2
      packages/lesspass-pure/src/i18n/zh-TW.json
  16. +1
    -0
      packages/lesspass-pure/src/services/localStore.js
  17. +4
    -10
      packages/lesspass-pure/src/store/actions.js
  18. +1
    -1
      packages/lesspass-pure/src/store/getters.js
  19. +8
    -4
      packages/lesspass-pure/src/store/getters.test.js
  20. +9
    -3
      packages/lesspass-pure/src/store/index.js
  21. +0
    -1
      packages/lesspass-pure/src/store/mutation-types.js
  22. +0
    -5
      packages/lesspass-pure/src/store/mutations.js
  23. +15
    -60
      packages/lesspass-pure/src/views/Login.vue
  24. +1
    -1
      packages/lesspass-pure/src/views/MyAccount.vue
  25. +1
    -1
      packages/lesspass-pure/src/views/PasswordResetConfirm.vue
  26. +6
    -36
      packages/lesspass-pure/src/views/Register.vue
  27. +64
    -12
      packages/lesspass-pure/src/views/Settings.vue
  28. +4
    -4
      packages/lesspass-pure/yarn.lock

+ 1
- 1
packages/lesspass-pure/package.json View File

@@ -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": {


+ 4
- 7
packages/lesspass-pure/src/LessPass.vue View File

@@ -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;


+ 8
- 2
packages/lesspass-pure/src/api/baseURL.js View File

@@ -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;
}

+ 5
- 5
packages/lesspass-pure/src/api/password.js View File

@@ -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}/`);
}
};

+ 4
- 4
packages/lesspass-pure/src/api/password.test.js View File

@@ -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(


+ 5
- 5
packages/lesspass-pure/src/api/user.js View File

@@ -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


+ 0
- 2
packages/lesspass-pure/src/i18n/de.json View File

@@ -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",


+ 0
- 2
packages/lesspass-pure/src/i18n/en.json View File

@@ -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.",


+ 0
- 2
packages/lesspass-pure/src/i18n/es.json View File

@@ -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",


+ 0
- 2
packages/lesspass-pure/src/i18n/fr.json View File

@@ -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",


+ 0
- 2
packages/lesspass-pure/src/i18n/pl.json View File

@@ -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",


+ 0
- 2
packages/lesspass-pure/src/i18n/pt.json View File

@@ -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",


+ 0
- 2
packages/lesspass-pure/src/i18n/ru.json View File

@@ -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": "Извините, копирование работает только в современных браузерах.",


+ 0
- 2
packages/lesspass-pure/src/i18n/zh-CN.json View File

@@ -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": "很抱歉,但复制功能仅适用于现代浏览器",


+ 0
- 2
packages/lesspass-pure/src/i18n/zh-TW.json View File

@@ -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": "很抱歉,複製功能僅適用於現代瀏覽器",


+ 1
- 0
packages/lesspass-pure/src/services/localStore.js View File

@@ -0,0 +1 @@
export const key = "lesspass-v2"

+ 4
- 10
packages/lesspass-pure/src/store/actions.js View File

@@ -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 });
});
}
};


+ 1
- 1
packages/lesspass-pure/src/store/getters.js View File

@@ -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}`;
};

+ 8
- 4
packages/lesspass-pure/src/store/getters.test.js View File

@@ -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"
);
});



+ 9
- 3
packages/lesspass-pure/src/store/index.js View File

@@ -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"]
})
]
});

+ 0
- 1
packages/lesspass-pure/src/store/mutation-types.js View File

@@ -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";


+ 0
- 5
packages/lesspass-pure/src/store/mutations.js View File

@@ -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;
},


+ 15
- 60
packages/lesspass-pure/src/views/Login.vue View File

@@ -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",


+ 1
- 1
packages/lesspass-pure/src/views/MyAccount.vue View File

@@ -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(


+ 1
- 1
packages/lesspass-pure/src/views/PasswordResetConfirm.vue View File

@@ -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) {


+ 6
- 36
packages/lesspass-pure/src/views/Register.vue View File

@@ -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"


+ 64
- 12
packages/lesspass-pure/src/views/Settings.vue View File

@@ -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" }));
}
}


+ 4
- 4
packages/lesspass-pure/yarn.lock View File

@@ -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"


Loading…
Cancel
Save