@@ -177,7 +177,6 @@ | |||
logging.success(this.$t('entries.entry_created')); | |||
}) | |||
.catch((err) => { | |||
console.log(err); | |||
logging.error(this.$t('entries.error_creation')); | |||
}); | |||
}, | |||
@@ -1,3 +1,17 @@ | |||
import 'vue'; | |||
import './locales'; | |||
import './router'; | |||
import http from './services/http'; | |||
window.setInterval(() => { | |||
let token = localStorage.getItem('token'); | |||
if (token) { | |||
http.auth.refreshToken(token).then((new_token) => { | |||
localStorage.setItem('token', new_token) | |||
}) | |||
} | |||
}, 60 * 60 * 1000); | |||
@@ -7,7 +7,7 @@ import LandingPage from './landing-page/LandingPage'; | |||
import LoginPage from './app/Login'; | |||
import RegisterPage from './app/Register'; | |||
import LessPassConnected from './app/Index'; | |||
import Http from './services/http'; | |||
import http from './services/http'; | |||
const router = new Router({ | |||
history: true, | |||
@@ -25,7 +25,7 @@ router.map({ | |||
component: RegisterPage, | |||
}, | |||
'/app/': { | |||
auth_required: false, | |||
auth_required: true, | |||
component: LessPassConnected, | |||
}, | |||
}); | |||
@@ -34,18 +34,22 @@ router.redirect({ | |||
'*': '/', | |||
}); | |||
Vue.config.debug = true; | |||
router.beforeEach(transition => { | |||
if (transition.to.path === '/' && Http.auth.user.authenticated) { | |||
transition.redirect('/app/'); | |||
} | |||
if (transition.to.auth_required && !Http.auth.user.authenticated) { | |||
transition.redirect('/login/'); | |||
if (transition.to.auth_required) { | |||
http.auth.checkAuth() | |||
.then(() => { | |||
if (transition.to.path === '/') { | |||
transition.redirect('/app/'); | |||
} else { | |||
transition.next(); | |||
} | |||
}) | |||
.catch(() => { | |||
transition.redirect('/login/'); | |||
}); | |||
} else { | |||
transition.next(); | |||
} | |||
transition.next(); | |||
}); | |||
@@ -1,23 +1,17 @@ | |||
import request from 'axios'; | |||
export default class Auth { | |||
constructor(localStorage = global.localStorage) { | |||
this.localStorage = localStorage; | |||
this.user = { | |||
authenticated: false, | |||
} | |||
} | |||
export default { | |||
localStorage: null, | |||
user: { | |||
authenticated: false, | |||
}, | |||
login(credentials) { | |||
var self = this; | |||
return request.post('/api/token-auth/', credentials) | |||
.then((response) => { | |||
self.localStorage.setItem('token', response.data.token); | |||
self.user.authenticated = true; | |||
this.authUser(response.data.token); | |||
return response; | |||
}); | |||
} | |||
}, | |||
refreshToken(token) { | |||
return request | |||
.post('/api/token-refresh/', {token: token}) | |||
@@ -27,36 +21,50 @@ export default class Auth { | |||
.catch((err) => { | |||
throw err; | |||
}); | |||
} | |||
}, | |||
getToken(token_name){ | |||
return new Promise((resolve, reject) => { | |||
const token = this.localStorage.getItem(token_name); | |||
if (token) { | |||
resolve(token); | |||
} else { | |||
reject(); | |||
} | |||
}); | |||
}, | |||
verifyToken(token){ | |||
return request.post('/api/token-verify/', {token: token}) | |||
.then(() => { | |||
return token | |||
}); | |||
}, | |||
gu() { | |||
return this.user.authenticated | |||
}, | |||
authUser(token){ | |||
this.localStorage.setItem('token', token); | |||
this.user.authenticated = true; | |||
}, | |||
resetAuth(e){ | |||
this.localStorage.removeItem('token'); | |||
this.user.authenticated = false; | |||
throw err; | |||
}, | |||
checkAuth() { | |||
var self = this; | |||
const token = self.localStorage.getItem('token'); | |||
if (token) { | |||
return request | |||
.post('/api/token-verify/', {token: token}) | |||
.then((response) => { | |||
self.user.authenticated = true; | |||
return response; | |||
}) | |||
.catch(() => { | |||
self.user.authenticated = false; | |||
self.localStorage.removeItem('token'); | |||
throw err; | |||
}); | |||
} | |||
} | |||
return this.getToken('token') | |||
.then(this.verifyToken) | |||
.then(this.authUser.bind(this)) | |||
.catch(this.resetAuth.bind(this)); | |||
}, | |||
logout() { | |||
var self = this; | |||
return new Promise((resolve, reject) => { | |||
try { | |||
self.localStorage.removeItem('token'); | |||
self.user.authenticated = false; | |||
this.localStorage.removeItem('token'); | |||
this.user.authenticated = false; | |||
resolve(); | |||
} catch (e) { | |||
reject(e); | |||
} | |||
}); | |||
} | |||
} | |||
}; |
@@ -1,22 +1,22 @@ | |||
import axios from 'axios'; | |||
import request from 'axios'; | |||
export default class Entry { | |||
constructor(localStorage = global.localStorage) { | |||
this.localStorage = localStorage; | |||
this.request = axios.create({ | |||
export default { | |||
localStorage: null, | |||
getRequestConfig() { | |||
return { | |||
headers: {'Authorization': 'JWT ' + this.localStorage.getItem('token')} | |||
}); | |||
} | |||
} | |||
}, | |||
create(entry) { | |||
return this.request.post('/api/entries/', entry) | |||
let config = this.getRequestConfig(); | |||
return request.post('/api/entries/', entry, config) | |||
.then((response) => { | |||
return response; | |||
}); | |||
} | |||
}, | |||
all() { | |||
return this.request.get('/api/entries/') | |||
let config = this.getRequestConfig(); | |||
return request.get('/api/entries/', config) | |||
.then((response) => { | |||
return response; | |||
}); | |||
@@ -1,14 +1,11 @@ | |||
import AuthService from './auth'; | |||
import EntryServices from './entries'; | |||
import auth from './auth'; | |||
import entries from './entries'; | |||
let Auth = new AuthService(); | |||
let Entries = new EntryServices(); | |||
export {Auth}; | |||
export {Entries}; | |||
auth.localStorage = localStorage; | |||
entries.localStorage = localStorage; | |||
export default { | |||
auth: Auth, | |||
entries: Entries | |||
auth: auth, | |||
entries: entries | |||
} | |||
@@ -0,0 +1,115 @@ | |||
import auth from '../src/services/auth'; | |||
import {localStorage} from './helpers'; | |||
auth.localStorage = localStorage; | |||
suite('auth', () => { | |||
var token, credentials; | |||
beforeEach(() => { | |||
credentials = { | |||
email: 'test@lesspass.com', | |||
password: 'password' | |||
}; | |||
token = 'eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9'; | |||
}); | |||
test('should make a post request to create a session', (done) => { | |||
nock('http://localhost/').post('/api/token-auth/', credentials).reply(201, {token: token}); | |||
auth.login(credentials).then(() => { | |||
done(); | |||
}); | |||
}); | |||
test('should throw error if bad request', (done) => { | |||
nock('http://localhost/').post('/api/token-auth/', credentials).reply(400, {}); | |||
auth.login(credentials).catch(() => { | |||
done(); | |||
}); | |||
}); | |||
test('should store token in localStorage', (done) => { | |||
nock('http://localhost/').post('/api/token-auth/', credentials).reply(201, {token: token}); | |||
auth.login(credentials).then(() => { | |||
assert.equal(token, localStorage.getItem('token')); | |||
done(); | |||
}); | |||
}); | |||
test('should authenticate the user', (done) => { | |||
nock('http://localhost/').post('/api/token-auth/', credentials).reply(201, {token: token}); | |||
auth.login(credentials).then(() => { | |||
assert(auth.user.authenticated); | |||
done(); | |||
}); | |||
}); | |||
test('check token with a valid token', (done) => { | |||
nock('http://localhost/').post('/api/token-verify/', {"token": token}).reply(200); | |||
localStorage.setItem('token', token); | |||
auth.checkAuth().then(() => { | |||
assert(auth.user.authenticated); | |||
done(); | |||
}); | |||
}); | |||
test('check token with an invalid token', (done) => { | |||
nock('http://localhost/').post('/api/token-verify/', {"token": token}).reply(400); | |||
localStorage.setItem('token', token); | |||
auth.checkAuth().catch(() => { | |||
assert(!auth.user.authenticated); | |||
done(); | |||
}); | |||
}); | |||
test('check auth without any token', (done) => { | |||
auth.user.authenticated = true; | |||
localStorage.removeItem('token'); | |||
auth.checkAuth().catch(() => { | |||
assert(!auth.user.authenticated); | |||
done(); | |||
}); | |||
}); | |||
test('get token', (done) => { | |||
localStorage.setItem('lesspass-token', token); | |||
auth.getToken('lesspass-token').then((expected_token) => { | |||
assert.equal(token, expected_token); | |||
localStorage.removeItem('lesspass-token'); | |||
done(); | |||
}); | |||
}); | |||
test('get missing token', (done) => { | |||
localStorage.removeItem('token'); | |||
auth.getToken('token').catch(() => { | |||
done(); | |||
}); | |||
}); | |||
test('check refresh token non-expired', (done) => { | |||
var new_token = 'wibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9eyJzdWIiOiIxMjM0NTY3ODkwIi'; | |||
nock('http://localhost/').post('/api/token-refresh/', {"token": token}).reply(200, {token: new_token}); | |||
auth.refreshToken(token).then((t) => { | |||
assert.equal(new_token, t); | |||
done(); | |||
}); | |||
}); | |||
test('check refresh token expired', (done) => { | |||
localStorage.setItem('token', token); | |||
nock('http://localhost/').post('/api/token-refresh/', {"token": token}).reply(400); | |||
auth.refreshToken(token).catch(() => { | |||
done(); | |||
}); | |||
}); | |||
test('logout', (done) => { | |||
auth.user.authenticated = true; | |||
auth.logout().then(()=> { | |||
assert(!auth.user.authenticated); | |||
assert(localStorage.getItem('token') === null); | |||
done(); | |||
}); | |||
}); | |||
}); |
@@ -0,0 +1,63 @@ | |||
import entries from '../src/services/entries'; | |||
import {localStorage} from './helpers'; | |||
entries.localStorage = localStorage; | |||
suite('entries', () => { | |||
var entry, token; | |||
beforeEach(() => { | |||
token = 'ZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFt'; | |||
localStorage.setItem('token', token); | |||
entry = { | |||
"site": "twitter.com", | |||
"password": { | |||
"counter": 1, | |||
"settings": [ | |||
"lowercase", | |||
"uppercase", | |||
"numbers", | |||
"symbols" | |||
], | |||
"length": 12 | |||
}, | |||
"email": "guillaume@oslab.fr", | |||
}; | |||
}); | |||
test('should send requests with Authorization header', (done) => { | |||
var headers = {reqheaders: {'Authorization': 'JWT ' + token}}; | |||
nock('http://localhost/', headers).get('/api/entries/').reply(200, {entries: []}); | |||
entries.all().then(() => { | |||
done(); | |||
}); | |||
}); | |||
test('should send requests with Authorization header updated', (done) => { | |||
var new_token = 'WV9eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRyd'; | |||
localStorage.setItem('token', new_token); | |||
var headers = {reqheaders: {'Authorization': 'JWT ' + new_token}}; | |||
nock('http://localhost/', headers).get('/api/entries/').reply(200, {entries: []}); | |||
entries.all().then(() => { | |||
done(); | |||
}); | |||
}); | |||
test('should make a post request to create an entry', (done) => { | |||
nock('http://localhost/').post('/api/entries/', entry).reply(201, {}); | |||
entries.create(entry) | |||
.then((response) => { | |||
assert.equal(201, response.status); | |||
done(); | |||
}); | |||
}); | |||
test('should get all entries', (done) => { | |||
nock('http://localhost/').get('/api/entries/').reply(200, {entries: []}); | |||
entries.all().then((response) => { | |||
assert.equal(200, response.status); | |||
assert.equal(0, response.data.entries.length); | |||
done(); | |||
}); | |||
}); | |||
}); |
@@ -0,0 +1,14 @@ | |||
import assert from 'assert'; | |||
import nock from 'nock'; | |||
global.assert = assert; | |||
global.nock = nock; | |||
import {LocalStorage} from 'node-localstorage'; | |||
const localStorage = new LocalStorage('./tests/localStorage'); | |||
export {localStorage}; | |||
after(()=> { | |||
localStorage._deleteLocation() | |||
}); |
@@ -1,157 +0,0 @@ | |||
import assert from 'assert'; | |||
import nock from 'nock'; | |||
import Auth from '../src/services/auth'; | |||
import Entries from '../src/services/entries'; | |||
import {LocalStorage} from 'node-localstorage'; | |||
const url = 'http://localhost/'; | |||
suite('auth', () => { | |||
var auth, localStorage, token, credentials; | |||
beforeEach(() => { | |||
credentials = { | |||
email: 'test@lesspass.com', | |||
password: 'password' | |||
}; | |||
token = 'eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9'; | |||
localStorage = new LocalStorage('./tests/localStorage'); | |||
auth = new Auth(localStorage); | |||
}); | |||
test('should make a post request to create a session', (done) => { | |||
nock(url).post('/api/token-auth/', credentials).reply(201, {token: token}); | |||
auth.login(credentials).then(() => { | |||
done(); | |||
}); | |||
}); | |||
test('should throw error if bad request', (done) => { | |||
nock(url).post('/api/token-auth/', credentials).reply(400, {}); | |||
auth.login(credentials).catch(() => { | |||
done(); | |||
}); | |||
}); | |||
test('should store token in localStorage', (done) => { | |||
nock(url).post('/api/token-auth/', credentials).reply(201, {token: token}); | |||
auth.login(credentials).then(() => { | |||
assert.equal(token, localStorage.getItem('token')); | |||
done(); | |||
}); | |||
}); | |||
test('should authenticate the user', (done) => { | |||
nock(url).post('/api/token-auth/', credentials).reply(201, {token: token}); | |||
auth.login(credentials).then(() => { | |||
assert(auth.user.authenticated); | |||
done(); | |||
}); | |||
}); | |||
test('check auth with a valid token', (done) => { | |||
nock(url).post('/api/token-verify/', {"token": token}).reply(200); | |||
localStorage.setItem('token', token); | |||
auth.checkAuth().then(() => { | |||
assert(auth.user.authenticated); | |||
done(); | |||
}); | |||
}); | |||
test('check auth with an invalid token', (done) => { | |||
nock(url).post('/api/token-verify/', {"token": token}).reply(400); | |||
localStorage.setItem('token', token); | |||
auth.checkAuth().catch(() => { | |||
assert(!auth.user.authenticated); | |||
done(); | |||
}); | |||
}); | |||
test('check refresh token non-expired', (done) => { | |||
var new_token = 'wibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9eyJzdWIiOiIxMjM0NTY3ODkwIi'; | |||
nock(url).post('/api/token-refresh/', {"token": token}).reply(200, {token: new_token}); | |||
auth.refreshToken(token).then((t) => { | |||
assert.equal(new_token, t); | |||
done(); | |||
}); | |||
}); | |||
test('check refresh token expired', (done) => { | |||
localStorage.setItem('token', token); | |||
nock(url).post('/api/token-refresh/', {"token": token}).reply(400); | |||
auth.refreshToken(token).catch(() => { | |||
done(); | |||
}); | |||
}); | |||
test('logout', (done) => { | |||
auth.user.authenticated = true; | |||
auth.logout().then(()=> { | |||
assert(!auth.user.authenticated); | |||
assert(localStorage.getItem('token') === null); | |||
done(); | |||
}); | |||
}); | |||
after(()=> { | |||
localStorage._deleteLocation() | |||
}); | |||
}); | |||
suite('entries', () => { | |||
var entries, entry, localStorage, token; | |||
beforeEach(() => { | |||
token = 'ZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFt'; | |||
localStorage = new LocalStorage('./tests/localStorageEntries'); | |||
localStorage.setItem('token', token); | |||
entries = new Entries(localStorage); | |||
entry = { | |||
"site": "twitter.com", | |||
"password": { | |||
"counter": 1, | |||
"settings": [ | |||
"lowercase", | |||
"uppercase", | |||
"numbers", | |||
"symbols" | |||
], | |||
"length": 12 | |||
}, | |||
"email": "guillaume@oslab.fr", | |||
}; | |||
}); | |||
test('should send requests with Authorization header', (done) => { | |||
var headers = {reqheaders: {'Authorization': 'JWT ' + token}}; | |||
nock(url, headers).get('/api/entries/').reply(200, {entries: []}); | |||
entries.all().then(() => { | |||
done(); | |||
}); | |||
}); | |||
test('should make a post request to create an entry', (done) => { | |||
nock(url).post('/api/entries/', entry).reply(201, {}); | |||
entries.create(entry) | |||
.then((response) => { | |||
assert.equal(201, response.status); | |||
done(); | |||
}); | |||
}); | |||
test('should get all entries', (done) => { | |||
nock(url).get('/api/entries/').reply(200, {entries: []}); | |||
entries.all().then((response) => { | |||
assert.equal(200, response.status); | |||
assert.equal(0, response.data.entries.length); | |||
done(); | |||
}); | |||
}); | |||
after(()=> { | |||
localStorage._deleteLocation() | |||
}); | |||
}); |