diff --git a/sequelize/data/user-role.json b/sequelize/data/user-role.json index 671264ea..2b9740d5 100644 --- a/sequelize/data/user-role.json +++ b/sequelize/data/user-role.json @@ -25,6 +25,11 @@ "path": "/entity", "method": "GET" }, + { + "role": "user", + "path": "/entity/*", + "method": "GET" + }, { "role": "user", "path": "/entity", @@ -40,6 +45,11 @@ "path": "/contact", "method": "GET" }, + { + "role": "user", + "path": "/contact/*", + "method": "GET" + }, { "role": "user", "path": "/contact", diff --git a/src/models/user.js b/src/models/user.js index 9318659a..531f7147 100644 --- a/src/models/user.js +++ b/src/models/user.js @@ -3,40 +3,40 @@ import jwt from 'jsonwebtoken' import utils from '../utils' const user = (sequelize, DataTypes) => { - // Defining our user table and setting User object. - const User = sequelize.define('User', { - id: { - type: DataTypes.UUID, - primaryKey: true, - defaultValue: DataTypes.UUIDV4, - allowNull: false, - autoIncrement: false, - }, - email: { - type: DataTypes.STRING, - unique: true, - required: true - }, - password: { - type: DataTypes.STRING, - required: true - }, - salt: { - type: DataTypes.STRING - }, - displayName: { - type: DataTypes.STRING - }, - phone: { - type: DataTypes.STRING - }, - attributes: { - type: DataTypes.JSON, - } - }, - { - schema: process.env.DATABASE_SCHEMA - }) + // Defining our user table and setting User object. + const User = sequelize.define('User', { + id: { + type: DataTypes.UUID, + primaryKey: true, + defaultValue: DataTypes.UUIDV4, + allowNull: false, + autoIncrement: false, + }, + email: { + type: DataTypes.STRING, + unique: true, + required: true + }, + password: { + type: DataTypes.STRING, + required: true + }, + salt: { + type: DataTypes.STRING + }, + displayName: { + type: DataTypes.STRING + }, + phone: { + type: DataTypes.STRING + }, + attributes: { + type: DataTypes.JSON, + } + }, + { + schema: process.env.DATABASE_SCHEMA + }) /** * Looks up and validates a user by email and password. @@ -46,40 +46,44 @@ const user = (sequelize, DataTypes) => { * * @return {String} returns either the valid login token or an error message. */ - User.findByLogin = async (email, password) => { - const user = await User.findOne({ - where: {email} - }) - if (user) { - const pw = User.encryptPassword(password, user.salt) - if (pw === user.password) { - return await User.getToken(user.id, user.email) - } - } - } - - User.decodeToken = async token => { - return jwt.verify(token, process.env.JWT_KEY) - } - - /** @todo deprecate this */ - User.getToken = async (userId, email, expiresIn = '1d') => { - const token = jwt.sign( - {userId, email, type: 'user'}, - process.env.JWT_KEY, - {expiresIn} - ) - return token - } + User.findByLogin = async (email, password) => { + const user = await User.findOne({ + where: { email } + }) + if (user) { + const pw = User.encryptPassword(password, user.salt) + if (pw === user.password) { + + const e = await utils.loadCasbin() + const roles = await e.getRolesForUser(user.email) + + return await User.getToken(user.id, user.email, roles[0]) + } + } + } + + User.decodeToken = async token => { + return jwt.verify(token, process.env.JWT_KEY) + } + + /** @todo deprecate this */ + User.getToken = async (userId, email, type, expiresIn = '1d') => { + const token = jwt.sign( + { userId, email, type }, + process.env.JWT_KEY, + { expiresIn } + ) + return token + } /** * Generates a random salt for password security. * * @return {String} The password salt. */ - User.generateSalt = () => { - return crypto.randomBytes(16).toString('base64') - } + User.generateSalt = () => { + return crypto.randomBytes(16).toString('base64') + } /** * Salts and hashes a password. @@ -89,45 +93,45 @@ const user = (sequelize, DataTypes) => { * * @return {String} The secured password. */ - User.encryptPassword = (plainText, salt) => { - return crypto - .createHash('RSA-SHA256') - .update(plainText) - .update(salt) - .digest('hex') - } - - // Setters - const setSaltAndPassword = user => { - if (user.changed('password')) { - user.salt = User.generateSalt() - // User.password = User.encryptPassword(user.password, user.salt) - user.password = utils.encryptPassword(user.password, user.salt) - } - } - - // Other Helpers - // const validateContactInfo = user => { - // let valid = true - - // if (!validator.isEmail(validator.normalizeEmail(user.email))) { - // valid = false - // } - - // /** @todo Add more validations for all contact info. */ - - // return valid - // } - - // Create prep actions - // User.beforeCreate(validateContactInfo) - User.beforeCreate(setSaltAndPassword) - - // Update prep actions - // User.beforeUpdate(validateContactInfo) - User.beforeUpdate(setSaltAndPassword) - - return User + User.encryptPassword = (plainText, salt) => { + return crypto + .createHash('RSA-SHA256') + .update(plainText) + .update(salt) + .digest('hex') + } + + // Setters + const setSaltAndPassword = user => { + if (user.changed('password')) { + user.salt = User.generateSalt() + // User.password = User.encryptPassword(user.password, user.salt) + user.password = utils.encryptPassword(user.password, user.salt) + } + } + + // Other Helpers + // const validateContactInfo = user => { + // let valid = true + + // if (!validator.isEmail(validator.normalizeEmail(user.email))) { + // valid = false + // } + + // /** @todo Add more validations for all contact info. */ + + // return valid + // } + + // Create prep actions + // User.beforeCreate(validateContactInfo) + User.beforeCreate(setSaltAndPassword) + + // Update prep actions + // User.beforeUpdate(validateContactInfo) + User.beforeUpdate(setSaltAndPassword) + + return User } export default user diff --git a/src/routes/entity.js b/src/routes/entity.js index da2f7e0e..fa530dd0 100644 --- a/src/routes/entity.js +++ b/src/routes/entity.js @@ -119,7 +119,7 @@ router.put('/', async (req, res) => { const response = new utils.Response() try { if (validator.isUUID(req.body.id)) { - let { id, name, type, address, phone, email, checkIn, contacts } = req.body + let { id, name, type, address, phone, email, checkIn, contacts, attributes } = req.body /** @todo validate emails */ // Validating emails @@ -140,7 +140,8 @@ router.put('/', async (req, res) => { entity.type = (type) ? type : entity.type entity.address = (address) ? address : entity.address entity.phone = (phone) ? phone : entity.phone - entity.email = (email) ? email : entity.email + entity.email = (email) ? email : entity.email + entity.attributes = (attributes) ? attributes : entity.attributes /** @todo validate checkIn JSON */ if (entity.checkIn === null && checkIn) { const checkIns = { diff --git a/src/routes/user.js b/src/routes/user.js index 45097a6e..22744a9c 100644 --- a/src/routes/user.js +++ b/src/routes/user.js @@ -5,7 +5,7 @@ import utils from '../utils' import email from '../email' const router = new Router() -const max = (process.env.NODE_ENV !== 'production') ? 50000 : 5 +const max = (process.env.NODE_ENV !== 'production') ? 50000 : 50 const loginLimiter = rateLimit({ windowMs: 60 * 60 * 1000, max, diff --git a/src/tests/entity.routes.spec.js b/src/tests/entity.routes.spec.js index 6e224796..919db848 100644 --- a/src/tests/entity.routes.spec.js +++ b/src/tests/entity.routes.spec.js @@ -9,7 +9,10 @@ const { expect } = chai const entity = { name: randomWords(), type: 'Test', - contacts: [] + contacts: [], + attributes: { + notes: 'test' + } } const contact = { name: randomWords(), diff --git a/swagger.json b/swagger.json index 8a7fab12..9b15e7ee 100644 --- a/swagger.json +++ b/swagger.json @@ -580,6 +580,22 @@ "type" : "string", "example" : "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InRlc3QiLCJpYXQiOjE1ODA3NTM0MDUsImV4cCI6MTU4MDgzOTgwNX0.Q6W7Vo6By35yjZBeLKkk96s8LyqIE2G39AG1H3LRD9M" } + }, { + "in" : "query", + "name" : "type", + "schema" : { + "type" : "string", + "example" : "name" + }, + "description" : "The type of field you are searching on" + }, { + "in" : "query", + "name" : "value", + "schema" : { + "type" : "string", + "example" : "The Leftorium" + }, + "description" : "The value you are searching for" } ], "responses" : { "200" : { @@ -699,6 +715,15 @@ "description" : { "type" : "string", "example" : "Everything for the left handed man, woman, and child!" + }, + "attributes" : { + "type" : "object", + "properties" : { + "capacity" : { + "type" : "number", + "example" : 42 + } + } } } } @@ -1022,15 +1047,15 @@ } }, "responses" : { - "200" : { + "201" : { "description" : "contact created" }, + "400" : { + "description" : "Bad Request" + }, "401" : { "description" : "Unauthorized" }, - "422" : { - "description" : "Invalid input" - }, "500" : { "description" : "Server error" } @@ -1064,14 +1089,6 @@ "example" : "ned.flanders@leftorium.com" }, "description" : "The value you are searching for" - }, { - "in" : "query", - "name" : "limit", - "schema" : { - "type" : "integer", - "example" : 10 - }, - "description" : "The maximum number of values you want returned" } ], "responses" : { "200" : { @@ -1213,6 +1230,15 @@ "id" : "", "title" : "" } ] + }, + "attributes" : { + "type" : "object", + "properties" : { + "notes" : { + "type" : "string", + "example" : "Neighbor" + } + } } } } @@ -1223,12 +1249,12 @@ "200" : { "description" : "contact updated" }, + "400" : { + "description" : "Bad Request" + }, "401" : { "description" : "Unauthorized" }, - "422" : { - "description" : "Invalid input" - }, "500" : { "description" : "Server error" } @@ -1273,12 +1299,12 @@ "200" : { "description" : "contacts emailed" }, + "400" : { + "description" : "Bad Request" + }, "401" : { "description" : "Unauthorized" }, - "422" : { - "description" : "Invalid input" - }, "500" : { "description" : "Server error" } @@ -1319,12 +1345,12 @@ } } }, + "400" : { + "description" : "Bad Request" + }, "401" : { "description" : "Unauthorized" }, - "422" : { - "description" : "Invalid input" - }, "500" : { "description" : "Server error" } @@ -1356,12 +1382,12 @@ "200" : { "description" : "contact_id deleted" }, + "400" : { + "description" : "Bad Request" + }, "401" : { "description" : "Unauthorized" }, - "422" : { - "description" : "Invalid input" - }, "500" : { "description" : "Server error" } @@ -1418,12 +1444,12 @@ "200" : { "description" : "Successful/already exists" }, + "400" : { + "description" : "Bad Request" + }, "401" : { "description" : "Unauthorized" }, - "422" : { - "description" : "Invalid input" - }, "500" : { "description" : "Server error" } @@ -1479,12 +1505,12 @@ "200" : { "description" : "Successful/already exists" }, + "400" : { + "description" : "Bad Request" + }, "401" : { "description" : "Unauthorized" }, - "422" : { - "description" : "Invalid input" - }, "500" : { "description" : "Server error" } @@ -1600,14 +1626,6 @@ } } }, - "UserRoleItem" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "minItems" : 3, - "maxItems" : 3 - }, "EntityItem" : { "type" : "object", "properties" : {