Skip to content

Commit

Permalink
feat(dashboard): Force password change on user
Browse files Browse the repository at this point in the history
  • Loading branch information
D34THWINGS committed May 12, 2017
1 parent 3642138 commit bd3554a
Show file tree
Hide file tree
Showing 16 changed files with 115 additions and 18 deletions.
4 changes: 2 additions & 2 deletions config/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ module.exports = {
},
},
mongodb: {
host: 'mongo',
host: 'localhost',
port: 27017,
database: 'lvconnect_test',
},
kue: {
redis: {
host: 'redis',
host: 'localhost',
port: 6379,
db: 0,
},
Expand Down
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@
"chai": "^3.5.0",
"eslint": "^3.8.1",
"eslint-config-airbnb-base": "^11.0.0",
"eslint-plugin-babel": "^4.0.0",
"eslint-plugin-import": "^2.0.1",
"mocha": "^3.0.2",
"nodemon": "^1.10.2"
Expand Down
15 changes: 15 additions & 0 deletions server/dashboard/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,21 @@ exports.register = (server, options, next) => {
});
server.route(routes);

// Middleware to force user to reset his password
const ignoredRoutes = ['/assets', '/login', '/change-password'];
server.ext({
type: 'onPreHandler',
method(req, res) {
if (!ignoredRoutes.some(r => req.path.includes(r)) && req.auth.credentials.needPasswordChange) {
return res().redirect('/dashboard/change-password');
}
return res.continue();
},
options: {
sandbox: 'plugin',
},
});

next();
};

Expand Down
10 changes: 10 additions & 0 deletions server/dashboard/routes/get-change-password.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
module.exports = {
method: 'GET',
path: '/dashboard/change-password',
config: { auth: 'session' },
handler(req, res) {
res.view('change-password', {
pageTitle: 'Password change',
});
},
};
4 changes: 4 additions & 0 deletions server/dashboard/routes/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ const getEditApplication = require('./get-edit-app');
const postCreateApplication = require('./post-create-app');
const postEditApplication = require('./post-edit-app');
const deleteApplication = require('./delete-app');
const getChangePassword = require('./get-change-password');
const postChangePassword = require('./post-change-password');

