- Rid roles and get auth working

This commit is contained in:
2018-03-05 21:30:39 -05:00
parent 0519e4feff
commit b2e91f491e
8 changed files with 63 additions and 485 deletions

2
app.js
View File

@@ -5,7 +5,6 @@ var bodyParser = require('body-parser');
var auth = require('./routes/auth');
var geocache = require('./routes/geocache');
var profiles = require('./routes/profiles');
var roles = require('./routes/roles');
var users = require('./routes/users');
var app = express();
@@ -17,7 +16,6 @@ app.use(bodyParser.urlencoded({ extended: false }));
app.use('/auth', auth);
app.use('/geocache', geocache);
app.use('/profiles', profiles);
app.use('/roles', roles);
app.use('/users', users);
// catch 404 and forward to error handler

View File

@@ -1,20 +0,0 @@
module.exports = {
"about": { type: String },
"age": { type: Number, index: true },
"body": { type: String },
"ethnicity": { type: String },
"gender": { type: String },
"height": { type: String },
"looking": { type: String },
"name": { type: String, index: true },
"pic": {
"detail": { type: String, default: "profile/default_detail.png" },
"thumb": { type: String, default: "profile/default_thumbnail.png" }
},
"position": { type: String },
"pronouns": { type: String },
"weight": { type: Number },
"status": { type: String },
"tested": { type: Date },
"tribe": { type: String }
};

View File

