Browse Source

Make clients compatible with the old API

old servers uses numbers instead of digits in the API.
This patch intercept API requests to make it compatible with new and old servers.
pull/763/head
Guillaume Vincent 1 year ago
parent
commit
c92c0e3d99
8 changed files with 254 additions and 73 deletions
  1. +46
    -9
      mobile/src/password/profilesActions.js
  2. +26
    -0
      mobile/src/password/profilesActions.test.js
  3. +6
    -17
      mobile/src/password/profilesReducer.js
  4. +0
    -17
      mobile/src/password/profilesReducer.test.js
  5. +1
    -1
      packages/lesspass-pure/package.json
  6. +41
    -5
      packages/lesspass-pure/src/api/password.js
  7. +6
    -4
      packages/lesspass-pure/src/services/encryption.js
  8. +128
    -20
      packages/lesspass-pure/tests/unit/api/password.spec.js

+ 46
- 9
mobile/src/password/profilesActions.js View File

@@ -22,6 +22,17 @@ function removePasswordProfile(profile) {
}; };
} }


function replaceNumbersWithDigitsInProfile(profile) {
if ("numbers" in profile) {
const { numbers, ...profileWithoutNumbers } = profile;
return {
...profileWithoutNumbers,
digits: numbers,
};
}
return profile;
}

export function getPasswordProfiles() { export function getPasswordProfiles() {
return (dispatch, getState) => { return (dispatch, getState) => {
const { settings, auth } = getState(); const { settings, auth } = getState();
@@ -30,21 +41,39 @@ export function getPasswordProfiles() {
headers: { Authorization: `Bearer ${auth.accessToken}` }, headers: { Authorization: `Bearer ${auth.accessToken}` },
}) })
.then((response) => { .then((response) => {
dispatch(setPasswordProfiles(response.data.results));
const profiles = response.data.results.map(
replaceNumbersWithDigitsInProfile
);
dispatch(setPasswordProfiles(profiles));
return response; return response;
}); });
}; };
} }


export function addNumbersFieldInProfile(profile) {
return {
...profile,
numbers: profile.digits,
};
}

