diff --git a/src/Auth.js b/src/Auth.js index 60273b9638..1cb2e96563 100644 --- a/src/Auth.js +++ b/src/Auth.js @@ -1,5 +1,6 @@ -var Parse = require('parse/node').Parse; -var RestQuery = require('./RestQuery'); +const cryptoUtils = require('./cryptoUtils'); +const RestQuery = require('./RestQuery'); +const Parse = require('parse/node'); // An Auth object tells you who is requesting something and whether // the master key was used. @@ -212,11 +213,46 @@ Auth.prototype._getAllRolesNamesForRoleIds = function(roleIDs, names = [], queri }) } +const createSession = function(config, { + userId, + createdWith, + installationId, + additionalSessionData, +}) { + const token = 'r:' + cryptoUtils.newToken(); + const expiresAt = config.generateSessionExpiresAt(); + const sessionData = { + sessionToken: token, + user: { + __type: 'Pointer', + className: '_User', + objectId: userId + }, + createdWith, + restricted: false, + expiresAt: Parse._encode(expiresAt) + }; + + if (installationId) { + sessionData.installationId = installationId + } + + Object.assign(sessionData, additionalSessionData); + // We need to import RestWrite at this point for the cyclic dependency it has to it + const RestWrite = require('./RestWrite'); + + return { + sessionData, + createSession: () => new RestWrite(config, master(config), '_Session', null, sessionData).execute() + } +} + module.exports = { Auth, master, nobody, readOnly, getAuthForSessionToken, - getAuthForLegacySessionToken + getAuthForLegacySessionToken, + createSession, }; diff --git a/src/Controllers/DatabaseController.js b/src/Controllers/DatabaseController.js index 19d0179fb6..349ac09063 100644 --- a/src/Controllers/DatabaseController.js +++ b/src/Controllers/DatabaseController.js @@ -511,7 +511,7 @@ class DatabaseController { addRelation(key: string, fromClassName: string, fromId: string, toId: string) { const doc = { relatedId: toId, - owningId : fromId + owningId: fromId }; return this.adapter.upsertOneObject(`_Join:${key}:${fromClassName}`, relationSchema, doc, doc); } @@ -658,7 +658,7 @@ class DatabaseController { // Returns a promise for a list of owning ids given some related ids. // className here is the owning className. - owningIds(className: string, key: string, relatedIds: string): Promise { + owningIds(className: string, key: string, relatedIds: string[]): Promise { return this.adapter.find(joinTableName(className, key), relationSchema, { relatedId: { '$in': relatedIds } }, {}) .then(results => results.map(result => result.owningId)); } diff --git a/src/RestWrite.js b/src/RestWrite.js index 424284d5ba..68050df992 100644 --- a/src/RestWrite.js +++ b/src/RestWrite.js @@ -5,7 +5,7 @@ var SchemaController = require('./Controllers/SchemaController'); var deepcopy = require('deepcopy'); -var Auth = require('./Auth'); +const Auth = require('./Auth'); var cryptoUtils = require('./cryptoUtils'); var passwordCrypto = require('./password'); var Parse = require('parse/node'); @@ -568,29 +568,24 @@ RestWrite.prototype.createSessionToken = function() { if (this.auth.installationId && this.auth.installationId === 'cloud') { return; } - var token = 'r:' + cryptoUtils.newToken(); - var expiresAt = this.config.generateSessionExpiresAt(); - var sessionData = { - sessionToken: token, - user: { - __type: 'Pointer', - className: '_User', - objectId: this.objectId() - }, + const { + sessionData, + createSession, + } = Auth.createSession(this.config, { + userId: this.objectId(), createdWith: { 'action': this.storage['authProvider'] ? 'login' : 'signup', 'authProvider': this.storage['authProvider'] || 'password' }, - restricted: false, installationId: this.auth.installationId, - expiresAt: Parse._encode(expiresAt) - }; + }); + if (this.response && this.response.response) { - this.response.response.sessionToken = token; + this.response.response.sessionToken = sessionData.sessionToken; } - return new RestWrite(this.config, Auth.master(this.config), '_Session', null, sessionData).execute(); + return createSession(); } RestWrite.prototype.destroyDuplicatedSessions = function() { @@ -675,29 +670,23 @@ RestWrite.prototype.handleSession = function() { } if (!this.query && !this.auth.isMaster) { - var token = 'r:' + cryptoUtils.newToken(); - var expiresAt = this.config.generateSessionExpiresAt(); - var sessionData = { - sessionToken: token, - user: { - __type: 'Pointer', - className: '_User', - objectId: this.auth.user.id - }, - createdWith: { - 'action': 'create' - }, - restricted: true, - expiresAt: Parse._encode(expiresAt) - }; + const additionalSessionData = {}; for (var key in this.data) { if (key === 'objectId' || key === 'user') { continue; } - sessionData[key] = this.data[key]; + additionalSessionData[key] = this.data[key]; } - var create = new RestWrite(this.config, Auth.master(this.config), '_Session', null, sessionData); - return create.execute().then((results) => { + + const { sessionData, createSession } = Auth.createSession(this.config, { + userId: this.auth.user.id, + createdWith: { + action: 'create', + }, + additionalSessionData + }); + + return createSession().then((results) => { if (!results.response) { throw new Parse.Error(Parse.Error.INTERNAL_SERVER_ERROR, 'Error creating session.'); diff --git a/src/Routers/SessionsRouter.js b/src/Routers/SessionsRouter.js index ed9b3830f7..52b9ba6f5a 100644 --- a/src/Routers/SessionsRouter.js +++ b/src/Routers/SessionsRouter.js @@ -3,8 +3,6 @@ import ClassesRouter from './ClassesRouter'; import Parse from 'parse/node'; import rest from '../rest'; import Auth from '../Auth'; -import RestWrite from '../RestWrite'; -import { newToken } from '../cryptoUtils'; export class SessionsRouter extends ClassesRouter { @@ -32,30 +30,24 @@ export class SessionsRouter extends ClassesRouter { handleUpdateToRevocableSession(req) { const config = req.config; - const masterAuth = Auth.master(config) const user = req.auth.user; // Issue #2720 // Calling without a session token would result in a not found user if (!user) { throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'invalid session'); } - const expiresAt = config.generateSessionExpiresAt(); - const sessionData = { - sessionToken: 'r:' + newToken(), - user: { - __type: 'Pointer', - className: '_User', - objectId: user.id - }, + const { + sessionData, + createSession + } = Auth.createSession(config, { + userId: user.id, createdWith: { 'action': 'upgrade', }, - restricted: false, installationId: req.auth.installationId, - expiresAt: Parse._encode(expiresAt) - }; - const create = new RestWrite(config, masterAuth, '_Session', null, sessionData); - return create.execute().then(() => { + }); + + return createSession().then(() => { // delete the session token, use the db to skip beforeSave return config.database.update('_User', { objectId: user.id diff --git a/src/Routers/UsersRouter.js b/src/Routers/UsersRouter.js index 9f671bd384..c18be9ae79 100644 --- a/src/Routers/UsersRouter.js +++ b/src/Routers/UsersRouter.js @@ -7,8 +7,6 @@ import ClassesRouter from './ClassesRouter'; import rest from '../rest'; import Auth from '../Auth'; import passwordCrypto from '../password'; -import RestWrite from '../RestWrite'; -const cryptoUtils = require('../cryptoUtils'); export class UsersRouter extends ClassesRouter { @@ -142,8 +140,6 @@ export class UsersRouter extends ClassesRouter { } } - const token = 'r:' + cryptoUtils.newToken(); - user.sessionToken = token; delete user.password; // Remove hidden properties. @@ -161,31 +157,19 @@ export class UsersRouter extends ClassesRouter { delete user.authData; } } + const { + sessionData, + createSession + } = Auth.createSession(req.config, { userId: user.objectId, createdWith: { + 'action': 'login', + 'authProvider': 'password' + }, installationId: req.info.installationId }); - req.config.filesController.expandFilesInObject(req.config, user); + user.sessionToken = sessionData.sessionToken; - const expiresAt = req.config.generateSessionExpiresAt(); - const 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 - } + req.config.filesController.expandFilesInObject(req.config, user); - const create = new RestWrite(req.config, Auth.master(req.config), '_Session', null, sessionData); - return create.execute(); + return createSession(); }).then(() => { return { response: user }; });