Переглянути джерело

use singleton for auth service

pull/342/head
Guillaume Vincent 8 роки тому
джерело
коміт
6fc3ef68ff
10 змінених файлів з 284 додано та 227 видалено
  1. +0
    -1
      src/app/Entries/newEntry.vue
  2. +14
    -0
      src/main.js
  3. +16
    -12
      src/router.js
  4. +44
    -36
      src/services/auth.js
  5. +12
    -12
      src/services/entries.js
  6. +6
    -9
      src/services/http.js
  7. +115
    -0
      tests/auth.tests.js
  8. +63
    -0
      tests/entries.tests.js
  9. +14
    -0
      tests/helpers.js
  10. +0
    -157
      tests/services.tests.js

+ 0
- 1
src/app/Entries/newEntry.vue Переглянути файл

@@ -177,7 +177,6 @@
logging.success(this.$t('entries.entry_created'));
})
.catch((err) => {
console.log(err);
logging.error(this.$t('entries.error_creation'));
});
},


+ 14
- 0
src/main.js Переглянути файл

@@ -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);




+ 16
- 12
src/router.js Переглянути файл

@@ -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();
});




+ 44
- 36
src/services/auth.js Переглянути файл

@@ -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);
}
});
}
}
};

+ 12
- 12
src/services/entries.js Переглянути файл

@@ -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;
});


+ 6
- 9
src/services/http.js Переглянути файл

@@ -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
}


+ 115
- 0
tests/auth.tests.js Переглянути файл

@@ -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();
});
});
});

+ 63
- 0
tests/entries.tests.js Переглянути файл

@@ -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();
});
});
});

+ 14
- 0
tests/helpers.js Переглянути файл

@@ -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()
});

+ 0
- 157
tests/services.tests.js Переглянути файл

@@ -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()
});
});

Завантаження…
Відмінити
Зберегти