Browse Source

Load already saved password profile on mount

Fixes https://github.com/lesspass/lesspass/issues/611
pull/612/head
Guillaume Vincent 3 years ago
parent
commit
309a8605e9
7 changed files with 178 additions and 183 deletions
  1. +1
    -0
      .gitignore
  2. +1
    -1
      packages/lesspass-pure/package.json
  3. +2
    -2
      packages/lesspass-pure/src/store/actions.js
  4. +0
    -1
      packages/lesspass-pure/src/store/mutation-types.js
  5. +29
    -17
      packages/lesspass-pure/src/store/mutations.js
  6. +144
    -161
      packages/lesspass-pure/src/store/mutations.test.js
  7. +1
    -1
      packages/lesspass-pure/src/views/PasswordGenerator.vue

+ 1
- 0
.gitignore View File

@@ -6,3 +6,4 @@ node_modules
package-lock.json package-lock.json
default.nix default.nix
.envrc .envrc
sandbox/lesspass-passwordrules

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

@@ -1,6 +1,6 @@
{ {
"name": "lesspass-pure", "name": "lesspass-pure",
"version": "9.4.2",
"version": "9.4.3",
"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>",


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

@@ -3,8 +3,8 @@ 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 loadPasswordProfile = ({ commit }, { site }) => {
commit(types.LOAD_PASSWORD_PROFILE, { site });
export const setSite = ({ commit }, { site }) => {
commit(types.SET_SITE, { site });
}; };


export const getPasswordFromUrlQuery = ({ commit }, { query }) => { export const getPasswordFromUrlQuery = ({ commit }, { query }) => {


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

@@ -7,6 +7,5 @@ export const SET_PASSWORDS = "SET_PASSWORDS";
export const SET_TOKENS = "SET_TOKENS"; 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 DELETE_PASSWORD = "DELETE_PASSWORD"; export const DELETE_PASSWORD = "DELETE_PASSWORD";
export const CLEAN_MESSAGE = "CLEAN_MESSAGE"; export const CLEAN_MESSAGE = "CLEAN_MESSAGE";

+ 29
- 17
packages/lesspass-pure/src/store/mutations.js View File

@@ -1,5 +1,21 @@
import * as types from "./mutation-types"; import * as types from "./mutation-types";


function loadPasswordProfileMatchingSite(passwordProfiles, site) {
let bestMatch = undefined;
const siteWithoutWWW = site.replace(/^www./g, "");
for (let i = 0; i < passwordProfiles.length; i++) {
const password = passwordProfiles[i];
if (site.endsWith(password.site)) {
return password;
} else if (password.site.endsWith(siteWithoutWWW)) {
bestMatch = password;
}
}
if (bestMatch) {
return bestMatch;
}
}

export default { export default {
[types.LOGIN](state) { [types.LOGIN](state) {
state.isAuthenticated = true; state.isAuthenticated = true;
@@ -24,6 +40,17 @@ export default {
state.defaultPassword = Object.assign({}, state.defaultPassword, options); state.defaultPassword = Object.assign({}, state.defaultPassword, options);
}, },
[types.SET_PASSWORDS](state, { passwords }) { [types.SET_PASSWORDS](state, { passwords }) {
if (state?.password?.site && !state.password.id) {
const matchingPasswordProfile = loadPasswordProfileMatchingSite(
passwords,
state.password.site
);
if (matchingPasswordProfile) {
state.password = {
...matchingPasswordProfile
};
}
}
state.passwords = passwords; state.passwords = passwords;
}, },
[types.DELETE_PASSWORD](state, { id }) { [types.DELETE_PASSWORD](state, { id }) {
@@ -35,23 +62,8 @@ export default {
} }
}, },
[types.SET_SITE](state, { site }) { [types.SET_SITE](state, { site }) {
state.password.site = site;
},
[types.LOAD_PASSWORD_PROFILE](state, { site }) {
if (!site || typeof state.password.id !== "undefined") {
return;
}
state.password = Object.assign({}, state.password, { site });
const passwords = state.passwords || [];
const siteWithoutWWW = site.replace(/^www./g, "");
for (let i = 0; i < passwords.length; i++) {
const password = passwords[i];
if (site.endsWith(password.site)) {
state.password = { ...password };
break;
} else if (password.site.endsWith(siteWithoutWWW)) {
state.password = { ...password };
}
if (site && !state?.password?.id) {
state.password.site = site;
} }
}, },
[types.SET_MESSAGE](state, { message }) { [types.SET_MESSAGE](state, { message }) {


+ 144
- 161
packages/lesspass-pure/src/store/mutations.test.js View File

@@ -113,206 +113,189 @@ test("DELETE_PASSWORD replace state.password with state.defaultPassword", () =>
DELETE_PASSWORD(state, { id: "1" }); DELETE_PASSWORD(state, { id: "1" });
expect(state.password.length).toBe(16); expect(state.password.length).toBe(16);
}); });

test("LOAD_PASSWORD_PROFILE", () => {
const state = {
password: {
login: "",
site: "",
uppercase: true,
describe("SET_PASSWORDS", () => {
const passwords = [
{
id: "b89fdd8e-8e82-475a-ace4-91bcbd2042dc",
login: "contact@example.org",
site: "subdomaine.example.org",
lowercase: true, lowercase: true,
numbers: true,
uppercase: true,
symbols: true, symbols: true,
numbers: true,
counter: 1,
length: 16, length: 16,
version: 2
},
{
id: "7cbadebf-49c8-4136-a579-6ee5beb6de7c",
login: "contact@example.org",
site: "www.example.org",
lowercase: true,
uppercase: false,
symbols: false,
numbers: true,
counter: 1, counter: 1,
length: 8,
version: 2 version: 2
}, },
passwords: [
{
id: "b89fdd8e-8e82-475a-ace4-91bcbd2042dc",
login: "contact@example.org",
site: "subdomaine.example.org",
lowercase: true,
uppercase: true,
symbols: true,
numbers: true,
counter: 1,
length: 16,
version: 2
},
{
id: "7cbadebf-49c8-4136-a579-6ee5beb6de7c",
login: "contact@example.org",
{
id: "31a50139-4add-4486-b553-5e33b4540640",
login: "contact@example.org",
site: "lesspass.com",
lowercase: true,
uppercase: true,
symbols: true,
numbers: true,
counter: 1,
length: 12,
version: 1
}
];

test("select good password profile base on site", () => {
const state = {
password: {
login: "",
site: "www.example.org", site: "www.example.org",
uppercase: true,
lowercase: true, lowercase: true,
uppercase: false,
symbols: false,
numbers: true, numbers: true,
symbols: true,
length: 16,
counter: 1, counter: 1,
length: 8,
version: 2 version: 2
}, },
{
id: "31a50139-4add-4486-b553-5e33b4540640",
login: "contact@example.org",
site: "lesspass.com",
lowercase: true,
passwords: [],
defaultPassword: {
login: "",
site: "",
uppercase: true, uppercase: true,
symbols: true,
lowercase: true,
numbers: true, numbers: true,
symbols: true,
length: 16,
counter: 1, counter: 1,
length: 12,
version: 1
version: 2
} }
],
defaultPassword: {
login: "",
site: "",
uppercase: true,
lowercase: true,
numbers: true,
symbols: true,
length: 16,
counter: 1,
version: 2
},
lastUse: null
};
const LOAD_PASSWORD_PROFILE = mutations[types.LOAD_PASSWORD_PROFILE];
LOAD_PASSWORD_PROFILE(state, { site: "www.example.org" });
expect(state.password).toEqual(state.passwords[1]);
});
};


test("LOAD_PASSWORD_PROFILE do nothing if id not empty", () => {
const state = {
password: {
id: "1",
site: "example.org"
},
passwords: []
};
const LOAD_PASSWORD_PROFILE = mutations[types.LOAD_PASSWORD_PROFILE];
LOAD_PASSWORD_PROFILE(state, { site: "lesspass.com" });
expect(state.password.site).toBe("example.org");
});
const SET_PASSWORDS = mutations[types.SET_PASSWORDS];
SET_PASSWORDS(state, { passwords });
expect(state.password).toEqual(passwords[1]);
});


test("LOAD_PASSWORD_PROFILE with passwords", () => {
const state = {
password: {
site: ""
},
passwords: [
{ id: "1", site: "www.example.org" },
{ id: "2", site: "www.google.com" }
]
};
const LOAD_PASSWORD_PROFILE = mutations[types.LOAD_PASSWORD_PROFILE];
LOAD_PASSWORD_PROFILE(state, { site: "www.google.com" });
expect(state.password.id).toBe("2");
expect(state.password.site).toBe("www.google.com");
});
test("SET_PASSWORDS do nothing if id not empty", () => {
const state = {
password: {
id: "1",
site: "example.org"
},
passwords: []
};
const SET_PASSWORDS = mutations[types.SET_PASSWORDS];
SET_PASSWORDS(state, { passwords });
expect(state.password.id).toBe("1");
});


test("LOAD_PASSWORD_PROFILE with no site keep password profile", () => {
const state = {
password: {
id: "1",
site: "example.org",
login: "contact@example.org",
length: 8,
version: 2
},
passwords: []
};
const LOAD_PASSWORD_PROFILE = mutations[types.LOAD_PASSWORD_PROFILE];
LOAD_PASSWORD_PROFILE(state, { site: "" });
expect(state.password.id).toBe("1");
expect(state.password.site).toBe("example.org");
expect(state.password.login).toBe("contact@example.org");
expect(state.password.length).toBe(8);
expect(state.password.version).toBe(2);
});
test("with no site keep password profile", () => {
const state = {
password: defaultPassword,
passwords: []
};
const SET_PASSWORDS = mutations[types.SET_PASSWORDS];
SET_PASSWORDS(state, { passwords });
expect(state.password).toEqual(defaultPassword);
});


test("LOAD_PASSWORD_PROFILE no passwords", () => {
const state = {
password: {
site: ""
},
passwords: []
};
const LOAD_PASSWORD_PROFILE = mutations[types.LOAD_PASSWORD_PROFILE];
LOAD_PASSWORD_PROFILE(state, { site: "account.google.com" });
expect(state.password.site).toBe("account.google.com");
});
test("multiple accounts matching criteria", () => {
const state = {
password: {
site: "example.org"
},
passwords: []
};
const SET_PASSWORDS = mutations[types.SET_PASSWORDS];
SET_PASSWORDS(state, { passwords });
expect(state.password.id).toBe("7cbadebf-49c8-4136-a579-6ee5beb6de7c");
});


test("LOAD_PASSWORD_PROFILE multiple accounts matching criteria", () => {
const state = {
password: {
site: ""
},
passwords: [
{ id: "1", site: "www.example.org" },
{ id: "2", site: "www.google.com" },
{ id: "3", site: "account.google.com" }
]
};
const LOAD_PASSWORD_PROFILE = mutations[types.LOAD_PASSWORD_PROFILE];
LOAD_PASSWORD_PROFILE(state, { site: "www.google.com" });
expect(state.password.id).toBe("2");
expect(state.password.site).toBe("www.google.com");
test("ends matching criteria nrt #285", () => {
const state = {
password: {
site: "www.google.com"
},
passwords: []
};
const SET_PASSWORDS = mutations[types.SET_PASSWORDS];
SET_PASSWORDS(state, {
passwords: [{ id: "1", site: "account.google.com" }]
});
expect(state.password.id).toBe("1");
expect(state.password.site).toBe("account.google.com");
});

test("without www", () => {
const state = {
password: {
site: "www.reddit.com"
},
passwords: []
};
const SET_PASSWORDS = mutations[types.SET_PASSWORDS];
SET_PASSWORDS(state, { passwords: [{ id: "1", site: "reddit.com" }] });
expect(state.password.id).toBe("1");
expect(state.password.site).toBe("reddit.com");
});

test("with no matching password profile let password profile intact", () => {
const state = {
password: {
site: "not-in-my-password-profile.org"
},
passwords: []
};
const SET_PASSWORDS = mutations[types.SET_PASSWORDS];
SET_PASSWORDS(state, { passwords });
expect(state.password.site).toBe("not-in-my-password-profile.org");
});
}); });


test("LOAD_PASSWORD_PROFILE multiple accounts matching criteria order doesn't matter", () => {
test("SET_SITE default state", () => {
const state = { const state = {
password: {
site: ""
},
passwords: [
{ id: "1", site: "www.example.org" },
{ id: "2", site: "account.google.com" },
{ id: "3", site: "www.google.com" }
]
password: defaultPassword,
passwords: [],
defaultPassword
}; };
const LOAD_PASSWORD_PROFILE = mutations[types.LOAD_PASSWORD_PROFILE];
LOAD_PASSWORD_PROFILE(state, { site: "www.google.com" });
expect(state.password.id).toBe("3");
expect(state.password.site).toBe("www.google.com");
const SET_SITE = mutations[types.SET_SITE];
SET_SITE(state, { site: "www.example.org" });
expect(state.password.site).toEqual("www.example.org");
}); });


test("LOAD_PASSWORD_PROFILE ends matching criteria nrt #285", () => {
test("SET_SITE ignore empty", () => {
const state = { const state = {
password: { password: {
site: ""
"site": "www.example.org"
}, },
passwords: [{ id: "1", site: "account.google.com" }]
passwords: [],
defaultPassword
}; };
const LOAD_PASSWORD_PROFILE = mutations[types.LOAD_PASSWORD_PROFILE];
LOAD_PASSWORD_PROFILE(state, { site: "www.google.com" });
expect(state.password.id).toBe("1");
expect(state.password.site).toBe("account.google.com");
const SET_SITE = mutations[types.SET_SITE];
SET_SITE(state, { site: "" });
expect(state.password.site).toEqual("www.example.org");
}); });


test("LOAD_PASSWORD_PROFILE without www", () => {
test("SET_SITE ignore if id set", () => {
const state = { const state = {
password: { password: {
site: ""
"id": "1",
"site": "www.example.org"
}, },
passwords: [{ id: "1", site: "reddit.com" }]
};
const LOAD_PASSWORD_PROFILE = mutations[types.LOAD_PASSWORD_PROFILE];
LOAD_PASSWORD_PROFILE(state, { site: "www.reddit.com" });
expect(state.password.id).toBe("1");
expect(state.password.site).toBe("reddit.com");
});

test("SET_SITE default state", () => {
const state = {
password: defaultPassword,
passwords: [], passwords: [],
defaultPassword: defaultPassword,
lastUse: null
defaultPassword
}; };
const SET_SITE = mutations[types.SET_SITE]; const SET_SITE = mutations[types.SET_SITE];
SET_SITE(state, { site: "www.example.org" });
SET_SITE(state, { site: "www.lesspass.com" });
expect(state.password.site).toEqual("www.example.org"); expect(state.password.site).toEqual("www.example.org");
}); });




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

@@ -137,7 +137,7 @@ export default {
}, },
beforeMount() { beforeMount() {
urlParser.getSite().then(site => { urlParser.getSite().then(site => {
this.$store.dispatch("loadPasswordProfile", { site });
this.$store.dispatch("setSite", { site })
}); });
this.$store.dispatch("getPasswordFromUrlQuery", { this.$store.dispatch("getPasswordFromUrlQuery", {
query: this.$route.query query: this.$route.query


Loading…
Cancel
Save