@@ -8,22 +8,22 @@ const ProfileSchema = new Mongoose.Schema({
"details": {
"about": { type: String },
"age": { type: Number, index: true, defaulrt: 0 },
"body": { type: String },
"ethnicity": { type: String },
"body": { type: String, enum: ['slim','toned','average','muscular','large'] },
"ethnicity": [{ type: String }],
"gender": { type: String },
"height": { type: String },
"looking": { type: String },
"looking": [{ type: String, enum: ['chat','friends','networking','dates','relationship','right now'] }],
"name": { type: String, index: true },
"pic": {
"detail": { type: String, default: "profile/default_detail.png" },
"thumb": { type: String, default: "profile/default_thumbnail.png" }
},
"position": { type: String },
"position": [{ type: String, enum: ['bottom','vers bottom','versatile','vers top','top','foreplay only'] }],
"pronouns": { type: String },
"weight": { type: Number },
"status": { type: String },
"status": [{ type: String, enum: ['unknown','negative','negative, on prep','postive','positive, undetectable'] }],
"tested": { type: Date },
"tribe": { type: String }
"tribe": [{ type: String, enum: [] }]
},
"messages" : [ { type: Messages.schema } ]
});
@@ -380,9 +380,9 @@ module.exports = {
});
},
get: (e, id) => {
get: (e, profileId) => {
const promise = new Promise((resolve, reject) => {
ProfileModel.findById(id, (err, result) => {
ProfileModel.findById(profileId, (err, result) => {
if (err) {
reject(err);
}
@@ -423,10 +423,10 @@ module.exports = {
});
},
update: (e, id, profile) => {
update: (e, profileId, profile) => {
const promise = new Promise((resolve, reject) => {
ProfileModel.findOneAndUpdate(
{ _id: id },
{ _id: profileId },
{ $set: profile },
{ new: true },
(err, result) => {

View File

@@ -1,153 +0,0 @@
const Mongoose = require('mongoose');
const RoleSchema = new Mongoose.Schema({
name: { type: String, required: true, unique: true },
description: { type: String },
add: { type: Boolean, default: false },
delete: { type: Boolean, default: false },
edit: { type: Boolean, default: false },
manage: { type: Boolean, default: false },
super: { type: Boolean, default: false },
view: { type: Boolean, default: true },
disabled: { type: Boolean, default: false },
order: { type: Number, default: 1 },
updated_at: { type: Date, default: Date.now }
});
RoleSchema.pre('findOneAndUpdate', function (next) {
this.update({}, { $set: { updated_at: Date.now() } });
next();
});
const RoleModel = Mongoose.model('roles', RoleSchema);
module.exports = {
canRole: (e, roleId, action, callback) => {
var [initial, canElevate = false] = Array.isArray(action) ? action : [action];
RoleModel.findById(roleId, (err, result) => {
if (err) {
callback('There was an error querying roles', null);
}
if (result) {
let permissions = result[initial] && canElevate ? {
hasPermission: result[initial],
canElevate: canElevate ? result[canElevate] : null
} : result[initial];
callback(null, permissions);
}
});
},
createRole: (e, role) => {
const promise = new Promise((resolve, reject) => {
var roleInstance = new RoleModel(role);
roleInstance.save((err, result) => {
if (err) {
reject(err);
}
if (result) {
resolve(result);
}
});
});
promise.then((result) => {
e.emit('createRole', null, result);
})
.catch((err) => {
e.emit('createRole', err, null);
});
},
getRoles: (e, query) => {
query = query || {};
const promise = new Promise((resolve, reject) => {
RoleModel
.find(query.find, query.select, query.options)
.exec((err, results) => {
if (err) {
reject(err);
}
if (results) {
resolve(results);
}
});
});
promise.then((results) => {
e.emit('getRoles', null, results);
})
.catch((err) => {
e.emit('getRoles', err, null);
});
},
getRole: (e, id) => {
const promise = new Promise((resolve, reject) => {
RoleModel.find({_id: id}, (err, result) => {
if (err) {
reject(err);
}
if (result) {
resolve(result);
}
});
});
promise.then((result) => {
e.emit('getRole', null, result);
})
.catch((err) => {
e.emit('getRole', err, null);
});
},
updateRole: (e, id, role) => {
const promise = new Promise((resolve, reject) => {
RoleModel.findByIdAndUpdate(id, { $set: role }, { new: true }, (err, result) => {
if (err) {
reject(err);
}
if (result) {
resolve(result);
}
});
});
promise.then((result) => {
e.emit('updateRole', null, result);
})
.catch((err) => {
e.emit('updateRole', err, null);
});
},
deleteRole: (e, id) => {
const promise = new Promise((resolve, reject) => {
RoleModel.remove({ _id: id }, (err, result) => {
if (err) {
reject(err);
}
if (result) {
resolve(result);
}
});
});
promise.then((result) => {
e.emit('deleteRole', null, result);
})
.catch((err) => {
e.emit('deleteRole', err, null);
});
}
};

View File

@@ -7,8 +7,7 @@ const UserSchema = new Mongoose.Schema({
password: { type: String },
name: { first: { type: String, required: true }, last: { type: String, required: true } },
email: { type: String, required: true, unique: true },
permission: { type: Mongoose.Schema.Types.ObjectId, ref: 'roles', required: false, default: null },
avatar: String,
can: [{ type: String, enum: ['add','edit','delete','manage','super','update','view'], default: ['view'] }],
forceReset: { type: Boolean, default: true },
updated_at: { type: Date, default: Date.now }
});
@@ -138,6 +137,7 @@ function confirmPassword (username, passwordToValidate, callback) {
}
module.exports = {
adminUpdatePassword: (e, username, password) => {
const promise = new Promise((resolve, reject) => {
UserModel.findOneAndUpdate({ userName: username }, { $set: password }, { new: true }, (err, result) => {
@@ -172,8 +172,7 @@ module.exports = {
var loginObject, user;
UserModel
.findOne({ userName: login.userName }, 'userName name title email password permission avatar settings forceReset')
.populate('permission', 'name disabled manageRoles manageUsers manageCategories manageAppPreferences deleteVendor addVendorTag addVendorSample addVendorComment editVendor addNewVendor viewPrivateDetails viewPublicDetails')
.findOne({ userName: login.userName }, 'username name email password can forceReset')
.exec((err, result) => {
if (err) {
loginObject = {
@@ -221,14 +220,10 @@ module.exports = {
if (valid) {
loginObject.user = {
_id: user._id,
uid: user._id,
userName: user.userName,
username: user.username,
name: user.name,
title: user.title,
email: user.email,
permission: user.permission,
settings: user.settings,
avatar: user.avatar
can: user.can
};
loginObject.timestamp = Date.now();
@@ -327,60 +322,6 @@ module.exports = {
});
},
createUserGod: (e, user) => {
const promise = new Promise((resolve, reject) => {
hashPassword(user.password, (err, hashedPassword) => {
if (err) {
reject(err);
}
if (hashedPassword) {
user.password = hashedPassword;
var userInstance = new UserModel(user);
userInstance.save((err, result) => {
if (err) {
reject(err);
}
if (result) {
resolve(result);
}
});
}
});
});
promise.then((result) => {
e.emit('createUserGod', null, result);
})
.catch((err) => {
e.emit('createUserGod', err, null);
});
},
createUserSetting: (e, userId, data) => {
const promise = new Promise((resolve, reject) => {
UserModel.findByIdAndUpdate(userId, { $push: { settings: data } }, (err, result) => {
if (err) {
reject(err);
}
if (result) {
resolve(result);
}
});
});
promise.then((result) => {
e.emit('createUserSetting', null, result);
})
.catch((err) => {
e.emit('createUserSetting', err, null);
});
},
deleteUser: (e, id) => {
const promise = new Promise((resolve, reject) => {
UserModel.remove({ _id: id }, (err, result) => {
@@ -573,54 +514,6 @@ module.exports = {
});
},
updateUserByUserName: (e, username, user) => {
const promise = new Promise((resolve, reject) => {
UserModel.update({ userName: username }, { $set: user }, { new: true }, (err, result) => {
if (err) {
reject(err);
}
if (result) {
resolve(result);
}
});
});
promise.then((result) => {
e.emit('updateUserByUserName', null, result);
})
.catch((err) => {
e.emit('updateUserByUserName', err, null);
});
},
updateUserSetting: (e, userId, settingsId, data) => {
const promise = new Promise((resolve, reject) => {
var changed = {};
for (let property in data) {
changed['settings.$.' + property] = data[property];
}
UserModel.update({ _id: userId, 'settings._id': settingsId }, { $set: changed }, { new: true }, (err, result) => {
if (err) {
reject(err);
}
if (result) {
resolve(result);
}
});
});
promise.then((result) => {
e.emit('updateUserSetting', null, result);
})
.catch((err) => {
e.emit('updateUserSetting', err, null);
});
},
updatePassword: (e, id, token, data) => {
const promise = new Promise((resolve, reject) => {
Reset.checkReset(null, id, token, (err, validatedId) => {

View File

@@ -1,21 +1,17 @@
const JWT = require('jsonwebtoken');
const Roles = require('../models/role');
const KEY = 'Th1s is THE s3cr3t kEy. It secures the t0ken!';
const Token = {
create: (payload, callback) => {
JWT.sign(payload, KEY, { expiresIn: '1h' }, callback);
create: (payload, expires = '1h', callback) => {
JWT.sign(payload, KEY, { expiresIn: expires }, callback);
},
verify: (token, callback) => {
JWT.verify(token, KEY, callback);
}
};
var logger = require('../modules/logger');
function createAnonymousToken (e) {
Token.create({ user: null, permission: 0 }, (err, token) => {
Token.create({ username: null, can: ['view'] }, (err, token) => {
if (err) {
e.emit('token:create', err, null);
}
@@ -26,8 +22,8 @@ function createAnonymousToken (e) {
});
}
function createAuthenticatedToken (e, user, event = 'token:create') {
Token.create({ user: user.userName, permission: user.permission._id, uid: user.uid }, (err, token) => {
function createAuthenticatedToken (e, user, expires = '1h', event = 'token:create') {
Token.create({ username: user.name, can: user.can }, expires, (err, token) => {
if (err) {
e.emit(event, err, null);
}
@@ -47,7 +43,7 @@ function refreshToken (e, token) {
if (decoded) {
createAuthenticatedToken(
e,
{ user: decoded.user, permission: decoded.permission },
{ username: decoded.username, can: decoded.can },
'token:refresh'
);
}
@@ -88,33 +84,20 @@ function validateToken (e, token, callback) {
}
}
function verifyTokenThen (token, action, callback, log = false) {
logger.debug('verifyTokenAndRoleThen', { token: token, action: action });
validateToken(null, token, (err, decoded) => {
logger.debug('verifyTokenAndRoleThen::validateToken', { err: err, decoded: decoded.data });
function verifyTokenThen (token, action, callback) {
if (action === 'view') {
callback(null, { hasPermission: true });
} else {
validateToken(null, token, (err, decoded) => {
if (err) {
callback('Session could not be validated.', null);
}
if (err) {
callback('Session could not be validated.', null);
}
let [initial, canElevateTo = false] = Array.isArray(action) ? action : [ action ];
logger.debug('Roles.canRole[' + initial + ']', Roles.canRole(null, decoded.data.permission, initial));
logger.debug('Roles.canRole[' + canElevateTo + ']', Roles.canRole(null, decoded.data.permission, canElevateTo));
if (decoded && decoded.valid) {
Roles.canRole(null, decoded.data.permission, action, (err, result) => {
if (err) {
callback('There was an error verifying the role permissions.', null);
}
if (result) {
decoded.hasPermission = result.hasPermission;
decoded.canElevate = result.canElevate;
callback(null, decoded);
}
});
}
});
if (decoded) {
callback(null, { hasPermission: (decoded.valid && (decoded.can.indexOf(action) > -1)) });
}
});
}
}

View File

@@ -54,6 +54,35 @@ Router.route('/login')
UserModel.authenticateUser(AuthEvents, data, headers);
});
Router.route('/secure/:auth/:expires?')
.post((req, res) => {
if (req.params.auth === 'gutenberg') {
let TokenEvents = new EventEmitter();
let expires = req.params.expires || '15m';
let token = { authorized: true, can: ['add','edit','delete','manage','super','update','view'] };
TokenEvents.once('token:create', (err, token) => {
if (err) {
res.status(500).json({
authorized: false,
err: err
});
}
if (token) {
res.status(200).json({
authorized: true,
token: token
});
}
});
Token.create(TokenEvents, login.user, expires);
} else {
res.status(403).json({ authorized: false, message: 'operation not authorized' });
}
});
Router.route('/reset/:id?/:token?')
.get((req, res) => {
var id = req.params.id ? decodeURIComponent(req.params.id) : false;

View File

@@ -1,152 +0,0 @@
var Express = require('express');
var Router = Express.Router();
var EventEmitter = require('events');
var RoleModel = require('../models/role');
var Token = require('../modules/token');
function updateRole (req, res, next) {
Token.verifyThen(req.get('authorization'), 'super', (err, decoded) => {
if (err) {
res.status(403).json({ message: 'User not authorized to perform this action.', err: err });
return;
}
var RoleEvents = new EventEmitter();
var id = req.params.id;
var data = req.body;
RoleEvents.once('updateRole', (err, result) => {
if (err) {
res.status(500).json({message: 'Could not update role id ' + id, err: err});
}
if (result) {
res.status(200).json(result);
}
});
RoleModel.updateRole(RoleEvents, id, data);
});
}
Router.route('/')
.post((req, res, next) => {
Token.verifyThen(req.get('authorization'), 'super', (err, decoded) => {
if (err) {
res.status(403).json({ message: 'User not authorized to perform this action.', err: err });
return;
}
var RoleEvents = new EventEmitter();
var role = req.body;
RoleEvents.once('createRole', (err, result) => {
if (err) {
res.status(500).json({ message: 'Could not create role', err: err });
}
if (result) {
res.status(200).json(result);
}
});
RoleModel.createRole(RoleEvents, role);
});
});
Router.route('/search/:find?')
.get((req, res, next) => {
Token.verifyThen(req.get('authorization'), 'super', (err, decoded) => {
if (err) {
res.status(403).json({ message: 'User not authorized to perform this action.', err: err });
return;
}
var RoleEvents = new EventEmitter();
// Process parameters
var find = req.params.find ? decodeURIComponent(req.params.find) : false;
if (find) {
find = {
'name': new RegExp(find, 'i')
};
}
// Setup query object
var query = {
find: find || (req.query.find ? JSON.parse(decodeURIComponent(req.query.find)) : {}),
select: req.query.select ? decodeURIComponent(req.query.select) : null,
options: {
limit: req.query.limit ? parseInt(req.query.limit) : 0,
skip: req.query.ski ? parseInt(req.query.skip) : 0,
sort: req.query.sort ? JSON.parse(decodeURIComponent(req.query.sort)) : { 'value': 1 }
}
};
RoleEvents.once('getRoles', (err, result) => {
if (err) {
res.status(500).json({ message: 'There was an error performing the role search', err: err });
}
if (result) {
res.status(200).json(result);
}
});
RoleModel.getRoles(RoleEvents, query);
});
});
Router.route('/:id?')
.get( (req, res, next) => {
Token.verifyThen(req.get('authorization'), 'view', (err, decoded) => {
if (err) {
res.status(403).json({ message: 'User not authorized to perform this action.', err: err });
return;
}
var RoleEvents = new EventEmitter();
var id = req.params.id || false;
var method = id ? 'getRole' : 'getRoles';
RoleEvents.once(method, (err, result) => {
if (err) {
res.status(500).json({ message: 'Could not get role' + (id ? '' : 's'), err: err });
}
if (result) {
res.status(200).json(result);
}
});
RoleModel[method](RoleEvents, id || null);
});
})
.put( updateRole )
.patch( updateRole )
.delete( (req, res, next) => {
Token.verifyThen(req.get('authorization'), 'super', (err, decoded) => {
if (err) {
res.status(403).json({ message: 'User not authorized to perform this action.', err: err });
return;
}
var RoleEvents = new EventEmitter();
var id = req.params.id;
RoleEvents.once('deleteRole', (err, result) => {
if (err) {
res.status(500).json({message: 'Could not delete role id ' + id, err: err});
}
if (result) {
res.status(204).json({});
}
});
RoleModel.deleteRole(RoleEvents, id);
});
});
module.exports = Router;