diff --git a/lib/schemas/editUser.json b/lib/schemas/editUser.json new file mode 100644 index 0000000..118e754 --- /dev/null +++ b/lib/schemas/editUser.json @@ -0,0 +1,24 @@ +{ + "$id": "editUser", + "type": "object", + "properties": { + "usersName": { + "type": "string" + }, + "userEmail": { + "type": "string", + "format": "emailAddress" + }, + "userPassword": { + "type": "string" + }, + "isAdmin": { + "type": "boolean" + } + }, + "required": [ + "usersName", + "userEmail", + "isAdmin" + ] +} \ No newline at end of file diff --git a/lib/schemas/newUser.json b/lib/schemas/newUser.json new file mode 100644 index 0000000..799d2fe --- /dev/null +++ b/lib/schemas/newUser.json @@ -0,0 +1,25 @@ +{ + "$id": "newUser", + "type": "object", + "properties": { + "usersName": { + "type": "string" + }, + "userEmail": { + "type": "string", + "format": "emailAddress" + }, + "userPassword": { + "type": "string" + }, + "isAdmin": { + "type": "boolean" + } + }, + "required": [ + "usersName", + "userEmail", + "userPassword", + "isAdmin" + ] +} \ No newline at end of file diff --git a/routes/user.js b/routes/user.js index 53eff63..a8cdfe8 100644 --- a/routes/user.js +++ b/routes/user.js @@ -3,6 +3,7 @@ const common = require('../lib/common'); const { restrict } = require('../lib/auth'); const colors = require('colors'); const bcrypt = require('bcryptjs'); +const { validateJson } = require('../lib/schema'); const router = express.Router(); router.get('/admin/users', restrict, async (req, res) => { @@ -212,6 +213,19 @@ router.post('/admin/user/update', restrict, async (req, res) => { updateDoc.userPassword = bcrypt.hashSync(req.body.userPassword); } + // Validate update user + const schemaResult = validateJson('editUser', updateDoc); + if(!schemaResult.result){ + if(req.apiAuthenticated){ + res.status(400).json(schemaResult.errors); + return; + } + req.session.message = 'Please check your inputs.'; + req.session.messageType = 'danger'; + res.redirect('/admin/user/edit/' + req.body.userId); + return; + } + try{ await db.users.updateOne( { _id: common.getId(req.body.userId) }, @@ -220,11 +234,11 @@ router.post('/admin/user/update', restrict, async (req, res) => { }, { multi: false } ); if(req.apiAuthenticated){ - res.status(200).json({ message: 'User account updated.' }); + res.status(200).json({ message: 'User account updated' }); return; } // show the view - req.session.message = 'User account updated.'; + req.session.message = 'User account updated'; req.session.messageType = 'success'; res.redirect('/admin/user/edit/' + req.body.userId); }catch(ex){ @@ -244,7 +258,7 @@ router.post('/admin/user/insert', restrict, async (req, res) => { const db = req.app.db; // set the account to admin if using the setup form. Eg: First user account - const urlParts = new URL(req.header('Referer')); + const urlParts = req.get('Referrer'); // Check number of users const userCount = await db.users.countDocuments({}); @@ -255,13 +269,26 @@ router.post('/admin/user/insert', restrict, async (req, res) => { isAdmin = true; } - const doc = { + const userObj = { usersName: req.body.usersName, userEmail: req.body.userEmail, userPassword: bcrypt.hashSync(req.body.userPassword, 10), isAdmin: isAdmin }; + // Validate new user + const schemaResult = validateJson('newUser', userObj); + if(!schemaResult.result){ + if(req.apiAuthenticated){ + res.status(400).json(schemaResult.errors); + return; + } + req.session.message = 'Invalid new user. Please check your inputs.'; + req.session.messageType = 'danger'; + res.redirect('/admin/user/new'); + return; + } + // check for existing user const user = await db.users.findOne({ userEmail: req.body.userEmail }); if(user){ @@ -278,10 +305,10 @@ router.post('/admin/user/insert', restrict, async (req, res) => { } // email is ok to be used. try{ - await db.users.insertOne(doc); + await db.users.insertOne(userObj); // if from setup we add user to session and redirect to login. // Otherwise we show users screen - if(urlParts.path === '/admin/setup'){ + if(urlParts && urlParts.path === '/admin/setup'){ req.session.user = req.body.userEmail; res.redirect('/admin/login'); return; @@ -295,11 +322,11 @@ router.post('/admin/user/insert', restrict, async (req, res) => { req.session.messageType = 'success'; res.redirect('/admin/users'); }catch(ex){ + console.error(colors.red('Failed to insert user: ' + ex)); if(req.apiAuthenticated){ res.status(400).json({ message: 'New user creation failed' }); return; } - console.error(colors.red('Failed to insert user: ' + ex)); req.session.message = 'New user creation failed'; req.session.messageType = 'danger'; res.redirect('/admin/user/new'); diff --git a/test/specs/users.js b/test/specs/users.js index dfe69ff..b362f35 100644 --- a/test/specs/users.js +++ b/test/specs/users.js @@ -60,3 +60,33 @@ test('[Fail] Delete invalid user ID', async t => { .expect(302); t.deepEqual(res.header['location'], '/admin/users'); }); + +test('[Success] Create new user', async t => { + const user = { + usersName: 'Jim Smith', + userEmail: 'jim.smith@gmail.com', + userPassword: 'test', + isAdmin: false + }; + const res = await g.request + .post('/admin/user/insert') + .send(user) + .set('apiKey', g.users[0].apiKey) + .expect(200); + t.deepEqual(res.body.message, 'User account inserted'); +}); + +test('[Fail] Create new user with invalid email', async t => { + const user = { + usersName: 'Jim Smith', + userEmail: 'jim.smith@gmail', + userPassword: 'test', + isAdmin: false + }; + const res = await g.request + .post('/admin/user/insert') + .send(user) + .set('apiKey', g.users[0].apiKey) + .expect(400); + t.deepEqual(res.body[0].message, 'should match format "emailAddress"'); +});