ソースを参照

Revert f5cb8af133

pull/483/head
Guillaume Vincent 5年前
コミット
eae348fd85
8個のファイルの変更241行の追加85行の削除
  1. +18
    -3
      packages/lesspass-pure/cypress/integration/passwordGeneration.spec.js
  2. +49
    -14
      packages/lesspass-pure/src/components/InputSite.test.js
  3. +13
    -15
      packages/lesspass-pure/src/components/InputSite.vue
  4. +2
    -2
      packages/lesspass-pure/src/store/actions.js
  5. +1
    -1
      packages/lesspass-pure/src/store/mutation-types.js
  6. +15
    -13
      packages/lesspass-pure/src/store/mutations.js
  7. +127
    -19
      packages/lesspass-pure/src/store/mutations.test.js
  8. +16
    -18
      packages/lesspass-pure/src/views/PasswordGenerator.vue

+ 18
- 3
packages/lesspass-pure/cypress/integration/passwordGeneration.spec.js ファイルの表示

@@ -19,7 +19,7 @@ describe("Password Generation", function() {
}

cy.visit("/");
cy.get("#siteField").type("lesspass.com").blur();
cy.get("#siteField").type("lesspass.com");
cy.get("#login").type("test@lesspass.com");
cy.get("#passwordField").type("test@lesspass.com");
cy.wait(500);
@@ -105,16 +105,31 @@ describe("Password Generation", function() {
});
it("should generate password when hit enter nrt_266", function() {
cy.visit("/");
cy.get("#siteField").type("lesspass.com").blur();
cy.get("#siteField").type("lesspass.com");
cy.get("#login").type("test@lesspass.com");
cy.get("#passwordField")
.type("test@lesspass.com")
.type("{enter}");
cy.get("#generated-password").should("have.value", "hjV@\\5ULp3bIs,6B");
});
it("should keep site field in sync nrt_441", function() {
cy.visit("/");
cy.get("#login").type("user");
cy.get("#passwordField").type("password");
cy.get("#siteField")
.type("subdomain.domain.com")
.type("{home}")
.type("{rightarrow}")
.type("{backspace}")
.type("{downarrow}")
.type("{downarrow}")
.type("{enter}");
cy.get("#generatePassword__btn").click();
cy.get("#generated-password").should("have.value", "ZT^IK2e!t@k$9`*)");
});
it("should clear password generated when master password change", function() {
cy.visit("/");
cy.get("#siteField").type("example.org").blur();
cy.get("#siteField").type("example.org");
cy.get("#login").type("user");
cy.get("#passwordField").type("password");
cy.get("#generatePassword__btn").should("be.visible");


+ 49
- 14
packages/lesspass-pure/src/components/InputSite.test.js ファイルの表示

@@ -1,6 +1,9 @@
import { mount } from "@vue/test-utils";
import InputSite from "./InputSite.vue";

jest.mock("../services/url-parser");
import { getSuggestions } from "../services/url-parser";

const createWrapper = data =>
mount({
data: () => {
@@ -19,6 +22,10 @@ const optionsFor = wrapper => wrapper.findAll("div.awesomplete li");
const inputField = wrapper => wrapper.find("#siteField");

describe("InputSite", () => {
beforeEach(() => {
getSuggestions.mockImplementation(() => []);
});

it("fills the input with the value property", () => {
const wrapper = createWrapper({ site: "lesspass.com" });
const input = inputField(wrapper);
@@ -30,8 +37,8 @@ describe("InputSite", () => {
it("filters according to site name", () => {
const wrapper = createWrapper({
passwords: [
{ id: "p1", site: "lesspass", login: "xavier" },
{ id: "p2", site: "wrongsite", login: "xavier" }
{ site: "lesspass", login: "xavier" },
{ site: "wrongsite", login: "xavier" }
]
});
inputField(wrapper).setValue("le");
@@ -41,16 +48,25 @@ describe("InputSite", () => {
});
it(`shows options that are contained in the user's value`, () => {
const wrapper = createWrapper({
passwords: [{ id: "p3", site: "lesspass", login: "xavier" }]
passwords: [{ site: "lesspass", login: "xavier" }]
});
inputField(wrapper).setValue("www.lesspass.com");
let options = optionsFor(wrapper);
expect(options.length).toBe(1);
expect(options.at(0).text()).toBe("lesspass xavier");
});
it("filters using suggestion", () => {
getSuggestions.mockImplementation(() => []);
const wrapper = createWrapper();
getSuggestions.mockImplementation(() => ["lesspass"]);
inputField(wrapper).setValue("lesspass.com");
let options = optionsFor(wrapper);
expect(options.length).toBe(1);
expect(options.at(0).text()).toBe("lesspass");
});
it("shows site and login in the list", () => {
const wrapper = createWrapper({
passwords: [{ id: "p4", site: "lesspass", login: "xavier" }]
passwords: [{ site: "lesspass", login: "xavier" }]
});
inputField(wrapper).setValue("le");
let options = optionsFor(wrapper);
@@ -59,7 +75,7 @@ describe("InputSite", () => {
});
it(`doesn't use login`, () => {
const wrapper = createWrapper({
passwords: [{ id: "p5", site: "lesspass", login: "xavier" }]
passwords: [{ site: "lesspass", login: "xavier" }]
});
inputField(wrapper).setValue("xa");
let options = optionsFor(wrapper);
@@ -68,10 +84,10 @@ describe("InputSite", () => {
it(`prints options sorted by site then login`, () => {
const wrapper = createWrapper({
passwords: [
{ id: "p6", site: "lesspass", login: "guillaume" },
{ id: "p7", site: "passless", login: "xavier" },
{ id: "p8", site: "passless", login: "guillaume" },
{ id: "p9", site: "lesspass", login: "xavier" }
{ site: "lesspass", login: "guillaume" },
{ site: "passless", login: "xavier" },
{ site: "passless", login: "guillaume" },
{ site: "lesspass", login: "xavier" }
]
});
inputField(wrapper).setValue("le");
@@ -88,7 +104,7 @@ describe("InputSite", () => {
let wrapper;
beforeEach(() => {
wrapper = createWrapper({
passwords: [{ id: "p10", site: "lesspass", login: "xavier" }]
passwords: [{ site: "lesspass", login: "xavier" }]
});
inputField(wrapper).setValue("le");
const options = optionsFor(wrapper);
@@ -99,13 +115,32 @@ describe("InputSite", () => {
});
it('emits a "passwordProfileSelected" with the value', () => {
const emitted = wrapper.find(InputSite).emitted();
const events = emitted["passwordProfileSelected"];
expect(events.length).toBe(1);
expect(events[0]).toEqual([
{ id: "p10", site: "lesspass", login: "xavier" }
const profileSelected = emitted["passwordProfileSelected"];
expect(profileSelected.length).toBe(1);
expect(profileSelected[0]).toEqual([
{ site: "lesspass", login: "xavier" }
]);
});
});
});
describe("when selecting suggestion", () => {
let wrapper;
beforeEach(() => {
getSuggestions.mockImplementation(() => ["lesspass"]);
wrapper = createWrapper();
inputField(wrapper).setValue("le");
const options = optionsFor(wrapper);
options.at(0).trigger("click");
});
it("completes field", () => {
expect(inputField(wrapper).element.value).toBe("lesspass");
});
it('emits a "suggestionSelected" with site value', () => {
const emitted = wrapper.find(InputSite).emitted();
const profileSelected = emitted["suggestionSelected"];
expect(profileSelected.length).toBe(1);
expect(profileSelected[0]).toEqual(["lesspass"]);
});
});
});
});

+ 13
- 15
packages/lesspass-pure/src/components/InputSite.vue ファイルの表示

@@ -39,12 +39,7 @@
}
},
mounted() {
const siteField = this.$refs.siteField;
this.awesomplete = new Awesomplete(siteField,{
minChars: 0,
maxItems: 5
});
this.awesomplete.list = this.passwords;
this.awesomplete = new Awesomplete(this.$refs.siteField);
this.awesomplete.item = (element, input) => {
let item = Awesomplete.ITEM(element.value.site, input);
item.innerHTML += ` ${element.value.login}`;
@@ -57,10 +52,13 @@
this.awesomplete.data = data => {
return {label: data.site, value: data}
};
this.awesomplete.replace = suggestion => {
siteField.value = suggestion.label;
const passwordProfile = suggestion.value;
this.$emit("passwordProfileSelected", suggestion.value);
this.awesomplete.replace = password => {
this.$refs.siteField.value = password.label;
if (password.value.suggestion) {
this.$emit("suggestionSelected", password.value.site);
} else {
this.$emit("passwordProfileSelected", password.value);
}
};
this.awesomplete.sort = (a,b) => {
return a.value.site.localeCompare(b.value.site) ||
@@ -75,14 +73,14 @@
set: function (newValue) {
this.$emit("input", newValue);
}
},
suggestions: function () {
return this.passwords
}
},
watch: {
suggestions: function (newValue, _) {
this.awesomplete.list = newValue;
site: function (newValue, _) {
const suggestions = getSuggestions(newValue).map(suggestion => {
return {site: suggestion, suggestion: true, login: ''}
});
this.awesomplete.list = this.passwords.concat(suggestions);
}
},
methods: {}


+ 2
- 2
packages/lesspass-pure/src/store/actions.js ファイルの表示

@@ -17,8 +17,8 @@ export const saveDefaultOptions = ({ commit }, payload) => {
commit(types.SET_DEFAULT_OPTIONS, payload);
};

export const addSuggestions = ({ commit }, { site }) => {
commit(types.ADD_SUGGESTIONS, { site });
export const loadPasswordProfile = ({ commit }, { site }) => {
commit(types.LOAD_PASSWORD_PROFILE, { site });
};

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


+ 1
- 1
packages/lesspass-pure/src/store/mutation-types.js ファイルの表示

@@ -8,6 +8,6 @@ export const SET_PASSWORDS = "SET_PASSWORDS";
export const SET_TOKEN = "SET_TOKEN";
export const RESET_PASSWORD = "RESET_PASSWORD";
export const SET_SITE = "SET_SITE";
export const ADD_SUGGESTIONS = "ADD_SUGGESTIONS";
export const LOAD_PASSWORD_PROFILE = "LOAD_PASSWORD_PROFILE";
export const DELETE_PASSWORD = "DELETE_PASSWORD";
export const CLEAN_MESSAGE = "CLEAN_MESSAGE";

+ 15
- 13
packages/lesspass-pure/src/store/mutations.js ファイルの表示

@@ -1,5 +1,4 @@
import * as types from "./mutation-types";
import { getSuggestions } from "../services/url-parser";

export default {
[types.LOGIN](state) {
@@ -39,19 +38,22 @@ export default {
[types.SET_SITE](state, { site }) {
state.password.site = site;
},
[types.ADD_SUGGESTIONS](state, { site }) {
if (!site) return;
[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 passwordsSites = passwords.map(p => p.site);
const suggestions = getSuggestions(site)
.filter(suggestion => passwordsSites.indexOf(suggestion) !== 1)
.map(suggestion => {
return {
...state.defaultPassword,
site: suggestion
};
});
state.passwords = suggestions.concat(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 };
}
}
},
[types.SET_MESSAGE](state, { message }) {
state.message = message;


+ 127
- 19
packages/lesspass-pure/src/store/mutations.test.js ファイルの表示

@@ -129,9 +129,9 @@ test("SET_BASE_URL", () => {
expect(state.baseURL).toBe(baseURL);
});

test("ADD_SUGGESTIONS create 2 suggestions", () => {
test("LOAD_PASSWORD_PROFILE", () => {
const state = {
defaultPassword: {
password: {
login: "",
site: "",
uppercase: true,
@@ -179,17 +179,7 @@ test("ADD_SUGGESTIONS create 2 suggestions", () => {
length: 12,
version: 1
}
]
};
const ADD_SUGGESTIONS = mutations[types.ADD_SUGGESTIONS];
ADD_SUGGESTIONS(state, { site: "www.example.org" });
expect(state.passwords.length).toEqual(5);
expect(state.passwords[0].site).toEqual("example");
expect(state.passwords[1].site).toEqual("example.org");
});

test("ADD_SUGGESTIONS no passwords", () => {
const state = {
],
defaultPassword: {
login: "",
site: "",
@@ -201,14 +191,132 @@ test("ADD_SUGGESTIONS no passwords", () => {
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");
});

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("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("LOAD_PASSWORD_PROFILE no passwords", () => {
const state = {
password: {
site: ""
},
passwords: []
};
const ADD_SUGGESTIONS = mutations[types.ADD_SUGGESTIONS];
ADD_SUGGESTIONS(state, { site: "www.example.org" });
expect(state.passwords.length).toBe(3);
expect(state.passwords[0].site).toEqual("example");
expect(state.passwords[1].site).toEqual("example.org");
expect(state.passwords[2].site).toEqual("www.example.org");
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("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("LOAD_PASSWORD_PROFILE multiple accounts matching criteria order doesn't matter", () => {
const state = {
password: {
site: ""
},
passwords: [
{ id: "1", site: "www.example.org" },
{ id: "2", site: "account.google.com" },
{ id: "3", 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("3");
expect(state.password.site).toBe("www.google.com");
});

test("LOAD_PASSWORD_PROFILE ends matching criteria nrt #285", () => {
const state = {
password: {
site: ""
},
passwords: [{ id: "1", 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("1");
expect(state.password.site).toBe("account.google.com");
});

test("LOAD_PASSWORD_PROFILE without www", () => {
const state = {
password: {
site: ""
},
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", () => {


+ 16
- 18
packages/lesspass-pure/src/views/PasswordGenerator.vue ファイルの表示

@@ -127,18 +127,18 @@ export default {
},
computed: {
...mapState({
password: state => ({
...state.password,
login: state.password.login || state.defaultPassword.login
}),
passwords: state => state.passwords
password: state => {
state.password.login == state.password.login || state.defaultPassword.login
return state.password
},
passwords: state => state.passwords,
}),
...mapGetters(["passwordURL", "isDefaultProfile"])
},
beforeMount() {
this.$store.dispatch("getPasswords").then(() => {
urlParser.getSite().then(site => {
this.$store.dispatch("addSuggestions", { site });
this.$store.dispatch("loadPasswordProfile", { site });
});
this.$store.dispatch("getPasswordFromUrlQuery", {
query: this.$route.query
@@ -234,18 +234,16 @@ export default {
});
},
focusBestInputField() {
const site = this.$refs.site;
const login = this.$refs.login;
const masterPassword = this.$refs.masterPassword;
if (site && login && masterPassword){
const siteField = site.$refs.siteField;
if (siteField.value && login.value){
return void masterPassword.$refs.passwordField.focus();
}
if (siteField.value){
return void login.focus();
}
return void siteField.focus();
try {
const site = this.$refs.site.$refs.siteField;
const login = this.$refs.login;
const masterPassword = this.$refs.masterPassword;
if (site && !site.value) return void site.focus();
if (login && !login.value) return void login.focus();
masterPassword.$refs.passwordField.focus();
}
catch(err) {
console.error("Can't focus password field")
}
},
copyPassword() {


読み込み中…
キャンセル
保存