Cache users by objectID, and clear cache when updated via master key (fixes #1836) (#1844)

* Cache users by objectID, and clear cache when updated via master key

* Go back to caching by session token. Clear out cache by querying _Session when user is modified with Master Key (ew, hopefully that can be improved later)

* Fix issue with user updates from different sessions causing stale reads

* Tests aren't transpiled...

* Still not transpiled
This commit is contained in:
Drew
2016-05-22 09:59:36 -07:00
parent eefa2ccac7
commit 392102eb97
6 changed files with 115 additions and 20 deletions

View File

@@ -53,7 +53,6 @@ export class InMemoryCache {
if (record.timeout) {
clearTimeout(record.timeout);
}
delete this.cache[key];
}

View File

@@ -72,7 +72,6 @@ var getAuthForSessionToken = function({ config, sessionToken, installationId } =
obj['className'] = '_User';
obj['sessionToken'] = sessionToken;
config.cacheController.user.put(sessionToken, obj);
let userObject = Parse.Object.fromJSON(obj);
return new Auth({config, isMaster: false, installationId, user: userObject});
});

View File

@@ -11,6 +11,7 @@ var cryptoUtils = require('./cryptoUtils');
var passwordCrypto = require('./password');
var Parse = require('parse/node');
var triggers = require('./triggers');
import RestQuery from './RestQuery';
// query and data are both provided in REST API format. So data
// types are encoded by plain old objects.
@@ -318,10 +319,17 @@ RestWrite.prototype.transformUser = function() {
var promise = Promise.resolve();
// If we're updating a _User object, clear the user cache for the session
if (this.query && this.auth.user && this.auth.user.getSessionToken()) {
let cacheAdapter = this.config.cacheController;
cacheAdapter.user.del(this.auth.user.getSessionToken());
if (this.query) {
// If we're updating a _User object, we need to clear out the cache for that user. Find all their
// session tokens, and remove them from the cache.
promise = new RestQuery(this.config, Auth.master(this.config), '_Session', { user: {
__type: "Pointer",
className: "_User",
objectId: this.objectId(),
}}).execute()
.then(results => {
results.results.forEach(session => this.config.cacheController.user.del(session.sessionToken));
});
}
return promise.then(() => {
@@ -414,8 +422,7 @@ RestWrite.prototype.createSessionTokenIfNeeded = function() {
if (this.response && this.response.response) {
this.response.response.sessionToken = token;
}
var create = new RestWrite(this.config, Auth.master(this.config),
'_Session', null, sessionData);
var create = new RestWrite(this.config, Auth.master(this.config), '_Session', null, sessionData);
return create.execute();
}
@@ -482,8 +489,7 @@ RestWrite.prototype.handleSession = function() {
}
sessionData[key] = this.data[key];
}
var create = new RestWrite(this.config, Auth.master(this.config),
'_Session', null, sessionData);
var create = new RestWrite(this.config, Auth.master(this.config), '_Session', null, sessionData);
return create.execute().then((results) => {
if (!results.response) {
throw new Parse.Error(Parse.Error.INTERNAL_SERVER_ERROR,

View File

@@ -85,6 +85,7 @@ export class UsersRouter extends ClassesRouter {
user = results[0];
return passwordCrypto.compare(req.body.password, user.password);
}).then((correct) => {
if (!correct) {
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Invalid username/password.');
}

View File

@@ -27,9 +27,9 @@ function handleParseHeaders(req, res, next) {
dotNetKey: req.get('X-Parse-Windows-Key'),
restAPIKey: req.get('X-Parse-REST-API-Key')
};
var basicAuth = httpAuth(req);
if (basicAuth) {
info.appId = basicAuth.appId
info.masterKey = basicAuth.masterKey || info.masterKey;
@@ -156,24 +156,24 @@ function httpAuth(req) {
if (!(req.req || req).headers.authorization)
return ;
var header = (req.req || req).headers.authorization;
var appId, masterKey, javascriptKey;
var header = (req.req || req).headers.authorization;
var appId, masterKey, javascriptKey;
// parse header
var authPrefix = 'basic ';
var match = header.toLowerCase().indexOf(authPrefix);
if (match == 0) {
var encodedAuth = header.substring(authPrefix.length, header.length);
var credentials = decodeBase64(encodedAuth).split(':');
if (credentials.length == 2) {
appId = credentials[0];
var key = credentials[1];
var jsKeyPrefix = 'javascript-key=';
var matchKey = key.indexOf(jsKeyPrefix)
if (matchKey == 0) {
javascriptKey = key.substring(jsKeyPrefix.length, key.length);
@@ -183,7 +183,7 @@ function httpAuth(req) {
}
}
}
return {appId: appId, masterKey: masterKey, javascriptKey: javascriptKey};
}