From 90a4ac70acf780c5e328a9e6335c4d76e526111d Mon Sep 17 00:00:00 2001 From: Francis Lessard Date: Thu, 11 Feb 2016 20:32:31 -0500 Subject: [PATCH 1/3] Fix session token issue In _User collection a field _session_token is present and if you fetch the user data form server, this field override the sessionToken saved in your browser. If you don't fetch the user, all request to server contain the right sessionToken and if you fetch the user data from the server, all next requests will contain the wrong sessionToken come form the _session_token in user data fetched. --- src/RestQuery.js | 5 +++++ src/Routers/ClassesRouter.js | 5 +++++ src/users.js | 3 +++ 3 files changed, 13 insertions(+) diff --git a/src/RestQuery.js b/src/RestQuery.js index 91ebe536b7..7cf8074f3e 100644 --- a/src/RestQuery.js +++ b/src/RestQuery.js @@ -415,6 +415,11 @@ function includePath(config, auth, response, path) { for (var obj of includeResponse.results) { obj.__type = 'Object'; obj.className = className; + + if(className == "_User"){ + delete obj.sessionToken; + } + replace[obj.objectId] = obj; } var resp = { diff --git a/src/Routers/ClassesRouter.js b/src/Routers/ClassesRouter.js index 11666b207a..a49d6d4a6d 100644 --- a/src/Routers/ClassesRouter.js +++ b/src/Routers/ClassesRouter.js @@ -51,6 +51,11 @@ export class ClassesRouter { if (!response.results || response.results.length == 0) { throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Object not found.'); } + + if(req.params.className === "_User"){ + delete response.results[0].sessionToken; + } + return { response: response.results[0] }; }); } diff --git a/src/users.js b/src/users.js index 4205c66631..9484ee64a4 100644 --- a/src/users.js +++ b/src/users.js @@ -133,6 +133,9 @@ function handleGet(req) { throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Object not found.'); } else { + if(req.params.className === "_User"){ + delete response.results[0].sessionToken; + } return {response: response.results[0]}; } }); From 56552537a1b6af6d6cb1680510aa75e287604446 Mon Sep 17 00:00:00 2001 From: Francis Lessard Date: Fri, 12 Feb 2016 08:15:58 -0500 Subject: [PATCH 2/3] Add test to the session token hasn't changed --- spec/ParseUser.spec.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/spec/ParseUser.spec.js b/spec/ParseUser.spec.js index 368bea2295..787a8ecb75 100644 --- a/spec/ParseUser.spec.js +++ b/spec/ParseUser.spec.js @@ -1358,6 +1358,25 @@ describe('Parse.User testing', () => { }); }); + it('retrieve user data from fetch, make sure the session token hasn\'t changed', (done) => { + var user = new Parse.User(); + user.setPassword("asdf"); + user.setUsername("zxcv"); + var currentSessionToken = ""; + Parse.Promise.as().then(function() { + return user.signUp(); + }).then(function(){ + currentSessionToken = user.getSessionToken(); + return user.fetch(); + }).then(function(u){ + expect(currentSessionToken).toEqual(u.getSessionToken()); + done(); + }, function(error) { + ok(false, error); + done(); + }) + }); + it('user save should fail with invalid email', (done) => { var user = new Parse.User(); user.set('username', 'teste'); From 66efd0d0305cac1484b456e78878443c6e368741 Mon Sep 17 00:00:00 2001 From: Francis Lessard Date: Fri, 12 Feb 2016 15:57:37 -0500 Subject: [PATCH 3/3] Rebase --- src/users.js | 215 --------------------------------------------------- 1 file changed, 215 deletions(-) delete mode 100644 src/users.js diff --git a/src/users.js b/src/users.js deleted file mode 100644 index 9484ee64a4..0000000000 --- a/src/users.js +++ /dev/null @@ -1,215 +0,0 @@ -// These methods handle the User-related routes. - -var mongodb = require('mongodb'); -var Parse = require('parse/node').Parse; -var rack = require('hat').rack(); - -var Auth = require('./Auth'); -var passwordCrypto = require('./password'); -var facebook = require('./facebook'); -var PromiseRouter = require('./PromiseRouter'); -var rest = require('./rest'); -var RestWrite = require('./RestWrite'); -var deepcopy = require('deepcopy'); - -var router = new PromiseRouter(); - -// Returns a promise for a {status, response, location} object. -function handleCreate(req) { - var data = deepcopy(req.body); - data.installationId = req.info.installationId; - return rest.create(req.config, req.auth, - '_User', data); -} - -// Returns a promise for a {response} object. -function handleLogIn(req) { - - // Use query parameters instead if provided in url - if (!req.body.username && req.query.username) { - req.body = req.query; - } - - // TODO: use the right error codes / descriptions. - if (!req.body.username) { - throw new Parse.Error(Parse.Error.USERNAME_MISSING, - 'username is required.'); - } - if (!req.body.password) { - throw new Parse.Error(Parse.Error.PASSWORD_MISSING, - 'password is required.'); - } - - var user; - return req.database.find('_User', {username: req.body.username}) - .then((results) => { - if (!results.length) { - throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, - 'Invalid username/password.'); - } - 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.'); - } - var token = 'r:' + rack(); - user.sessionToken = token; - delete user.password; - - req.config.filesController.expandFilesInObject(req.config, user); - - var expiresAt = new Date(); - expiresAt.setFullYear(expiresAt.getFullYear() + 1); - - var sessionData = { - sessionToken: token, - user: { - __type: 'Pointer', - className: '_User', - objectId: user.objectId - }, - createdWith: { - 'action': 'login', - 'authProvider': 'password' - }, - restricted: false, - expiresAt: Parse._encode(expiresAt) - }; - - if (req.info.installationId) { - sessionData.installationId = req.info.installationId - } - - var create = new RestWrite(req.config, Auth.master(req.config), - '_Session', null, sessionData); - return create.execute(); - }).then(() => { - return {response: user}; - }); -} - -// Returns a promise that resolves to a {response} object. -// TODO: share code with ClassesRouter.js -function handleFind(req) { - var options = {}; - if (req.body.skip) { - options.skip = Number(req.body.skip); - } - if (req.body.limit) { - options.limit = Number(req.body.limit); - } - if (req.body.order) { - options.order = String(req.body.order); - } - if (req.body.count) { - options.count = true; - } - if (typeof req.body.keys == 'string') { - options.keys = req.body.keys; - } - if (req.body.include) { - options.include = String(req.body.include); - } - if (req.body.redirectClassNameForKey) { - options.redirectClassNameForKey = String(req.body.redirectClassNameForKey); - } - - return rest.find(req.config, req.auth, - '_User', req.body.where, options) - .then((response) => { - return {response: response}; - }); - -} - -// Returns a promise for a {response} object. -function handleGet(req) { - return rest.find(req.config, req.auth, '_User', - {objectId: req.params.objectId}) - .then((response) => { - if (!response.results || response.results.length == 0) { - throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, - 'Object not found.'); - } else { - if(req.params.className === "_User"){ - delete response.results[0].sessionToken; - } - return {response: response.results[0]}; - } - }); -} - -function handleMe(req) { - if (!req.info || !req.info.sessionToken) { - throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, - 'Object not found.'); - } - return rest.find(req.config, Auth.master(req.config), '_Session', - {_session_token: req.info.sessionToken}, - {include: 'user'}) - .then((response) => { - if (!response.results || response.results.length == 0 || - !response.results[0].user) { - throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, - 'Object not found.'); - } else { - var user = response.results[0].user; - return {response: user}; - } - }); -} - -function handleDelete(req) { - return rest.del(req.config, req.auth, - req.params.className, req.params.objectId) - .then(() => { - return {response: {}}; - }); -} - -function handleLogOut(req) { - var success = {response: {}}; - if (req.info && req.info.sessionToken) { - return rest.find(req.config, Auth.master(req.config), '_Session', - {_session_token: req.info.sessionToken} - ).then((records) => { - if (records.results && records.results.length) { - return rest.del(req.config, Auth.master(req.config), '_Session', - records.results[0].objectId - ).then(() => { - return Promise.resolve(success); - }); - } - return Promise.resolve(success); - }); - } - return Promise.resolve(success); -} - -function handleUpdate(req) { - return rest.update(req.config, req.auth, '_User', - req.params.objectId, req.body) - .then((response) => { - return {response: response}; - }); -} - -function notImplementedYet(req) { - throw new Parse.Error(Parse.Error.COMMAND_UNAVAILABLE, - 'This path is not implemented yet.'); -} - -router.route('POST', '/users', handleCreate); -router.route('GET', '/login', handleLogIn); -router.route('POST', '/logout', handleLogOut); -router.route('GET', '/users/me', handleMe); -router.route('GET', '/users/:objectId', handleGet); -router.route('PUT', '/users/:objectId', handleUpdate); -router.route('GET', '/users', handleFind); -router.route('DELETE', '/users/:objectId', handleDelete); - -router.route('POST', '/requestPasswordReset', notImplementedYet); - -module.exports = router;