Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,13 @@ module.exports = [
curly: ["error", "all"],
"block-spacing": ["error", "always"],
"no-unused-vars": "off",
"no-restricted-syntax": [
"error",
{
selector: "BinaryExpression[operator='instanceof'][right.name='Array']",
message: "Use Array.isArray() instead of instanceof Array (cross-realm safe).",
},
],
"no-console": "warn"
},
},
Expand Down
28 changes: 28 additions & 0 deletions spec/DatabaseController.spec.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const Config = require('../lib/Config');
const DatabaseController = require('../lib/Controllers/DatabaseController.js');
const validateQuery = DatabaseController._validateQuery;
const vm = require('vm');

describe('DatabaseController', function () {
describe('validateQuery', function () {
Expand Down Expand Up @@ -55,6 +56,33 @@ describe('DatabaseController', function () {
expect(() => validateQuery({ $or: [{ a: 1 }, { b: 2 }] })).not.toThrow();
done();
});

it('should accept cross-realm arrays for $or', done => {
const query = {
$or: vm.runInNewContext('[{ a: 1 }, { b: 2 }]'),
};
expect(Array.isArray(query.$or)).toBe(true);
expect(() => validateQuery(query)).not.toThrow();
done();
});

it('should accept cross-realm arrays for $and', done => {
const query = {
$and: vm.runInNewContext('[{ a: 1 }, { b: 2 }]'),
};
expect(Array.isArray(query.$and)).toBe(true);
expect(() => validateQuery(query)).not.toThrow();
done();
});

it('should accept cross-realm arrays for $nor', done => {
const query = {
$nor: vm.runInNewContext('[{ a: 1 }]'),
};
expect(Array.isArray(query.$nor)).toBe(true);
expect(() => validateQuery(query)).not.toThrow();
done();
});
});

describe('addPointerPermissions', function () {
Expand Down
8 changes: 4 additions & 4 deletions spec/MongoStorageAdapter.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -243,15 +243,15 @@ describe_only_db('mongo')('MongoStorageAdapter', () => {
.then(results => {
expect(results.length).toEqual(1);
const mob = results[0];
expect(mob.array instanceof Array).toBe(true);
expect(Array.isArray(mob.array)).toBe(true);
expect(typeof mob.object).toBe('object');
expect(mob.date instanceof Date).toBe(true);
return adapter.find('MyClass', schema, {}, {});
})
.then(results => {
expect(results.length).toEqual(1);
const mob = results[0];
expect(mob.array instanceof Array).toBe(true);
expect(Array.isArray(mob.array)).toBe(true);
expect(typeof mob.object).toBe('object');
expect(mob.date.__type).toBe('Date');
expect(mob.date.iso).toBe('2016-05-26T20:55:01.154Z');
Expand Down Expand Up @@ -376,7 +376,7 @@ describe_only_db('mongo')('MongoStorageAdapter', () => {
})
.then(results => {
const mob = results;
expect(mob.array instanceof Array).toBe(true);
expect(Array.isArray(mob.array)).toBe(true);
expect(typeof mob.object).toBe('object');
expect(mob.date.__type).toBe('Date');
expect(mob.date.iso).toBe('2016-05-26T20:55:01.154Z');
Expand All @@ -385,7 +385,7 @@ describe_only_db('mongo')('MongoStorageAdapter', () => {
.then(results => {
expect(results.length).toEqual(1);
const mob = results[0];
expect(mob.array instanceof Array).toBe(true);
expect(Array.isArray(mob.array)).toBe(true);
expect(typeof mob.object).toBe('object');
expect(mob.date instanceof Date).toBe(true);
done();
Expand Down
4 changes: 2 additions & 2 deletions spec/ParseAPI.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -328,8 +328,8 @@ describe('miscellaneous', () => {
})
.then(obj2 => {
expect(obj2.get('date') instanceof Date).toBe(true);
expect(obj2.get('array') instanceof Array).toBe(true);
expect(obj2.get('object') instanceof Array).toBe(false);
expect(Array.isArray(obj2.get('array'))).toBe(true);
expect(Array.isArray(obj2.get('object'))).toBe(false);
expect(obj2.get('object') instanceof Object).toBe(true);
done();
});
Expand Down
7 changes: 7 additions & 0 deletions spec/eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,13 @@ module.exports = [
curly: ["error", "all"],
"block-spacing": ["error", "always"],
"no-unused-vars": "off",
"no-restricted-syntax": [
"error",
{
selector: "BinaryExpression[operator='instanceof'][right.name='Array']",
message: "Use Array.isArray() instead of instanceof Array (cross-realm safe).",
},
],
},
},
];
2 changes: 1 addition & 1 deletion spec/helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ function normalize(obj) {
if (obj === null || typeof obj !== 'object') {
return JSON.stringify(obj);
}
if (obj instanceof Array) {
if (Array.isArray(obj)) {
return '[' + obj.map(normalize).join(', ') + ']';
}
let answer = '{';
Expand Down
2 changes: 1 addition & 1 deletion spec/rest.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ describe('rest create', () => {
.then(results => {
expect(results.length).toEqual(1);
const mob = results[0];
expect(mob.array instanceof Array).toBe(true);
expect(Array.isArray(mob.array)).toBe(true);
expect(typeof mob.object).toBe('object');
expect(mob.date.__type).toBe('Date');
expect(new Date(mob.date.iso).getTime()).toBe(now.getTime());
Expand Down
36 changes: 18 additions & 18 deletions src/Adapters/Storage/Mongo/MongoTransform.js
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ const transformKeyValueForUpdate = (className, restKey, restValue, parseFormatSc
}

// Handle arrays
if (restValue instanceof Array) {
if (Array.isArray(restValue)) {
value = restValue.map(transformInteriorValue);
return { key, value };
}
Expand Down Expand Up @@ -192,7 +192,7 @@ const transformInteriorValue = restValue => {
if (value instanceof Date) {
return value;
}
if (value instanceof Array) {
if (Array.isArray(value)) {
value = value.map(transformInteriorValue);
} else {
value = mapValues(value, transformInteriorValue);
Expand All @@ -202,7 +202,7 @@ const transformInteriorValue = restValue => {
}

// Handle arrays
if (restValue instanceof Array) {
if (Array.isArray(restValue)) {
return restValue.map(transformInteriorValue);
}

Expand Down Expand Up @@ -338,7 +338,7 @@ function transformQueryKeyValue(className, key, value, schema, count = false) {
return { key, value: transformedConstraint };
}

if (expectedTypeIsArray && !(value instanceof Array)) {
if (expectedTypeIsArray && !Array.isArray(value)) {
return { key, value: { $all: [transformInteriorAtom(value)] } };
}

Expand Down Expand Up @@ -444,7 +444,7 @@ const parseObjectKeyValueToMongoObjectKeyValue = (restKey, restValue, schema) =>
}

// Handle arrays
if (restValue instanceof Array) {
if (Array.isArray(restValue)) {
value = restValue.map(transformInteriorValue);
return { key: restKey, value: value };
}
Expand Down Expand Up @@ -721,7 +721,7 @@ function transformConstraint(constraint, field, queryKey, count = false) {
case '$in':
case '$nin': {
const arr = constraint[key];
if (!(arr instanceof Array)) {
if (!Array.isArray(arr)) {
throw new Parse.Error(Parse.Error.INVALID_JSON, 'bad ' + key + ' value');
}
answer[key] = _.flatMap(arr, value => {
Expand All @@ -737,7 +737,7 @@ function transformConstraint(constraint, field, queryKey, count = false) {
}
case '$all': {
const arr = constraint[key];
if (!(arr instanceof Array)) {
if (!Array.isArray(arr)) {
throw new Parse.Error(Parse.Error.INVALID_JSON, 'bad ' + key + ' value');
}
answer[key] = arr.map(transformInteriorAtom);
Expand All @@ -762,7 +762,7 @@ function transformConstraint(constraint, field, queryKey, count = false) {

case '$containedBy': {
const arr = constraint[key];
if (!(arr instanceof Array)) {
if (!Array.isArray(arr)) {
throw new Parse.Error(Parse.Error.INVALID_JSON, `bad $containedBy: should be an array`);
}
answer.$elemMatch = {
Expand Down Expand Up @@ -872,7 +872,7 @@ function transformConstraint(constraint, field, queryKey, count = false) {
);
}
points = polygon.coordinates;
} else if (polygon instanceof Array) {
} else if (Array.isArray(polygon)) {
if (polygon.length < 3) {
throw new Parse.Error(
Parse.Error.INVALID_JSON,
Expand All @@ -887,7 +887,7 @@ function transformConstraint(constraint, field, queryKey, count = false) {
);
}
points = points.map(point => {
if (point instanceof Array && point.length === 2) {
if (Array.isArray(point) && point.length === 2) {
Parse.GeoPoint._validate(point[1], point[0]);
return point;
}
Expand All @@ -902,15 +902,15 @@ function transformConstraint(constraint, field, queryKey, count = false) {
$polygon: points,
};
} else if (centerSphere !== undefined) {
if (!(centerSphere instanceof Array) || centerSphere.length < 2) {
if (!Array.isArray(centerSphere) || centerSphere.length < 2) {
throw new Parse.Error(
Parse.Error.INVALID_JSON,
'bad $geoWithin value; $centerSphere should be an array of Parse.GeoPoint and distance'
);
}
// Get point, convert to geo point if necessary and validate
let point = centerSphere[0];
if (point instanceof Array && point.length === 2) {
if (Array.isArray(point) && point.length === 2) {
point = new Parse.GeoPoint(point[1], point[0]);
} else if (!GeoPointCoder.isValidJSON(point)) {
throw new Parse.Error(
Expand Down Expand Up @@ -999,7 +999,7 @@ function transformUpdateOperator({ __op, amount, objects }, flatten) {

case 'Add':
case 'AddUnique':
if (!(objects instanceof Array)) {
if (!Array.isArray(objects)) {
throw new Parse.Error(Parse.Error.INVALID_JSON, 'objects to add must be an array');
}
var toAdd = objects.map(transformInteriorAtom);
Expand All @@ -1014,7 +1014,7 @@ function transformUpdateOperator({ __op, amount, objects }, flatten) {
}

case 'Remove':
if (!(objects instanceof Array)) {
if (!Array.isArray(objects)) {
throw new Parse.Error(Parse.Error.INVALID_JSON, 'objects to remove must be an array');
}
var toRemove = objects.map(transformInteriorAtom);
Expand Down Expand Up @@ -1053,7 +1053,7 @@ const nestedMongoObjectToNestedParseObject = mongoObject => {
if (mongoObject === null) {
return null;
}
if (mongoObject instanceof Array) {
if (Array.isArray(mongoObject)) {
return mongoObject.map(nestedMongoObjectToNestedParseObject);
}

Expand Down Expand Up @@ -1116,7 +1116,7 @@ const mongoObjectToParseObject = (className, mongoObject, schema) => {
if (mongoObject === null) {
return null;
}
if (mongoObject instanceof Array) {
if (Array.isArray(mongoObject)) {
return mongoObject.map(nestedMongoObjectToNestedParseObject);
}

Expand Down Expand Up @@ -1347,7 +1347,7 @@ var GeoPointCoder = {
},

isValidDatabaseObject(object) {
return object instanceof Array && object.length == 2;
return Array.isArray(object) && object.length == 2;
},

JSONToDatabase(json) {
Expand All @@ -1373,7 +1373,7 @@ var PolygonCoder = {

isValidDatabaseObject(object) {
const coords = object.coordinates[0];
if (object.type !== 'Polygon' || !(coords instanceof Array)) {
if (object.type !== 'Polygon' || !Array.isArray(coords)) {
return false;
}
for (let i = 0; i < coords.length; i++) {
Expand Down
10 changes: 5 additions & 5 deletions src/Adapters/Storage/Postgres/PostgresStorageAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -572,7 +572,7 @@ const buildWhereClause = ({ schema, query, index, caseInsensitive }): WhereClaus

if (fieldValue.$containedBy) {
const arr = fieldValue.$containedBy;
if (!(arr instanceof Array)) {
if (!Array.isArray(arr)) {
throw new Parse.Error(Parse.Error.INVALID_JSON, `bad $containedBy: should be an array`);
}

Expand Down Expand Up @@ -654,15 +654,15 @@ const buildWhereClause = ({ schema, query, index, caseInsensitive }): WhereClaus

if (fieldValue.$geoWithin && fieldValue.$geoWithin.$centerSphere) {
const centerSphere = fieldValue.$geoWithin.$centerSphere;
if (!(centerSphere instanceof Array) || centerSphere.length < 2) {
if (!Array.isArray(centerSphere) || centerSphere.length < 2) {
throw new Parse.Error(
Parse.Error.INVALID_JSON,
'bad $geoWithin value; $centerSphere should be an array of Parse.GeoPoint and distance'
);
}
// Get point, convert to geo point if necessary and validate
let point = centerSphere[0];
if (point instanceof Array && point.length === 2) {
if (Array.isArray(point) && point.length === 2) {
point = new Parse.GeoPoint(point[1], point[0]);
} else if (!GeoPointCoder.isValidJSON(point)) {
throw new Parse.Error(
Expand Down Expand Up @@ -699,7 +699,7 @@ const buildWhereClause = ({ schema, query, index, caseInsensitive }): WhereClaus
);
}
points = polygon.coordinates;
} else if (polygon instanceof Array) {
} else if (Array.isArray(polygon)) {
if (polygon.length < 3) {
throw new Parse.Error(
Parse.Error.INVALID_JSON,
Expand All @@ -715,7 +715,7 @@ const buildWhereClause = ({ schema, query, index, caseInsensitive }): WhereClaus
}
points = points
.map(point => {
if (point instanceof Array && point.length === 2) {
if (Array.isArray(point) && point.length === 2) {
Parse.GeoPoint._validate(point[1], point[0]);
return `(${point[0]}, ${point[1]})`;
}
Expand Down
6 changes: 3 additions & 3 deletions src/Config.js
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,7 @@ export class Config {
}
if (pages.customRoutes === undefined) {
pages.customRoutes = PagesOptions.customRoutes.default;
} else if (!(pages.customRoutes instanceof Array)) {
} else if (!Array.isArray(pages.customRoutes)) {
throw 'Parse Server option pages.customRoutes must be an array.';
}
if (pages.encodePageParamHeaders === undefined) {
Expand All @@ -369,7 +369,7 @@ export class Config {
}
if (!idempotencyOptions.paths) {
idempotencyOptions.paths = IdempotencyOptions.paths.default;
} else if (!(idempotencyOptions.paths instanceof Array)) {
} else if (!Array.isArray(idempotencyOptions.paths)) {
throw 'idempotency paths must be of an array of strings';
}
}
Expand Down Expand Up @@ -536,7 +536,7 @@ export class Config {

static validateFileUploadOptions(fileUpload) {
try {
if (fileUpload == null || typeof fileUpload !== 'object' || fileUpload instanceof Array) {
if (fileUpload == null || typeof fileUpload !== 'object' || Array.isArray(fileUpload)) {
throw 'fileUpload must be an object value.';
}
} catch (e) {
Expand Down
Loading
Loading