mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-03 23:00:14 -05:00
✨ Deleted all but active sessions on password change (#11639)
closes #10323 * Fixed usage of hasMany for user->session * Refactored changePassword to async function * Deleted all user sessions when password changed * Tested for session retained after password changed * Added the session to the frame * Skipped the current session when changing password
This commit is contained in:
parent
7e1c7ef9d2
commit
58187175c3
5 changed files with 36 additions and 23 deletions
|
@ -160,6 +160,7 @@ module.exports = {
|
|||
}
|
||||
},
|
||||
query(frame) {
|
||||
frame.options.skipSessionID = frame.original.session.id;
|
||||
return models.User.changePassword(frame.data.password[0], frame.options);
|
||||
}
|
||||
},
|
||||
|
|
|
@ -40,6 +40,7 @@ const http = (apiImpl) => {
|
|||
query: req.query,
|
||||
params: req.params,
|
||||
user: req.user,
|
||||
session: req.session,
|
||||
context: {
|
||||
api_key: apiKey,
|
||||
user: user,
|
||||
|
|
|
@ -155,6 +155,7 @@ module.exports = {
|
|||
}
|
||||
},
|
||||
query(frame) {
|
||||
frame.options.skipSessionID = frame.original.session.id;
|
||||
return models.User.changePassword(frame.data.password[0], frame.options);
|
||||
}
|
||||
},
|
||||
|
|
|
@ -235,7 +235,7 @@ User = ghostBookshelf.Model.extend({
|
|||
},
|
||||
|
||||
sessions: function sessions() {
|
||||
return this.hasMany('Sessions');
|
||||
return this.hasMany('Session');
|
||||
},
|
||||
|
||||
roles: function roles() {
|
||||
|
@ -864,31 +864,36 @@ User = ghostBookshelf.Model.extend({
|
|||
* @param {Object} object
|
||||
* @param {Object} unfilteredOptions
|
||||
*/
|
||||
changePassword: function changePassword(object, unfilteredOptions) {
|
||||
var options = this.filterOptions(unfilteredOptions, 'changePassword'),
|
||||
self = this,
|
||||
newPassword = object.newPassword,
|
||||
userId = object.user_id,
|
||||
oldPassword = object.oldPassword,
|
||||
isLoggedInUser = userId === options.context.user,
|
||||
user;
|
||||
changePassword: async function changePassword(object, unfilteredOptions) {
|
||||
const options = this.filterOptions(unfilteredOptions, 'changePassword');
|
||||
const newPassword = object.newPassword;
|
||||
const userId = object.user_id;
|
||||
const oldPassword = object.oldPassword;
|
||||
const isLoggedInUser = userId === options.context.user;
|
||||
const skipSessionID = unfilteredOptions.skipSessionID;
|
||||
|
||||
options.require = true;
|
||||
options.withRelated = ['sessions'];
|
||||
|
||||
return self.forge({id: userId}).fetch(options)
|
||||
.then(function then(_user) {
|
||||
user = _user;
|
||||
const user = await this.forge({id: userId}).fetch(options);
|
||||
|
||||
if (isLoggedInUser) {
|
||||
return self.isPasswordCorrect({
|
||||
plainPassword: oldPassword,
|
||||
hashedPassword: user.get('password')
|
||||
});
|
||||
}
|
||||
})
|
||||
.then(function then() {
|
||||
return user.save({password: newPassword});
|
||||
if (isLoggedInUser) {
|
||||
await this.isPasswordCorrect({
|
||||
plainPassword: oldPassword,
|
||||
hashedPassword: user.get('password')
|
||||
});
|
||||
}
|
||||
|
||||
const updatedUser = await user.save({password: newPassword});
|
||||
|
||||
const sessions = user.related('sessions');
|
||||
for (const session of sessions) {
|
||||
if (session.get('session_id') !== skipSessionID) {
|
||||
await session.destroy(options);
|
||||
}
|
||||
}
|
||||
|
||||
return updatedUser;
|
||||
},
|
||||
|
||||
transferOwnership: function transferOwnership(object, unfilteredOptions) {
|
||||
|
|
|
@ -310,8 +310,8 @@ describe('User API', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('Can change password', function () {
|
||||
return request
|
||||
it('Can change password and retain the session', async function () {
|
||||
await request
|
||||
.put(localUtils.API.getApiQuery('users/password'))
|
||||
.set('Origin', config.get('url'))
|
||||
.send({
|
||||
|
@ -329,5 +329,10 @@ describe('User API', function () {
|
|||
should.exist(res.body.password);
|
||||
should.exist(res.body.password[0].message);
|
||||
});
|
||||
|
||||
await request
|
||||
.get(localUtils.API.getApiQuery('session/'))
|
||||
.set('Origin', config.get('url'))
|
||||
.expect(200);
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Add table
Reference in a new issue