Remove all other tokens when a connection calls changePassword

This commit is contained in:
Emily Stark
2014-03-17 18:06:47 -07:00
parent 8a16f50138
commit 7839c26cef
2 changed files with 70 additions and 3 deletions

View File

@@ -198,10 +198,18 @@ Meteor.methods({changePassword: function (options) {
if (!verifier)
throw new Meteor.Error(400, "Invalid verifier");
// XXX this should invalidate all login tokens other than the current one
// (or it should assign a new login token, replacing existing ones)
// It would be better if this removed ALL existing tokens and replaced
// the token for the current connection with a new one, but that would
// be tricky, so we'll settle for just replacing all tokens other than
// the one for the current connection.
var currentToken = Accounts._getLoginToken(this.connection.id);
Meteor.users.update({_id: this.userId},
{$set: {'services.password.srp': verifier}});
{
$set: { 'services.password.srp': verifier },
$pull: {
'services.resume.loginTokens': { hashedToken: { $ne: currentToken } }
}
});
var ret = {passwordChanged: true};
if (serialized)

View File

@@ -191,6 +191,65 @@ if (Meteor.isClient) (function () {
logoutStep
]);
testAsyncMulti("passwords - changing password logs out other clients", [
function (test, expect) {
this.username = Random.id();
this.email = Random.id() + '-intercept@example.com';
this.password = 'password';
this.password2 = 'password2';
Accounts.createUser(
{ username: this.username, email: this.email, password: this.password },
loggedInAs(this.username, test, expect));
},
// Log in a second connection as this user.
function (test, expect) {
var self = this;
// copied from livedata/client_convenience.js
var ddpUrl = '/';
if (typeof __meteor_runtime_config__ !== "undefined") {
if (__meteor_runtime_config__.DDP_DEFAULT_CONNECTION_URL)
ddpUrl = __meteor_runtime_config__.DDP_DEFAULT_CONNECTION_URL;
}
// XXX can we get the url from the existing connection somehow
// instead?
self.secondConn = DDP.connect(ddpUrl);
self.secondConn.call('login',
{ user: { username: self.username }, password: self.password },
expect(function (err, result) {
test.isFalse(err);
self.secondConn.setUserId(result.id);
test.isTrue(self.secondConn.userId());
self.secondConn.onReconnect = function () {
self.secondConn.apply(
'login',
[{ resume: result.token }],
{ wait: true },
function (err, result) {
self.secondConn.setUserId(result && result.id || null);
}
);
};
}));
},
function (test, expect) {
var self = this;
Accounts.changePassword(self.password, self.password2, expect(function (err) {
test.isFalse(err);
}));
},
// Now that we've changed the password, wait until the second
// connection gets logged out.
function (test, expect) {
var self = this;
pollUntil(expect, function () {
return self.secondConn.userId() === null;
}, 10 * 1000, 100);
}
]);
testAsyncMulti("passwords - new user hooks", [
function (test, expect) {