Adds liniting into the workflow (#3082)

* initial linting of src

* fix indent to 2 spaces

* Removes unnecessary rules

* ignore spec folder for now

* Spec linting

* Fix spec indent

* nits

* nits

* no no-empty rule
This commit is contained in:
Florent Vilmart
2016-11-24 15:47:41 -05:00
committed by GitHub
parent 6e2fba4ae4
commit 8c2c76dd26
149 changed files with 3478 additions and 3507 deletions

View File

@@ -1,6 +1,5 @@
// This class handles the Account Lockout Policy settings.
import Config from './Config';
import Parse from 'parse/node';
export class AccountLockout {
constructor(user, config) {
@@ -13,7 +12,7 @@ export class AccountLockout {
*/
_setFailedLoginCount(value) {
let query = {
username: this._user.username,
username: this._user.username
};
const updateFields = {
@@ -76,7 +75,7 @@ export class AccountLockout {
*/
_incrementFailedLoginCount() {
const query = {
username: this._user.username,
username: this._user.username
};
const updateFields = {_failed_login_count: {__op: 'Increment', amount: 1}};
@@ -93,7 +92,7 @@ export class AccountLockout {
return new Promise((resolve, reject) => {
const query = {
username: this._user.username,
_failed_login_count: { $gte: this._config.accountLockout.threshold },
_failed_login_count: { $gte: this._config.accountLockout.threshold }
};
const now = new Date();

View File

@@ -1,3 +1,4 @@
/*eslint no-unused-vars: "off"*/
export class AnalyticsAdapter {
/*

View File

@@ -1,3 +1,4 @@
/*eslint no-unused-vars: "off"*/
export class CacheAdapter {
/**
* Get a value in the cache

View File

@@ -7,7 +7,7 @@ export class InMemoryCacheAdapter {
}
get(key) {
return new Promise((resolve, reject) => {
return new Promise((resolve) => {
let record = this.cache.get(key);
if (record == null) {
return resolve(null);

View File

@@ -1,19 +1,18 @@
export class NullCacheAdapter {
constructor(ctx) {
}
constructor() {}
get(key) {
return new Promise((resolve, _) => {
get() {
return new Promise((resolve) => {
return resolve(null);
})
}
put(key, value, ttl) {
put() {
return Promise.resolve();
}
del(key) {
del() {
return Promise.resolve();
}

View File

@@ -3,7 +3,7 @@ import logger from '../../logger';
const DEFAULT_REDIS_TTL = 30 * 1000; // 30 seconds in milliseconds
function debug() {
function debug() {
logger.debug.apply(logger, ['RedisCacheAdapter', ...arguments]);
}
@@ -16,8 +16,8 @@ export class RedisCacheAdapter {
get(key) {
debug('get', key);
this.p = this.p.then(() => {
return new Promise((resolve, _) => {
this.p = this.p.then(() => {
return new Promise((resolve) => {
this.client.get(key, function(err, res) {
debug('-> get', key, res);
if(!res) {
@@ -39,14 +39,14 @@ export class RedisCacheAdapter {
if (ttl < 0 || isNaN(ttl)) {
ttl = DEFAULT_REDIS_TTL;
}
this.p = this.p.then(() => {
return new Promise((resolve, _) => {
this.p = this.p.then(() => {
return new Promise((resolve) => {
if (ttl === Infinity) {
this.client.set(key, value, function(err, res) {
this.client.set(key, value, function() {
resolve();
});
} else {
this.client.psetex(key, ttl, value, function(err, res) {
this.client.psetex(key, ttl, value, function() {
resolve();
});
}
@@ -57,9 +57,9 @@ export class RedisCacheAdapter {
del(key) {
debug('del', key);
this.p = this.p.then(() => {
return new Promise((resolve, _) => {
this.client.del(key, function(err, res) {
this.p = this.p.then(() => {
return new Promise((resolve) => {
this.client.del(key, function() {
resolve();
});
});
@@ -69,9 +69,9 @@ export class RedisCacheAdapter {
clear() {
debug('clear');
this.p = this.p.then(() => {
return new Promise((resolve, _) => {
this.client.flushall(function(err, res) {
this.p = this.p.then(() => {
return new Promise((resolve) => {
this.client.flushall(function() {
resolve();
});
});

View File

@@ -1,4 +1,4 @@
/*eslint no-unused-vars: "off"*/
/*
Mail Adapter prototype
A MailAdapter should implement at least sendMail()

View File

@@ -1,3 +1,4 @@
/*eslint no-unused-vars: "off"*/
// Files Adapter
//
// Allows you to change the file storage mechanism.

View File

@@ -28,7 +28,7 @@ export class GridStoreAdapter extends FilesAdapter {
// For a given config object, filename, and data, store a file
// Returns a promise
createFile(filename: string, data, contentType) {
createFile(filename: string, data) {
return this._connect().then(database => {
let gridStore = new GridStore(database, filename, 'w');
return gridStore.open();

View File

@@ -1,3 +1,4 @@
/*eslint no-unused-vars: "off"*/
// Logger Adapter
//
// Allows you to change the logger mechanism

View File

@@ -37,7 +37,7 @@ function updateTransports(options) {
}, options));
}
// Mount the additional transports
additionalTransports.forEach((transport) => {
additionalTransports.forEach((transport) => {
transports[transport.name] = transport;
});
logger.configure({
@@ -65,7 +65,7 @@ export function configureLogger({
}
try {
fs.mkdirSync(logsFolder);
} catch (exception) {}
} catch (e) { /* */ }
}
options.dirname = logsFolder;
options.level = logLevel;
@@ -90,7 +90,7 @@ export function removeTransport(transport) {
logger.configure({
transports: _.values(transports)
});
_.remove(additionalTransports, (transport) => {
_.remove(additionalTransports, (transport) => {
return transport.name === transportName;
});
}

View File

@@ -3,11 +3,6 @@ import { logger, addTransport, configureLogger } from './WinstonLogger';
const MILLISECONDS_IN_A_DAY = 24 * 60 * 60 * 1000;
// returns Date object rounded to nearest day
let _getNearestDay = (date) => {
return new Date(date.getFullYear(), date.getMonth(), date.getDate());
}
export class WinstonLoggerAdapter extends LoggerAdapter {
constructor(options) {
super();
@@ -38,18 +33,16 @@ export class WinstonLoggerAdapter extends LoggerAdapter {
let limit = options.size || 10;
let order = options.order || 'desc';
let level = options.level || 'info';
let roundedUntil = _getNearestDay(until);
let roundedFrom = _getNearestDay(from);
var options = {
const queryOptions = {
from,
until,
limit,
order
};
return new Promise((resolve, reject) => {
logger.query(options, (err, res) => {
return new Promise((resolve, reject) => {
logger.query(queryOptions, (err, res) => {
if (err) {
callback(err);
return reject(err);

View File

@@ -1,3 +1,4 @@
/*eslint no-unused-vars: "off"*/
// Push Adapter
//
// Allows you to change the push notification mechanism.

View File

@@ -84,7 +84,7 @@ export default class MongoCollection {
_ensureSparseUniqueIndexInBackground(indexRequest) {
return new Promise((resolve, reject) => {
this._mongoCollection.ensureIndex(indexRequest, { unique: true, background: true, sparse: true }, (error, indexName) => {
this._mongoCollection.ensureIndex(indexRequest, { unique: true, background: true, sparse: true }, (error) => {
if (error) {
reject(error);
} else {

View File

@@ -1,4 +1,5 @@
import MongoCollection from './MongoCollection';
import Parse from 'parse/node';
function mongoFieldToParseSchemaField(type) {
if (type[0] === '*') {
@@ -14,16 +15,16 @@ function mongoFieldToParseSchemaField(type) {
};
}
switch (type) {
case 'number': return {type: 'Number'};
case 'string': return {type: 'String'};
case 'boolean': return {type: 'Boolean'};
case 'date': return {type: 'Date'};
case 'map':
case 'object': return {type: 'Object'};
case 'array': return {type: 'Array'};
case 'geopoint': return {type: 'GeoPoint'};
case 'file': return {type: 'File'};
case 'bytes': return {type: 'Bytes'};
case 'number': return {type: 'Number'};
case 'string': return {type: 'String'};
case 'boolean': return {type: 'Boolean'};
case 'date': return {type: 'Date'};
case 'map':
case 'object': return {type: 'Object'};
case 'array': return {type: 'Array'};
case 'geopoint': return {type: 'GeoPoint'};
case 'file': return {type: 'File'};
case 'bytes': return {type: 'Bytes'};
}
}
@@ -87,16 +88,16 @@ function _mongoSchemaQueryFromNameQuery(name: string, query) {
// Does no validation. That is expected to be done in Parse Server.
function parseFieldTypeToMongoFieldType({ type, targetClass }) {
switch (type) {
case 'Pointer': return `*${targetClass}`;
case 'Relation': return `relation<${targetClass}>`;
case 'Number': return 'number';
case 'String': return 'string';
case 'Boolean': return 'boolean';
case 'Date': return 'date';
case 'Object': return 'object';
case 'Array': return 'array';
case 'GeoPoint': return 'geopoint';
case 'File': return 'file';
case 'Pointer': return `*${targetClass}`;
case 'Relation': return `relation<${targetClass}>`;
case 'Number': return 'number';
case 'String': return 'string';
case 'Boolean': return 'boolean';
case 'Date': return 'date';
case 'Object': return 'object';
case 'Array': return 'array';
case 'GeoPoint': return 'geopoint';
case 'File': return 'file';
}
}

View File

@@ -11,7 +11,9 @@ import {
transformWhere,
transformUpdate,
} from './MongoTransform';
import Parse from 'parse/node';
import _ from 'lodash';
import defaults from '../../../defaults';
let mongodb = require('mongodb');
let MongoClient = mongodb.MongoClient;
@@ -63,7 +65,7 @@ const mongoSchemaFromFieldsAndClassNameAndCLP = (fields, className, classLevelPe
}
if (typeof classLevelPermissions !== 'undefined') {
mongoObject._metadata = mongoObject._metadata || {};
mongoObject._metadata = mongoObject._metadata || {};
if (!classLevelPermissions) {
delete mongoObject._metadata.class_permissions;
} else {
@@ -111,14 +113,14 @@ export class MongoStorageAdapter {
delete this.connectionPromise;
return;
}
database.on('error', (error) => {
database.on('error', () => {
delete this.connectionPromise;
});
database.on('close', (error) => {
database.on('close', () => {
delete this.connectionPromise;
});
this.database = database;
}).catch((err) => {
}).catch((err) => {
delete this.connectionPromise;
return Promise.reject(err);
});
@@ -288,7 +290,7 @@ export class MongoStorageAdapter {
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Object not found.');
}
return Promise.resolve();
}, error => {
}, () => {
throw new Parse.Error(Parse.Error.INTERNAL_SERVER_ERROR, 'Database adapter error');
});
}
@@ -327,7 +329,7 @@ export class MongoStorageAdapter {
schema = convertParseSchemaToMongoSchema(schema);
let mongoWhere = transformWhere(className, query, schema);
let mongoSort = _.mapKeys(sort, (value, fieldName) => transformKey(className, fieldName, schema));
let mongoKeys = _.reduce(keys, (memo, key) => {
let mongoKeys = _.reduce(keys, (memo, key) => {
memo[transformKey(className, key, schema)] = 1;
return memo;
}, {});

View File

@@ -6,10 +6,10 @@ var Parse = require('parse/node').Parse;
const transformKey = (className, fieldName, schema) => {
// Check if the schema is known since it's a built-in field.
switch(fieldName) {
case 'objectId': return '_id';
case 'createdAt': return '_created_at';
case 'updatedAt': return '_updated_at';
case 'sessionToken': return '_session_token';
case 'objectId': return '_id';
case 'createdAt': return '_created_at';
case 'updatedAt': return '_updated_at';
case 'sessionToken': return '_session_token';
}
if (schema.fields[fieldName] && schema.fields[fieldName].__type == 'Pointer') {
@@ -197,7 +197,7 @@ function transformQueryKeyValue(className, key, value, schema) {
return {key: '$or', value: value.map(subQuery => transformWhere(className, subQuery, schema))};
case '$and':
return {key: '$and', value: value.map(subQuery => transformWhere(className, subQuery, schema))};
default:
default: {
// Other auth data
const authDataMatch = key.match(/^authData\.([a-zA-Z0-9_]+)\.id$/);
if (authDataMatch) {
@@ -206,6 +206,7 @@ function transformQueryKeyValue(className, key, value, schema) {
return {key: `_auth_data_${provider}.id`, value};
}
}
}
const expectedTypeIsArray =
schema &&
@@ -530,8 +531,8 @@ function transformConstraint(constraint, inArray) {
break;
case '$in':
case '$nin':
var arr = constraint[key];
case '$nin': {
let arr = constraint[key];
if (!(arr instanceof Array)) {
throw new Parse.Error(Parse.Error.INVALID_JSON, 'bad ' + key + ' value');
}
@@ -543,16 +544,16 @@ function transformConstraint(constraint, inArray) {
return result;
});
break;
case '$all':
var arr = constraint[key];
}
case '$all': {
let arr = constraint[key];
if (!(arr instanceof Array)) {
throw new Parse.Error(Parse.Error.INVALID_JSON,
'bad ' + key + ' value');
}
answer[key] = arr.map(transformInteriorAtom);
break;
}
case '$regex':
var s = constraint[key];
if (typeof s !== 'string') {
@@ -736,7 +737,7 @@ const mongoObjectToParseObject = (className, mongoObject, schema) => {
case 'symbol':
case 'function':
throw 'bad value in mongoObjectToParseObject';
case 'object':
case 'object': {
if (mongoObject === null) {
return null;
}
@@ -868,6 +869,7 @@ const mongoObjectToParseObject = (className, mongoObject, schema) => {
});
return { ...restObject, ...relationFields };
}
default:
throw 'unknown js type';
}

View File

@@ -1,4 +1,5 @@
import { createClient } from './PostgresClient';
import Parse from 'parse/node';
const PostgresRelationDoesNotExistError = '42P01';
const PostgresDuplicateRelationError = '42P07';
@@ -16,21 +17,21 @@ const debug = function(){
const parseTypeToPostgresType = type => {
switch (type.type) {
case 'String': return 'text';
case 'Date': return 'timestamp with time zone';
case 'Object': return 'jsonb';
case 'File': return 'text';
case 'Boolean': return 'boolean';
case 'Pointer': return 'char(10)';
case 'Number': return 'double precision';
case 'GeoPoint': return 'point';
case 'Array':
if (type.contents && type.contents.type === 'String') {
return 'text[]';
} else {
return 'jsonb';
}
default: throw `no type for ${JSON.stringify(type)} yet`;
case 'String': return 'text';
case 'Date': return 'timestamp with time zone';
case 'Object': return 'jsonb';
case 'File': return 'text';
case 'Boolean': return 'boolean';
case 'Pointer': return 'char(10)';
case 'Number': return 'double precision';
case 'GeoPoint': return 'point';
case 'Array':
if (type.contents && type.contents.type === 'String') {
return 'text[]';
} else {
return 'jsonb';
}
default: throw `no type for ${JSON.stringify(type)} yet`;
}
};
@@ -41,7 +42,7 @@ const ParseToPosgresComparator = {
'$lte': '<='
}
const toPostgresValue = value => {
const toPostgresValue = value => {
if (typeof value === 'object') {
if (value.__type === 'Date') {
return value.iso;
@@ -53,7 +54,7 @@ const toPostgresValue = value => {
return value;
}
const transformValue = value => {
const transformValue = value => {
if (value.__type === 'Pointer') {
return value.objectId;
}
@@ -79,7 +80,7 @@ const defaultCLPS = Object.freeze({
addField: {'*': true},
});
const toParseSchema = (schema) => {
const toParseSchema = (schema) => {
if (schema.className === '_User') {
delete schema.fields._hashed_password;
}
@@ -98,7 +99,7 @@ const toParseSchema = (schema) => {
};
}
const toPostgresSchema = (schema) => {
const toPostgresSchema = (schema) => {
if (!schema) {
return schema;
}
@@ -111,8 +112,8 @@ const toPostgresSchema = (schema) => {
return schema;
}
const handleDotFields = (object) => {
Object.keys(object).forEach(fieldName => {
const handleDotFields = (object) => {
Object.keys(object).forEach(fieldName => {
if (fieldName.indexOf('.') > -1) {
let components = fieldName.split('.');
let first = components.shift();
@@ -123,7 +124,9 @@ const handleDotFields = (object) => {
if (value && value.__op === 'Delete') {
value = undefined;
}
while(next = components.shift()) {
/* eslint-disable no-cond-assign */
while(next = components.shift()) {
/* eslint-enable no-cond-assign */
currentObj[next] = currentObj[next] || {};
if (components.length === 0) {
currentObj[next] = value;
@@ -151,7 +154,7 @@ const validateKeys = (object) => {
}
// Returns the list of join tables on a schema
const joinTablesForSchema = (schema) => {
const joinTablesForSchema = (schema) => {
let list = [];
if (schema) {
Object.keys(schema.fields).forEach((field) => {
@@ -185,11 +188,11 @@ const buildWhereClause = ({ schema, query, index }) => {
}
if (fieldName.indexOf('.') >= 0) {
let components = fieldName.split('.').map((cmpt, index) => {
let components = fieldName.split('.').map((cmpt, index) => {
if (index === 0) {
return `"${cmpt}"`;
}
return `'${cmpt}'`; 
return `'${cmpt}'`;
});
let name = components.slice(0, components.length-1).join('->');
name+='->>'+components[components.length-1];
@@ -209,7 +212,7 @@ const buildWhereClause = ({ schema, query, index }) => {
} else if (fieldName === '$or' || fieldName === '$and') {
let clauses = [];
let clauseValues = [];
fieldValue.forEach((subQuery, idx) =>  {
fieldValue.forEach((subQuery) => {
let clause = buildWhereClause({ schema, query: subQuery, index });
if (clause.pattern.length > 0) {
clauses.push(clause.pattern);
@@ -268,7 +271,7 @@ const buildWhereClause = ({ schema, query, index }) => {
}
index = index + 1 + inPatterns.length;
} else if (isInOrNin) {
var createConstraint = (baseArray, notIn) => {
var createConstraint = (baseArray, notIn) => {
if (baseArray.length > 0) {
let not = notIn ? ' NOT ' : '';
if (isArrayField) {
@@ -375,7 +378,7 @@ const buildWhereClause = ({ schema, query, index }) => {
index += 2;
}
Object.keys(ParseToPosgresComparator).forEach(cmp => {
Object.keys(ParseToPosgresComparator).forEach(cmp => {
if (fieldValue[cmp]) {
let pgComparator = ParseToPosgresComparator[cmp];
patterns.push(`$${index}:name ${pgComparator} $${index + 1}`);
@@ -416,10 +419,10 @@ export class PostgresStorageAdapter {
throw error;
}
});
};
}
classExists(name) {
return this._client.one(`SELECT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = $1)`, [name]).then((res) => {
return this._client.one(`SELECT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = $1)`, [name]).then((res) => {
return res.exists;
});
}
@@ -433,15 +436,15 @@ export class PostgresStorageAdapter {
createClass(className, schema) {
return this._client.tx(t => {
const q1 = this.createTable(className, schema, t);
const q2 = t.none('INSERT INTO "_SCHEMA" ("className", "schema", "isParseClass") VALUES ($<className>, $<schema>, true)', { className, schema });
const q1 = this.createTable(className, schema, t);
const q2 = t.none('INSERT INTO "_SCHEMA" ("className", "schema", "isParseClass") VALUES ($<className>, $<schema>, true)', { className, schema });
return t.batch([q1, q2]);
return t.batch([q1, q2]);
})
.then(() => {
return toParseSchema(schema)
})
.catch((err) => {
.catch((err) => {
if (Array.isArray(err.data) && err.data.length > 1 && err.data[0].result.code === PostgresTransactionAbortedError) {
err = err.data[1].result;
}
@@ -500,9 +503,9 @@ export class PostgresStorageAdapter {
} else {
throw error;
}
}).then(() => {
}).then(() => {
// Create the relation tables
return Promise.all(relations.map((fieldName) => {
return Promise.all(relations.map((fieldName) => {
return conn.none('CREATE TABLE IF NOT EXISTS $<joinTable:name> ("relatedId" varChar(120), "owningId" varChar(120), PRIMARY KEY("relatedId", "owningId") )', {joinTable: `_Join:${fieldName}:${className}`});
}));
});
@@ -551,11 +554,11 @@ export class PostgresStorageAdapter {
// Drops a collection. Resolves with true if it was a Parse Schema (eg. _User, Custom, etc.)
// and resolves with false if it wasn't (eg. a join table). Rejects if deletion was impossible.
deleteClass(className) {
return Promise.resolve().then(() => {
return Promise.resolve().then(() => {
let operations = [[`DROP TABLE IF EXISTS $1:name`, [className]],
[`DELETE FROM "_SCHEMA" WHERE "className"=$1`, [className]]];
return this._client.tx(t=>t.batch(operations.map(statement=>t.none(statement[0], statement[1]))));
}).then(() => {
}).then(() => {
// resolves with false when _Join table
return className.indexOf('_Join:') != 0;
});
@@ -567,7 +570,7 @@ export class PostgresStorageAdapter {
debug('deleteAllClasses');
return this._client.any('SELECT * FROM "_SCHEMA"')
.then(results => {
let joins = results.reduce((list, schema) => {
let joins = results.reduce((list, schema) => {
return list.concat(joinTablesForSchema(schema.schema));
}, []);
const classes = ['_SCHEMA','_PushStatus','_JobStatus','_Hooks','_GlobalConfig', ...results.map(result => result.className), ...joins];
@@ -579,7 +582,7 @@ export class PostgresStorageAdapter {
} else {
throw error;
}
}).then(() => {
}).then(() => {
debug(`deleteAllClasses done in ${new Date().getTime() - now}`);
});
}
@@ -600,8 +603,8 @@ export class PostgresStorageAdapter {
deleteFields(className, schema, fieldNames) {
debug('deleteFields', className, fieldNames);
return Promise.resolve()
.then(() => {
fieldNames = fieldNames.reduce((list, fieldName) => {
.then(() => {
fieldNames = fieldNames.reduce((list, fieldName) => {
let field = schema.fields[fieldName]
if (field.type !== 'Relation') {
list.push(fieldName);
@@ -611,11 +614,11 @@ export class PostgresStorageAdapter {
}, []);
let values = [className, ...fieldNames];
let columns = fieldNames.map((name, idx) => {
let columns = fieldNames.map((name, idx) => {
return `$${idx+2}:name`;
}).join(',');
let doBatch = (t) => {
let doBatch = (t) => {
let batch = [
t.none('UPDATE "_SCHEMA" SET "schema"=$<schema> WHERE "className"=$<className>', {schema, className})
];
@@ -624,7 +627,7 @@ export class PostgresStorageAdapter {
}
return batch;
}
return this._client.tx((t) => {
return this._client.tx((t) => {
return t.batch(doBatch(t));
});
});
@@ -658,7 +661,6 @@ export class PostgresStorageAdapter {
createObject(className, schema, object) {
debug('createObject', className, object);
let columnsArray = [];
let newFieldsArray = [];
let valuesArray = [];
schema = toPostgresSchema(schema);
let geoPoints = {};
@@ -705,39 +707,39 @@ export class PostgresStorageAdapter {
return;
}
switch (schema.fields[fieldName].type) {
case 'Date':
if (object[fieldName]) {
valuesArray.push(object[fieldName].iso);
} else {
valuesArray.push(null);
}
break;
case 'Pointer':
valuesArray.push(object[fieldName].objectId);
break;
case 'Array':
if (['_rperm', '_wperm'].indexOf(fieldName) >= 0) {
valuesArray.push(object[fieldName]);
} else {
valuesArray.push(JSON.stringify(object[fieldName]));
}
break;
case 'Object':
case 'String':
case 'Number':
case 'Boolean':
case 'Date':
if (object[fieldName]) {
valuesArray.push(object[fieldName].iso);
} else {
valuesArray.push(null);
}
break;
case 'Pointer':
valuesArray.push(object[fieldName].objectId);
break;
case 'Array':
if (['_rperm', '_wperm'].indexOf(fieldName) >= 0) {
valuesArray.push(object[fieldName]);
break;
case 'File':
valuesArray.push(object[fieldName].name);
break;
case 'GeoPoint':
} else {
valuesArray.push(JSON.stringify(object[fieldName]));
}
break;
case 'Object':
case 'String':
case 'Number':
case 'Boolean':
valuesArray.push(object[fieldName]);
break;
case 'File':
valuesArray.push(object[fieldName].name);
break;
case 'GeoPoint':
// pop the point and process later
geoPoints[fieldName] = object[fieldName];
columnsArray.pop();
break;
default:
throw `Type ${schema.fields[fieldName].type} not supported yet`;
geoPoints[fieldName] = object[fieldName];
columnsArray.pop();
break;
default:
throw `Type ${schema.fields[fieldName].type} not supported yet`;
}
});
@@ -752,7 +754,7 @@ export class PostgresStorageAdapter {
}
return `$${index + 2 + columnsArray.length}${termination}`;
});
let geoPointsInjects = Object.keys(geoPoints).map((key, idx) => {
let geoPointsInjects = Object.keys(geoPoints).map((key) => {
let value = geoPoints[key];
valuesArray.push(value.longitude, value.latitude);
let l = valuesArray.length + columnsArray.length;
@@ -802,13 +804,12 @@ export class PostgresStorageAdapter {
// Return value not currently well specified.
findOneAndUpdate(className, schema, query, update) {
debug('findOneAndUpdate', className, query, update);
return this.updateObjectsByQuery(className, schema, query, update).then((val) => val[0]);
return this.updateObjectsByQuery(className, schema, query, update).then((val) => val[0]);
}
// Apply the update to all objects that match the given Parse Query.
updateObjectsByQuery(className, schema, query, update) {
debug('updateObjectsByQuery', className, query, update);
let conditionPatterns = [];
let updatePatterns = [];
let values = [className]
let index = 2;
@@ -838,8 +839,8 @@ export class PostgresStorageAdapter {
} else if (fieldName == 'authData') {
// This recursively sets the json_object
// Only 1 level deep
let generate = (jsonb, key, value) => {
return `json_object_set_key(COALESCE(${jsonb}, '{}'::jsonb), ${key}, ${value})::jsonb`; 
let generate = (jsonb, key, value) => {
return `json_object_set_key(COALESCE(${jsonb}, '{}'::jsonb), ${key}, ${value})::jsonb`;
}
let lastKey = `$${index}:name`;
let fieldNameIndex = index;
@@ -930,10 +931,10 @@ export class PostgresStorageAdapter {
return p + ` - '$${index + 1 + i}:value'`;
}, '');
updatePatterns.push(`$${index}:name = ( COALESCE($${index}:name, '{}'::jsonb) ${deletePatterns} || $${index + 1 + keysToDelete.length}::jsonb )`);
updatePatterns.push(`$${index}:name = ( COALESCE($${index}:name, '{}'::jsonb) ${deletePatterns} || $${index + 1 + keysToDelete.length}::jsonb )`);
values.push(fieldName, ...keysToDelete, JSON.stringify(fieldValue));
index += 2 + keysToDelete.length;
values.push(fieldName, ...keysToDelete, JSON.stringify(fieldValue));
index += 2 + keysToDelete.length;
} else if (Array.isArray(fieldValue)
&& schema.fields[fieldName]
&& schema.fields[fieldName].type === 'Array') {
@@ -970,7 +971,7 @@ export class PostgresStorageAdapter {
upsertOneObject(className, schema, query, update) {
debug('upsertOneObject', {className, query, update});
let createValue = Object.assign({}, query, update);
return this.createObject(className, schema, createValue).catch((err) => {
return this.createObject(className, schema, createValue).catch((err) => {
// ignore duplicate value errors as it's upsert
if (err.code === Parse.Error.DUPLICATE_VALUE) {
return this.findOneAndUpdate(className, schema, query, update);
@@ -999,26 +1000,26 @@ export class PostgresStorageAdapter {
let sortPattern = '';
if (sort) {
let sorting = Object.keys(sort).map((key) => {
let sorting = Object.keys(sort).map((key) => {
// Using $idx pattern gives: non-integer constant in ORDER BY
if (sort[key] === 1) {
return `"${key}" ASC`;
}
return `"${key}" DESC`;
}).join(',');
sortPattern = sort !== undefined && Object.keys(sort).length > 0 ? `ORDER BY ${sorting}` : '';
sortPattern = sort !== undefined && Object.keys(sort).length > 0 ? `ORDER BY ${sorting}` : '';
}
if (where.sorts && Object.keys(where.sorts).length > 0) {
if (where.sorts && Object.keys(where.sorts).length > 0) {
sortPattern = `ORDER BY ${where.sorts.join(',')}`;
}
let columns = '*';
if (keys) {
// Exclude empty keys
keys = keys.filter((key) => {
keys = keys.filter((key) => {
return key.length > 0;
});
columns = keys.map((key, index) => {
columns = keys.map((key, index) => {
return `$${index+values.length+1}:name`;
}).join(',');
values = values.concat(keys);
@@ -1027,7 +1028,7 @@ export class PostgresStorageAdapter {
const qs = `SELECT ${columns} FROM $1:name ${wherePattern} ${sortPattern} ${limitPattern} ${skipPattern}`;
debug(qs, values);
return this._client.any(qs, values)
.catch((err) => {
.catch((err) => {
// Query on non existing table, don't crash
if (err.code === PostgresRelationDoesNotExistError) {
return [];
@@ -1127,7 +1128,7 @@ export class PostgresStorageAdapter {
const wherePattern = where.pattern.length > 0 ? `WHERE ${where.pattern}` : '';
const qs = `SELECT count(*) FROM $1:name ${wherePattern}`;
return this._client.one(qs, values, a => +a.count).catch((err) => {
return this._client.one(qs, values, a => +a.count).catch((err) => {
if (err.code === PostgresRelationDoesNotExistError) {
return 0;
}
@@ -1138,7 +1139,7 @@ export class PostgresStorageAdapter {
performInitialization({ VolatileClassesSchemas }) {
let now = new Date().getTime();
debug('performInitialization');
let promises = VolatileClassesSchemas.map((schema) => {
let promises = VolatileClassesSchemas.map((schema) => {
return this.createTable(schema.className, schema).catch((err) =>{
if (err.code === PostgresDuplicateRelationError || err.code === Parse.Error.INVALID_CLASS_NAME) {
return Promise.resolve();
@@ -1146,36 +1147,34 @@ export class PostgresStorageAdapter {
throw err;
});
});
/* eslint-disable no-console */
promises = promises.concat([
this._client.any(json_object_set_key).catch((err) => {
console.error(err);
}),
this._client.any(array_add).catch((err) => {
console.error(err);
}),
this._client.any(array_add_unique).catch((err) => {
console.error(err);
}),
this._client.any(array_remove).catch((err) => {
console.error(err);
}),
this._client.any(array_contains_all).catch((err) => {
console.error(err);
}),
this._client.any(array_contains).catch((err) => {
console.error(err);
})
]);
return Promise.all(promises).then(() => {
this._client.any(json_object_set_key).catch((err) => {
console.error(err);
}),
this._client.any(array_add).catch((err) => {
console.error(err);
}),
this._client.any(array_add_unique).catch((err) => {
console.error(err);
}),
this._client.any(array_remove).catch((err) => {
console.error(err);
}),
this._client.any(array_contains_all).catch((err) => {
console.error(err);
}),
this._client.any(array_contains).catch((err) => {
console.error(err);
})
]);
/* eslint-enable no-console */
return Promise.all(promises).then(() => {
debug(`initialzationDone in ${new Date().getTime() - now}`);
}, (err) => {});
}, () => {});
}
}
function notImplemented() {
return Promise.reject(new Error('Not implemented yet.'));
}
function removeWhiteSpace(regex) {
if (!regex.endsWith('\n')){
regex += '\n';

View File

@@ -1,4 +1,3 @@
var deepcopy = require('deepcopy');
var Parse = require('parse/node').Parse;
var RestQuery = require('./RestQuery');
@@ -80,13 +79,13 @@ var getAuthForSessionToken = function({ config, sessionToken, installationId } =
var getAuthForLegacySessionToken = function({config, sessionToken, installationId } = {}) {
var restOptions = {
limit: 1
limit: 1
};
var query = new RestQuery(config, master(config), '_User', { sessionToken: sessionToken}, restOptions);
return query.execute().then((response) => {
return query.execute().then((response) => {
var results = response.results;
if (results.length !== 1) {
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'invalid legacy session token');
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'invalid legacy session token');
}
let obj = results[0];
obj.className = '_User';
@@ -163,7 +162,7 @@ Auth.prototype._loadRoles = function() {
// Given a list of roleIds, find all the parent roles, returns a promise with all names
Auth.prototype._getAllRolesNamesForRoleIds = function(roleIDs, names = [], queriedRoles = {}) {
let ins = roleIDs.filter((roleID) => {
let ins = roleIDs.filter((roleID) => {
return queriedRoles[roleID] !== true;
}).map((roleID) => {
// mark as queried
@@ -194,7 +193,7 @@ Auth.prototype._getAllRolesNamesForRoleIds = function(roleIDs, names = [], queri
return Promise.resolve(names);
}
// Map the results with all Ids and names
let resultMap = results.reduce((memo, role) => {
let resultMap = results.reduce((memo, role) => {
memo.names.push(role.name);
memo.ids.push(role.objectId);
return memo;

View File

@@ -50,15 +50,15 @@ export class AdaptableController {
// Makes sure the prototype matches
let mismatches = Object.getOwnPropertyNames(Type.prototype).reduce( (obj, key) => {
const adapterType = typeof adapter[key];
const expectedType = typeof Type.prototype[key];
if (adapterType !== expectedType) {
obj[key] = {
expected: expectedType,
actual: adapterType
}
}
return obj;
const adapterType = typeof adapter[key];
const expectedType = typeof Type.prototype[key];
if (adapterType !== expectedType) {
obj[key] = {
expected: expectedType,
actual: adapterType
}
}
return obj;
}, {});
if (Object.keys(mismatches).length > 0) {

View File

@@ -7,7 +7,7 @@ export class AnalyticsController extends AdaptableController {
return this.adapter.appOpened(req.body, req);
}).then((response) => {
return { response: response || {} };
}).catch((err) => {
}).catch(() => {
return { response: {} };
});
}
@@ -17,7 +17,7 @@ export class AnalyticsController extends AdaptableController {
return this.adapter.trackEvent(req.params.eventName, req.body, req);
}).then((response) => {
return { response: response || {} };
}).catch((err) => {
}).catch(() => {
return { response: {} };
});
}

View File

@@ -3,7 +3,6 @@
import { Parse } from 'parse/node';
import _ from 'lodash';
import mongdb from 'mongodb';
import intersect from 'intersect';
import deepcopy from 'deepcopy';
import logger from '../logger';
@@ -45,7 +44,7 @@ const transformObjectACL = ({ ACL, ...result }) => {
const specialQuerykeys = ['$and', '$or', '_rperm', '_wperm', '_perishable_token', '_email_verify_token', '_email_verify_token_expires_at', '_account_lockout_expires_at', '_failed_login_count'];
const isSpecialQueryKey = key => {
const isSpecialQueryKey = key => {
return specialQuerykeys.indexOf(key) >= 0;
}
@@ -148,7 +147,7 @@ DatabaseController.prototype.validateObject = function(className, object, query,
return Promise.resolve();
}
return this.canAddField(schema, className, object, aclGroup);
}).then(() => {
}).then(() => {
return schema.validateObject(className, object, query);
});
};
@@ -193,7 +192,7 @@ const filterSensitiveData = (isMaster, aclGroup, className, object) => {
// write permissions.
const specialKeysForUpdate = ['_hashed_password', '_perishable_token', '_email_verify_token', '_email_verify_token_expires_at', '_account_lockout_expires_at', '_failed_login_count', '_perishable_token_expires_at', '_password_changed_at'];
const isSpecialUpdateKey = key => {
const isSpecialUpdateKey = key => {
return specialKeysForUpdate.indexOf(key) >= 0;
}
@@ -208,7 +207,6 @@ DatabaseController.prototype.update = function(className, query, update, {
var isMaster = acl === undefined;
var aclGroup = acl || [];
var mongoUpdate;
return this.loadSchema()
.then(schemaController => {
return (isMaster ? Promise.resolve() : schemaController.validatePermission(className, aclGroup, 'update'))
@@ -280,7 +278,7 @@ function sanitizeDatabaseResult(originalObject, result) {
let keyUpdate = originalObject[key];
// determine if that was an op
if (keyUpdate && typeof keyUpdate === 'object' && keyUpdate.__op
&& ['Add', 'AddUnique', 'Remove', 'Increment'].indexOf(keyUpdate.__op) > -1) {
&& ['Add', 'AddUnique', 'Remove', 'Increment'].indexOf(keyUpdate.__op) > -1) {
// only valid ops that produce an actionable result
response[key] = result[key];
}
@@ -302,7 +300,7 @@ DatabaseController.prototype.handleRelationUpdates = function(className, objectI
return;
}
if (op.__op == 'AddRelation') {
for (var object of op.objects) {
for (let object of op.objects) {
pending.push(this.addRelation(key, className,
objectId,
object.objectId));
@@ -311,7 +309,7 @@ DatabaseController.prototype.handleRelationUpdates = function(className, objectI
}
if (op.__op == 'RemoveRelation') {
for (var object of op.objects) {
for (let object of op.objects) {
pending.push(this.removeRelation(key, className,
objectId,
object.objectId));
@@ -326,10 +324,10 @@ DatabaseController.prototype.handleRelationUpdates = function(className, objectI
}
};
for (var key in update) {
for (let key in update) {
process(update[key], key);
}
for (var key of deleteMe) {
for (let key of deleteMe) {
delete update[key];
}
return Promise.all(pending);
@@ -415,35 +413,35 @@ const flattenUpdateOperatorsForCreate = object => {
for (let key in object) {
if (object[key] && object[key].__op) {
switch (object[key].__op) {
case 'Increment':
if (typeof object[key].amount !== 'number') {
throw new Parse.Error(Parse.Error.INVALID_JSON, 'objects to add must be an array');
}
object[key] = object[key].amount;
break;
case 'Add':
if (!(object[key].objects instanceof Array)) {
throw new Parse.Error(Parse.Error.INVALID_JSON, 'objects to add must be an array');
}
object[key] = object[key].objects;
break;
case 'AddUnique':
if (!(object[key].objects instanceof Array)) {
throw new Parse.Error(Parse.Error.INVALID_JSON, 'objects to add must be an array');
}
object[key] = object[key].objects;
break;
case 'Remove':
if (!(object[key].objects instanceof Array)) {
throw new Parse.Error(Parse.Error.INVALID_JSON, 'objects to add must be an array');
}
object[key] = []
break;
case 'Delete':
delete object[key];
break;
default:
throw new Parse.Error(Parse.Error.COMMAND_UNAVAILABLE, `The ${object[key].__op} operator is not supported yet.`);
case 'Increment':
if (typeof object[key].amount !== 'number') {
throw new Parse.Error(Parse.Error.INVALID_JSON, 'objects to add must be an array');
}
object[key] = object[key].amount;
break;
case 'Add':
if (!(object[key].objects instanceof Array)) {
throw new Parse.Error(Parse.Error.INVALID_JSON, 'objects to add must be an array');
}
object[key] = object[key].objects;
break;
case 'AddUnique':
if (!(object[key].objects instanceof Array)) {
throw new Parse.Error(Parse.Error.INVALID_JSON, 'objects to add must be an array');
}
object[key] = object[key].objects;
break;
case 'Remove':
if (!(object[key].objects instanceof Array)) {
throw new Parse.Error(Parse.Error.INVALID_JSON, 'objects to add must be an array');
}
object[key] = []
break;
case 'Delete':
delete object[key];
break;
default:
throw new Parse.Error(Parse.Error.COMMAND_UNAVAILABLE, `The ${object[key].__op} operator is not supported yet.`);
}
}
}
@@ -451,7 +449,7 @@ const flattenUpdateOperatorsForCreate = object => {
const transformAuthData = (className, object, schema) => {
if (object.authData && className === '_User') {
Object.keys(object.authData).forEach(provider => {
Object.keys(object.authData).forEach(provider => {
const providerData = object.authData[provider];
const fieldName = `_auth_data_${provider}`;
if (providerData == null) {
@@ -504,7 +502,7 @@ DatabaseController.prototype.canAddField = function(schema, className, object, a
}
let fields = Object.keys(object);
let schemaFields = Object.keys(classSchema);
let newKeys = fields.filter((field) => {
let newKeys = fields.filter((field) => {
return schemaFields.indexOf(field) < 0;
})
if (newKeys.length > 0) {
@@ -523,20 +521,6 @@ DatabaseController.prototype.deleteEverything = function() {
]);
};
// Finds the keys in a query. Returns a Set. REST format only
function keysForQuery(query) {
var sublist = query['$and'] || query['$or'];
if (sublist) {
let answer = sublist.reduce((memo, subquery) => {
return memo.concat(keysForQuery(subquery));
}, []);
return new Set(answer);
}
return new Set(Object.keys(query));
}
// Returns a promise for a list of related ids given an owning id.
// className here is the owning className.
DatabaseController.prototype.relatedIds = function(className, key, owningId) {
@@ -561,10 +545,10 @@ DatabaseController.prototype.reduceInRelation = function(className, query, schem
if (query['$or']) {
let ors = query['$or'];
return Promise.all(ors.map((aQuery, index) => {
return this.reduceInRelation(className, aQuery, schema).then((aQuery) => {
return this.reduceInRelation(className, aQuery, schema).then((aQuery) => {
query['$or'][index] = aQuery;
});
})).then(() => {
})).then(() => {
return Promise.resolve(query);
});
}
@@ -575,7 +559,6 @@ DatabaseController.prototype.reduceInRelation = function(className, query, schem
if (!t || t.type !== 'Relation') {
return Promise.resolve(query);
}
let relatedClassName = t.targetClass;
// Build the list of queries
let queries = Object.keys(query[key]).map((constraintKey) => {
let relatedIds;
@@ -625,7 +608,7 @@ DatabaseController.prototype.reduceInRelation = function(className, query, schem
return Promise.resolve();
})
return Promise.all(promises).then(() => {
return Promise.all(promises).then(() => {
return Promise.resolve(query);
})
};
@@ -839,7 +822,7 @@ DatabaseController.prototype.deleteSchema = function(className) {
})
.then(schema => {
return this.collectionExists(className)
.then(exist => this.adapter.count(className, { fields: {} }))
.then(() => this.adapter.count(className, { fields: {} }))
.then(count => {
if (count > 0) {
throw new Parse.Error(255, `Class ${className} is not empty, contains ${count} objects, cannot drop schema.`);
@@ -866,10 +849,10 @@ DatabaseController.prototype.addPointerPermissions = function(schema, className,
let perms = schema.perms[className];
let field = ['get', 'find'].indexOf(operation) > -1 ? 'readUserFields' : 'writeUserFields';
let userACL = aclGroup.filter((acl) => {
return acl.indexOf('role:') != 0 && acl != '*';
return acl.indexOf('role:') != 0 && acl != '*';
});
// the ACL should have exactly 1 user
if (perms && perms[field] && perms[field].length > 0) {
if (perms && perms[field] && perms[field].length > 0) {
// No user set return undefined
// If the length is > 1, that means we didn't dedup users correctly
if (userACL.length != 1) {
@@ -877,20 +860,19 @@ DatabaseController.prototype.addPointerPermissions = function(schema, className,
}
let userId = userACL[0];
let userPointer = {
"__type": "Pointer",
"className": "_User",
"objectId": userId
};
"__type": "Pointer",
"className": "_User",
"objectId": userId
};
let constraints = {};
let permFields = perms[field];
let ors = permFields.map((key) => {
let ors = permFields.map((key) => {
let q = {
[key]: userPointer
};
return {'$and': [q, query]};
});
if (ors.length > 1) {
if (ors.length > 1) {
return {'$or': ors};
}
return ors[0];

View File

@@ -1,5 +1,4 @@
// FilesController.js
import { Parse } from 'parse/node';
import { randomHexString } from '../cryptoUtils';
import AdaptableController from './AdaptableController';
import { FilesAdapter } from '../Adapters/Files/FilesAdapter';
@@ -85,7 +84,7 @@ export class FilesController extends AdaptableController {
getFileStream(config, filename) {
return this.adapter.getFileStream(filename);
}
}
}
export default FilesController;

View File

@@ -51,8 +51,7 @@ export class HooksController {
return this._removeHooks({ className: className, triggerName: triggerName });
}
_getHooks(query = {}, limit) {
let options = limit ? { limit: limit } : undefined;
_getHooks(query = {}) {
return this.database.find(DefaultHooksCollectionName, query).then((results) => {
return results.map((result) => {
delete result.objectId;
@@ -113,7 +112,7 @@ export class HooksController {
}
return this.addHook(hook);
};
}
createHook(aHook) {
if (aHook.functionName) {
@@ -134,7 +133,7 @@ export class HooksController {
}
throw new Parse.Error(143, "invalid hook declaration");
};
}
updateHook(aHook) {
if (aHook.functionName) {
@@ -153,7 +152,7 @@ export class HooksController {
});
}
throw new Parse.Error(143, "invalid hook declaration");
};
}
}
function wrapToHTTPRequest(hook, key) {
@@ -170,7 +169,7 @@ function wrapToHTTPRequest(hook, key) {
jsonBody.original = req.original.toJSON();
jsonBody.original.className = req.original.className;
}
let jsonRequest = {
let jsonRequest: any = {
headers: {
'Content-Type': 'application/json'
},

View File

@@ -5,7 +5,6 @@ export class LiveQueryController {
liveQueryPublisher: any;
constructor(config: any) {
let classNames;
// If config is empty, we just assume no classs needs to be registered as LiveQuery
if (!config || !config.classNames) {
this.classNames = new Set();

View File

@@ -1,5 +1,4 @@
import { Parse } from 'parse/node';
import PromiseRouter from '../PromiseRouter';
import AdaptableController from './AdaptableController';
import { LoggerAdapter } from '../Adapters/Logger/LoggerAdapter';
import url from 'url';

View File

@@ -1,5 +1,4 @@
import { Parse } from 'parse/node';
import PromiseRouter from '../PromiseRouter';
import rest from '../rest';
import AdaptableController from './AdaptableController';
import { PushAdapter } from '../Adapters/Push/PushAdapter';
@@ -9,7 +8,6 @@ import RestWrite from '../RestWrite';
import { master } from '../Auth';
import { pushStatusHandler } from '../StatusHandler';
const FEATURE_NAME = 'push';
const UNSUPPORTED_BADGE_KEY = "unsupported";
export class PushController extends AdaptableController {
@@ -24,7 +22,7 @@ export class PushController extends AdaptableController {
var deviceTypes = [];
if (typeof deviceTypeField === 'string') {
deviceTypes.push(deviceTypeField);
} else if (typeof deviceTypeField['$in'] === 'array') {
} else if (Array.isArray(deviceTypeField['$in'])) {
deviceTypes.concat(deviceTypeField['$in']);
}
for (var i = 0; i < deviceTypes.length; i++) {
@@ -98,13 +96,13 @@ export class PushController extends AdaptableController {
}).then((results) => {
return pushStatus.complete(results);
}).catch((err) => {
return pushStatus.fail(err).then(() => {
return pushStatus.fail(err).then(() => {
throw err;
});
});
}
sendToAdapter(body, installations, pushStatus, config) {
sendToAdapter(body, installations, pushStatus) {
if (body.data && body.data.badge && typeof body.data.badge == 'string' && body.data.badge.toLowerCase() == "increment") {
// Collect the badges to reduce the # of calls
let badgeInstallationsMap = installations.reduce((map, installation) => {

View File

@@ -21,7 +21,7 @@ export default class SchemaCache {
}
put(key, value) {
return this.cache.get(this.prefix+ALL_KEYS).then((allKeys) => {
return this.cache.get(this.prefix+ALL_KEYS).then((allKeys) => {
allKeys = allKeys || {};
allKeys[key] = true;
return Promise.all([this.cache.put(this.prefix+ALL_KEYS, allKeys, this.ttl), this.cache.put(key, value, this.ttl)]);
@@ -72,8 +72,7 @@ export default class SchemaCache {
clear() {
// That clears all caches...
let promise = Promise.resolve();
return this.cache.get(this.prefix+ALL_KEYS).then((allKeys) => {
return this.cache.get(this.prefix+ALL_KEYS).then((allKeys) => {
if (!allKeys) {
return;
}

View File

@@ -15,7 +15,6 @@
// TODO: hide all schema logic inside the database adapter.
const Parse = require('parse/node').Parse;
import _ from 'lodash';
const defaultColumns = Object.freeze({
// Contain the default columns for every parse object type (except _Join collection)
@@ -152,7 +151,7 @@ function validateCLP(perms, fields) {
} else {
perms[operation].forEach((key) => {
if (!fields[key] || fields[key].type != 'Pointer' || fields[key].targetClass != '_User') {
throw new Parse.Error(Parse.Error.INVALID_JSON, `'${key}' is not a valid column for class level pointer permissions ${operation}`);
throw new Parse.Error(Parse.Error.INVALID_JSON, `'${key}' is not a valid column for class level pointer permissions ${operation}`);
}
});
}
@@ -222,19 +221,19 @@ const fieldTypeIsInvalid = ({ type, targetClass }) => {
if (!targetClass) {
return new Parse.Error(135, `type ${type} needs a class name`);
} else if (typeof targetClass !== 'string') {
return invalidJsonError;
return invalidJsonError;
} else if (!classNameIsValid(targetClass)) {
return new Parse.Error(Parse.Error.INVALID_CLASS_NAME, invalidClassNameMessage(targetClass));
} else {
} else {
return undefined;
}
}
if (typeof type !== 'string') {
}
}
if (typeof type !== 'string') {
return invalidJsonError;
}
}
if (validNonRelationOrPointerTypes.indexOf(type) < 0) {
return new Parse.Error(Parse.Error.INCORRECT_TYPE, `invalid field type: ${type}`);
}
}
return undefined;
}
@@ -280,14 +279,14 @@ const injectDefaultSchema = ({className, fields, classLevelPermissions}) => ({
const _HooksSchema = {className: "_Hooks", fields: defaultColumns._Hooks};
const _GlobalConfigSchema = { className: "_GlobalConfig", fields: defaultColumns._GlobalConfig }
const _PushStatusSchema = convertSchemaToAdapterSchema(injectDefaultSchema({
className: "_PushStatus",
fields: {},
classLevelPermissions: {}
className: "_PushStatus",
fields: {},
classLevelPermissions: {}
}));
const _JobStatusSchema = convertSchemaToAdapterSchema(injectDefaultSchema({
className: "_JobStatus",
fields: {},
classLevelPermissions: {}
className: "_JobStatus",
fields: {},
classLevelPermissions: {}
}));
const VolatileClassesSchemas = [_HooksSchema, _JobStatusSchema, _PushStatusSchema, _GlobalConfigSchema];
@@ -325,7 +324,7 @@ export default class SchemaController {
reloadData(options = {clearCache: false}) {
let promise = Promise.resolve();
if (options.clearCache) {
promise = promise.then(() => {
promise = promise.then(() => {
return this._cache.clear();
});
}
@@ -334,7 +333,7 @@ export default class SchemaController {
}
this.data = {};
this.perms = {};
this.reloadDataPromise = promise.then(() => {
this.reloadDataPromise = promise.then(() => {
return this.getAllClasses(options);
})
.then(allSchemas => {
@@ -352,7 +351,7 @@ export default class SchemaController {
});
});
delete this.reloadDataPromise;
}, (err) => {
}, (err) => {
delete this.reloadDataPromise;
throw err;
});
@@ -364,16 +363,16 @@ export default class SchemaController {
if (options.clearCache) {
promise = this._cache.clear();
}
return promise.then(() => {
return this._cache.getAllClasses()
}).then((allClasses) => {
return promise.then(() => {
return this._cache.getAllClasses()
}).then((allClasses) => {
if (allClasses && allClasses.length && !options.clearCache) {
return Promise.resolve(allClasses);
}
return this._dbAdapter.getAllClasses()
.then(allSchemas => allSchemas.map(injectDefaultSchema))
.then(allSchemas => {
return this._cache.setAllClasses(allSchemas).then(() => {
return this._cache.setAllClasses(allSchemas).then(() => {
return allSchemas;
});
})
@@ -385,18 +384,18 @@ export default class SchemaController {
if (options.clearCache) {
promise = this._cache.clear();
}
return promise.then(() => {
return promise.then(() => {
if (allowVolatileClasses && volatileClasses.indexOf(className) > -1) {
return Promise.resolve(this.data[className]);
}
return this._cache.getOneSchema(className).then((cached) => {
return this._cache.getOneSchema(className).then((cached) => {
if (cached && !options.clearCache) {
return Promise.resolve(cached);
}
return this._dbAdapter.getClass(className)
.then(injectDefaultSchema)
.then((result) => {
return this._cache.setOneSchema(className, result).then(() => {
.then((result) => {
return this._cache.setOneSchema(className, result).then(() => {
return result;
})
});
@@ -419,9 +418,9 @@ export default class SchemaController {
return this._dbAdapter.createClass(className, convertSchemaToAdapterSchema({ fields, classLevelPermissions, className }))
.then(convertAdapterSchemaToParseSchema)
.then((res) => {
return this._cache.clear().then(() => {
return Promise.resolve(res);
.then((res) => {
return this._cache.clear().then(() => {
return Promise.resolve(res);
});
})
.catch(error => {
@@ -504,7 +503,7 @@ export default class SchemaController {
return this.addClassIfNotExists(className)
// The schema update succeeded. Reload the schema
.then(() => this.reloadData({ clearCache: true }))
.catch(error => {
.catch(() => {
// The schema update failed. This can be okay - it might
// have failed because there's a race condition and a different
// client is making the exact same schema update that we want.
@@ -519,7 +518,7 @@ export default class SchemaController {
throw new Parse.Error(Parse.Error.INVALID_JSON, `Failed to add ${className}`);
}
})
.catch(error => {
.catch(() => {
// The schema still doesn't validate. Give up
throw new Parse.Error(Parse.Error.INVALID_JSON, 'schema class name does not revalidate');
});
@@ -586,7 +585,7 @@ export default class SchemaController {
// object if the provided className-fieldName-type tuple is valid.
// The className must already be validated.
// If 'freeze' is true, refuse to update the schema for this field.
enforceFieldExists(className, fieldName, type, freeze) {
enforceFieldExists(className, fieldName, type) {
if (fieldName.indexOf(".") > 0) {
// subdocument key (x.y) => ok if x is of type 'object'
fieldName = fieldName.split(".")[ 0 ];
@@ -620,14 +619,14 @@ export default class SchemaController {
return this._dbAdapter.addFieldIfNotExists(className, fieldName, type).then(() => {
// The update succeeded. Reload the schema
return this.reloadData({ clearCache: true });
}, error => {
}, () => {
//TODO: introspect the error and only reload if the error is one for which is makes sense to reload
// The update failed. This can be okay - it might have been a race
// condition where another client updated the schema in the same
// way that we wanted to. So, just reload the schema
return this.reloadData({ clearCache: true });
}).then(error => {
}).then(() => {
// Ensure that the schema now validates
if (!dbTypeMatchesObjectType(this.getExpectedType(className, fieldName), type)) {
throw new Parse.Error(Parse.Error.INVALID_JSON, `Could not add field ${fieldName}`);
@@ -676,7 +675,7 @@ export default class SchemaController {
.then(() => database.adapter.deleteClass(`_Join:${fieldName}:${className}`));
}
return database.adapter.deleteFields(className, schema, [fieldName]);
}).then(() => {
}).then(() => {
this._cache.clear();
});
}
@@ -772,7 +771,6 @@ export default class SchemaController {
return true;
}
let classPerms = this.perms[className];
let perms = classPerms[operation];
// No matching CLP, let's check the Pointer permissions
// And handle those later
let permissionField = ['get', 'find'].indexOf(operation) > -1 ? 'readUserFields' : 'writeUserFields';
@@ -785,11 +783,11 @@ export default class SchemaController {
// Process the readUserFields later
if (Array.isArray(classPerms[permissionField]) && classPerms[permissionField].length > 0) {
return Promise.resolve();
return Promise.resolve();
}
throw new Parse.Error(Parse.Error.OPERATION_FORBIDDEN,
`Permission denied for action ${operation} on class ${className}.`);
};
}
// Returns the expected type for a className+key combination
// or undefined if the schema is not set
@@ -799,7 +797,7 @@ export default class SchemaController {
return expectedType === 'map' ? 'Object' : expectedType;
}
return undefined;
};
}
// Checks if a given class is in the schema.
hasClass(className) {
@@ -859,23 +857,23 @@ function thenValidateRequiredColumns(schemaPromise, className, object, query) {
function getType(obj) {
let type = typeof obj;
switch(type) {
case 'boolean':
return 'Boolean';
case 'string':
return 'String';
case 'number':
return 'Number';
case 'map':
case 'object':
if (!obj) {
return undefined;
}
return getObjectType(obj);
case 'function':
case 'symbol':
case 'undefined':
default:
throw 'bad obj: ' + obj;
case 'boolean':
return 'Boolean';
case 'string':
return 'String';
case 'number':
return 'Number';
case 'map':
case 'object':
if (!obj) {
return undefined;
}
return getObjectType(obj);
case 'function':
case 'symbol':
case 'undefined':
default:
throw 'bad obj: ' + obj;
}
}
@@ -888,63 +886,68 @@ function getObjectType(obj) {
}
if (obj.__type){
switch(obj.__type) {
case 'Pointer' :
if(obj.className) {
return {
type: 'Pointer',
targetClass: obj.className
}
case 'Pointer' :
if(obj.className) {
return {
type: 'Pointer',
targetClass: obj.className
}
case 'Relation' :
if(obj.className) {
return {
type: 'Relation',
targetClass: obj.className
}
}
break;
case 'Relation' :
if(obj.className) {
return {
type: 'Relation',
targetClass: obj.className
}
case 'File' :
if(obj.name) {
return 'File';
}
case 'Date' :
if(obj.iso) {
return 'Date';
}
case 'GeoPoint' :
if(obj.latitude != null && obj.longitude != null) {
return 'GeoPoint';
}
case 'Bytes' :
if(obj.base64) {
return;
}
default:
throw new Parse.Error(Parse.Error.INCORRECT_TYPE, "This is not a valid "+obj.__type);
}
break;
case 'File' :
if(obj.name) {
return 'File';
}
break;
case 'Date' :
if(obj.iso) {
return 'Date';
}
break;
case 'GeoPoint' :
if(obj.latitude != null && obj.longitude != null) {
return 'GeoPoint';
}
break;
case 'Bytes' :
if(obj.base64) {
return;
}
break;
}
throw new Parse.Error(Parse.Error.INCORRECT_TYPE, "This is not a valid "+obj.__type);
}
if (obj['$ne']) {
return getObjectType(obj['$ne']);
}
if (obj.__op) {
switch(obj.__op) {
case 'Increment':
return 'Number';
case 'Delete':
return null;
case 'Add':
case 'AddUnique':
case 'Remove':
return 'Array';
case 'AddRelation':
case 'RemoveRelation':
return {
type: 'Relation',
targetClass: obj.objects[0].className
}
case 'Batch':
return getObjectType(obj.ops[0]);
default:
throw 'unexpected op: ' + obj.__op;
case 'Increment':
return 'Number';
case 'Delete':
return null;
case 'Add':
case 'AddUnique':
case 'Remove':
return 'Array';
case 'AddRelation':
case 'RemoveRelation':
return {
type: 'Relation',
targetClass: obj.objects[0].className
}
case 'Batch':
return getObjectType(obj.ops[0]);
default:
throw 'unexpected op: ' + obj.__op;
}
}
return 'Object';

View File

@@ -3,10 +3,9 @@ import { inflate } from '../triggers';
import AdaptableController from './AdaptableController';
import MailAdapter from '../Adapters/Email/MailAdapter';
import rest from '../rest';
import Parse from 'parse/node';
var RestWrite = require('../RestWrite');
var RestQuery = require('../RestQuery');
var hash = require('../password').hash;
var Auth = require('../Auth');
export class UserController extends AdaptableController {
@@ -118,7 +117,7 @@ export class UserController extends AdaptableController {
}
const token = encodeURIComponent(user._email_verify_token);
// We may need to fetch the user in case of update email
this.getUserIfNeeded(user).then((user) => {
this.getUserIfNeeded(user).then((user) => {
const username = encodeURIComponent(user.username);
let link = `${this.config.verifyEmailURL}?token=${token}&username=${username}`;
let options = {
@@ -148,7 +147,6 @@ export class UserController extends AdaptableController {
if (!this.adapter) {
throw "Trying to send a reset password but no adapter is set";
// TODO: No adapter?
return;
}
return this.setPasswordResetToken(email)
@@ -173,7 +171,7 @@ export class UserController extends AdaptableController {
});
}
updatePassword(username, token, password, config) {
updatePassword(username, token, password) {
return this.checkResetTokenValidity(username, token)
.then(user => updateUserPassword(user.objectId, password, this.config))
// clear reset password token
@@ -191,9 +189,9 @@ export class UserController extends AdaptableController {
defaultVerificationEmail({link, user, appName, }) {
let text = "Hi,\n\n" +
"You are being asked to confirm the e-mail address " + user.get("email") + " with " + appName + "\n\n" +
"" +
"Click here to confirm it:\n" + link;
"You are being asked to confirm the e-mail address " + user.get("email") + " with " + appName + "\n\n" +
"" +
"Click here to confirm it:\n" + link;
let to = user.get("email");
let subject = 'Please verify your e-mail for ' + appName;
return { text, to, subject };
@@ -215,6 +213,6 @@ function updateUserPassword(userId, password, config) {
return rest.update(config, Auth.master(config), '_User', userId, {
password: password
});
}
}
export default UserController;

View File

@@ -1,4 +1,3 @@
import Parse from 'parse/node';
import logger from '../logger';
import type { FlattenedObjectData } from './Subscription';
@@ -54,7 +53,7 @@ class Client {
this.subscriptionInfos.set(requestId, subscriptionInfo);
}
getSubscriptionInfo(requestId: numner): any {
getSubscriptionInfo(requestId: number): any {
return this.subscriptionInfos.get(requestId);
}

View File

@@ -251,21 +251,21 @@ class ParseLiveQueryServer {
}
switch(request.op) {
case 'connect':
this._handleConnect(parseWebsocket, request);
break;
case 'subscribe':
this._handleSubscribe(parseWebsocket, request);
break;
case 'update':
this._handleUpdateSubscription(parseWebsocket, request);
break;
case 'unsubscribe':
this._handleUnsubscribe(parseWebsocket, request);
break;
default:
Client.pushError(parseWebsocket, 3, 'Get unknown operation');
logger.error('Get unknown operation', request.op);
case 'connect':
this._handleConnect(parseWebsocket, request);
break;
case 'subscribe':
this._handleSubscribe(parseWebsocket, request);
break;
case 'update':
this._handleUpdateSubscription(parseWebsocket, request);
break;
case 'unsubscribe':
this._handleUnsubscribe(parseWebsocket, request);
break;
default:
Client.pushError(parseWebsocket, 3, 'Get unknown operation');
logger.error('Get unknown operation', request.op);
}
});
@@ -335,48 +335,48 @@ class ParseLiveQueryServer {
// Resolve false right away if the acl doesn't have any roles
const acl_has_roles = Object.keys(acl.permissionsById).some(key => key.startsWith("role:"));
if (!acl_has_roles) {
return resolve(false);
return resolve(false);
}
this.sessionTokenCache.getUserId(subscriptionSessionToken)
.then((userId) => {
// Pass along a null if there is no user id
if (!userId) {
return Parse.Promise.as(null);
}
if (!userId) {
return Parse.Promise.as(null);
}
// Prepare a user object to query for roles
// To eliminate a query for the user, create one locally with the id
var user = new Parse.User();
user.id = userId;
return user;
var user = new Parse.User();
user.id = userId;
return user;
})
.then((user) => {
// Pass along an empty array (of roles) if no user
if (!user) {
return Parse.Promise.as([]);
}
if (!user) {
return Parse.Promise.as([]);
}
// Then get the user's roles
var rolesQuery = new Parse.Query(Parse.Role);
rolesQuery.equalTo("users", user);
return rolesQuery.find();
var rolesQuery = new Parse.Query(Parse.Role);
rolesQuery.equalTo("users", user);
return rolesQuery.find();
}).
then((roles) => {
// Finally, see if any of the user's roles allow them read access
for (let role of roles) {
if (acl.getRoleReadAccess(role)) {
return resolve(true);
}
for (let role of roles) {
if (acl.getRoleReadAccess(role)) {
return resolve(true);
}
resolve(false);
}
resolve(false);
})
.catch((error) => {
reject(error);
reject(error);
});
});
@@ -393,7 +393,7 @@ class ParseLiveQueryServer {
});
}).then((isMatched) => {
return Parse.Promise.as(isMatched);
}, (error) => {
}, () => {
return Parse.Promise.as(false);
});
}

View File

@@ -38,7 +38,7 @@ export class ParseWebSocket {
this.ws.on(wsType, callback);
}
send(message: any, channel: string): void {
send(message: any): void {
this.ws.send(message);
}
}

View File

@@ -167,117 +167,118 @@ function matchesKeyConstraints(object, key, constraints) {
compareTo = Parse._decode(key, compareTo);
}
switch (condition) {
case '$lt':
if (object[key] >= compareTo) {
case '$lt':
if (object[key] >= compareTo) {
return false;
}
break;
case '$lte':
if (object[key] > compareTo) {
return false;
}
break;
case '$gt':
if (object[key] <= compareTo) {
return false;
}
break;
case '$gte':
if (object[key] < compareTo) {
return false;
}
break;
case '$ne':
if (equalObjects(object[key], compareTo)) {
return false;
}
break;
case '$in':
if (compareTo.indexOf(object[key]) < 0) {
return false;
}
break;
case '$nin':
if (compareTo.indexOf(object[key]) > -1) {
return false;
}
break;
case '$all':
for (i = 0; i < compareTo.length; i++) {
if (object[key].indexOf(compareTo[i]) < 0) {
return false;
}
break;
case '$lte':
if (object[key] > compareTo) {
return false;
}
break;
case '$gt':
if (object[key] <= compareTo) {
return false;
}
break;
case '$gte':
if (object[key] < compareTo) {
return false;
}
break;
case '$ne':
if (equalObjects(object[key], compareTo)) {
return false;
}
break;
case '$in':
if (compareTo.indexOf(object[key]) < 0) {
return false;
}
break;
case '$nin':
if (compareTo.indexOf(object[key]) > -1) {
return false;
}
break;
case '$all':
for (i = 0; i < compareTo.length; i++) {
if (object[key].indexOf(compareTo[i]) < 0) {
return false;
}
}
break;
case '$exists':
let propertyExists = typeof object[key] !== 'undefined';
let existenceIsRequired = constraints['$exists'];
if (typeof constraints['$exists'] !== 'boolean') {
}
break;
case '$exists': {
let propertyExists = typeof object[key] !== 'undefined';
let existenceIsRequired = constraints['$exists'];
if (typeof constraints['$exists'] !== 'boolean') {
// The SDK will never submit a non-boolean for $exists, but if someone
// tries to submit a non-boolean for $exits outside the SDKs, just ignore it.
break;
}
if ((!propertyExists && existenceIsRequired) || (propertyExists && !existenceIsRequired)) {
return false;
}
break;
case '$regex':
if (typeof compareTo === 'object') {
return compareTo.test(object[key]);
}
}
if ((!propertyExists && existenceIsRequired) || (propertyExists && !existenceIsRequired)) {
return false;
}
break;
}
case '$regex':
if (typeof compareTo === 'object') {
return compareTo.test(object[key]);
}
// JS doesn't support perl-style escaping
var expString = '';
var escapeEnd = -2;
var escapeStart = compareTo.indexOf('\\Q');
while (escapeStart > -1) {
var expString = '';
var escapeEnd = -2;
var escapeStart = compareTo.indexOf('\\Q');
while (escapeStart > -1) {
// Add the unescaped portion
expString += compareTo.substring(escapeEnd + 2, escapeStart);
escapeEnd = compareTo.indexOf('\\E', escapeStart);
if (escapeEnd > -1) {
expString += compareTo.substring(escapeStart + 2, escapeEnd)
expString += compareTo.substring(escapeEnd + 2, escapeStart);
escapeEnd = compareTo.indexOf('\\E', escapeStart);
if (escapeEnd > -1) {
expString += compareTo.substring(escapeStart + 2, escapeEnd)
.replace(/\\\\\\\\E/g, '\\E').replace(/\W/g, '\\$&');
}
}
escapeStart = compareTo.indexOf('\\Q', escapeEnd);
}
expString += compareTo.substring(Math.max(escapeStart, escapeEnd + 2));
var exp = new RegExp(expString, constraints.$options || '');
if (!exp.test(object[key])) {
return false;
}
break;
case '$nearSphere':
var distance = compareTo.radiansTo(object[key]);
var max = constraints.$maxDistance || Infinity;
return distance <= max;
case '$within':
var southWest = compareTo.$box[0];
var northEast = compareTo.$box[1];
if (southWest.latitude > northEast.latitude ||
escapeStart = compareTo.indexOf('\\Q', escapeEnd);
}
expString += compareTo.substring(Math.max(escapeStart, escapeEnd + 2));
var exp = new RegExp(expString, constraints.$options || '');
if (!exp.test(object[key])) {
return false;
}
break;
case '$nearSphere':
var distance = compareTo.radiansTo(object[key]);
var max = constraints.$maxDistance || Infinity;
return distance <= max;
case '$within':
var southWest = compareTo.$box[0];
var northEast = compareTo.$box[1];
if (southWest.latitude > northEast.latitude ||
southWest.longitude > northEast.longitude) {
// Invalid box, crosses the date line
return false;
}
return (
return false;
}
return (
object[key].latitude > southWest.latitude &&
object[key].latitude < northEast.latitude &&
object[key].longitude > southWest.longitude &&
object[key].longitude < northEast.longitude
);
case '$options':
);
case '$options':
// Not a query type, but a way to add options to $regex. Ignore and
// avoid the default
break;
case '$maxDistance':
break;
case '$maxDistance':
// Not a query type, but a way to add a cap to $nearSphere. Ignore and
// avoid the default
break;
case '$select':
return false;
case '$dontSelect':
return false;
default:
return false;
break;
case '$select':
return false;
case '$dontSelect':
return false;
default:
return false;
}
}
return true;

View File

@@ -61,7 +61,7 @@ let subscribe = {
'fields': {
"type": "array",
"items": {
"type": "string"
"type": "string"
},
"minItems": 1,
"uniqueItems": true
@@ -99,7 +99,7 @@ let update = {
'fields': {
"type": "array",
"items": {
"type": "string"
"type": "string"
},
"minItems": 1,
"uniqueItems": true

View File

@@ -1,4 +1,3 @@
import {matchesQuery, queryHash} from './QueryTools';
import logger from '../logger';
export type FlattenedObjectData = { [attr: string]: any };

View File

@@ -1,20 +1,18 @@
// ParseServer - open-source compatible API Server for Parse apps
var batch = require('./batch'),
bodyParser = require('body-parser'),
express = require('express'),
middlewares = require('./middlewares'),
multer = require('multer'),
Parse = require('parse/node').Parse,
path = require('path'),
url = require('url'),
authDataManager = require('./authDataManager');
bodyParser = require('body-parser'),
express = require('express'),
middlewares = require('./middlewares'),
Parse = require('parse/node').Parse,
path = require('path'),
url = require('url'),
authDataManager = require('./authDataManager');
import defaults from './defaults';
import * as logging from './logger';
import AppCache from './cache';
import Config from './Config';
import parseServerPackage from '../package.json';
import PromiseRouter from './PromiseRouter';
import requiredParameter from './requiredParameter';
import { AnalyticsRouter } from './Routers/AnalyticsRouter';
@@ -43,7 +41,6 @@ import { PublicAPIRouter } from './Routers/PublicAPIRouter';
import { PushController } from './Controllers/PushController';
import { PushRouter } from './Routers/PushRouter';
import { CloudCodeRouter } from './Routers/CloudCodeRouter';
import { randomString } from './cryptoUtils';
import { RolesRouter } from './Routers/RolesRouter';
import { SchemasRouter } from './Routers/SchemasRouter';
import { SessionsRouter } from './Routers/SessionsRouter';
@@ -260,20 +257,20 @@ class ParseServer {
try {
const parsedURI = url.parse(databaseURI);
protocol = parsedURI.protocol ? parsedURI.protocol.toLowerCase() : null;
} catch(e) {}
} catch(e) { /* */ }
switch (protocol) {
case 'postgres:':
return new PostgresStorageAdapter({
uri: databaseURI,
collectionPrefix,
databaseOptions
});
default:
return new MongoStorageAdapter({
uri: databaseURI,
collectionPrefix,
mongoOptions: databaseOptions,
});
case 'postgres:':
return new PostgresStorageAdapter({
uri: databaseURI,
collectionPrefix,
databaseOptions
});
default:
return new MongoStorageAdapter({
uri: databaseURI,
collectionPrefix,
mongoOptions: databaseOptions,
});
}
}
@@ -309,7 +306,9 @@ class ParseServer {
if (!process.env.TESTING) {
process.on('uncaughtException', (err) => {
if ( err.code === "EADDRINUSE" ) { // user-friendly message for this common error
/* eslint-disable no-console */
console.error(`Unable to listen on port ${err.port}. The port is already in use.`);
/* eslint-enable no-console */
process.exit(0);
} else {
throw err;

View File

@@ -13,7 +13,7 @@ function getSessionToken(options) {
function getAuth(options, config) {
if (options.useMasterKey) {
return Parse.Promise.as(new Auth.Auth({config, isMaster: true, installationId: 'cloud' }));
return Parse.Promise.as(new Auth.Auth({config, isMaster: true, installationId: 'cloud' }));
}
return getSessionToken(options).then((sessionToken) => {
if (sessionToken) {
@@ -75,7 +75,7 @@ function ParseServerRESTController(applicationId, router) {
return Promise.resolve().then(() => {
return router.tryRouteRequest(method, path, request);
}).then((response) => {
resolve(response.response, response.status, response);
resolve(response.response, response.status, response);
}, (err) => {
if (err instanceof Parse.Error &&
err.code == Parse.Error.INVALID_JSON &&
@@ -87,13 +87,13 @@ function ParseServerRESTController(applicationId, router) {
});
}, reject);
});
};
}
return {
request: handleRequest,
ajax: RESTController.ajax
};
};
}
export default ParseServerRESTController;
export { ParseServerRESTController };

View File

@@ -5,9 +5,8 @@
// themselves use our routing information, without disturbing express
// components that external developers may be modifying.
import AppCache from './cache';
import Parse from 'parse/node';
import express from 'express';
import url from 'url';
import log from './logger';
import {inspect} from 'util';
const Layer = require('express/lib/router/layer');
@@ -52,7 +51,7 @@ export default class PromiseRouter {
for (var route of router.routes) {
this.routes.push(route);
}
};
}
route(method, path, ...handlers) {
switch(method) {
@@ -68,10 +67,9 @@ export default class PromiseRouter {
let handler = handlers[0];
if (handlers.length > 1) {
const length = handlers.length;
handler = function(req) {
return handlers.reduce((promise, handler) => {
return promise.then((result) => {
return promise.then(() => {
return handler(req);
});
}, Promise.resolve());
@@ -84,7 +82,7 @@ export default class PromiseRouter {
handler: handler,
layer: new Layer(path, null, handler)
});
};
}
// Returns an object with:
// handler: the handler that should deal with this request
@@ -105,17 +103,17 @@ export default class PromiseRouter {
return {params: params, handler: route.handler};
}
}
};
}
// Mount the routes on this router onto an express app (or express router)
mountOnto(expressApp) {
this.routes.forEach((route) => {
this.routes.forEach((route) => {
let method = route.method.toLowerCase();
let handler = makeExpressHandler(this.appId, route.handler);
expressApp[method].call(expressApp, route.path, handler);
});
return expressApp;
};
}
expressRouter() {
return this.mountOnto(express.Router());
@@ -140,7 +138,6 @@ export default class PromiseRouter {
// Express handlers should never throw; if a promise handler throws we
// just treat it like it resolved to an error.
function makeExpressHandler(appId, promiseHandler) {
let config = AppCache.get(appId);
return function(req, res, next) {
try {
let url = maskSensitiveUrl(req);

View File

@@ -5,8 +5,6 @@ var SchemaController = require('./Controllers/SchemaController');
var Parse = require('parse/node').Parse;
const triggers = require('./triggers');
import { default as FilesController } from './Controllers/FilesController';
// restOptions can include:
// skip
// limit
@@ -34,11 +32,11 @@ function RestQuery(config, auth, className, restWhere = {}, restOptions = {}, cl
}
this.restWhere = {
'$and': [this.restWhere, {
'user': {
__type: 'Pointer',
className: '_User',
objectId: this.auth.user.id
}
'user': {
__type: 'Pointer',
className: '_User',
objectId: this.auth.user.id
}
}]
};
}
@@ -188,7 +186,7 @@ RestQuery.prototype.validateClientClassCreation = function() {
'This user is not allowed to access ' +
'non-existent class: ' + this.className);
}
});
});
} else {
return Promise.resolve();
}
@@ -397,41 +395,41 @@ RestQuery.prototype.runFind = function(options = {}) {
}
let findOptions = Object.assign({}, this.findOptions);
if (this.keys) {
findOptions.keys = Array.from(this.keys).map((key) => {
findOptions.keys = Array.from(this.keys).map((key) => {
return key.split('.')[0];
});
}
if (options.op) {
findOptions.op = options.op;
findOptions.op = options.op;
}
return this.config.database.find(
this.className, this.restWhere, findOptions).then((results) => {
if (this.className === '_User') {
for (var result of results) {
delete result.password;
if (this.className === '_User') {
for (var result of results) {
delete result.password;
if (result.authData) {
Object.keys(result.authData).forEach((provider) => {
if (result.authData[provider] === null) {
delete result.authData[provider];
if (result.authData) {
Object.keys(result.authData).forEach((provider) => {
if (result.authData[provider] === null) {
delete result.authData[provider];
}
});
if (Object.keys(result.authData).length == 0) {
delete result.authData;
}
});
if (Object.keys(result.authData).length == 0) {
delete result.authData;
}
}
}
}
this.config.filesController.expandFilesInObject(this.config, results);
this.config.filesController.expandFilesInObject(this.config, results);
if (this.redirectClassName) {
for (var r of results) {
r.className = this.redirectClassName;
if (this.redirectClassName) {
for (var r of results) {
r.className = this.redirectClassName;
}
}
}
this.response = {results: results};
});
this.response = {results: results};
});
};
// Returns a promise for whether it was successful.
@@ -510,7 +508,7 @@ function includePath(config, auth, response, path, restOptions = {}) {
let includeRestOptions = {};
if (restOptions.keys) {
let keys = new Set(restOptions.keys.split(','));
let keySet = Array.from(keys).reduce((set, key) => {
let keySet = Array.from(keys).reduce((set, key) => {
let keyPath = key.split('.');
let i=0;
for (i; i<path.length; i++) {
@@ -528,10 +526,10 @@ function includePath(config, auth, response, path, restOptions = {}) {
}
}
let queryPromises = Object.keys(pointersHash).map((className) => {
let queryPromises = Object.keys(pointersHash).map((className) => {
let where = {'objectId': {'$in': Array.from(pointersHash[className])}};
var query = new RestQuery(config, auth, className, where, includeRestOptions);
return query.execute({op: 'get'}).then((results) => {
return query.execute({op: 'get'}).then((results) => {
results.className = className;
return Promise.resolve(results);
})
@@ -604,7 +602,7 @@ function findPointers(object, path) {
function replacePointers(object, path, replace) {
if (object instanceof Array) {
return object.map((obj) => replacePointers(obj, path, replace))
.filter((obj) => typeof obj !== 'undefined');
.filter((obj) => typeof obj !== 'undefined');
}
if (typeof object !== 'object' || !object) {
@@ -642,7 +640,7 @@ function findObjectWithKey(root, key) {
}
if (root instanceof Array) {
for (var item of root) {
var answer = findObjectWithKey(item, key);
let answer = findObjectWithKey(item, key);
if (answer) {
return answer;
}
@@ -652,7 +650,7 @@ function findObjectWithKey(root, key) {
return root;
}
for (var subkey in root) {
var answer = findObjectWithKey(root[subkey], key);
let answer = findObjectWithKey(root[subkey], key);
if (answer) {
return answer;
}

View File

@@ -6,7 +6,6 @@ var SchemaController = require('./Controllers/SchemaController');
var deepcopy = require('deepcopy');
var Auth = require('./Auth');
var Config = require('./Config');
var cryptoUtils = require('./cryptoUtils');
var passwordCrypto = require('./password');
var Parse = require('parse/node');
@@ -124,7 +123,7 @@ RestWrite.prototype.validateClientClassCreation = function() {
'This user is not allowed to access ' +
'non-existent class: ' + this.className);
}
});
});
} else {
return Promise.resolve();
}
@@ -236,7 +235,7 @@ RestWrite.prototype.validateAuthData = function() {
};
RestWrite.prototype.handleAuthDataValidation = function(authData) {
let validations = Object.keys(authData).map((provider) => {
let validations = Object.keys(authData).map((provider) => {
if (authData[provider] === null) {
return Promise.resolve();
}
@@ -244,7 +243,7 @@ RestWrite.prototype.handleAuthDataValidation = function(authData) {
if (!validateAuthData) {
throw new Parse.Error(Parse.Error.UNSUPPORTED_SERVICE,
'This authentication method is unsupported.');
};
}
return validateAuthData(authData[provider]);
});
return Promise.all(validations);
@@ -252,7 +251,7 @@ RestWrite.prototype.handleAuthDataValidation = function(authData) {
RestWrite.prototype.findUsersWithAuthData = function(authData) {
let providers = Object.keys(authData);
let query = providers.reduce((memo, provider) => {
let query = providers.reduce((memo, provider) => {
if (!authData[provider]) {
return memo;
}
@@ -261,13 +260,13 @@ RestWrite.prototype.findUsersWithAuthData = function(authData) {
query[queryKey] = authData[provider].id;
memo.push(query);
return memo;
}, []).filter((q) => {
}, []).filter((q) => {
return typeof q !== 'undefined';
});
let findPromise = Promise.resolve([]);
if (query.length > 0) {
findPromise = this.config.database.find(
findPromise = this.config.database.find(
this.className,
{'$or': query}, {})
}
@@ -279,8 +278,8 @@ RestWrite.prototype.findUsersWithAuthData = function(authData) {
RestWrite.prototype.handleAuthData = function(authData) {
let results;
return this.handleAuthDataValidation(authData).then(() => {
return this.findUsersWithAuthData(authData);
}).then((r) => {
return this.findUsersWithAuthData(authData);
}).then((r) => {
results = r;
if (results.length > 1) {
// More than 1 user with the passed id's
@@ -317,9 +316,9 @@ RestWrite.prototype.handleAuthData = function(authData) {
// We have authData that is updated on login
// that can happen when token are refreshed,
// We should update the token and let the user in
if (Object.keys(mutatedAuthData).length > 0) {
if (Object.keys(mutatedAuthData).length > 0) {
// Assign the new authData in the response
Object.keys(mutatedAuthData).forEach((provider) => {
Object.keys(mutatedAuthData).forEach((provider) => {
this.response.response.authData[provider] = mutatedAuthData[provider];
});
// Run the DB update directly, as 'master'
@@ -507,10 +506,10 @@ RestWrite.prototype.handleFollowup = function() {
if (this.storage && this.storage['clearSessions'] && this.config.revokeSessionOnPasswordReset) {
var sessionQuery = {
user: {
__type: 'Pointer',
className: '_User',
objectId: this.objectId()
}
__type: 'Pointer',
className: '_User',
objectId: this.objectId()
}
};
delete this.storage['clearSessions'];
return this.config.database.destroy('_Session', sessionQuery)
@@ -636,7 +635,7 @@ RestWrite.prototype.handleInstallation = function() {
let orQueries = [];
if (this.query && this.query.objectId) {
orQueries.push({
objectId: this.query.objectId
objectId: this.query.objectId
});
}
if (installationId) {
@@ -652,12 +651,12 @@ RestWrite.prototype.handleInstallation = function() {
return;
}
promise = promise.then(() => {
promise = promise.then(() => {
return this.config.database.find('_Installation', {
'$or': orQueries
'$or': orQueries
}, {});
}).then((results) => {
results.forEach((result) => {
}).then((results) => {
results.forEach((result) => {
if (this.query && this.query.objectId && result.objectId == this.query.objectId) {
objectIdMatch = result;
}
@@ -677,23 +676,23 @@ RestWrite.prototype.handleInstallation = function() {
}
if (this.data.installationId && objectIdMatch.installationId &&
this.data.installationId !== objectIdMatch.installationId) {
throw new Parse.Error(136,
throw new Parse.Error(136,
'installationId may not be changed in this ' +
'operation');
}
if (this.data.deviceToken && objectIdMatch.deviceToken &&
}
if (this.data.deviceToken && objectIdMatch.deviceToken &&
this.data.deviceToken !== objectIdMatch.deviceToken &&
!this.data.installationId && !objectIdMatch.installationId) {
throw new Parse.Error(136,
throw new Parse.Error(136,
'deviceToken may not be changed in this ' +
'operation');
}
if (this.data.deviceType && this.data.deviceType &&
}
if (this.data.deviceType && this.data.deviceType &&
this.data.deviceType !== objectIdMatch.deviceType) {
throw new Parse.Error(136,
throw new Parse.Error(136,
'deviceType may not be changed in this ' +
'operation');
}
}
}
if (this.query && this.query.objectId && objectIdMatch) {
@@ -748,7 +747,7 @@ RestWrite.prototype.handleInstallation = function() {
// Exactly one device token match and it doesn't have an installation
// ID. This is the one case where we want to merge with the existing
// object.
var delQuery = {objectId: idMatch.objectId};
let delQuery = {objectId: idMatch.objectId};
return this.config.database.destroy('_Installation', delQuery)
.then(() => {
return deviceTokenMatches[0]['objectId'];
@@ -759,7 +758,7 @@ RestWrite.prototype.handleInstallation = function() {
// We're setting the device token on an existing installation, so
// we should try cleaning out old installations that match this
// device token.
var delQuery = {
let delQuery = {
'deviceToken': this.data.deviceToken,
};
// We have a unique install Id, use that to preserve
@@ -969,7 +968,7 @@ RestWrite.prototype.objectId = function() {
// Returns a copy of the data and delete bad keys (_auth_data, _hashed_password...)
RestWrite.prototype.sanitizedData = function() {
let data = Object.keys(this.data).reduce((data, key) => {
let data = Object.keys(this.data).reduce((data, key) => {
// Regexp comes from Parse.Object.prototype.validate
if (!(/^[A-Za-z][0-9A-Za-z_]*$/).test(key)) {
delete data[key];

View File

@@ -2,7 +2,7 @@
import PromiseRouter from '../PromiseRouter';
import rest from '../rest';
import _ from 'lodash';
import url from 'url';
import Parse from 'parse/node';
const ALLOWED_GET_QUERY_KEYS = ['keys', 'include'];

View File

@@ -10,7 +10,7 @@ export class CloudCodeRouter extends PromiseRouter {
let config = req.config;
let jobs = triggers.getJobs(config.applicationId) || {};
return Promise.resolve({
response: Object.keys(jobs).map((jobName) => {
response: Object.keys(jobs).map((jobName) => {
return {
jobName,
}

View File

@@ -47,9 +47,9 @@ export class FeaturesRouter extends PromiseRouter {
};
return { response: {
features: features,
parseServerVersion: version,
} };
features: features,
parseServerVersion: version,
} };
});
}
}

View File

@@ -1,7 +1,7 @@
import express from 'express';
import BodyParser from 'body-parser';
import * as Middlewares from '../middlewares';
import { randomHexString } from '../cryptoUtils';
import Parse from 'parse/node';
import Config from '../Config';
import mime from 'mime';
@@ -40,7 +40,7 @@ export class FilesRouter {
if (isFileStreamable(req, filesController)) {
filesController.getFileStream(config, filename).then((stream) => {
handleFileStream(stream, req, res, contentType);
}).catch((err) => {
}).catch(() => {
res.status(404);
res.set('Content-Type', 'text/plain');
res.end('File not found.');
@@ -51,7 +51,7 @@ export class FilesRouter {
res.set('Content-Type', contentType);
res.set('Content-Length', data.length);
res.end(data);
}).catch((err) => {
}).catch(() => {
res.status(404);
res.set('Content-Type', 'text/plain');
res.end('File not found.');
@@ -87,7 +87,7 @@ export class FilesRouter {
res.status(201);
res.set('Location', result.url);
res.json(result);
}).catch((err) => {
}).catch(() => {
next(new Parse.Error(Parse.Error.FILE_SAVE_ERROR, 'Could not store file.'));
});
}
@@ -98,7 +98,7 @@ export class FilesRouter {
res.status(200);
// TODO: return useful JSON here?
res.end();
}).catch((error) => {
}).catch(() => {
next(new Parse.Error(Parse.Error.FILE_DELETE_ERROR,
'Could not delete file.'));
});
@@ -138,7 +138,7 @@ function handleFileStream(stream, req, res, contentType) {
if (!partialend) {
if (((stream.length-1) - start) < (buffer_size)) {
end = stream.length - 1;
end = stream.length - 1;
}else{
end = start + (buffer_size);
}
@@ -159,8 +159,6 @@ function handleFileStream(stream, req, res, contentType) {
stream.seek(start, function () {
// get gridFile stream
var gridFileStream = stream.stream(true);
var ended = false;
var bufferIdx = 0;
var bufferAvail = 0;
var range = (end - start) + 1;
var totalbyteswanted = (end - start) + 1;
@@ -176,7 +174,6 @@ function handleFileStream(stream, req, res, contentType) {
res.write(buff);
totalbyteswritten += buff.length;
range -= buff.length;
bufferIdx += buff.length;
bufferAvail -= buff.length;
}
} else {
@@ -185,7 +182,6 @@ function handleFileStream(stream, req, res, contentType) {
const buffer = buff.slice(0,range);
res.write(buffer);
totalbyteswritten += buffer.length;
bufferIdx += range;
bufferAvail -= range;
}
}

View File

@@ -1,8 +1,7 @@
// FunctionsRouter.js
var express = require('express'),
Parse = require('parse/node').Parse,
triggers = require('../triggers');
var Parse = require('parse/node').Parse,
triggers = require('../triggers');
import PromiseRouter from '../PromiseRouter';
import { promiseEnforceMasterKeyAccess } from '../middlewares';
@@ -12,9 +11,9 @@ import { logger } from '../logger';
function parseObject(obj) {
if (Array.isArray(obj)) {
return obj.map((item) => {
return parseObject(item);
});
return obj.map((item) => {
return parseObject(item);
});
} else if (obj && obj.__type == 'Date') {
return Object.assign(new Date(obj.iso), obj);
} else if (obj && obj.__type == 'File') {
@@ -63,10 +62,10 @@ export class FunctionsRouter extends PromiseRouter {
error: jobHandler.setFailed.bind(jobHandler),
message: jobHandler.setMessage.bind(jobHandler)
}
return jobHandler.setRunning(jobName, params).then((jobStatus) => {
return jobHandler.setRunning(jobName, params).then((jobStatus) => {
request.jobId = jobStatus.objectId
// run the function async
process.nextTick(() => {
process.nextTick(() => {
jobFunction(request, status);
});
return {
@@ -131,10 +130,10 @@ export class FunctionsRouter extends PromiseRouter {
const cleanResult = logger.truncateLogMessage(JSON.stringify(result.response.result));
logger.info(`Ran cloud function ${functionName} for user ${userString} `
+ `with:\n Input: ${cleanInput }\n Result: ${cleanResult }`, {
functionName,
params,
user: userString,
});
functionName,
params,
user: userString,
});
resolve(result);
} catch (e) {
reject(e);
@@ -144,11 +143,11 @@ export class FunctionsRouter extends PromiseRouter {
logger.error(`Failed running cloud function ${functionName} for `
+ `user ${userString} with:\n Input: ${cleanInput}\n Error: `
+ JSON.stringify(error), {
functionName,
error,
params,
user: userString
});
functionName,
error,
params,
user: userString
});
reject(error);
} catch (e) {
reject(e);

View File

@@ -22,7 +22,7 @@ export class GlobalConfigRouter extends PromiseRouter {
acc[`params.${key}`] = params[key];
return acc;
}, {});
return req.config.database.update('_GlobalConfig', {objectId: "1"}, update, {upsert: true}).then(() => ({ response: { result: true } }));
return req.config.database.update('_GlobalConfig', {objectId: "1"}, update, {upsert: true}).then(() => ({ response: { result: true } }));
}
mountRoutes() {

View File

@@ -5,15 +5,15 @@ import * as middleware from "../middlewares";
export class HooksRouter extends PromiseRouter {
createHook(aHook, config) {
return config.hooksController.createHook(aHook).then( (hook) => ({response: hook}));
};
}
updateHook(aHook, config) {
return config.hooksController.updateHook(aHook).then((hook) => ({response: hook}));
};
}
handlePost(req) {
return this.createHook(req.body, req.config);
};
}
handleGetFunctions(req) {
var hooksController = req.config.hooksController;

View File

@@ -1,7 +1,7 @@
import PromiseRouter from '../PromiseRouter';
var request = require("request");
var rest = require("../rest");
var Auth = require("../Auth");
import Parse from 'parse/node';
// TODO move validation logic in IAPValidationController
const IAP_SANDBOX_URL = "https://sandbox.itunes.apple.com/verifyReceipt";
@@ -59,7 +59,7 @@ function getFileForProductIdentifier(productIdentifier, req) {
export class IAPValidationRouter extends PromiseRouter {
handleRequest(req) {
handleRequest(req) {
let receipt = req.body.receipt;
const productIdentifier = req.body.productIdentifier;
@@ -81,11 +81,11 @@ export class IAPValidationRouter extends PromiseRouter {
}
function successCallback() {
return getFileForProductIdentifier(productIdentifier, req);
};
return getFileForProductIdentifier(productIdentifier, req);
}
function errorCallback(error) {
return Promise.resolve({response: appStoreError(error.status) });
return Promise.resolve({response: appStoreError(error.status) });
}
return validateWithAppStore(IAP_PRODUCTION_URL, receipt).then( () => {
@@ -95,10 +95,10 @@ export class IAPValidationRouter extends PromiseRouter {
}, (error) => {
if (error.status == 21007) {
return validateWithAppStore(IAP_SANDBOX_URL, receipt).then( () => {
return successCallback();
}, (error) => {
return errorCallback(error);
}
return successCallback();
}, (error) => {
return errorCallback(error);
}
);
}

View File

@@ -1,5 +1,4 @@
import PromiseRouter from '../PromiseRouter';
import UserController from '../Controllers/UserController';
import Config from '../Config';
import express from 'express';
import path from 'path';
@@ -46,7 +45,7 @@ export class PublicAPIRouter extends PromiseRouter {
});
}
// Should we keep the file in memory or leave like that?
fs.readFile(path.resolve(views, "choose_password"), 'utf-8', (err, data) => {
fs.readFile(path.resolve(views, "choose_password"), 'utf-8', (err, data) => {
if (err) {
return reject(err);
}
@@ -72,7 +71,7 @@ export class PublicAPIRouter extends PromiseRouter {
return this.invalidLink(req);
}
return config.userController.checkResetTokenValidity(username, token).then( (user) => {
return config.userController.checkResetTokenValidity(username, token).then( () => {
let params = qs.stringify({token, id: config.applicationId, username, app: config.appName, });
return Promise.resolve({
status: 302,
@@ -101,7 +100,7 @@ export class PublicAPIRouter extends PromiseRouter {
return this.invalidLink(req);
}
return config.userController.updatePassword(username, token, new_password).then((result) => {
return config.userController.updatePassword(username, token, new_password).then(() => {
let params = qs.stringify({username: username});
return Promise.resolve({
status: 302,
@@ -119,8 +118,8 @@ export class PublicAPIRouter extends PromiseRouter {
invalidLink(req) {
return Promise.resolve({
status: 302,
location: req.config.invalidLinkURL
status: 302,
location: req.config.invalidLinkURL
});
}

View File

@@ -1,7 +1,5 @@
import ClassesRouter from './ClassesRouter';
import PromiseRouter from '../PromiseRouter';
import rest from '../rest';
export class RolesRouter extends ClassesRouter {
handleFind(req) {

View File

@@ -1,7 +1,6 @@
// schemas.js
var express = require('express'),
Parse = require('parse/node').Parse,
var Parse = require('parse/node').Parse,
SchemaController = require('../Controllers/SchemaController');
import PromiseRouter from '../PromiseRouter';

View File

@@ -1,6 +1,6 @@
import ClassesRouter from './ClassesRouter';
import PromiseRouter from '../PromiseRouter';
import Parse from 'parse/node';
import rest from '../rest';
import Auth from '../Auth';
import RestWrite from '../RestWrite';
@@ -75,14 +75,14 @@ export class SessionsRouter extends ClassesRouter {
expiresAt: Parse._encode(expiresAt)
};
const create = new RestWrite(config, masterAuth, '_Session', null, sessionData);
return create.execute().then(() => {
return create.execute().then(() => {
// delete the session token, use the db to skip beforeSave
return config.database.update('_User', {
objectId: user.id
}, {
sessionToken: {__op: 'Delete'}
});
}).then((res) => {
}).then(() => {
return Promise.resolve({ response: sessionData });
});
}
@@ -94,7 +94,7 @@ export class SessionsRouter extends ClassesRouter {
this.route('POST', '/sessions', req => { return this.handleCreate(req); });
this.route('PUT', '/sessions/:objectId', req => { return this.handleUpdate(req); });
this.route('DELETE', '/sessions/:objectId', req => { return this.handleDelete(req); });
this.route('POST', '/upgradeToRevocableSession', req => { return this.handleUpdateToRevocableSession(req); })
this.route('POST', '/upgradeToRevocableSession', req => { return this.handleUpdateToRevocableSession(req); })
}
}

View File

@@ -1,16 +1,15 @@
// These methods handle the User-related routes.
import deepcopy from 'deepcopy';
import Parse from 'parse/node';
import Config from '../Config';
import AccountLockout from '../AccountLockout';
import ClassesRouter from './ClassesRouter';
import PromiseRouter from '../PromiseRouter';
import rest from '../rest';
import Auth from '../Auth';
import passwordCrypto from '../password';
import RestWrite from '../RestWrite';
let cryptoUtils = require('../cryptoUtils');
let triggers = require('../triggers');
export class UsersRouter extends ClassesRouter {
handleFind(req) {
@@ -216,10 +215,10 @@ export class UsersRouter extends ClassesRouter {
throw new Parse.Error(Parse.Error.INVALID_EMAIL_ADDRESS, 'you must provide a valid email string');
}
let userController = req.config.userController;
return userController.sendPasswordResetEmail(email).then(token => {
return Promise.resolve({
response: {}
});
return userController.sendPasswordResetEmail(email).then(() => {
return Promise.resolve({
response: {}
});
}, err => {
if (err.code === Parse.Error.OBJECT_NOT_FOUND) {
throw new Parse.Error(Parse.Error.EMAIL_NOT_FOUND, `No user found with email ${email}.`);

View File

@@ -5,7 +5,7 @@ const PUSH_STATUS_COLLECTION = '_PushStatus';
const JOB_STATUS_COLLECTION = '_JobStatus';
export function flatten(array) {
return array.reduce((memo, element) => {
return array.reduce((memo, element) => {
if (Array.isArray(element)) {
memo = memo.concat(flatten(element));
} else {
@@ -19,8 +19,8 @@ function statusHandler(className, database) {
let lastPromise = Promise.resolve();
function create(object) {
lastPromise = lastPromise.then(() => {
return database.create(className, object).then(() => {
lastPromise = lastPromise.then(() => {
return database.create(className, object).then(() => {
return Promise.resolve(object);
});
});
@@ -28,7 +28,7 @@ function statusHandler(className, database) {
}
function update(where, object) {
lastPromise = lastPromise.then(() => {
lastPromise = lastPromise.then(() => {
return database.update(className, where, object);
});
return lastPromise;
@@ -44,7 +44,6 @@ export function jobStatusHandler(config) {
let jobStatus;
let objectId = newObjectId();
let database = config.database;
let lastPromise = Promise.resolve();
let handler = statusHandler(JOB_STATUS_COLLECTION, database);
let setRunning = function(jobName, params) {
let now = new Date();
@@ -138,7 +137,7 @@ export function pushStatusHandler(config) {
let setRunning = function(installations) {
logger.verbose('sending push to %d installations', installations.length);
return handler.update({status:"pending", objectId: objectId},
return handler.update({status:"pending", objectId: objectId},
{status: "running", updatedAt: new Date() });
}
@@ -151,7 +150,7 @@ export function pushStatusHandler(config) {
};
if (Array.isArray(results)) {
results = flatten(results);
results.reduce((memo, result) => {
results.reduce((memo, result) => {
// Cannot handle that
if (!result || !result.device || !result.device.deviceType) {
return memo;

View File

@@ -6,11 +6,11 @@ export function destroyAllDataPermanently() {
throw 'Only supported in test environment';
}
return Promise.all(Object.keys(AppCache.cache).map(appId => {
const app = AppCache.get(appId);
if (app.databaseController) {
return app.databaseController.deleteEverything();
} else {
return Promise.resolve();
}
}));
const app = AppCache.get(appId);
if (app.databaseController) {
return app.databaseController.deleteEverything();
} else {
return Promise.resolve();
}
}));
}

View File

@@ -24,11 +24,11 @@ OAuth.prototype.send = function(method, path, params, body){
data = JSON.parse(data);
resolve(data);
});
}).on('error', function(e) {
}).on('error', function() {
reject('Failed to make an OAuth request');
});
if (request.body) {
httpRequest.write(request.body);
httpRequest.write(request.body);
}
httpRequest.end();
});
@@ -63,11 +63,11 @@ OAuth.prototype.buildRequest = function(method, path, params, body) {
}
OAuth.prototype.get = function(path, params) {
return this.send("GET", path, params);
return this.send("GET", path, params);
}
OAuth.prototype.post = function(path, params, body) {
return this.send("POST", path, params, body);
return this.send("POST", path, params, body);
}
/*
@@ -115,29 +115,27 @@ OAuth.version = "1.0";
Generate a nonce
*/
OAuth.nonce = function(){
var text = "";
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
var text = "";
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for( var i=0; i < 30; i++ )
text += possible.charAt(Math.floor(Math.random() * possible.length));
for( var i=0; i < 30; i++ )
text += possible.charAt(Math.floor(Math.random() * possible.length));
return text;
return text;
}
OAuth.buildParameterString = function(obj){
var result = {};
// Sort keys and encode values
if (obj) {
var keys = Object.keys(obj).sort();
if (obj) {
var keys = Object.keys(obj).sort();
// Map key=value, join them by &
return keys.map(function(key){
return key + "=" + OAuth.encode(obj[key]);
}).join("&");
}
return keys.map(function(key){
return key + "=" + OAuth.encode(obj[key]);
}).join("&");
}
return "";
return "";
}
/*
@@ -145,81 +143,81 @@ OAuth.buildParameterString = function(obj){
*/
OAuth.buildSignatureString = function(method, url, parameters){
return [method.toUpperCase(), OAuth.encode(url), OAuth.encode(parameters)].join("&");
return [method.toUpperCase(), OAuth.encode(url), OAuth.encode(parameters)].join("&");
}
/*
Retuns encoded HMAC-SHA1 from key and text
*/
OAuth.signature = function(text, key){
crypto = require("crypto");
return OAuth.encode(crypto.createHmac('sha1', key).update(text).digest('base64'));
crypto = require("crypto");
return OAuth.encode(crypto.createHmac('sha1', key).update(text).digest('base64'));
}
OAuth.signRequest = function(request, oauth_parameters, consumer_secret, auth_token_secret){
oauth_parameters = oauth_parameters || {};
oauth_parameters = oauth_parameters || {};
// Set default values
if (!oauth_parameters.oauth_nonce) {
oauth_parameters.oauth_nonce = OAuth.nonce();
}
if (!oauth_parameters.oauth_timestamp) {
oauth_parameters.oauth_timestamp = Math.floor(new Date().getTime()/1000);
}
if (!oauth_parameters.oauth_signature_method) {
oauth_parameters.oauth_signature_method = OAuth.signatureMethod;
}
if (!oauth_parameters.oauth_version) {
oauth_parameters.oauth_version = OAuth.version;
}
if (!oauth_parameters.oauth_nonce) {
oauth_parameters.oauth_nonce = OAuth.nonce();
}
if (!oauth_parameters.oauth_timestamp) {
oauth_parameters.oauth_timestamp = Math.floor(new Date().getTime()/1000);
}
if (!oauth_parameters.oauth_signature_method) {
oauth_parameters.oauth_signature_method = OAuth.signatureMethod;
}
if (!oauth_parameters.oauth_version) {
oauth_parameters.oauth_version = OAuth.version;
}
if(!auth_token_secret){
auth_token_secret="";
}
if(!auth_token_secret){
auth_token_secret="";
}
// Force GET method if unset
if (!request.method) {
request.method = "GET"
}
if (!request.method) {
request.method = "GET"
}
// Collect all the parameters in one signatureParameters object
var signatureParams = {};
var parametersToMerge = [request.params, request.body, oauth_parameters];
for(var i in parametersToMerge) {
var parameters = parametersToMerge[i];
for(var k in parameters) {
signatureParams[k] = parameters[k];
}
}
var signatureParams = {};
var parametersToMerge = [request.params, request.body, oauth_parameters];
for(var i in parametersToMerge) {
var parameters = parametersToMerge[i];
for(var k in parameters) {
signatureParams[k] = parameters[k];
}
}
// Create a string based on the parameters
var parameterString = OAuth.buildParameterString(signatureParams);
var parameterString = OAuth.buildParameterString(signatureParams);
// Build the signature string
var url = "https://"+request.host+""+request.path;
var url = "https://"+request.host+""+request.path;
var signatureString = OAuth.buildSignatureString(request.method, url, parameterString);
var signatureString = OAuth.buildSignatureString(request.method, url, parameterString);
// Hash the signature string
var signatureKey = [OAuth.encode(consumer_secret), OAuth.encode(auth_token_secret)].join("&");
var signatureKey = [OAuth.encode(consumer_secret), OAuth.encode(auth_token_secret)].join("&");
var signature = OAuth.signature(signatureString, signatureKey);
var signature = OAuth.signature(signatureString, signatureKey);
// Set the signature in the params
oauth_parameters.oauth_signature = signature;
if(!request.headers){
request.headers = {};
}
oauth_parameters.oauth_signature = signature;
if(!request.headers){
request.headers = {};
}
// Set the authorization header
var signature = Object.keys(oauth_parameters).sort().map(function(key){
var value = oauth_parameters[key];
return key+'="'+value+'"';
}).join(", ")
var authHeader = Object.keys(oauth_parameters).sort().map(function(key){
var value = oauth_parameters[key];
return key+'="'+value+'"';
}).join(", ")
request.headers.Authorization = 'OAuth ' + signature;
request.headers.Authorization = 'OAuth ' + authHeader;
// Set the content type header
request.headers["Content-Type"] = "application/x-www-form-urlencoded";
return request;
request.headers["Content-Type"] = "application/x-www-form-urlencoded";
return request;
}

View File

@@ -46,7 +46,7 @@ function graphRequest(path) {
data = JSON.parse(data);
resolve(data);
});
}).on('error', function(e) {
}).on('error', function() {
reject('Failed to validate this access token with Facebook.');
});
});

View File

@@ -39,7 +39,7 @@ function request(path, access_token) {
data = JSON.parse(data);
resolve(data);
});
}).on('error', function(e) {
}).on('error', function() {
reject('Failed to validate this access token with Github.');
});
});

View File

@@ -58,7 +58,7 @@ function request(path) {
data = JSON.parse(data);
resolve(data);
});
}).on('error', function(e) {
}).on('error', function() {
reject('Failed to validate this access token with Google.');
});
});

View File

@@ -79,7 +79,7 @@ module.exports = function(oauthOptions = {}, enableAnonymousUsers = true) {
if (optionalProvider.module) {
validateAuthData = require(optionalProvider.module).validateAuthData;
validateAppId = require(optionalProvider.module).validateAppId;
};
}
if (optionalProvider.validateAuthData) {
validateAuthData = optionalProvider.validateAuthData;
@@ -94,7 +94,7 @@ module.exports = function(oauthOptions = {}, enableAnonymousUsers = true) {
}
return function(authData) {
return validateAuthData(authData, optionalProvider).then(() => {
return validateAuthData(authData, optionalProvider).then(() => {
if (appIds) {
return validateAppId(appIds, authData, optionalProvider);
}

View File

@@ -32,7 +32,7 @@ function request(path) {
data = JSON.parse(data);
resolve(data);
});
}).on('error', function(e) {
}).on('error', function() {
reject('Failed to validate this access token with Instagram.');
});
});

View File

@@ -42,7 +42,7 @@ function request(host, access_token) {
res.on('end', function () {
resolve(JSON.parse(data));
});
}).on('error', function(e) {
}).on('error', function() {
reject('Failed to validate this access token with Janrain capture.');
});
});

View File

@@ -41,7 +41,7 @@ function request(api_key, auth_token) {
}
};
return new Promise(function (resolve, reject) {
return new Promise(function (resolve) {
// Create the post request.
var post_req = https.request(post_options, function (res) {
var data = '';

View File

@@ -45,7 +45,7 @@ function request(path, access_token, is_mobile_sdk) {
data = JSON.parse(data);
resolve(data);
});
}).on('error', function(e) {
}).on('error', function() {
reject('Failed to validate this access token with Linkedin.');
});
});

View File

@@ -38,7 +38,7 @@ function request(path, access_token) {
data = JSON.parse(data);
resolve(data);
});
}).on('error', function(e) {
}).on('error', function() {
reject('Failed to validate this access token with Meetup.');
});
});

View File

@@ -13,7 +13,7 @@ function validateAuthData(authData) {
}
// Returns a promise that fulfills if this app id is valid.
function validateAppId(appIds, authData) {
function validateAppId() {
return Promise.resolve();
}
@@ -35,7 +35,7 @@ function graphRequest(path) {
data = JSON.parse(data);
resolve(data);
});
}).on('error', function (e) {
}).on('error', function () {
reject('Failed to validate this access token with qq.');
});
});

View File

@@ -52,7 +52,7 @@ function request(path, access_token) {
data = JSON.parse(data);
resolve(data);
});
}).on('error', function(e) {
}).on('error', function() {
reject('Failed to validate this access token with Spotify.');
});
});

View File

@@ -33,7 +33,7 @@ function handleMultipleConfigurations(authData, options) {
logger.error('Twitter Auth', 'Multiple twitter configurations are available, by no consumer_key was sent by the client.');
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Twitter auth is invalid for this user.');
}
options = options.filter((option) => {
options = options.filter((option) => {
return option.consumer_key == consumer_key;
});

View File

@@ -50,7 +50,7 @@ function request(host, path) {
data = JSON.parse(data);
resolve(data);
});
}).on('error', function (e) {
}).on('error', function () {
reject('Failed to validate this access token with Vk.');
});
});

View File

@@ -13,7 +13,7 @@ function validateAuthData(authData) {
}
// Returns a promise that fulfills if this app id is valid.
function validateAppId(appIds, authData) {
function validateAppId() {
return Promise.resolve();
}
@@ -29,7 +29,7 @@ function graphRequest(path) {
data = JSON.parse(data);
resolve(data);
});
}).on('error', function (e) {
}).on('error', function () {
reject('Failed to validate this access token with weixin.');
});
});

View File

@@ -14,7 +14,7 @@ function validateAuthData(authData) {
}
// Returns a promise that fulfills if this app id is valid.
function validateAppId(appIds, authData) {
function validateAppId() {
return Promise.resolve();
}
@@ -42,11 +42,11 @@ function graphRequest(access_token) {
data = JSON.parse(data);
resolve(data);
});
res.on('error', function (err) {
res.on('error', function () {
reject('Failed to validate this access token with weibo.');
});
});
req.on('error', function (e){
req.on('error', function () {
reject('Failed to validate this access token with weibo.');
});
req.write(postData);

View File

@@ -13,7 +13,7 @@ function mountOnto(router) {
// Returns a promise for a {response} object.
// TODO: pass along auth correctly
function handleBatch(router, req) {
if (!req.body.requests instanceof Array) {
if (!Array.isArray(req.body.requests)) {
throw new Parse.Error(Parse.Error.INVALID_JSON,
'requests must be an array');
}

View File

@@ -1,11 +1,5 @@
import {
numberParser,
numberOrBoolParser,
objectParser,
arrayParser,
moduleOrObjectParser,
booleanParser,
nullParser
numberParser
} from '../utils/parsers';
@@ -40,9 +34,9 @@ export default {
help: "Optional. This string defines the log level of the LiveQuery server. We support VERBOSE, INFO, ERROR, NONE. Defaults to INFO.",
},
"port": {
env: "PORT",
help: "The port to run the ParseServer. defaults to 1337.",
default: 1337,
action: numberParser("port")
env: "PORT",
help: "The port to run the ParseServer. defaults to 1337.",
default: 1337,
action: numberParser("port")
},
};

View File

@@ -21,10 +21,10 @@ export default {
required: true
},
"port": {
env: "PORT",
help: "The port to run the ParseServer. defaults to 1337.",
default: 1337,
action: numberParser("port")
env: "PORT",
help: "The port to run the ParseServer. defaults to 1337.",
default: 1337,
action: numberParser("port")
},
"databaseURI": {
env: "PARSE_SERVER_DATABASE_URI",
@@ -150,11 +150,6 @@ export default {
help: "Adapter module for the logging sub-system",
action: moduleOrObjectParser
},
"liveQuery": {
env: "PARSE_SERVER_LIVE_QUERY_OPTIONS",
help: "liveQuery options",
action: objectParser
},
"customPages": {
env: "PARSE_SERVER_CUSTOM_PAGES",
help: "custom pages for password validation and reset",
@@ -210,7 +205,8 @@ export default {
help: "Run with cluster, optionally set the number of processes default to os.cpus().length",
action: numberOrBoolParser("cluster")
},
"liveQuery": {
"liveQuery": {
env: "PARSE_SERVER_LIVE_QUERY_OPTIONS",
help: "parse-server's LiveQuery configuration object",
action: objectParser
},

View File

@@ -1,4 +1,4 @@
import path from 'path';
/* eslint-disable no-console */
import express from 'express';
import { ParseServer } from '../index';
import definitions from './definitions/parse-server';
@@ -65,7 +65,7 @@ function startServer(options, callback) {
for (const socketId in sockets) {
try {
sockets[socketId].destroy();
} catch (e) { }
} catch (e) { /* */ }
}
}
@@ -115,12 +115,12 @@ runner({
for(var i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster.on('exit', (worker, code, signal) => {
console.log(`worker ${worker.process.pid} died... Restarting`);
cluster.on('exit', (worker, code) => {
console.log(`worker ${worker.process.pid} died (${code})... Restarting`);
cluster.fork();
});
} else {
startServer(options, () => {
startServer(options, () => {
console.log('['+process.pid+'] parse-server running on '+options.serverURL);
});
}
@@ -134,5 +134,4 @@ runner({
}
})
/* eslint-enable no-console */

View File

@@ -1,3 +1,4 @@
/* eslint-disable no-console */
import { Command } from 'commander';
import path from 'path';
let _definitions;
@@ -27,18 +28,18 @@ Command.prototype.loadDefinitions = function(definitions) {
}, {});
_reverseDefinitions = Object.keys(definitions).reduce((object, key) => {
let value = definitions[key];
if (typeof value == "object") {
value = value.env;
}
if (value) {
object[value] = key;
}
return object;
}, {});
let value = definitions[key];
if (typeof value == "object") {
value = value.env;
}
if (value) {
object[value] = key;
}
return object;
}, {});
/* istanbul ignore next */
this.on('--help', function(){
this.on('--help', function(){
console.log(' Configure From Environment:');
console.log('');
Object.keys(_reverseDefinitions).forEach((key) => {
@@ -93,9 +94,9 @@ function parseConfigFile(program) {
Command.prototype.setValuesIfNeeded = function(options) {
Object.keys(options).forEach((key) => {
if (!this[key]) {
this[key] = options[key];
}
if (!this[key]) {
this[key] = options[key];
}
});
}
@@ -124,3 +125,4 @@ Command.prototype.getOptions = function() {
}
export default new Command();
/* eslint-enable no-console */

View File

@@ -46,7 +46,7 @@ export function moduleOrObjectParser(opt) {
}
try {
return JSON.parse(opt);
} catch(e) {}
} catch(e) { /* */ }
return opt;
}

View File

@@ -1,6 +1,5 @@
import program from './commander';
import { mergeWithOptions } from './commander';
function logStartupOptions(options) {
for (let key in options) {
@@ -11,7 +10,9 @@ function logStartupOptions(options) {
if (typeof value === 'object') {
value = JSON.stringify(value);
}
/* eslint-disable no-console */
console.log(`${key}: ${value}`);
/* eslint-enable no-console */
}
}

View File

@@ -14,7 +14,7 @@ export default class HTTPResponse {
_data = body;
}
let getText = () => {
let getText = () => {
if (!_text && this.buffer) {
_text = this.buffer.toString('utf-8');
} else if (!_text && _data) {
@@ -26,8 +26,8 @@ export default class HTTPResponse {
let getData = () => {
if (!_data) {
try {
_data = JSON.parse(getText());
} catch (e) {}
_data = JSON.parse(getText());
} catch (e) { /* */ }
}
return _data;
}

View File

@@ -1,6 +1,6 @@
import {nullParser} from './cli/utils/parsers';
let logsFolder = (() => {
let logsFolder = (() => {
let folder = './logs/';
if (typeof process !== 'undefined' && process.env.NODE_ENV === 'test') {
folder = './test_logs/'
@@ -11,7 +11,7 @@ let logsFolder = (() => {
return folder;
})();
let { verbose, level } = (() => {
let { verbose, level } = (() => {
let verbose = process.env.VERBOSE ? true : false;
return { verbose, level: verbose ? 'verbose' : undefined }
})();

View File

@@ -142,21 +142,21 @@ export function handleParseHeaders(req, res, next) {
return;
}
return Promise.resolve().then(() => {
return Promise.resolve().then(() => {
// handle the upgradeToRevocableSession path on it's own
if (info.sessionToken &&
req.url === '/upgradeToRevocableSession' &&
info.sessionToken.indexOf('r:') != 0) {
return auth.getAuthForLegacySessionToken({ config: req.config, installationId: info.installationId, sessionToken: info.sessionToken })
return auth.getAuthForLegacySessionToken({ config: req.config, installationId: info.installationId, sessionToken: info.sessionToken })
} else {
return auth.getAuthForSessionToken({ config: req.config, installationId: info.installationId, sessionToken: info.sessionToken })
return auth.getAuthForSessionToken({ config: req.config, installationId: info.installationId, sessionToken: info.sessionToken })
}
}).then((auth) => {
if (auth) {
req.auth = auth;
next();
}
})
if (auth) {
req.auth = auth;
next();
}
})
.catch((error) => {
if(error instanceof Parse.Error) {
next(error);
@@ -221,7 +221,7 @@ export function allowCrossDomain(req, res, next) {
else {
next();
}
};
}
export function allowMethodOverride(req, res, next) {
if (req.method === 'POST' && req.body._method) {
@@ -230,7 +230,7 @@ export function allowMethodOverride(req, res, next) {
delete req.body._method;
}
next();
};
}
export function handleParseErrors(err, req, res, next) {
// TODO: Add logging as those errors won't make it to the PromiseRouter
@@ -258,10 +258,10 @@ export function handleParseErrors(err, req, res, next) {
log.error('Uncaught internal server error.', err, err.stack);
res.status(500);
res.json({code: Parse.Error.INTERNAL_SERVER_ERROR,
message: 'Internal server error.'});
message: 'Internal server error.'});
}
next(err);
};
}
export function enforceMasterKeyAccess(req, res, next) {
if (!req.auth.isMaster) {

View File

@@ -4,7 +4,7 @@ var bcrypt = require('bcryptjs');
try {
bcrypt = require('bcrypt');
} catch(e) {}
} catch(e) { /* */ }
// Returns a promise for a hashed password string.
function hash(password) {

View File

@@ -17,7 +17,7 @@ var triggers = require('./triggers');
// Returns a promise for an object with optional keys 'results' and 'count'.
function find(config, auth, className, restWhere, restOptions, clientSDK) {
enforceRoleSecurity('find', className, auth);
return triggers.maybeRunQueryTrigger(triggers.Types.beforeFind, className, restWhere, restOptions, config, auth).then((result) => {
return triggers.maybeRunQueryTrigger(triggers.Types.beforeFind, className, restWhere, restOptions, config, auth).then((result) => {
restWhere = result.restWhere || restWhere;
restOptions = result.restOptions || restOptions;
let query = new RestQuery(config, auth, className, restWhere, restOptions, clientSDK);
@@ -33,7 +33,7 @@ const get = (config, auth, className, objectId, restOptions, clientSDK) => {
}
// Returns a promise that doesn't resolve to any useful value.
function del(config, auth, className, objectId, clientSDK) {
function del(config, auth, className, objectId) {
if (typeof objectId !== 'string') {
throw new Parse.Error(Parse.Error.INVALID_JSON,
'bad objectId');

View File

@@ -1,6 +1,5 @@
// triggers.js
import Parse from 'parse/node';
import AppCache from './cache';
import { logger } from './logger';
export const Types = {
@@ -51,18 +50,18 @@ export function addTrigger(type, className, handler, applicationId) {
}
export function removeFunction(functionName, applicationId) {
applicationId = applicationId || Parse.applicationId;
delete _triggerStore[applicationId].Functions[functionName]
applicationId = applicationId || Parse.applicationId;
delete _triggerStore[applicationId].Functions[functionName]
}
export function removeJob(jobName, applicationId) {
applicationId = applicationId || Parse.applicationId;
delete _triggerStore[applicationId].Jobs[jobName]
applicationId = applicationId || Parse.applicationId;
delete _triggerStore[applicationId].Jobs[jobName]
}
export function removeTrigger(type, className, applicationId) {
applicationId = applicationId || Parse.applicationId;
delete _triggerStore[applicationId].Triggers[type][className]
applicationId = applicationId || Parse.applicationId;
delete _triggerStore[applicationId].Triggers[type][className]
}
export function _unregister(appId,category,className,type) {
@@ -90,7 +89,7 @@ export function getTrigger(className, triggerType, applicationId) {
return manager.Triggers[triggerType][className];
}
return undefined;
};
}
export function triggerExists(className: string, type: string, applicationId: string): boolean {
return (getTrigger(className, type, applicationId) != undefined);
@@ -100,7 +99,7 @@ export function getFunction(functionName, applicationId) {
var manager = _triggerStore[applicationId];
if (manager && manager.Functions) {
return manager.Functions[functionName];
};
}
return undefined;
}
@@ -108,7 +107,7 @@ export function getJob(jobName, applicationId) {
var manager = _triggerStore[applicationId];
if (manager && manager.Jobs) {
return manager.Jobs[jobName];
};
}
return undefined;
}
@@ -116,7 +115,7 @@ export function getJobs(applicationId) {
var manager = _triggerStore[applicationId];
if (manager && manager.Jobs) {
return manager.Jobs;
};
}
return undefined;
}
@@ -125,7 +124,7 @@ export function getValidator(functionName, applicationId) {
var manager = _triggerStore[applicationId];
if (manager && manager.Validators) {
return manager.Validators[functionName];
};
}
return undefined;
}
@@ -215,7 +214,7 @@ export function getResponseObject(request, resolve, reject) {
return reject(scriptError);
}
}
};
}
function userIdForLog(auth) {
return (auth && auth.user) ? auth.user.id : undefined;
@@ -258,12 +257,12 @@ export function maybeRunAfterFindTrigger(triggerType, auth, className, objects,
}
const request = getRequestObject(triggerType, auth, null, null, config);
const response = getResponseObject(request,
object => {
object => {
resolve(object);
},
error => {
error => {
reject(error);
});
});
logTriggerSuccessBeforeHook(triggerType, className, 'AfterFind', JSON.stringify(objects), auth);
request.objects = objects.map(object => {
//setting the class name to transform into parse object
@@ -297,23 +296,23 @@ export function maybeRunQueryTrigger(triggerType, className, restWhere, restOpti
let parseQuery = new Parse.Query(className);
if (restWhere) {
parseQuery._where = restWhere;
parseQuery._where = restWhere;
}
if (restOptions) {
if (restOptions.include && restOptions.include.length > 0) {
parseQuery._include = restOptions.include.split(',');
}
if (restOptions.skip) {
parseQuery._skip = restOptions.skip;
parseQuery._skip = restOptions.skip;
}
if (restOptions.limit) {
parseQuery._limit = restOptions.limit;
parseQuery._limit = restOptions.limit;
}
}
let requestObject = getRequestQueryObject(triggerType, auth, parseQuery, config);
return Promise.resolve().then(() => {
return Promise.resolve().then(() => {
return trigger(requestObject);
}).then((result) => {
}).then((result) => {
let queryResult = parseQuery;
if (result && result instanceof Parse.Query) {
queryResult = result;
@@ -338,7 +337,7 @@ export function maybeRunQueryTrigger(triggerType, className, restWhere, restOpti
restWhere,
restOptions
};
}, (err) => {
}, (err) => {
if (typeof err === 'string') {
throw new Parse.Error(1, err);
} else {
@@ -360,11 +359,11 @@ export function maybeRunTrigger(triggerType, auth, parseObject, originalParseObj
var trigger = getTrigger(parseObject.className, triggerType, config.applicationId);
if (!trigger) return resolve();
var request = getRequestObject(triggerType, auth, parseObject, originalParseObject, config);
var response = getResponseObject(request, (object) => {
var response = getResponseObject(request, (object) => {
logTriggerSuccessBeforeHook(
triggerType, parseObject.className, parseObject.toJSON(), object, auth);
resolve(object);
}, (error) => {
}, (error) => {
logTriggerErrorBeforeHook(
triggerType, parseObject.className, parseObject.toJSON(), auth, error);
reject(error);
@@ -382,16 +381,16 @@ export function maybeRunTrigger(triggerType, auth, parseObject, originalParseObj
var triggerPromise = trigger(request, response);
if(triggerType === Types.afterSave || triggerType === Types.afterDelete)
{
logTriggerAfterHook(triggerType, parseObject.className, parseObject.toJSON(), auth);
if(triggerPromise && typeof triggerPromise.then === "function") {
return triggerPromise.then(resolve, resolve);
}
else {
return resolve();
}
logTriggerAfterHook(triggerType, parseObject.className, parseObject.toJSON(), auth);
if(triggerPromise && typeof triggerPromise.then === "function") {
return triggerPromise.then(resolve, resolve);
}
else {
return resolve();
}
}
});
};
}
// Converts a REST-format object to a Parse.Object
// data is either className or an object

View File

@@ -120,18 +120,18 @@ Url.prototype.parse = function(url, parseQueryString, slashesDenoteHost) {
// Only convert backslashes while we haven't seen a split character
if (!split) {
switch (code) {
case 35: // '#'
hasHash = true;
case 35: // '#'
hasHash = true;
// Fall through
case 63: // '?'
split = true;
break;
case 92: // '\\'
if (i - lastPos > 0)
rest += url.slice(lastPos, i);
rest += '/';
lastPos = i + 1;
break;
case 63: // '?'
split = true;
break;
case 92: // '\\'
if (i - lastPos > 0)
rest += url.slice(lastPos, i);
rest += '/';
lastPos = i + 1;
break;
}
} else if (!hasHash && code === 35/*#*/) {
hasHash = true;
@@ -226,40 +226,40 @@ Url.prototype.parse = function(url, parseQueryString, slashesDenoteHost) {
var nonHost = -1;
for (i = 0; i < rest.length; ++i) {
switch (rest.charCodeAt(i)) {
case 9: // '\t'
case 10: // '\n'
case 13: // '\r'
case 32: // ' '
case 34: // '"'
case 37: // '%'
case 39: // '\''
case 59: // ';'
case 60: // '<'
case 62: // '>'
case 92: // '\\'
case 94: // '^'
case 96: // '`'
case 123: // '{'
case 124: // '|'
case 125: // '}'
case 9: // '\t'
case 10: // '\n'
case 13: // '\r'
case 32: // ' '
case 34: // '"'
case 37: // '%'
case 39: // '\''
case 59: // ';'
case 60: // '<'
case 62: // '>'
case 92: // '\\'
case 94: // '^'
case 96: // '`'
case 123: // '{'
case 124: // '|'
case 125: // '}'
// Characters that are never ever allowed in a hostname from RFC 2396
if (nonHost === -1)
nonHost = i;
break;
case 35: // '#'
case 47: // '/'
case 63: // '?'
if (nonHost === -1)
nonHost = i;
break;
case 35: // '#'
case 47: // '/'
case 63: // '?'
// Find the first instance of any host-ending characters
if (nonHost === -1)
nonHost = i;
hostEnd = i;
break;
case 64: // '@'
if (nonHost === -1)
nonHost = i;
hostEnd = i;
break;
case 64: // '@'
// At this point, either we have an explicit point where the
// auth portion cannot go past, or the last @ char is the decider.
atSign = i;
nonHost = -1;
break;
atSign = i;
nonHost = -1;
break;
}
if (hostEnd !== -1)
break;
@@ -440,90 +440,90 @@ function autoEscapeStr(rest) {
// Automatically escape all delimiters and unwise characters from RFC 2396
// Also escape single quotes in case of an XSS attack
switch (rest.charCodeAt(i)) {
case 9: // '\t'
if (i - lastPos > 0)
newRest += rest.slice(lastPos, i);
newRest += '%09';
lastPos = i + 1;
break;
case 10: // '\n'
if (i - lastPos > 0)
newRest += rest.slice(lastPos, i);
newRest += '%0A';
lastPos = i + 1;
break;
case 13: // '\r'
if (i - lastPos > 0)
newRest += rest.slice(lastPos, i);
newRest += '%0D';
lastPos = i + 1;
break;
case 32: // ' '
if (i - lastPos > 0)
newRest += rest.slice(lastPos, i);
newRest += '%20';
lastPos = i + 1;
break;
case 34: // '"'
if (i - lastPos > 0)
newRest += rest.slice(lastPos, i);
newRest += '%22';
lastPos = i + 1;
break;
case 39: // '\''
if (i - lastPos > 0)
newRest += rest.slice(lastPos, i);
newRest += '%27';
lastPos = i + 1;
break;
case 60: // '<'
if (i - lastPos > 0)
newRest += rest.slice(lastPos, i);
newRest += '%3C';
lastPos = i + 1;
break;
case 62: // '>'
if (i - lastPos > 0)
newRest += rest.slice(lastPos, i);
newRest += '%3E';
lastPos = i + 1;
break;
case 92: // '\\'
if (i - lastPos > 0)
newRest += rest.slice(lastPos, i);
newRest += '%5C';
lastPos = i + 1;
break;
case 94: // '^'
if (i - lastPos > 0)
newRest += rest.slice(lastPos, i);
newRest += '%5E';
lastPos = i + 1;
break;
case 96: // '`'
if (i - lastPos > 0)
newRest += rest.slice(lastPos, i);
newRest += '%60';
lastPos = i + 1;
break;
case 123: // '{'
if (i - lastPos > 0)
newRest += rest.slice(lastPos, i);
newRest += '%7B';
lastPos = i + 1;
break;
case 124: // '|'
if (i - lastPos > 0)
newRest += rest.slice(lastPos, i);
newRest += '%7C';
lastPos = i + 1;
break;
case 125: // '}'
if (i - lastPos > 0)
newRest += rest.slice(lastPos, i);
newRest += '%7D';
lastPos = i + 1;
break;
case 9: // '\t'
if (i - lastPos > 0)
newRest += rest.slice(lastPos, i);
newRest += '%09';
lastPos = i + 1;
break;
case 10: // '\n'
if (i - lastPos > 0)
newRest += rest.slice(lastPos, i);
newRest += '%0A';
lastPos = i + 1;
break;
case 13: // '\r'
if (i - lastPos > 0)
newRest += rest.slice(lastPos, i);
newRest += '%0D';
lastPos = i + 1;
break;
case 32: // ' '
if (i - lastPos > 0)
newRest += rest.slice(lastPos, i);
newRest += '%20';
lastPos = i + 1;
break;
case 34: // '"'
if (i - lastPos > 0)
newRest += rest.slice(lastPos, i);
newRest += '%22';
lastPos = i + 1;
break;
case 39: // '\''
if (i - lastPos > 0)
newRest += rest.slice(lastPos, i);
newRest += '%27';
lastPos = i + 1;
break;
case 60: // '<'
if (i - lastPos > 0)
newRest += rest.slice(lastPos, i);
newRest += '%3C';
lastPos = i + 1;
break;
case 62: // '>'
if (i - lastPos > 0)
newRest += rest.slice(lastPos, i);
newRest += '%3E';
lastPos = i + 1;
break;
case 92: // '\\'
if (i - lastPos > 0)
newRest += rest.slice(lastPos, i);
newRest += '%5C';
lastPos = i + 1;
break;
case 94: // '^'
if (i - lastPos > 0)
newRest += rest.slice(lastPos, i);
newRest += '%5E';
lastPos = i + 1;
break;
case 96: // '`'
if (i - lastPos > 0)
newRest += rest.slice(lastPos, i);
newRest += '%60';
lastPos = i + 1;
break;
case 123: // '{'
if (i - lastPos > 0)
newRest += rest.slice(lastPos, i);
newRest += '%7B';
lastPos = i + 1;
break;
case 124: // '|'
if (i - lastPos > 0)
newRest += rest.slice(lastPos, i);
newRest += '%7C';
lastPos = i + 1;
break;
case 125: // '}'
if (i - lastPos > 0)
newRest += rest.slice(lastPos, i);
newRest += '%7D';
lastPos = i + 1;
break;
}
}
if (lastPos === 0)
@@ -589,18 +589,18 @@ Url.prototype.format = function() {
var lastPos = 0;
for (var i = 0; i < pathname.length; ++i) {
switch (pathname.charCodeAt(i)) {
case 35: // '#'
if (i - lastPos > 0)
newPathname += pathname.slice(lastPos, i);
newPathname += '%23';
lastPos = i + 1;
break;
case 63: // '?'
if (i - lastPos > 0)
newPathname += pathname.slice(lastPos, i);
newPathname += '%3F';
lastPos = i + 1;
break;
case 35: // '#'
if (i - lastPos > 0)
newPathname += pathname.slice(lastPos, i);
newPathname += '%23';
lastPos = i + 1;
break;
case 63: // '?'
if (i - lastPos > 0)
newPathname += pathname.slice(lastPos, i);
newPathname += '%3F';
lastPos = i + 1;
break;
}
}
if (lastPos > 0) {