From b2e91f491e4e98705004d727861a19916d2cea86 Mon Sep 17 00:00:00 2001 From: Mike Fitzpatrick Date: Mon, 5 Mar 2018 21:30:39 -0500 Subject: [PATCH] - Rid roles and get auth working --- app.js | 2 - models/detail.js | 20 ------ models/profile.js | 20 +++--- models/role.js | 153 ---------------------------------------------- models/user.js | 117 ++--------------------------------- modules/token.js | 55 ++++++----------- routes/auth.js | 29 +++++++++ routes/roles.js | 152 --------------------------------------------- 8 files changed, 63 insertions(+), 485 deletions(-) delete mode 100644 models/detail.js delete mode 100644 models/role.js delete mode 100644 routes/roles.js diff --git a/app.js b/app.js index 8afea20..eaec115 100644 --- a/app.js +++ b/app.js @@ -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 diff --git a/models/detail.js b/models/detail.js deleted file mode 100644 index be51d2f..0000000 --- a/models/detail.js +++ /dev/null @@ -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 } -}; diff --git a/models/profile.js b/models/profile.js index 617d8e9..517434d 100644 --- a/models/profile.js +++ b/models/profile.js @@ -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) => { diff --git a/models/role.js b/models/role.js deleted file mode 100644 index effaca5..0000000 --- a/models/role.js +++ /dev/null @@ -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); - }); - } -}; diff --git a/models/user.js b/models/user.js index f916db5..5b40382 100644 --- a/models/user.js +++ b/models/user.js @@ -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) => { diff --git a/modules/token.js b/modules/token.js index 7bfc06b..f93098f 100644 --- a/modules/token.js +++ b/modules/token.js @@ -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)) }); + } + }); + } } diff --git a/routes/auth.js b/routes/auth.js index 22c9bf0..23aca8d 100644 --- a/routes/auth.js +++ b/routes/auth.js @@ -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; diff --git a/routes/roles.js b/routes/roles.js deleted file mode 100644 index 8d4c67b..0000000 --- a/routes/roles.js +++ /dev/null @@ -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;