Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ENHANCEMENT] Created an auth module #18

Merged
merged 2 commits into from
Sep 5, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ Project related (documentation, website, ...):
- [Added relationship routes](https://github.com/olavoasantos/faux-call/issues/8)
- [Added custom route responses](https://github.com/olavoasantos/faux-call/issues/9)
- [Added API route prefix](https://github.com/olavoasantos/faux-call/issues/6)
- [Refactored the Auth implementation to a module](https://github.com/olavoasantos/faux-call/pull/18)
- Bug fixes and internal refactoring

- **v0.1.x**:
Expand Down
95 changes: 95 additions & 0 deletions auth/JWT.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');

const Config = require('../config');
const { getDataFromBody } = require('../helpers');

const JWT = {
sign: data => {
const SECRET = Config.get('auth.secret');
const EXPIRATION = Config.get('auth.expiration');

return jwt.sign(data, SECRET, { expiresIn: EXPIRATION });
},

authenticate: (Model, user, data) => {
return Model.authenticate.reduce((isValid, column) => {
if (!isValid) return isValid;
if (Model.encrypt.includes(column)) {
return bcrypt.compareSync(data[column], user[column]);
}

return data[column] === user[column];
}, true);
},

getUser: (Model, data) => {
const authColumn = Model.authenticate.filter(
column => !Model.encrypt.includes(column)
)[0];

return Model.database.where(authColumn, data[authColumn]);
},

onSuccess: ({ user, token, errors }) => {
return { auth: true, token };
},

onFail: ({ user, token, errors }) => {
return { auth: false, token: null, message: errors };
},

response: ({ user, type, token, errors }) => {
if (type === 'success') {
return JWT.onSuccess({ user, token });
}

if (type === 'fail') {
return JWT.onFail({ user, errors });
}
},

register: (App, Model, prefix) =>
App.post(`${prefix}/register`, (req, res) => {
const data = getDataFromBody(Model.columns, req.body);

const errors = Model.validate(data);
if (Object.keys(errors).length !== 0) {
return res
.status(500)
.send(JWT.response({ type: 'fail', Model, errors }));
}

const user = Model.create(data);
const token = JWT.sign({ id: user.id, created_at: user.created_at });

res.send(JWT.response({ type: 'success', user, token }));
}),

login: (App, Model, prefix) =>
App.post(`${prefix}/login`, (req, res) => {
const data = Model.mutate(getDataFromBody(Model.authenticate, req.body));

const user = JWT.getUser(Model, data);
if (!user)
return res
.status(401)
.send(JWT.response({ type: 'fail', user, errors: `User not found` }));

const isValid = JWT.authenticate(Model, user, data);
if (!isValid)
return res
.status(401)
.send(JWT.response({ user, type: 'fail', errors: `Not authorized` }));

const token = JWT.sign({ id: user.id, created_at: user.created_at });
res.send(JWT.response({ type: 'success', user, token }));
}),

logout: (App, Model, prefix) =>
App.post(`${prefix}/logout`, (req, res) => {
res.send(JWT.response({ user: {}, token: null, auth: false }));
})
};

module.exports = JWT;
50 changes: 6 additions & 44 deletions auth/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,58 +3,20 @@ const jwt = require('jsonwebtoken');

const App = require('../server');
const Config = require('../config');
const Modules = require('../modules');
const Database = require('../database');
const { getDataFromBody } = require('../helpers');

const Auth = () => {
const Model = Config.get('authModel');
const AuthModule = Modules.get('auth');

const namespace = `${Config.get('auth.namespace').toLowerCase().replace(/^\/?|\/?$/, '')}`;
const prefix = namespace ? `/${namespace}` : namespace;

App.post(`${prefix}/register`, (req, res) => {
const data = getDataFromBody(Model.columns, req.body);

const errors = Model.validate(data);
if (Object.keys(errors).length !== 0) {
return res.status(500).send(errors);
}

const registered = Model.create(data);
const token = jwt.sign({ id: registered.id, created_at: registered.created_at }, Config.get('secret'), { expiresIn: 86400 });

res.send({ auth: true, token });
});

App.post(`${prefix}/login`, (req, res) => {
let data = getDataFromBody(Model.authenticate, req.body);

data = Model.mutate(data);

let registered;
Model.authenticate.forEach(column => {
if (!Model.encrypt || (Model.encrypt && !Model.encrypt.includes(column))) {
registered = Model.database.where(column, data[column]);
}
});
if (!registered) return res.status(401).send({ auth: false, token: null, message: 'User not found' });

Model.authenticate.forEach(column => {
let checkField;
if (Model.encrypt && Model.encrypt.includes(column)) {
checkField = bcrypt.compareSync(data[column], registered[column]);
} else {
checkField = data[column] === registered[column];
}
if (!checkField) return res.status(401).send({ message: `Invalid ${column}` });
});

const token = jwt.sign({ id: registered.id, created_at: registered.created_at }, Config.get('secret'), { expiresIn: 86400 });
res.send({ auth: true, token });
});

App.post(`${prefix}/logout`, (req, res) => {
res.send({ auth: false, token: null });
});
AuthModule.register(App, Model, prefix);
AuthModule.login(App, Model, prefix);
AuthModule.logout(App, Model, prefix);
};

module.exports = Auth;
4 changes: 4 additions & 0 deletions config/base.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ module.exports = {
'api.prefix': '/',

'auth.namespace': '/',
'auth.secret': 'SUPER_SECRET_SECRET',
'auth.expiration': 86400,
'auth.header': 'Authorization',

'token.header': 'Authorization',

seed: {},
Expand Down
3 changes: 2 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
const { Start, Register, App, Config } = require('./main');
const { Start, Register, App, Config, Modules } = require('./main');

/** Base faux wrapper */
const faux = {
config: Config,
register: Register,
modules: Modules,
start: Start,
route: App,
}
Expand Down
3 changes: 2 additions & 1 deletion main/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ const Start = require('./Start');
const Register = require('./Register');
const App = require('../server');
const Config = require('../config');
const Modules = require('../modules');

module.exports = { Config, App, Start, Register };
module.exports = { Config, App, Start, Register, Modules };
16 changes: 16 additions & 0 deletions modules/Modules.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
const base = require('./base.modules');

module.exports = () => {
const list = {...base};

const all = () => list;
const get = (name) => list[name];
const push = (name, value) => list[name].push(value);
const assign = (name, key, value) => list[name][key] = value;
const set = (name, value) => {
list[name] = value;
return list[name];
};

return { get, set, all, push, assign };
};
5 changes: 5 additions & 0 deletions modules/base.modules.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const AuthModule = require('../auth/JWT');

module.exports = {
auth: AuthModule,
};
3 changes: 3 additions & 0 deletions modules/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const Modules = require('./Modules')();

module.exports = Modules;
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "faux-call",
"version": "0.2.1",
"version": "0.2.2",
"description": "Simple mock server for your convenience and testing",
"main": "index.js",
"keywords": [
Expand Down