module.exports = [
getDashboard,
Expand All @@ -30,4 +32,6 @@ module.exports = [
postCreateApplication,
postEditApplication,
deleteApplication,
getChangePassword,
postChangePassword,
];
46 changes: 46 additions & 0 deletions server/dashboard/routes/post-change-password.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
const Joi = require('joi');

module.exports = {
method: 'POST',
path: '/dashboard/change-password',
config: {
auth: 'session',
validate: {
payload: {
plainPassword: Joi.string().min(6).required(),
plainPasswordCheck: Joi.string().required(),
},
},
},
handler(req, res) {
if (req.payload.plainPassword !== req.payload.plainPasswordCheck) {
return res.view('change-password', {
pageTitle: 'Password change',
error: 'Passwords don\'t match',
}).code(401);
}

const user = req.auth.credentials;

return user.comparePassword(req.payload.plainPassword)
.then((isSamePassword) => {
if (isSamePassword) {
return res.view('change-password', {
pageTitle: 'Password change',
error: 'You must choose a password different from the previous one',
}).code(401);
}

return user.hashPassword(req.payload.plainPassword)
.then(() => {
user.needPasswordChange = false;
return user.save();
})
.then(() => res.redirect('/dashboard'));
})
.catch(() => res.view('change-password', {
pageTitle: 'Password change',
error: 'An unknown error occurred',
}).code(401));
},
};
2 changes: 1 addition & 1 deletion server/dashboard/routes/post-create-user.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@ module.exports = {
firstName: Joi.string().min(2).required(),
lastName: Joi.string().min(2).required(),
plainPassword: Joi.string().min(6).required(),
plainPasswordCheck: Joi.string().required(),
email: Joi.string().email().required(),
description: Joi.string().max(255).allow(''),
roles: Joi.array().items(Joi.string().valid(validRoles)).min(1).single()
.required(),
githubHandle: Joi.string().allow(''),
trelloHandle: Joi.string().allow(''),
city: Joi.string().valid(validCities).required(),
plainPasswordCheck: Joi.string().required(),
}),
failAction: (req, res, src, error) => {
res.view('create-user', {
Expand Down
31 changes: 31 additions & 0 deletions server/dashboard/views/change-password.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<div class="mdl-grid">
<form class="mdl-cell mdl-cell--6-col mdl-cell--3-offset-desktop mdl-cell--1-offset-tablet mdl-card mdl-shadow--2dp"
method="POST">
<div class="mdl-card__title">
<h2 class="mdl-card__title-text">Change password</h2>
</div>
<div class="mdl-card__supporting-text mdl-grid">
You've been requested to change your password for security reasons. Choose a new password bellow :

<div class="mdl-cell mdl-cell--6-col mdl-cell--8-col-tablet mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
<input class="mdl-textfield__input" type="password" id="plainPasswordInput" name="plainPassword" pattern=".{6,}" required>
<label class="mdl-textfield__label" for="plainPasswordInput">Password</label>
</div>

<div class="mdl-cell mdl-cell--6-col mdl-cell--8-col-tablet mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
<input class="mdl-textfield__input" type="password" id="plainPasswordCheckInput" name="plainPasswordCheck" pattern=".{6,}" required>
<label class="mdl-textfield__label" for="plainPasswordCheckInput">Repeat Password</label>
</div>

{{ error }}

<input type="hidden" name="crumb" value="{{crumb}}">
</div>

<div class="mdl-card__actions mdl-card--border">
<button class="mdl-button mdl-button--colored mdl-js-button mdl-js-ripple-effect" type="submit">
Save
</button>
</div>
</form>
</div>
1 change: 1 addition & 0 deletions server/users/models/user.model.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const userSchema = new mongoose.Schema({
createdAt: { type: Date, default: Date.now },
description: String,
city: String,
needPasswordChange: { type: Boolean, default: true },
});

userSchema.virtual('profilePictureUrl').get(function getProfilePictureUrl(value) {
Expand Down
2 changes: 1 addition & 1 deletion server/users/routes/cget-users.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ module.exports = {
.where(email ? { email: { $eq: email } } : null)
.limit(limit)
.skip(page * limit || 0)
.select('-password -thirdParty')
.select('-password -thirdParty -needPasswordChange')
.exec();

const countPromise = User.count();
Expand Down
2 changes: 1 addition & 1 deletion server/users/routes/get-me.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ module.exports = {
pre: [hasScopeInList('profile:get')],
},
handler(req, res) {
return res.mongodb(req.auth.credentials.user, ['password']);
return res.mongodb(req.auth.credentials.user, ['password', 'thirdParty', 'needPasswordChange']);
},
};
2 changes: 1 addition & 1 deletion server/users/routes/get-users.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ module.exports = {

const userPromise = User
.findOne({ _id: req.params.user })
.select('-password -thirdParty')
.select('-password -thirdParty -needPasswordChange')
.exec()
.then((user) => {
if (!user) {
Expand Down
2 changes: 1 addition & 1 deletion server/users/routes/post-users.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,6 @@ module.exports = {
return Promise.reject(Boom.wrap(err));
});

res.mongodb(userPromise, ['password']).code(201);
res.mongodb(userPromise, ['password', 'thirdParty', 'needPasswordChange']).code(201);
},
};
2 changes: 1 addition & 1 deletion server/users/routes/put-users.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,6 @@ module.exports = {
return Promise.resolve(savedUser);
});

return res.mongodb(userPromise, ['password', 'thirdParty']);
return res.mongodb(userPromise, ['password', 'thirdParty', 'needPasswordChange']);
},
};
5 changes: 0 additions & 5 deletions test/.eslintrc
Original file line number Diff line number Diff line change
@@ -1,19 +1,14 @@
{
"parser": "babel-eslint",
"extends": ["airbnb-base"],
"plugins": [
"babel"
],
"env": {
"node": true,
"mocha": true
},
"rules": {
"prefer-arrow-callback": 0,
"generator-star-spacing": 0,
"func-names": 0,
"import/no-extraneous-dependencies": 0,
"babel/generator-star-spacing": 1,
"no-underscore-dangle": 0
}
}
4 changes: 0 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1095,10 +1095,6 @@ eslint-module-utils@^2.0.0:
debug "2.2.0"
pkg-dir "^1.0.0"

eslint-plugin-babel@^4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/eslint-plugin-babel/-/eslint-plugin-babel-4.0.1.tgz#77de74dabd67a6bef3b16bf258f5804e971e7349"

eslint-plugin-import@^2.0.1:
version "2.2.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.2.0.tgz#72ba306fad305d67c4816348a4699a4229ac8b4e"
Expand Down

0 comments on commit bd3554a

Please sign in to comment.