export function savePasswordProfile(profile) { export function savePasswordProfile(profile) {
return (dispatch, getState) => { return (dispatch, getState) => {
const { settings, auth } = getState(); const { settings, auth } = getState();
return axios return axios
.post(`${settings.baseURL}/passwords/`, profile, {
headers: { Authorization: `Bearer ${auth.accessToken}` },
})
.post(
`${settings.baseURL}/passwords/`,
addNumbersFieldInProfile(profile),
{
headers: { Authorization: `Bearer ${auth.accessToken}` },
}
)
.then((response) => { .then((response) => {
dispatch(addPasswordProfile({ ...response.data }));
dispatch(
addPasswordProfile(
replaceNumbersWithDigitsInProfile({ ...response.data })
)
);
return response; return response;
}) })
.catch(() => .catch(() =>
@@ -61,11 +90,19 @@ export function updatePasswordProfile(profile) {
return (dispatch, getState) => { return (dispatch, getState) => {
const { settings, auth } = getState(); const { settings, auth } = getState();
return axios return axios
.put(`${settings.baseURL}/passwords/${profile.id}/`, profile, {
headers: { Authorization: `Bearer ${auth.accessToken}` },
})
.put(
`${settings.baseURL}/passwords/${profile.id}/`,
addNumbersFieldInProfile(profile),
{
headers: { Authorization: `Bearer ${auth.accessToken}` },
}
)
.then((response) => { .then((response) => {
dispatch(addPasswordProfile({ ...response.data }));
dispatch(
addPasswordProfile(
replaceNumbersWithDigitsInProfile({ ...response.data })
)
);
return response; return response;
}) })
.catch(() => .catch(() =>


+ 26
- 0
mobile/src/password/profilesActions.test.js View File

@@ -0,0 +1,26 @@
import {
replaceNumbersWithDigitsInProfile,
addNumbersFieldInProfile,
} from "./profilesActions";

it("replaceNumbersWithDigitsInProfile numbers become digits", () => {
expect(
replaceNumbersWithDigitsInProfile({ id: "p2", numbers: false })
).toEqual({ id: "p2", digits: false });
expect(
replaceNumbersWithDigitsInProfile([{ id: "p1", numbers: true }])
).toEqual({ id: "p1", digits: true });
});

it("addNumbersFieldInProfile add numbers with digits", () => {
expect(addNumbersFieldInProfile({ id: "p1", digits: true })).toEqual({
id: "p1",
digits: true,
numbers: true,
});
expect(addNumbersFieldInProfile({ id: "p2", digits: false })).toEqual({
id: "p2",
digits: false,
numbers: false,
});
});

+ 6
- 17
mobile/src/password/profilesReducer.js View File

@@ -3,23 +3,12 @@ const initialState = {};
export default function reduce(state = initialState, action) { export default function reduce(state = initialState, action) {
switch (action.type) { switch (action.type) {
case "SET_PASSWORD_PROFILES": case "SET_PASSWORD_PROFILES":
return action.profiles
.map((profile) => {
if ("numbers" in profile) {
const { numbers, ...profileWithoutNumbers } = profile;
return {
...profileWithoutNumbers,
digits: numbers,
};
}
return profile;
})
.reduce((acc, p) => {
acc[p.id] = {
...p,
};
return acc;
}, {});
return action.profiles.reduce((acc, profile) => {
acc[profile.id] = {
...profile,
};
return acc;
}, {});
case "ADD_PASSWORD_PROFILE": case "ADD_PASSWORD_PROFILE":
return { return {
...state, ...state,


+ 0
- 17
mobile/src/password/profilesReducer.test.js View File

@@ -18,23 +18,6 @@ describe("profiles reducer", () => {
p2: { id: "p2" }, p2: { id: "p2" },
}); });
}); });
it("SET_PASSWORD_PROFILES numbers become digits", () => {
expect(
reducer(
{},
{
type: "SET_PASSWORD_PROFILES",
profiles: [
{ id: "p1", numbers: true },
{ id: "p2", numbers: false },
],
}
)
).toEqual({
p1: { id: "p1", digits: true },
p2: { id: "p2", digits: false },
});
});
it("REMOVE_PASSWORD_PROFILE", () => { it("REMOVE_PASSWORD_PROFILE", () => {
expect( expect(
reducer( reducer(


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

@@ -11,7 +11,7 @@
"i18n:translate": "node src/i18n/translate.js", "i18n:translate": "node src/i18n/translate.js",
"prettier": "prettier --write 'src/**/*'", "prettier": "prettier --write 'src/**/*'",
"test": "yarn test:unit && yarn test:e2e", "test": "yarn test:unit && yarn test:e2e",
"test:watch": "jest --watch",
"test:watch": "vue-cli-service test:unit --watch",
"test:unit": "vue-cli-service test:unit", "test:unit": "vue-cli-service test:unit",
"test:e2e": "vue-cli-service test:e2e --headless", "test:e2e": "vue-cli-service test:e2e --headless",
"lint": "vue-cli-service lint" "lint": "vue-cli-service lint"


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

@@ -1,19 +1,55 @@
import http from "./http"; import http from "./http";


function addNumbersFieldInProfile(profile) {
return {
...profile,
numbers: profile.digits,
};
}

function replaceNumbersWithDigitsInProfile(profile) {
if ("numbers" in profile) {
const { numbers, ...profileWithoutNumbers } = profile;
return {
...profileWithoutNumbers,
digits: numbers,
};
}
return profile;
}

export default { export default {
all() { all() {
return http.get("/passwords/");
return http.get("/passwords/").then((response) => {
response.data.results = response.data.results.map(
replaceNumbersWithDigitsInProfile
);
return response;
});
}, },
create(resource) { create(resource) {
return http.post("/passwords/", resource);
return http
.post("/passwords/", addNumbersFieldInProfile(resource))
.then((response) => {
response.data = replaceNumbersWithDigitsInProfile(response.data);
return response;
});
}, },
read(resource) { read(resource) {
return http.get(`/passwords/${resource.id}/`);
return http.get(`/passwords/${resource.id}/`).then((response) => {
response.data = replaceNumbersWithDigitsInProfile(response.data);
return response;
});
}, },
update(resource) { update(resource) {
return http.put(`/passwords/${resource.id}/`, resource);
return http
.put(`/passwords/${resource.id}/`, addNumbersFieldInProfile(resource))
.then((response) => {
response.data = replaceNumbersWithDigitsInProfile(response.data);
return response;
});
}, },
delete(resource) { delete(resource) {
return http.delete(`/passwords/${resource.id}/`); return http.delete(`/passwords/${resource.id}/`);
}
},
}; };

+ 6
- 4
packages/lesspass-pure/src/services/encryption.js View File

@@ -3,9 +3,11 @@ import defaultPasswordProfile from "../store/defaultPassword";


export function encryptPassword(email, password) { export function encryptPassword(email, password) {
return LessPass.generatePassword( return LessPass.generatePassword(
"lesspass.com",
email,
password,
defaultPasswordProfile
{
...defaultPasswordProfile,
site: "lesspass.com",
login: email,
},
password
); );
} }

+ 128
- 20
packages/lesspass-pure/tests/unit/api/password.spec.js View File

@@ -4,51 +4,159 @@ import Passwords from "@/api/password";


const mock = new MockAdapter(axios); const mock = new MockAdapter(axios);


test("Passwords.create", () => {
const password = { login: "text@example.org" };
test("Passwords.create on old server replace numbers field after creation", () => {
mock mock
.onPost("https://api.lesspass.com/passwords/", password)
.reply(201, { ...password, id: "1" });
return Passwords.create(password).then(response => {
const passwordCreated = response.data;
expect(passwordCreated.id).toBe("1");
expect(passwordCreated.login).toBe(password.login);
.onPost("https://api.lesspass.com/passwords/", {
login: "text@example.org",
digits: false,
numbers: false,
})
.reply(201, { id: "p1", login: "text@example.org", numbers: false });
const password = { login: "text@example.org", digits: false };
return Passwords.create(password).then((response) => {
expect(response.status).toBe(201);
expect(response.data).toEqual({
id: "p1",
login: "text@example.org",
digits: false,
});
}); });
}); });


test("Passwords.all", () => {
mock.onGet("https://api.lesspass.com/passwords/").reply(200, {});
return Passwords.all().then(response => {
test("Passwords.create on new server keeps digits", () => {
mock
.onPost("https://api.lesspass.com/passwords/", {
login: "text@example.org",
digits: false,
numbers: false,
})
.reply(201, { id: "p1", login: "text@example.org", digits: false });
const password = { login: "text@example.org", digits: false };
return Passwords.create(password).then((response) => {
expect(response.status).toBe(201);
expect(response.data).toEqual({
id: "p1",
login: "text@example.org",
digits: false,
});
});
});

test("Passwords.all on old server transform numbers into digits", () => {
mock.onGet("https://api.lesspass.com/passwords/").reply(200, {
results: [{ id: "p1", numbers: false }],
});
return Passwords.all().then((response) => {
expect(response.status).toBe(200);
expect(response.data).toEqual({
results: [{ id: "p1", digits: false }],
});
});
});

test("Passwords.all on new server keeps digits", () => {
mock.onGet("https://api.lesspass.com/passwords/").reply(200, {
results: [{ id: "p2", digits: false }],
});
return Passwords.all().then((response) => {
expect(response.status).toBe(200); expect(response.status).toBe(200);
expect(response.data).toEqual({
results: [{ id: "p2", digits: false }],
});
}); });
}); });


test("Passwords.get", () => {
test("Passwords.get on old server replace numbers with digits", () => {
mock mock
.onGet( .onGet(
"https://api.lesspass.com/passwords/c8e4f983-8ffe-b705-4064-d3b7aa4a4782/" "https://api.lesspass.com/passwords/c8e4f983-8ffe-b705-4064-d3b7aa4a4782/"
) )
.reply(200, {});
.reply(200, { id: "p1", numbers: false });
return Passwords.read({ id: "c8e4f983-8ffe-b705-4064-d3b7aa4a4782" }).then( return Passwords.read({ id: "c8e4f983-8ffe-b705-4064-d3b7aa4a4782" }).then(
response => {
(response) => {
expect(response.status).toBe(200); expect(response.status).toBe(200);
expect(response.data).toEqual({ id: "p1", digits: false });
} }
); );
}); });


test("Passwords.update", () => {
test("Passwords.get on new server keeps digits", () => {
mock
.onGet(
"https://api.lesspass.com/passwords/c8e4f983-8ffe-b705-4064-d3b7aa4a4782/"
)
.reply(200, { id: "p1", digits: false });
return Passwords.read({ id: "c8e4f983-8ffe-b705-4064-d3b7aa4a4782" }).then(
(response) => {
expect(response.status).toBe(200);
expect(response.data).toEqual({ id: "p1", digits: false });
}
);
});

test("Passwords.update on old server replace numbers field after update", () => {
mock
.onPut(
"https://api.lesspass.com/passwords/c8e4f983-4064-8ffe-b705-d3b7aa4a4782/",
{
id: "c8e4f983-4064-8ffe-b705-d3b7aa4a4782",
login: "test@example.org",
digits: true,
numbers: true,
}
)
.reply(200, {
id: "c8e4f983-4064-8ffe-b705-d3b7aa4a4782",
login: "test@example.org",
numbers: true,
});

const password = { const password = {
id: "c8e4f983-4064-8ffe-b705-d3b7aa4a4782", id: "c8e4f983-4064-8ffe-b705-d3b7aa4a4782",
login: "test@example.org"
login: "test@example.org",
digits: true,
}; };

return Passwords.update(password).then((response) => {
expect(response.status).toBe(200);
expect(response.data).toEqual({
id: "c8e4f983-4064-8ffe-b705-d3b7aa4a4782",
login: "test@example.org",
digits: true,
});
});
});

test("Passwords.update on new keeps digits", () => {
mock mock
.onPut( .onPut(
"https://api.lesspass.com/passwords/c8e4f983-4064-8ffe-b705-d3b7aa4a4782/", "https://api.lesspass.com/passwords/c8e4f983-4064-8ffe-b705-d3b7aa4a4782/",
password
{
id: "c8e4f983-4064-8ffe-b705-d3b7aa4a4782",
login: "test@example.org",
digits: true,
numbers: true,
}
) )
.reply(200, {});
return Passwords.update(password).then(response => {
.reply(200, {
id: "c8e4f983-4064-8ffe-b705-d3b7aa4a4782",
login: "test@example.org",
digits: true,
});

const password = {
id: "c8e4f983-4064-8ffe-b705-d3b7aa4a4782",
login: "test@example.org",
digits: true,
};

return Passwords.update(password).then((response) => {
expect(response.status).toBe(200); expect(response.status).toBe(200);
expect(response.data).toEqual({
id: "c8e4f983-4064-8ffe-b705-d3b7aa4a4782",
login: "test@example.org",
digits: true,
});
}); });
}); });


@@ -59,7 +167,7 @@ test("Passwords.delete", () => {
) )
.reply(204); .reply(204);
return Passwords.delete({ id: "c8e4f983-8ffe-4064-b705-d3b7aa4a4782" }).then( return Passwords.delete({ id: "c8e4f983-8ffe-4064-b705-d3b7aa4a4782" }).then(
response => {
(response) => {
expect(response.status).toBe(204); expect(response.status).toBe(204);
} }
); );


Loading…
Cancel
Save