@@ -1,31 +0,0 @@ | |||
<!DOCTYPE html> | |||
<html> | |||
<head> | |||
<meta charset="utf-8"> | |||
<title>LessPass</title> | |||
<meta http-equiv=X-UA-Compatible content="IE=edge,chrome=1"> | |||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> | |||
<link rel="shortcut icon" href="dist/favicon.ico"> | |||
<link rel="stylesheet" href="dist/lesspass.min.css"> | |||
<style> | |||
div.center { | |||
max-width: 420px; | |||
display: block; | |||
margin-left: auto; | |||
margin-right: auto; | |||
} | |||
@media (min-width: 544px) { | |||
#lesspass { | |||
margin-top: 3em; | |||
} | |||
} | |||
</style> | |||
</head> | |||
<body> | |||
<div class="center lesspass--full-width"> | |||
<div id="lesspass"></div> | |||
</div> | |||
<script src="dist/lesspass.min.js"></script> | |||
</body> | |||
</html> |
@@ -6,72 +6,82 @@ | |||
"author": "Guillaume Vincent <guillaume@oslab.fr>", | |||
"scripts": { | |||
"start": "NODE_ENV=production node server.js", | |||
"build": "rm -rf dist && cross-env NODE_ENV=production webpack -p", | |||
"build": "rm -rf dist && webpack --mode=production --config webpack.prod.js", | |||
"build:i18n": "cd scripts && node buildI18n.js", | |||
"dev": "webpack-dev-server --inline --hot --host 0.0.0.0", | |||
"test": "ava", | |||
"dev": "webpack-dev-server --config webpack.dev.js", | |||
"test": "npm run test:unit", | |||
"test:unit": "jest", | |||
"test:e2e": "node test/e2e/runner.js" | |||
}, | |||
"babel": { | |||
"presets": [ | |||
"env" | |||
"@babel/preset-env" | |||
], | |||
"plugins": [ | |||
"transform-object-rest-spread" | |||
"@babel/plugin-proposal-object-rest-spread" | |||
] | |||
}, | |||
"dependencies": { | |||
"@oslab/atob": "0.1.0", | |||
"@oslab/btoa": "0.1.0", | |||
"awesomplete": "1.1.2", | |||
"awesomplete": "^1.1.4", | |||
"axios": "0.18.0", | |||
"balloon-css": "0.5.0", | |||
"bootstrap": "4.0.0", | |||
"copy-text-to-clipboard": "1.0.4", | |||
"bootstrap": "^4.3.1", | |||
"copy-text-to-clipboard": "^2.0.0", | |||
"font-awesome": "4.7.0", | |||
"jwt-decode": "2.2.0", | |||
"lesspass": "6.0.0", | |||
"lodash.debounce": "4.0.8", | |||
"lodash.uniqby": "4.7.0", | |||
"vue": "2.5.16", | |||
"vue": "^2.6.10", | |||
"vue-polyglot": "0.2.3", | |||
"vue-router": "3.0.1", | |||
"vuejs-paginate": "1.8.0", | |||
"vuex": "3.0.1", | |||
"vuex-persistedstate": "2.5.1", | |||
"vue-router": "^3.0.2", | |||
"vuejs-paginate": "^2.1.0", | |||
"vuex": "^3.1.0", | |||
"vuex-persistedstate": "^2.5.4", | |||
"vuex-router-sync": "5.0.0" | |||
}, | |||
"devDependencies": { | |||
"ava": "0.25.0", | |||
"babel-core": "6.26.0", | |||
"babel-loader": "7.1.4", | |||
"babel-plugin-transform-object-rest-spread": "6.26.0", | |||
"babel-preset-env": "1.6.1", | |||
"babel-register": "6.26.0", | |||
"chromedriver": "2.37.0", | |||
"copy-webpack-plugin": "4.5.1", | |||
"cross-env": "5.1.4", | |||
"css-loader": "0.28.11", | |||
"express": "4.16.3", | |||
"extract-text-webpack-plugin": "3.0.2", | |||
"file-loader": "1.1.11", | |||
"nightwatch": "0.9.20", | |||
"nock": "9.2.3", | |||
"node-sass": "4.8.3", | |||
"prettier": "1.11.1", | |||
"sass-loader": "6.0.7", | |||
"style-loader": "0.20.3", | |||
"timekeeper": "2.1.0", | |||
"url-loader": "1.0.1", | |||
"vue-loader": "14.2.2", | |||
"@babel/core": "^7.1.6", | |||
"@babel/plugin-proposal-object-rest-spread": "^7.0.0", | |||
"@babel/plugin-transform-object-assign": "^7.0.0", | |||
"@babel/plugin-transform-react-jsx": "^7.1.6", | |||
"@babel/preset-env": "^7.1.6", | |||
"@babel/register": "^7.4.0", | |||
"axios-mock-adapter": "^1.16.0", | |||
"babel-loader": "^8.0.5", | |||
"chromedriver": "^2.46.0", | |||
"clean-webpack-plugin": "^2.0.1", | |||
"copy-webpack-plugin": "^5.0.1", | |||
"cross-env": "^5.2.0", | |||
"css-loader": "^2.1.1", | |||
"express": "^4.16.4", | |||
"file-loader": "^3.0.1", | |||
"mini-css-extract-plugin": "^0.5.0", | |||
"nightwatch": "^1.0.19", | |||
"nock": "^10.0.6", | |||
"node-sass": "^4.11.0", | |||
"postcss-loader": "^3.0.0", | |||
"prettier": "^1.16.4", | |||
"raw-loader": "^2.0.0", | |||
"sass-loader": "^7.1.0", | |||
"style-loader": "^0.23.1", | |||
"timekeeper": "^2.2.0", | |||
"url-loader": "^1.1.2", | |||
"vue-loader": "^15.7.0", | |||
"vue-polyglot-utils": "0.1.1", | |||
"vue-template-compiler": "2.5.16", | |||
"walk": "2.3.13", | |||
"webpack": "3.10.0", | |||
"webpack-dev-server": "2.9.5" | |||
"vue-template-compiler": "^2.6.10", | |||
"walk": "^2.3.14", | |||
"webpack": "^4.29.6", | |||
"webpack-cli": "^3.3.0", | |||
"webpack-dev-server": "^3.2.1", | |||
"webpack-merge": "^4.2.1" | |||
}, | |||
"ava": { | |||
"require": "babel-register", | |||
"require": [ | |||
"@babel/register" | |||
], | |||
"babel": "inherit", | |||
"files": [ | |||
"test/unit/**/*.js" | |||
@@ -0,0 +1,65 @@ | |||
import axios from "axios"; | |||
import MockAdapter from "axios-mock-adapter"; | |||
import Passwords from "./password"; | |||
const mock = new MockAdapter(axios); | |||
const config = { baseURL: "https://lesspass.com", token: "abc" }; | |||
test("Passwords.create", () => { | |||
const password = { login: "text@example.org" }; | |||
mock | |||
.onPost("/api/passwords/", password) | |||
.reply(201, { ...password, id: "1" }); | |||
return Passwords.create(password, config).then(response => { | |||
const passwordCreated = response.data; | |||
expect(passwordCreated.id).toBe("1"); | |||
expect(passwordCreated.login).toBe(password.login); | |||
}); | |||
}); | |||
test("Passwords.all", () => { | |||
mock.onGet("https://lesspass.com/api/passwords/").reply(200, {}); | |||
return Passwords.all(config).then(response => { | |||
expect(response.status).toBe(200); | |||
}); | |||
}); | |||
test("Passwords.get", () => { | |||
mock | |||
.onGet( | |||
"https://lesspass.com/api/passwords/c8e4f983-8ffe-b705-4064-d3b7aa4a4782/" | |||
) | |||
.reply(200, {}); | |||
return Passwords.read( | |||
{ id: "c8e4f983-8ffe-b705-4064-d3b7aa4a4782" }, | |||
config | |||
).then(response => { | |||
expect(response.status).toBe(200); | |||
}); | |||
}); | |||
test("Passwords.update", () => { | |||
const password = { | |||
id: "c8e4f983-4064-8ffe-b705-d3b7aa4a4782", | |||
login: "test@example.org" | |||
}; | |||
mock | |||
.onPut("https://lesspass.com/api/passwords/c8e4f983-4064-8ffe-b705-d3b7aa4a4782/", password) | |||
.reply(200, {}); | |||
return Passwords.update(password, config).then(response => { | |||
expect(response.status).toBe(200); | |||
}); | |||
}); | |||
test("Passwords.delete", () => { | |||
mock | |||
.onDelete("https://lesspass.com/api/passwords/c8e4f983-8ffe-4064-b705-d3b7aa4a4782/") | |||
.reply(204); | |||
return Passwords.delete( | |||
{ id: "c8e4f983-8ffe-4064-b705-d3b7aa4a4782" }, | |||
config | |||
).then(response => { | |||
expect(response.status).toBe(204); | |||
}); | |||
}); |
@@ -1,72 +1,74 @@ | |||
import test from "ava"; | |||
import nock from "nock"; | |||
import User from "../../src/api/user"; | |||
import axios from "axios"; | |||
import MockAdapter from "axios-mock-adapter"; | |||
import User from "./user"; | |||
test("login", t => { | |||
const mock = new MockAdapter(axios); | |||
test("login", () => { | |||
const token = "5e0651"; | |||
const user = { email: "test@example.org", password: "password" }; | |||
nock("https://lesspass.com") | |||
.post("/api/tokens/auth/", user) | |||
mock | |||
.onPost("/api/tokens/auth/", user) | |||
.reply(201, { token }); | |||
return User.login(user, { | |||
baseURL: "https://lesspass.com" | |||
}).then(response => { | |||
t.is(response.token, token); | |||
expect(response.token).toBe(token); | |||
}); | |||
}); | |||
test("register", t => { | |||
test("register", () => { | |||
const user = { email: "test@example.org", password: "password" }; | |||
nock("https://lesspass.com") | |||
.post("/api/auth/register/", user) | |||
mock | |||
.onPost("/api/auth/register/", user) | |||
.reply(201, { email: user.email, pk: 1 }); | |||
return User.register(user, { | |||
baseURL: "https://lesspass.com" | |||
}).then(response => { | |||
t.is(response.email, user.email); | |||
expect(response.email).toBe(user.email); | |||
}); | |||
}); | |||
test("resetPassword", t => { | |||
test("resetPassword", () => { | |||
var email = "test@lesspass.com"; | |||
nock("https://lesspass.com") | |||
.post("/api/auth/password/reset/", { email }) | |||
mock | |||
.onPost("/api/auth/password/reset/", { email }) | |||
.reply(204); | |||
return User.resetPassword( | |||
{ email }, | |||
{ baseURL: "https://lesspass.com" } | |||
).then(data => { | |||
t.is(data.status, 204); | |||
expect(data.status).toBe(204); | |||
}); | |||
}); | |||
test("confirmResetPassword", t => { | |||
test("confirmResetPassword", () => { | |||
var newPassword = { | |||
uid: "MQ", | |||
token: "5g1-2bd69bd6f6dcd73f8124", | |||
new_password: "password1" | |||
}; | |||
nock("https://lesspass.com") | |||
.post("/api/auth/password/reset/confirm/", newPassword) | |||
mock | |||
.onPost("/api/auth/password/reset/confirm/", newPassword) | |||
.reply(204); | |||
return User.confirmResetPassword(newPassword, { | |||
baseURL: "https://lesspass.com" | |||
}).then(data => { | |||
t.is(data.status, 204); | |||
expect(data.status).toBe(204); | |||
}); | |||
}); | |||
test("refresh token", t => { | |||
test("refresh token", () => { | |||
const token = "3e3231"; | |||
const newToken = | |||
"wibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9eyJzdWIiOiIxMjM0NTY3ODkwIi"; | |||
nock("https://lesspass.com") | |||
.post("/api/tokens/refresh/", { token }) | |||
mock | |||
.onPost("/api/tokens/refresh/", { token }) | |||
.reply(200, { token: newToken }); | |||
return User.requestNewToken( | |||
{ token }, | |||
{ baseURL: "https://lesspass.com" } | |||
).then(refreshedToken => { | |||
t.is(refreshedToken, newToken); | |||
expect(refreshedToken).toBe(newToken); | |||
}); | |||
}); |
@@ -0,0 +1,34 @@ | |||
<!DOCTYPE html> | |||
<html> | |||
<head> | |||
<meta charset="utf-8" /> | |||
<title>LessPass</title> | |||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" /> | |||
<meta | |||
name="viewport" | |||
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" | |||
/> | |||
<link rel="shortcut icon" href="dist/favicon.ico" /> | |||
<link rel="stylesheet" href="dist/lesspass.min.css" /> | |||
<style> | |||
div.center { | |||
max-width: 420px; | |||
display: block; | |||
margin-left: auto; | |||
margin-right: auto; | |||
} | |||
@media (min-width: 544px) { | |||
#lesspass { | |||
margin-top: 3em; | |||
} | |||
} | |||
</style> | |||
</head> | |||
<body> | |||
<div class="center lesspass--full-width"> | |||
<div id="lesspass"></div> | |||
</div> | |||
<script src="dist/lesspass.min.js"></script> | |||
</body> | |||
</html> |
@@ -0,0 +1,18 @@ | |||
import formValidator from "./form-validator"; | |||
test("formValidator.increment()", () => { | |||
expect(formValidator.increment(1, { min: 0, max: 10 })).toBe(2); | |||
expect(formValidator.increment(9, { min: 0, max: 10 })).toBe(10); | |||
expect(formValidator.increment(10, { min: 0, max: 10 })).toBe(10); | |||
expect(formValidator.increment(-1, { min: 0, max: 10 })).toBe(0); | |||
expect(formValidator.increment(-5, { min: 0, max: 10 })).toBe(0); | |||
expect(formValidator.increment(5, { min: 0 })).toBe(6); | |||
}); | |||
test("formValidator.decrement()", () => { | |||
expect(formValidator.decrement(2, { min: 0, max: 10 })).toBe(1); | |||
expect(formValidator.decrement(1, { min: 0, max: 10 })).toBe(0); | |||
expect(formValidator.decrement(0, { min: 0, max: 10 })).toBe(0); | |||
expect(formValidator.decrement(-1, { min: 0, max: 10 })).toBe(0); | |||
expect(formValidator.decrement(15, { min: 0, max: 10 })).toBe(10); | |||
}); |
@@ -0,0 +1,110 @@ | |||
import * as urlParser from "./url-parser"; | |||
test("cleanUrl", () => { | |||
expect("lesspass.com").toBe(urlParser.cleanUrl("https://lesspass.com/#!/")); | |||
expect("lesspass.com").toBe(urlParser.cleanUrl("https://lesspass.com/api/")); | |||
expect("api.lesspass.com").toBe(urlParser.cleanUrl("https://api.lesspass.com/")); | |||
expect("lesspass.com").toBe(urlParser.cleanUrl("http://lesspass.com")); | |||
expect("stackoverflow.com").toBe(urlParser.cleanUrl( | |||
"http://stackoverflow.com/questions/3689423/google-chrome-plugin-how-to-get-domain-from-url-tab-url" | |||
)); | |||
expect("v4-alpha.getbootstrap.com").toBe(urlParser.cleanUrl("http://v4-alpha.getbootstrap.com/components/buttons/")); | |||
expect("accounts.google.com").toBe(urlParser.cleanUrl( | |||
"https://accounts.google.com/ServiceLogin?service=mail&passive=true&rm=false&continue=https://mail.google.com/mail/&ss=1&scc=1<mpl=default<mplcache=2&emr=1&osid=1#identifier" | |||
)); | |||
expect("www.netflix.com").toBe(urlParser.cleanUrl("https://www.netflix.com/browse")); | |||
expect("www.bbc.co.uk").toBe(urlParser.cleanUrl("https://www.bbc.co.uk")); | |||
expect("192.168.1.1:10443").toBe(urlParser.cleanUrl("https://192.168.1.1:10443/webapp/")); | |||
expect("").toBe(urlParser.cleanUrl(undefined)); | |||
expect("").toBe(urlParser.cleanUrl(undefined)); | |||
expect("").toBe(urlParser.cleanUrl("chrome://extensions/")); | |||
}); | |||
test("getSuggestions", () => { | |||
expect(["bbc", "bbc.com", "www.bbc.com"]).toEqual(urlParser.getSuggestions("https://www.bbc.com")); | |||
expect(["example", "example.org", "www.example.org"]).toEqual( | |||
urlParser.getSuggestions("https://www.example.org/api/?offset=100&limit=10") | |||
); | |||
expect(["example", "example.org"]).toEqual(urlParser.getSuggestions("https://example.org")); | |||
expect(["example", "example.org"]).toEqual(urlParser.getSuggestions("example.org")); | |||
expect([]).toEqual(urlParser.getSuggestions("https://192.168.1.1:10443/webapp/")); | |||
expect([]).toEqual(urlParser.getSuggestions("example")); | |||
expect([]).toEqual(urlParser.getSuggestions("example.")); | |||
expect([]).toEqual(urlParser.getSuggestions("example.o")); | |||
expect(urlParser.getSuggestions("http://example.org")).toEqual(urlParser.getSuggestions("https://example.org")); | |||
expect(["example", "example.org"]).toEqual(urlParser.getSuggestions("EXAMPLE.org")); | |||
}); | |||
test("getSite", () => { | |||
global.chrome = { | |||
tabs: { | |||
query(a, callback) { | |||
callback([{ url: "https://example.org" }]); | |||
} | |||
} | |||
}; | |||
return urlParser.getSite().then(site => { | |||
expect(site).toBe("example.org"); | |||
}); | |||
}); | |||
test("getPasswordFromUrlQuery", () => { | |||
const query = { | |||
login: "test@example.org", | |||
site: "example.org", | |||
uppercase: "true", | |||
lowercase: "true", | |||
numbers: "true", | |||
symbols: "false", | |||
length: "16", | |||
counter: "1", | |||
version: "2" | |||
}; | |||
const expectedPassword = { | |||
login: "test@example.org", | |||
site: "example.org", | |||
uppercase: true, | |||
lowercase: true, | |||
numbers: true, | |||
symbols: false, | |||
length: 16, | |||
counter: 1, | |||
version: 2 | |||
}; | |||
expect(urlParser.getPasswordFromUrlQuery(query)).toEqual(expectedPassword); | |||
}); | |||
test("getPasswordFromUrlQuery with base 64 encoded password profile", () => { | |||
const query = { | |||
passwordProfileEncoded: | |||
"eyJsb2dpbiI6InRlc3RAZXhhbXBsZS5vcmciLCJzaXRlIjoiZXhhbXBsZS5vcmciLCJ1cHBlcmNhc2UiOnRydWUsImxvd2VyY2FzZSI6dHJ1ZSwibnVtYmVycyI6dHJ1ZSwic3ltYm9scyI6ZmFsc2UsImxlbmd0aCI6MTYsImNvdW50ZXIiOjEsInZlcnNpb24iOjJ9" | |||
}; | |||
const expectedPassword = { | |||
login: "test@example.org", | |||
site: "example.org", | |||
uppercase: true, | |||
lowercase: true, | |||
numbers: true, | |||
symbols: false, | |||
length: 16, | |||
counter: 1, | |||
version: 2 | |||
}; | |||
expect(urlParser.getPasswordFromUrlQuery(query)).toEqual(expectedPassword); | |||
}); | |||
test("getPasswordFromUrlQuery booleanish", () => { | |||
const query = { | |||
uppercase: "true", | |||
lowercase: "TrUe", | |||
numbers: "1", | |||
symbols: "0" | |||
}; | |||
const expectedPassword = { | |||
uppercase: true, | |||
lowercase: true, | |||
numbers: true, | |||
symbols: false | |||
}; | |||
expect(urlParser.getPasswordFromUrlQuery(query)).toEqual(expectedPassword); | |||
}); |
@@ -1,7 +1,6 @@ | |||
import test from "ava"; | |||
import * as getters from "../../src/store/getters"; | |||
import * as getters from "./getters"; | |||
test("passwordURL", t => { | |||
test("passwordURL", () => { | |||
const state = { | |||
password: { | |||
login: "test@example.org", | |||
@@ -17,13 +16,12 @@ test("passwordURL", t => { | |||
baseURL: "https://lesspass.com" | |||
}; | |||
t.is( | |||
getters.passwordURL(state), | |||
expect(getters.passwordURL(state)).toBe( | |||
"https://lesspass.com/#/?passwordProfileEncoded=eyJsb2dpbiI6InRlc3RAZXhhbXBsZS5vcmciLCJzaXRlIjoiZXhhbXBsZS5vcmciLCJ1cHBlcmNhc2UiOnRydWUsImxvd2VyY2FzZSI6dHJ1ZSwibnVtYmVycyI6dHJ1ZSwic3ltYm9scyI6ZmFsc2UsImxlbmd0aCI6MTYsImNvdW50ZXIiOjEsInZlcnNpb24iOjJ9" | |||
); | |||
}); | |||
test("passwordURL encode uri component", t => { | |||
test("passwordURL encode uri component", () => { | |||
const state = { | |||
password: { | |||
login: "contact@lesspass.com" | |||
@@ -31,13 +29,12 @@ test("passwordURL encode uri component", t => { | |||
baseURL: "https://lesspass.com" | |||
}; | |||
t.is( | |||
getters.passwordURL(state), | |||
expect(getters.passwordURL(state)).toBe( | |||
"https://lesspass.com/#/?passwordProfileEncoded=eyJsb2dpbiI6ImNvbnRhY3RAbGVzc3Bhc3MuY29tIn0%3D" | |||
); | |||
}); | |||
test("isDefaultProfile", t => { | |||
test("isDefaultProfile", () => { | |||
const state = { | |||
password: { | |||
login: "test@example.org", | |||
@@ -62,10 +59,10 @@ test("isDefaultProfile", t => { | |||
version: 2 | |||
} | |||
}; | |||
t.true(getters.isDefaultProfile(state)); | |||
expect(getters.isDefaultProfile(state)).toBe(true); | |||
}); | |||
test("isDefaultProfile false", t => { | |||
test("isDefaultProfile false", () => { | |||
const state = { | |||
password: { | |||
login: "test@example.org", | |||
@@ -90,21 +87,21 @@ test("isDefaultProfile false", t => { | |||
version: 2 | |||
} | |||
}; | |||
t.false(getters.isDefaultProfile(state)); | |||
expect(getters.isDefaultProfile(state)).toBe(false); | |||
}); | |||
test("isAuthenticated", t => { | |||
test("isAuthenticated", () => { | |||
const state = { | |||
authenticated: true | |||
}; | |||
t.true(getters.isAuthenticated(state)); | |||
t.false(getters.isGuest(state)); | |||
expect(getters.isAuthenticated(state)).toBe(true); | |||
expect(getters.isGuest(state)).toBe(false); | |||
}); | |||
test("isGuest", t => { | |||
test("isGuest", () => { | |||
const state = { | |||
authenticated: false | |||
}; | |||
t.false(getters.isAuthenticated(state)); | |||
t.true(getters.isGuest(state)); | |||
expect(getters.isAuthenticated(state)).toBe(false); | |||
expect(getters.isGuest(state)).toBe(true); | |||
}); |
@@ -1,29 +1,28 @@ | |||
import test from "ava"; | |||
import timekeeper from "timekeeper"; | |||
import mutations from "../../src/store/mutations"; | |||
import * as types from "../../src/store/mutation-types"; | |||
import defaultPassword from "../../src/store/defaultPassword"; | |||
import mutations from "./mutations"; | |||
import * as types from "./mutation-types"; | |||
import defaultPassword from "./defaultPassword"; | |||
test("LOGOUT", t => { | |||
test("LOGOUT", () => { | |||
const LOGOUT = mutations[types.LOGOUT]; | |||
const state = { | |||
authenticated: true | |||
}; | |||
LOGOUT(state); | |||
t.false(state.authenticated); | |||
expect(state.authenticated).toBe(false); | |||
}); | |||
test("RESET_PASSWORD set default password", t => { | |||
test("RESET_PASSWORD set default password", () => { | |||
const RESET_PASSWORD = mutations[types.RESET_PASSWORD]; | |||
const state = { | |||
password: { counter: 2 }, | |||
defaultPassword: { counter: 1 } | |||
}; | |||
RESET_PASSWORD(state); | |||
t.is(state.password.counter, 1); | |||
expect(state.password.counter).toBe(1); | |||
}); | |||
test("LOGOUT clean user personal info", t => { | |||
test("LOGOUT clean user personal info", () => { | |||
const LOGOUT = mutations[types.LOGOUT]; | |||
const state = { | |||
token: "123456", | |||
@@ -32,44 +31,44 @@ test("LOGOUT clean user personal info", t => { | |||
defaultPassword: { counter: 1 } | |||
}; | |||
LOGOUT(state); | |||
t.true(state.token === null); | |||
t.is(state.passwords.length, 0); | |||
t.is(state.password.counter, 2); | |||
expect(state.token === null).toBe(true); | |||
expect(state.passwords.length).toBe(0); | |||
expect(state.password.counter).toBe(2); | |||
}); | |||
test("LOGIN", t => { | |||
test("LOGIN", () => { | |||
const LOGIN = mutations[types.LOGIN]; | |||
const state = { authenticated: false }; | |||
LOGIN(state); | |||
t.true(state.authenticated); | |||
expect(state.authenticated).toBe(true); | |||
}); | |||
test("SET_TOKEN", t => { | |||
test("SET_TOKEN", () => { | |||
const token = "123456"; | |||
const SET_TOKEN = mutations[types.SET_TOKEN]; | |||
const state = { token: null }; | |||
SET_TOKEN(state, { token }); | |||
t.is(state.token, token); | |||
expect(state.token).toBe(token); | |||
}); | |||
test("SET_PASSWORD", t => { | |||
test("SET_PASSWORD", () => { | |||
const SET_PASSWORD = mutations[types.SET_PASSWORD]; | |||
const state = { password: null }; | |||
SET_PASSWORD(state, { password: { uppercase: true, counter: 2 } }); | |||
t.is(state.password.counter, 2); | |||
t.true(state.password.uppercase); | |||
expect(state.password.counter).toBe(2); | |||
expect(state.password.uppercase).toBe(true); | |||
}); | |||
test("SET_PASSWORD immutable", t => { | |||
test("SET_PASSWORD immutable", () => { | |||
const SET_PASSWORD = mutations[types.SET_PASSWORD]; | |||
const state = {}; | |||
const password = { counter: 2 }; | |||
SET_PASSWORD(state, { password }); | |||
password.counter = 1; | |||
t.is(state.password.counter, 2); | |||
expect(state.password.counter).toBe(2); | |||
}); | |||
test("SET_DEFAULT_OPTIONS", t => { | |||
test("SET_DEFAULT_OPTIONS", () => { | |||
const SET_DEFAULT_OPTIONS = mutations[types.SET_DEFAULT_OPTIONS]; | |||
const state = { | |||
defaultPassword: { | |||
@@ -85,31 +84,31 @@ test("SET_DEFAULT_OPTIONS", t => { | |||
} | |||
}; | |||
SET_DEFAULT_OPTIONS(state, { options: { symbols: false, length: 30 } }); | |||
t.is(state.defaultPassword.length, 30); | |||
t.false(state.defaultPassword.symbols); | |||
expect(state.defaultPassword.length).toBe(30); | |||
expect(state.defaultPassword.symbols).toBe(false); | |||
}); | |||
test("SET_PASSWORDS", t => { | |||
test("SET_PASSWORDS", () => { | |||
const SET_PASSWORDS = mutations[types.SET_PASSWORDS]; | |||
const state = { | |||
passwords: [] | |||
}; | |||
SET_PASSWORDS(state, { passwords: [{ site: "site1" }, { site: "site2" }] }); | |||
t.is(state.passwords[0].site, "site1"); | |||
t.is(state.passwords[1].site, "site2"); | |||
expect(state.passwords[0].site).toBe("site1"); | |||
expect(state.passwords[1].site).toBe("site2"); | |||
}); | |||
test("DELETE_PASSWORD", t => { | |||
test("DELETE_PASSWORD", () => { | |||
const DELETE_PASSWORD = mutations[types.DELETE_PASSWORD]; | |||
const state = { | |||
passwords: [{ id: "1", site: "site1" }, { id: "2", site: "site2" }] | |||
}; | |||
t.is(state.passwords.length, 2); | |||
expect(state.passwords.length).toBe(2); | |||
DELETE_PASSWORD(state, { id: "1" }); | |||
t.is(state.passwords.length, 1); | |||
expect(state.passwords.length).toBe(1); | |||
}); | |||
test("DELETE_PASSWORD replace state.password with state.defaultPassword", t => { | |||
test("DELETE_PASSWORD replace state.password with state.defaultPassword", () => { | |||
const DELETE_PASSWORD = mutations[types.DELETE_PASSWORD]; | |||
const state = { | |||
passwords: [{ id: "1", length: 30 }, { id: "2", length: 16 }], | |||
@@ -117,20 +116,20 @@ test("DELETE_PASSWORD replace state.password with state.defaultPassword", t => { | |||
defaultPassword: { length: 16 } | |||
}; | |||
DELETE_PASSWORD(state, { id: "1" }); | |||
t.is(state.password.length, 16); | |||
expect(state.password.length).toBe(16); | |||
}); | |||
test("SET_BASE_URL", t => { | |||
test("SET_BASE_URL", () => { | |||
const SET_BASE_URL = mutations[types.SET_BASE_URL]; | |||
const state = { | |||
baseURL: "https://lesspass.com" | |||
}; | |||
const baseURL = "https://example.org"; | |||
SET_BASE_URL(state, { baseURL: baseURL }); | |||
t.is(state.baseURL, baseURL); | |||
expect(state.baseURL).toBe(baseURL); | |||
}); | |||
test("LOAD_PASSWORD_PROFILE", t => { | |||
test("LOAD_PASSWORD_PROFILE", () => { | |||
const state = { | |||
password: { | |||
login: "", | |||
@@ -196,10 +195,10 @@ test("LOAD_PASSWORD_PROFILE", t => { | |||
}; | |||
const LOAD_PASSWORD_PROFILE = mutations[types.LOAD_PASSWORD_PROFILE]; | |||
LOAD_PASSWORD_PROFILE(state, { site: "www.example.org" }); | |||
t.deepEqual(state.password, state.passwords[1]); | |||
expect(state.password).toEqual(state.passwords[1]); | |||
}); | |||
test("LOAD_PASSWORD_PROFILE do nothing if id not empty", t => { | |||
test("LOAD_PASSWORD_PROFILE do nothing if id not empty", () => { | |||
const state = { | |||
password: { | |||
id: "1", | |||
@@ -209,10 +208,10 @@ test("LOAD_PASSWORD_PROFILE do nothing if id not empty", t => { | |||
}; | |||
const LOAD_PASSWORD_PROFILE = mutations[types.LOAD_PASSWORD_PROFILE]; | |||
LOAD_PASSWORD_PROFILE(state, { site: "lesspass.com" }); | |||
t.is(state.password.site, "example.org"); | |||
expect(state.password.site).toBe("example.org"); | |||
}); | |||
test("LOAD_PASSWORD_PROFILE with passwords", t => { | |||
test("LOAD_PASSWORD_PROFILE with passwords", () => { | |||
const state = { | |||
password: { | |||
site: "" | |||
@@ -224,11 +223,11 @@ test("LOAD_PASSWORD_PROFILE with passwords", t => { | |||
}; | |||
const LOAD_PASSWORD_PROFILE = mutations[types.LOAD_PASSWORD_PROFILE]; | |||
LOAD_PASSWORD_PROFILE(state, { site: "www.google.com" }); | |||
t.is(state.password.id, "2"); | |||
t.is(state.password.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", t => { | |||
test("LOAD_PASSWORD_PROFILE with no site keep password profile", () => { | |||
const state = { | |||
password: { | |||
id: "1", | |||
@@ -241,14 +240,14 @@ test("LOAD_PASSWORD_PROFILE with no site keep password profile", t => { | |||
}; | |||
const LOAD_PASSWORD_PROFILE = mutations[types.LOAD_PASSWORD_PROFILE]; | |||
LOAD_PASSWORD_PROFILE(state, { site: "" }); | |||
t.is(state.password.id, "1"); | |||
t.is(state.password.site, "example.org"); | |||
t.is(state.password.login, "contact@example.org"); | |||
t.is(state.password.length, 8); | |||
t.is(state.password.version, 2); | |||
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", t => { | |||
test("LOAD_PASSWORD_PROFILE no passwords", () => { | |||
const state = { | |||
password: { | |||
site: "" | |||
@@ -257,10 +256,10 @@ test("LOAD_PASSWORD_PROFILE no passwords", t => { | |||
}; | |||
const LOAD_PASSWORD_PROFILE = mutations[types.LOAD_PASSWORD_PROFILE]; | |||
LOAD_PASSWORD_PROFILE(state, { site: "account.google.com" }); | |||
t.is(state.password.site, "account.google.com"); | |||
expect(state.password.site).toBe("account.google.com"); | |||
}); | |||
test("LOAD_PASSWORD_PROFILE multiple accounts matching criteria", t => { | |||
test("LOAD_PASSWORD_PROFILE multiple accounts matching criteria", () => { | |||
const state = { | |||
password: { | |||
site: "" | |||
@@ -273,11 +272,11 @@ test("LOAD_PASSWORD_PROFILE multiple accounts matching criteria", t => { | |||
}; | |||
const LOAD_PASSWORD_PROFILE = mutations[types.LOAD_PASSWORD_PROFILE]; | |||
LOAD_PASSWORD_PROFILE(state, { site: "www.google.com" }); | |||
t.is(state.password.id, "2"); | |||
t.is(state.password.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", t => { | |||
test("LOAD_PASSWORD_PROFILE multiple accounts matching criteria order doesn't matter", () => { | |||
const state = { | |||
password: { | |||
site: "" | |||
@@ -290,11 +289,11 @@ test("LOAD_PASSWORD_PROFILE multiple accounts matching criteria order doesn't ma | |||
}; | |||
const LOAD_PASSWORD_PROFILE = mutations[types.LOAD_PASSWORD_PROFILE]; | |||
LOAD_PASSWORD_PROFILE(state, { site: "www.google.com" }); | |||
t.is(state.password.id, "3"); | |||
t.is(state.password.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", t => { | |||
test("LOAD_PASSWORD_PROFILE ends matching criteria nrt #285", () => { | |||
const state = { | |||
password: { | |||
site: "" | |||
@@ -303,11 +302,11 @@ test("LOAD_PASSWORD_PROFILE ends matching criteria nrt #285", t => { | |||
}; | |||
const LOAD_PASSWORD_PROFILE = mutations[types.LOAD_PASSWORD_PROFILE]; | |||
LOAD_PASSWORD_PROFILE(state, { site: "www.google.com" }); | |||
t.is(state.password.id, "1"); | |||
t.is(state.password.site, "account.google.com"); | |||
expect(state.password.id).toBe("1"); | |||
expect(state.password.site).toBe("account.google.com"); | |||
}); | |||
test("LOAD_PASSWORD_PROFILE without www", t => { | |||
test("LOAD_PASSWORD_PROFILE without www", () => { | |||
const state = { | |||
password: { | |||
site: "" | |||
@@ -316,11 +315,11 @@ test("LOAD_PASSWORD_PROFILE without www", t => { | |||
}; | |||
const LOAD_PASSWORD_PROFILE = mutations[types.LOAD_PASSWORD_PROFILE]; | |||
LOAD_PASSWORD_PROFILE(state, { site: "www.reddit.com" }); | |||
t.is(state.password.id, "1"); | |||
t.is(state.password.site, "reddit.com"); | |||
expect(state.password.id).toBe("1"); | |||
expect(state.password.site).toBe("reddit.com"); | |||
}); | |||
test("SET_SITE default state", t => { | |||
test("SET_SITE default state", () => { | |||
const state = { | |||
password: defaultPassword, | |||
passwords: [], | |||
@@ -329,23 +328,23 @@ test("SET_SITE default state", t => { | |||
}; | |||
const SET_SITE = mutations[types.SET_SITE]; | |||
SET_SITE(state, { site: "www.example.org" }); | |||
t.deepEqual(state.password.site, "www.example.org"); | |||
expect(state.password.site).toEqual("www.example.org"); | |||
}); | |||
test("SET_MESSAGE", t => { | |||
test("SET_MESSAGE", () => { | |||
const SET_MESSAGE = mutations[types.SET_MESSAGE]; | |||
const state = {}; | |||
SET_MESSAGE(state, { | |||
message: { text: "success message", status: "success" } | |||
}); | |||
t.is(state.message.text, "success message"); | |||
t.is(state.message.status, "success"); | |||
expect(state.message.text).toBe("success message"); | |||
expect(state.message.status).toBe("success"); | |||
}); | |||
test("CLEAN_MESSAGE", t => { | |||
test("CLEAN_MESSAGE", () => { | |||
const CLEAN_MESSAGE = mutations[types.CLEAN_MESSAGE]; | |||
const state = { message: { text: "error message", status: "error" } }; | |||
CLEAN_MESSAGE(state); | |||
t.is(state.message.text, ""); | |||
t.is(state.message.status, "success"); | |||
expect(state.message.text).toBe(""); | |||
expect(state.message.status).toBe("success"); | |||
}); |
@@ -1,86 +0,0 @@ | |||
import test from "ava"; | |||
import nock from "nock"; | |||
import Passwords from "../../src/api/password"; | |||
const token = | |||
"ZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFt"; | |||
const config = { baseURL: "https://lesspass.com", token: token }; | |||
const headers = { reqheaders: { Authorization: `JWT ${token}` } }; | |||
test("Passwords.create", t => { | |||
const password = { login: "text@example.org" }; | |||
nock("https://lesspass.com") | |||
.post("/api/passwords/", password) | |||
.reply(201, { ...password, id: "1" }); | |||
return Passwords.create(password, config).then(response => { | |||
const passwordCreated = response.data; | |||
t.is(passwordCreated.id, "1"); | |||
t.is(passwordCreated.login, password.login); | |||
}); | |||
}); | |||
test("Passwords.create set Authorization header", t => { | |||
const password = { login: "text@example.org" }; | |||
nock("https://lesspass.com", headers) | |||
.post("/api/passwords/", password) | |||
.query(true) | |||
.reply(201, { | |||
id: "1", | |||
...password | |||
}); | |||
return Passwords.create(password, config).then(response => { | |||
const passwordCreated = response.data; | |||
t.is(passwordCreated.id, "1"); | |||
t.is(passwordCreated.login, password.login); | |||
}); | |||
}); | |||
test("Passwords.all", t => { | |||
nock("https://lesspass.com", headers) | |||
.get("/api/passwords/") | |||
.query(true) | |||
.reply(200, {}); | |||
return Passwords.all(config).then(response => { | |||
t.is(response.status, 200); | |||
}); | |||
}); | |||
test("Passwords.get", t => { | |||
nock("https://lesspass.com", headers) | |||
.get("/api/passwords/c8e4f983-8ffe-b705-4064-d3b7aa4a4782/") | |||
.query(true) | |||
.reply(200, {}); | |||
return Passwords.read( | |||
{ id: "c8e4f983-8ffe-b705-4064-d3b7aa4a4782" }, | |||
config | |||
).then(response => { | |||
t.is(response.status, 200); | |||
}); | |||
}); | |||
test("Passwords.update", t => { | |||
const password = { | |||
id: "c8e4f983-4064-8ffe-b705-d3b7aa4a4782", | |||
login: "test@example.org" | |||
}; | |||
nock("https://lesspass.com", headers) | |||
.put("/api/passwords/c8e4f983-4064-8ffe-b705-d3b7aa4a4782/", password) | |||
.query(true) | |||
.reply(200, {}); | |||
return Passwords.update(password, config).then(response => { | |||
t.is(response.status, 200); | |||
}); | |||
}); | |||
test("Passwords.delete", t => { | |||
nock("https://lesspass.com", headers) | |||
.delete("/api/passwords/c8e4f983-8ffe-4064-b705-d3b7aa4a4782/") | |||
.query(true) | |||
.reply(204); | |||
return Passwords.delete( | |||
{ id: "c8e4f983-8ffe-4064-b705-d3b7aa4a4782" }, | |||
config | |||
).then(response => { | |||
t.is(response.status, 204); | |||
}); | |||
}); |
@@ -1,19 +0,0 @@ | |||
import test from "ava"; | |||
import formValidator from "../../src/services/form-validator"; | |||
test("formValidator.increment()", t => { | |||
t.is(formValidator.increment(1, { min: 0, max: 10 }), 2); | |||
t.is(formValidator.increment(9, { min: 0, max: 10 }), 10); | |||
t.is(formValidator.increment(10, { min: 0, max: 10 }), 10); | |||
t.is(formValidator.increment(-1, { min: 0, max: 10 }), 0); | |||
t.is(formValidator.increment(-5, { min: 0, max: 10 }), 0); | |||
t.is(formValidator.increment(5, { min: 0 }), 6); | |||
}); | |||
test("formValidator.decrement()", t => { | |||
t.is(formValidator.decrement(2, { min: 0, max: 10 }), 1); | |||
t.is(formValidator.decrement(1, { min: 0, max: 10 }), 0); | |||
t.is(formValidator.decrement(0, { min: 0, max: 10 }), 0); | |||
t.is(formValidator.decrement(-1, { min: 0, max: 10 }), 0); | |||
t.is(formValidator.decrement(15, { min: 0, max: 10 }), 10); | |||
}); |
@@ -1,142 +0,0 @@ | |||
import test from "ava"; | |||
import * as urlParser from "../../src/services/url-parser"; | |||
test("cleanUrl", t => { | |||
t.is("lesspass.com", urlParser.cleanUrl("https://lesspass.com/#!/")); | |||
t.is("lesspass.com", urlParser.cleanUrl("https://lesspass.com/api/")); | |||
t.is("api.lesspass.com", urlParser.cleanUrl("https://api.lesspass.com/")); | |||
t.is("lesspass.com", urlParser.cleanUrl("http://lesspass.com")); | |||
t.is( | |||
"stackoverflow.com", | |||
urlParser.cleanUrl( | |||
"http://stackoverflow.com/questions/3689423/google-chrome-plugin-how-to-get-domain-from-url-tab-url" | |||
) | |||
); | |||
t.is( | |||
"v4-alpha.getbootstrap.com", | |||
urlParser.cleanUrl("http://v4-alpha.getbootstrap.com/components/buttons/") | |||
); | |||
t.is( | |||
"accounts.google.com", | |||
urlParser.cleanUrl( | |||
"https://accounts.google.com/ServiceLogin?service=mail&passive=true&rm=false&continue=https://mail.google.com/mail/&ss=1&scc=1<mpl=default<mplcache=2&emr=1&osid=1#identifier" | |||
) | |||
); | |||
t.is("www.netflix.com", urlParser.cleanUrl("https://www.netflix.com/browse")); | |||
t.is("www.bbc.co.uk", urlParser.cleanUrl("https://www.bbc.co.uk")); | |||
t.is( | |||
"192.168.1.1:10443", | |||
urlParser.cleanUrl("https://192.168.1.1:10443/webapp/") | |||
); | |||
t.is("", urlParser.cleanUrl(undefined)); | |||
t.is("", urlParser.cleanUrl(undefined)); | |||
t.is("", urlParser.cleanUrl("chrome://extensions/")); | |||
}); | |||
test("getSuggestions", t => { | |||
t.deepEqual( | |||
["bbc", "bbc.com", "www.bbc.com"], | |||
urlParser.getSuggestions("https://www.bbc.com") | |||
); | |||
t.deepEqual( | |||
["example", "example.org", "www.example.org"], | |||
urlParser.getSuggestions("https://www.example.org/api/?offset=100&limit=10") | |||
); | |||
t.deepEqual( | |||
["example", "example.org"], | |||
urlParser.getSuggestions("https://example.org") | |||
); | |||
t.deepEqual( | |||
["example", "example.org"], | |||
urlParser.getSuggestions("example.org") | |||
); | |||
t.deepEqual( | |||
[], | |||
urlParser.getSuggestions("https://192.168.1.1:10443/webapp/") | |||
); | |||
t.deepEqual([], urlParser.getSuggestions("example")); | |||
t.deepEqual([], urlParser.getSuggestions("example.")); | |||
t.deepEqual([], urlParser.getSuggestions("example.o")); | |||
t.deepEqual( | |||
urlParser.getSuggestions("http://example.org"), | |||
urlParser.getSuggestions("https://example.org") | |||
); | |||
t.deepEqual( | |||
["example", "example.org"], | |||
urlParser.getSuggestions("EXAMPLE.org") | |||
); | |||
}); | |||
test("getSite", t => { | |||
global.chrome = { | |||
tabs: { | |||
query(a, callback) { | |||
callback([{ url: "https://example.org" }]); | |||
} | |||
} | |||
}; | |||
return urlParser.getSite().then(site => { | |||
t.is(site, "example.org"); | |||
}); | |||
}); | |||
test("getPasswordFromUrlQuery", t => { | |||
const query = { | |||
login: "test@example.org", | |||
site: "example.org", | |||
uppercase: "true", | |||
lowercase: "true", | |||
numbers: "true", | |||
symbols: "false", | |||
length: "16", | |||
counter: "1", | |||
version: "2" | |||
}; | |||
const expectedPassword = { | |||
login: "test@example.org", | |||
site: "example.org", | |||
uppercase: true, | |||
lowercase: true, | |||
numbers: true, | |||
symbols: false, | |||
length: 16, | |||
counter: 1, | |||
version: 2 | |||
}; | |||
t.deepEqual(urlParser.getPasswordFromUrlQuery(query), expectedPassword); | |||
}); | |||
test("getPasswordFromUrlQuery with base 64 encoded password profile", t => { | |||
const query = { | |||
passwordProfileEncoded: | |||
"eyJsb2dpbiI6InRlc3RAZXhhbXBsZS5vcmciLCJzaXRlIjoiZXhhbXBsZS5vcmciLCJ1cHBlcmNhc2UiOnRydWUsImxvd2VyY2FzZSI6dHJ1ZSwibnVtYmVycyI6dHJ1ZSwic3ltYm9scyI6ZmFsc2UsImxlbmd0aCI6MTYsImNvdW50ZXIiOjEsInZlcnNpb24iOjJ9" | |||
}; | |||
const expectedPassword = { | |||
login: "test@example.org", | |||
site: "example.org", | |||
uppercase: true, | |||
lowercase: true, | |||
numbers: true, | |||
symbols: false, | |||
length: 16, | |||
counter: 1, | |||
version: 2 | |||
}; | |||
t.deepEqual(urlParser.getPasswordFromUrlQuery(query), expectedPassword); | |||
}); | |||
test("getPasswordFromUrlQuery booleanish", t => { | |||
const query = { | |||
uppercase: "true", | |||
lowercase: "TrUe", | |||
numbers: "1", | |||
symbols: "0" | |||
}; | |||
const expectedPassword = { | |||
uppercase: true, | |||
lowercase: true, | |||
numbers: true, | |||
symbols: false | |||
}; | |||
t.deepEqual(urlParser.getPasswordFromUrlQuery(query), expectedPassword); | |||
}); |
@@ -2,12 +2,12 @@ const path = require("path"); | |||
const webpack = require("webpack"); | |||
const HtmlWebpackPlugin = require("html-webpack-plugin"); | |||
const CleanWebpackPlugin = require("clean-webpack-plugin"); | |||
const CopyWebpackPlugin = require("copy-webpack-plugin"); | |||
const VueLoaderPlugin = require("vue-loader/lib/plugin"); | |||
const MiniCssExtractPlugin = require("mini-css-extract-plugin"); | |||
const productionMode = process.env.NODE_ENV === "production"; | |||
module.exports = { | |||
entry: "./src/index.js", | |||
entry: "./src/main.js", | |||
resolve: { | |||
modules: [path.resolve(__dirname, "src"), "node_modules"] | |||
}, | |||
@@ -16,31 +16,35 @@ module.exports = { | |||
filename: productionMode ? "[name].[hash].css" : "[name].css", | |||
chunkFilename: productionMode ? "[id].[hash].css" : "[id].css" | |||
}), | |||
new CleanWebpackPlugin(["build"]), | |||
new CleanWebpackPlugin(), | |||
new HtmlWebpackPlugin({ | |||
template: "./src/index.html", | |||
inject: "body" | |||
}), | |||
new CopyWebpackPlugin([{ context: "./src", from: "config.json", to: "" }]), | |||
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/), | |||
new webpack.WatchIgnorePlugin(["./src/config.json"]) | |||
new VueLoaderPlugin() | |||
], | |||
output: { | |||
filename: "[name].[chunkhash].js", | |||
path: path.resolve(__dirname, "build") | |||
path: path.resolve(__dirname, "dist") | |||
}, | |||
module: { | |||
rules: [ | |||
{ | |||
test: /\.vue$/, | |||
loader: "vue-loader" | |||
}, | |||
{ | |||
test: /\.js$/, | |||
exclude: /node_modules\/(?!copy-text-to-clipboard)/, | |||
loader: "babel-loader" | |||
}, | |||
{ | |||
test: /\.css$/, | |||
test: /\.(sa|sc|c)ss$/, | |||
use: [ | |||
productionMode ? MiniCssExtractPlugin.loader : "style-loader", | |||
"css-loader" | |||
"css-loader", | |||
"sass-loader" | |||
] | |||
}, | |||
{ | |||
@@ -1,35 +0,0 @@ | |||
const webpack = require('webpack'); | |||
const path = require('path'); | |||
const ExtractTextPlugin = require('extract-text-webpack-plugin'); | |||
const CopyWebpackPlugin = require('copy-webpack-plugin'); | |||
module.exports = { | |||
entry: { | |||
app: './src/main.js', | |||
}, | |||
output: { | |||
path: path.resolve(__dirname, './dist'), | |||
publicPath: '/dist/', | |||
filename: 'lesspass.min.js' | |||
}, | |||
module: { | |||
rules: [ | |||
{test: /\.vue$/, loader: 'vue-loader'}, | |||
{test: /\.js$/, exclude: /node_modules\/(?!copy-text-to-clipboard)/, loader: "babel-loader"}, | |||
{test: /\.(png|jpg|jpeg|gif|ico)$/, loader: 'file-loader?name=[name].[ext]'}, | |||
{ | |||
test: /\.scss$/, | |||
loader: ExtractTextPlugin.extract({fallback: 'style-loader', use: 'css-loader!sass-loader', publicPath: ''}) | |||
}, | |||
{test: /\.woff(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader?limit=8192&mimetype=application/font-woff'}, | |||
{test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader?limit=8192&mimetype=application/font-woff'}, | |||
{test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader?limit=8192&mimetype=application/octet-stream'}, | |||
{test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: 'file-loader'}, | |||
{test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader?limit=8192&mimetype=image/svg+xml'}, | |||
] | |||
}, | |||
plugins: [ | |||
new ExtractTextPlugin('lesspass.min.css'), | |||
new CopyWebpackPlugin([{context: './src/i18n', from: '**/*.json', to: 'i18n'}]) | |||
] | |||
}; |
@@ -7,7 +7,7 @@ module.exports = merge(common, { | |||
devServer: { | |||
host: "0.0.0.0", | |||
port: 8000, | |||
contentBase: "./build", | |||
contentBase: "./dist", | |||
historyApiFallback: true | |||
} | |||
}); |