forked from parse-community/parse-server
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial release, parse-server, 2.0.0
- Loading branch information
0 parents
commit 7f5d744
Showing
53 changed files
with
14,974 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
# Logs | ||
logs | ||
*.log | ||
|
||
# Runtime data | ||
pids | ||
*.pid | ||
*.seed | ||
|
||
# Directory for instrumented libs generated by jscoverage/JSCover | ||
lib-cov | ||
|
||
# Coverage directory used by tools like istanbul | ||
coverage | ||
|
||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) | ||
.grunt | ||
|
||
# node-waf configuration | ||
.lock-wscript | ||
|
||
# Compiled binary addons (http://nodejs.org/api/addons.html) | ||
build/Release | ||
|
||
# Dependency directory | ||
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git | ||
node_modules | ||
|
||
# Emacs | ||
*~ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,170 @@ | ||
var deepcopy = require('deepcopy'); | ||
var Parse = require('parse/node').Parse; | ||
var RestQuery = require('./RestQuery'); | ||
|
||
var cache = require('./cache'); | ||
|
||
// An Auth object tells you who is requesting something and whether | ||
// the master key was used. | ||
// userObject is a Parse.User and can be null if there's no user. | ||
function Auth(config, isMaster, userObject) { | ||
this.config = config; | ||
this.isMaster = isMaster; | ||
this.user = userObject; | ||
|
||
// Assuming a users roles won't change during a single request, we'll | ||
// only load them once. | ||
this.userRoles = []; | ||
this.fetchedRoles = false; | ||
this.rolePromise = null; | ||
} | ||
|
||
// Whether this auth could possibly modify the given user id. | ||
// It still could be forbidden via ACLs even if this returns true. | ||
Auth.prototype.couldUpdateUserId = function(userId) { | ||
if (this.isMaster) { | ||
return true; | ||
} | ||
if (this.user && this.user.id === userId) { | ||
return true; | ||
} | ||
return false; | ||
}; | ||
|
||
// A helper to get a master-level Auth object | ||
function master(config) { | ||
return new Auth(config, true, null); | ||
} | ||
|
||
// A helper to get a nobody-level Auth object | ||
function nobody(config) { | ||
return new Auth(config, false, null); | ||
} | ||
|
||
// Returns a promise that resolves to an Auth object | ||
var getAuthForSessionToken = function(config, sessionToken) { | ||
var cachedUser = cache.getUser(sessionToken); | ||
if (cachedUser) { | ||
return Promise.resolve(new Auth(config, false, cachedUser)); | ||
} | ||
var restOptions = { | ||
limit: 1, | ||
include: 'user' | ||
}; | ||
var restWhere = { | ||
_session_token: sessionToken | ||
}; | ||
var query = new RestQuery(config, master(config), '_Session', | ||
restWhere, restOptions); | ||
return query.execute().then((response) => { | ||
var results = response.results; | ||
if (results.length !== 1 || !results[0]['user']) { | ||
return nobody(config); | ||
} | ||
var obj = results[0]['user']; | ||
delete obj.password; | ||
obj['className'] = '_User'; | ||
var userObject = Parse.Object.fromJSON(obj); | ||
cache.setUser(sessionToken, userObject); | ||
return new Auth(config, false, userObject); | ||
}); | ||
}; | ||
|
||
// Returns a promise that resolves to an array of role names | ||
Auth.prototype.getUserRoles = function() { | ||
if (this.isMaster || !this.user) { | ||
return Promise.resolve([]); | ||
} | ||
if (this.fetchedRoles) { | ||
return Promise.resolve(this.userRoles); | ||
} | ||
if (this.rolePromise) { | ||
return rolePromise; | ||
} | ||
this.rolePromise = this._loadRoles(); | ||
return this.rolePromise; | ||
}; | ||
|
||
// Iterates through the role tree and compiles a users roles | ||
Auth.prototype._loadRoles = function() { | ||
var restWhere = { | ||
'users': { | ||
__type: 'Pointer', | ||
className: '_User', | ||
objectId: this.user.id | ||
} | ||
}; | ||
// First get the role ids this user is directly a member of | ||
var query = new RestQuery(this.config, master(this.config), '_Role', | ||
restWhere, {}); | ||
return query.execute().then((response) => { | ||
var results = response.results; | ||
if (!results.length) { | ||
this.userRoles = []; | ||
this.fetchedRoles = true; | ||
this.rolePromise = null; | ||
return Promise.resolve(this.userRoles); | ||
} | ||
|
||
var roleIDs = results.map(r => r.objectId); | ||
var promises = [Promise.resolve(roleIDs)]; | ||
for (var role of roleIDs) { | ||
promises.push(this._getAllRoleNamesForId(role)); | ||
} | ||
return Promise.all(promises).then((results) => { | ||
var allIDs = []; | ||
for (var x of results) { | ||
Array.prototype.push.apply(allIDs, x); | ||
} | ||
var restWhere = { | ||
objectId: { | ||
'$in': allIDs | ||
} | ||
}; | ||
var query = new RestQuery(this.config, master(this.config), | ||
'_Role', restWhere, {}); | ||
return query.execute(); | ||
}).then((response) => { | ||
var results = response.results; | ||
this.userRoles = results.map((r) => { | ||
return 'role:' + r.name; | ||
}); | ||
this.fetchedRoles = true; | ||
this.rolePromise = null; | ||
return Promise.resolve(this.userRoles); | ||
}); | ||
}); | ||
}; | ||
|
||
// Given a role object id, get any other roles it is part of | ||
// TODO: Make recursive to support role nesting beyond 1 level deep | ||
Auth.prototype._getAllRoleNamesForId = function(roleID) { | ||
var rolePointer = { | ||
__type: 'Pointer', | ||
className: '_Role', | ||
objectId: roleID | ||
}; | ||
var restWhere = { | ||
'$relatedTo': { | ||
key: 'roles', | ||
object: rolePointer | ||
} | ||
}; | ||
var query = new RestQuery(this.config, master(this.config), '_Role', | ||
restWhere, {}); | ||
return query.execute().then((response) => { | ||
var results = response.results; | ||
if (!results.length) { | ||
return Promise.resolve([]); | ||
} | ||
var roleIDs = results.map(r => r.objectId); | ||
return Promise.resolve(roleIDs); | ||
}); | ||
}; | ||
|
||
module.exports = { | ||
Auth: Auth, | ||
master: master, | ||
nobody: nobody, | ||
getAuthForSessionToken: getAuthForSessionToken | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
// A Config object provides information about how a specific app is | ||
// configured. | ||
// mount is the URL for the root of the API; includes http, domain, etc. | ||
function Config(applicationId, mount) { | ||
var cache = require('./cache'); | ||
var DatabaseAdapter = require('./DatabaseAdapter'); | ||
|
||
var cacheInfo = cache.apps[applicationId]; | ||
this.valid = !!cacheInfo; | ||
if (!this.valid) { | ||
return; | ||
} | ||
|
||
this.applicationId = applicationId; | ||
this.collectionPrefix = cacheInfo.collectionPrefix || ''; | ||
this.database = DatabaseAdapter.getDatabaseConnection(applicationId); | ||
this.masterKey = cacheInfo.masterKey; | ||
this.clientKey = cacheInfo.clientKey; | ||
this.javascriptKey = cacheInfo.javascriptKey; | ||
this.dotNetKey = cacheInfo.dotNetKey; | ||
this.restAPIKey = cacheInfo.restAPIKey; | ||
this.fileKey = cacheInfo.fileKey; | ||
this.mount = mount; | ||
} | ||
|
||
|
||
module.exports = Config; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
// Database Adapter | ||
// | ||
// Allows you to change the underlying database. | ||
// | ||
// Adapter classes must implement the following methods: | ||
// * a constructor with signature (connectionString, optionsObject) | ||
// * connect() | ||
// * loadSchema() | ||
// * create(className, object) | ||
// * find(className, query, options) | ||
// * update(className, query, update, options) | ||
// * destroy(className, query, options) | ||
// * This list is incomplete and the database process is not fully modularized. | ||
// | ||
// Default is ExportAdapter, which uses mongo. | ||
|
||
var ExportAdapter = require('./ExportAdapter'); | ||
|
||
var adapter = ExportAdapter; | ||
var cache = require('./cache'); | ||
var dbConnections = {}; | ||
var databaseURI = 'mongodb://localhost:27017/parse'; | ||
|
||
function setAdapter(databaseAdapter) { | ||
adapter = databaseAdapter; | ||
} | ||
|
||
function setDatabaseURI(uri) { | ||
databaseURI = uri; | ||
} | ||
|
||
function getDatabaseConnection(appId) { | ||
if (dbConnections[appId]) { | ||
return dbConnections[appId]; | ||
} | ||
dbConnections[appId] = new adapter(databaseURI, { | ||
collectionPrefix: cache.apps[appId]['collectionPrefix'] | ||
}); | ||
dbConnections[appId].connect(); | ||
return dbConnections[appId]; | ||
} | ||
|
||
module.exports = { | ||
dbConnections: dbConnections, | ||
getDatabaseConnection: getDatabaseConnection, | ||
setAdapter: setAdapter, | ||
setDatabaseURI: setDatabaseURI | ||
}; |
Oops, something went wrong.