mirror of
https://github.com/parse-community/parse-server
synced 2026-08-09 13:03:18 +00:00
fix: Pre-authentication denial of service via client version header regex backtracking ([GHSA-38m6-82c8-4xfm](https://github.com/parse-community/parse-server/security/advisories/GHSA-38m6-82c8-4xfm)) (#10464)
This commit is contained in:
@@ -1,49 +0,0 @@
|
||||
const ClientSDK = require('../lib/ClientSDK');
|
||||
|
||||
describe('ClientSDK', () => {
|
||||
it('should properly parse the SDK versions', () => {
|
||||
const clientSDKFromVersion = ClientSDK.fromString;
|
||||
expect(clientSDKFromVersion('i1.1.1')).toEqual({
|
||||
sdk: 'i',
|
||||
version: '1.1.1',
|
||||
});
|
||||
expect(clientSDKFromVersion('i1')).toEqual({
|
||||
sdk: 'i',
|
||||
version: '1',
|
||||
});
|
||||
expect(clientSDKFromVersion('apple-tv1.13.0')).toEqual({
|
||||
sdk: 'apple-tv',
|
||||
version: '1.13.0',
|
||||
});
|
||||
expect(clientSDKFromVersion('js1.9.0')).toEqual({
|
||||
sdk: 'js',
|
||||
version: '1.9.0',
|
||||
});
|
||||
});
|
||||
|
||||
it('should properly sastisfy', () => {
|
||||
expect(
|
||||
ClientSDK.compatible({
|
||||
js: '>=1.9.0',
|
||||
})('js1.9.0')
|
||||
).toBe(true);
|
||||
|
||||
expect(
|
||||
ClientSDK.compatible({
|
||||
js: '>=1.9.0',
|
||||
})('js2.0.0')
|
||||
).toBe(true);
|
||||
|
||||
expect(
|
||||
ClientSDK.compatible({
|
||||
js: '>=1.9.0',
|
||||
})('js1.8.0')
|
||||
).toBe(false);
|
||||
|
||||
expect(
|
||||
ClientSDK.compatible({
|
||||
js: '>=1.9.0',
|
||||
})(undefined)
|
||||
).toBe(true);
|
||||
});
|
||||
});
|
||||
@@ -112,7 +112,6 @@ describe('middlewares', () => {
|
||||
});
|
||||
|
||||
const BodyParams = {
|
||||
clientVersion: '_ClientVersion',
|
||||
installationId: '_InstallationId',
|
||||
sessionToken: '_SessionToken',
|
||||
masterKey: '_MasterKey',
|
||||
|
||||
@@ -5245,4 +5245,102 @@ describe('Vulnerabilities', () => {
|
||||
expect(meResponse.data.user).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('(GHSA-38m6-82c8-4xfm) Pre-auth polynomial ReDoS via client version parsing', () => {
|
||||
const middlewares = require('../lib/middlewares');
|
||||
const AppCache = require('../lib/cache').AppCache;
|
||||
|
||||
const AppCachePut = (appId, config) =>
|
||||
AppCache.put(appId, {
|
||||
...config,
|
||||
maintenanceKeyIpsStore: new Map(),
|
||||
masterKeyIpsStore: new Map(),
|
||||
readOnlyMasterKeyIpsStore: new Map(),
|
||||
});
|
||||
|
||||
const buildFakeReq = ({ headers = {}, body = {} } = {}) => {
|
||||
const req = {
|
||||
ip: '127.0.0.1',
|
||||
originalUrl: 'http://example.com/parse/',
|
||||
url: 'http://example.com/',
|
||||
body: { _ApplicationId: 'FakeAppId', ...body },
|
||||
headers,
|
||||
get: key => req.headers[key.toLowerCase()],
|
||||
};
|
||||
return req;
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
AppCachePut('FakeAppId', {
|
||||
masterKeyIps: ['0.0.0.0/0'],
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
AppCache.del('FakeAppId');
|
||||
});
|
||||
|
||||
it('does not capture client version from X-Parse-Client-Version header into req.info', async () => {
|
||||
const req = buildFakeReq({ headers: { 'x-parse-client-version': 'js5.0.0' } });
|
||||
const res = jasmine.createSpyObj('res', ['end', 'status']);
|
||||
let nextCalled = false;
|
||||
await middlewares.handleParseHeaders(req, res, () => {
|
||||
nextCalled = true;
|
||||
});
|
||||
expect(nextCalled).toBe(true);
|
||||
expect(res.status).not.toHaveBeenCalled();
|
||||
expect(req.info.clientVersion).toBeUndefined();
|
||||
expect(req.info.clientSDK).toBeUndefined();
|
||||
});
|
||||
|
||||
it('does not capture client version from _ClientVersion body field into req.info', async () => {
|
||||
const req = buildFakeReq({ body: { _ClientVersion: 'js5.0.0' } });
|
||||
const res = jasmine.createSpyObj('res', ['end', 'status']);
|
||||
let nextCalled = false;
|
||||
await middlewares.handleParseHeaders(req, res, () => {
|
||||
nextCalled = true;
|
||||
});
|
||||
expect(nextCalled).toBe(true);
|
||||
expect(res.status).not.toHaveBeenCalled();
|
||||
expect(req.info.clientVersion).toBeUndefined();
|
||||
expect(req.info.clientSDK).toBeUndefined();
|
||||
expect(req.body._ClientVersion).toBeUndefined();
|
||||
});
|
||||
|
||||
it('does not invoke any regex on adversarial X-Parse-Client-Version header (16 KB of dashes)', async () => {
|
||||
const adversarial = '-'.repeat(16000);
|
||||
const req = buildFakeReq({ headers: { 'x-parse-client-version': adversarial } });
|
||||
const res = jasmine.createSpyObj('res', ['end', 'status']);
|
||||
await middlewares.handleParseHeaders(req, res, () => {});
|
||||
expect(req.info.clientVersion).toBeUndefined();
|
||||
expect(req.info.clientSDK).toBeUndefined();
|
||||
});
|
||||
|
||||
it('does not invoke any regex on adversarial _ClientVersion body field (200 KB of dashes)', async () => {
|
||||
const adversarial = '-'.repeat(200000);
|
||||
const req = buildFakeReq({ body: { _ClientVersion: adversarial } });
|
||||
const res = jasmine.createSpyObj('res', ['end', 'status']);
|
||||
const t0 = process.hrtime.bigint();
|
||||
await middlewares.handleParseHeaders(req, res, () => {});
|
||||
const elapsedMs = Number(process.hrtime.bigint() - t0) / 1e6;
|
||||
expect(elapsedMs).toBeLessThan(3000);
|
||||
expect(req.info.clientVersion).toBeUndefined();
|
||||
expect(req.info.clientSDK).toBeUndefined();
|
||||
expect(req.body._ClientVersion).toBeUndefined();
|
||||
});
|
||||
|
||||
it('strips _ClientVersion from req.body even when value is non-string (no rejection, no capture)', async () => {
|
||||
const req = buildFakeReq({ body: { _ClientVersion: { toLowerCase: 'evil' } } });
|
||||
const res = jasmine.createSpyObj('res', ['end', 'status']);
|
||||
let nextCalled = false;
|
||||
await middlewares.handleParseHeaders(req, res, () => {
|
||||
nextCalled = true;
|
||||
});
|
||||
expect(nextCalled).toBe(true);
|
||||
expect(res.status).not.toHaveBeenCalled();
|
||||
expect(req.body._ClientVersion).toBeUndefined();
|
||||
expect(req.info.clientVersion).toBeUndefined();
|
||||
expect(req.info.clientSDK).toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
var semver = require('semver');
|
||||
|
||||
function compatible(compatibleSDK) {
|
||||
return function (clientSDK) {
|
||||
if (typeof clientSDK === 'string') {
|
||||
clientSDK = fromString(clientSDK);
|
||||
}
|
||||
// REST API, or custom SDK
|
||||
if (!clientSDK) {
|
||||
return true;
|
||||
}
|
||||
const clientVersion = clientSDK.version;
|
||||
const compatiblityVersion = compatibleSDK[clientSDK.sdk];
|
||||
return semver.satisfies(clientVersion, compatiblityVersion);
|
||||
};
|
||||
}
|
||||
|
||||
function supportsForwardDelete(clientSDK) {
|
||||
return compatible({
|
||||
js: '>=1.9.0',
|
||||
})(clientSDK);
|
||||
}
|
||||
|
||||
function fromString(version) {
|
||||
const versionRE = /([-a-zA-Z]+)([0-9\.]+)/;
|
||||
const match = version.toLowerCase().match(versionRE);
|
||||
if (match && match.length === 3) {
|
||||
return {
|
||||
sdk: match[1],
|
||||
version: match[2],
|
||||
};
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
compatible,
|
||||
supportsForwardDelete,
|
||||
fromString,
|
||||
};
|
||||
@@ -5,8 +5,7 @@ const createObject = async (className, fields, config, auth, info) => {
|
||||
fields = {};
|
||||
}
|
||||
|
||||
return (await rest.create(config, auth, className, fields, info.clientSDK, info.context))
|
||||
.response;
|
||||
return (await rest.create(config, auth, className, fields, info.context)).response;
|
||||
};
|
||||
|
||||
const updateObject = async (className, objectId, fields, config, auth, info) => {
|
||||
@@ -14,9 +13,7 @@ const updateObject = async (className, objectId, fields, config, auth, info) =>
|
||||
fields = {};
|
||||
}
|
||||
|
||||
return (
|
||||
await rest.update(config, auth, className, { objectId }, fields, info.clientSDK, info.context)
|
||||
).response;
|
||||
return (await rest.update(config, auth, className, { objectId }, fields, info.context)).response;
|
||||
};
|
||||
|
||||
const deleteObject = async (className, objectId, config, auth, info) => {
|
||||
|
||||
@@ -69,7 +69,6 @@ const getObject = async (
|
||||
className,
|
||||
objectId,
|
||||
options,
|
||||
info.clientSDK,
|
||||
info.context
|
||||
);
|
||||
|
||||
@@ -131,9 +130,8 @@ const findObjects = async (
|
||||
if (Object.keys(where).length > 0 && subqueryReadPreference) {
|
||||
preCountOptions.subqueryReadPreference = subqueryReadPreference;
|
||||
}
|
||||
preCount = (
|
||||
await rest.find(config, auth, className, where, preCountOptions, info.clientSDK, info.context)
|
||||
).count;
|
||||
preCount = (await rest.find(config, auth, className, where, preCountOptions, info.context))
|
||||
.count;
|
||||
if ((skip || 0) + limit < preCount) {
|
||||
skip = preCount - limit;
|
||||
}
|
||||
@@ -199,7 +197,6 @@ const findObjects = async (
|
||||
className,
|
||||
where,
|
||||
options,
|
||||
info.clientSDK,
|
||||
info.context
|
||||
);
|
||||
results = findResult.results;
|
||||
|
||||
@@ -59,7 +59,6 @@ const getUserFromSessionToken = async (context, queryInfo, keysPrefix, userId) =
|
||||
// Get the user it self from auth object
|
||||
{ objectId: context.auth.user.id },
|
||||
options,
|
||||
info.clientVersion,
|
||||
info.context
|
||||
);
|
||||
if (!response.results || response.results.length == 0) {
|
||||
|
||||
+1
-8
@@ -31,7 +31,6 @@ const { createSanitizedError } = require('./Error');
|
||||
* @param options.className {string} The name of the class to query
|
||||
* @param options.restWhere {object} The where object for the query
|
||||
* @param options.restOptions {object} The options object for the query
|
||||
* @param options.clientSDK {string} The client SDK that is performing the query
|
||||
* @param options.runAfterFind {boolean} Whether to run the afterFind trigger
|
||||
* @param options.runBeforeFind {boolean} Whether to run the beforeFind trigger
|
||||
* @param options.context {object} The context object for the query
|
||||
@@ -44,7 +43,6 @@ async function RestQuery({
|
||||
className,
|
||||
restWhere = {},
|
||||
restOptions = {},
|
||||
clientSDK,
|
||||
runAfterFind = true,
|
||||
runBeforeFind = true,
|
||||
context,
|
||||
@@ -73,7 +71,6 @@ async function RestQuery({
|
||||
className,
|
||||
result.restWhere || restWhere,
|
||||
result.restOptions || restOptions,
|
||||
clientSDK,
|
||||
runAfterFind,
|
||||
context,
|
||||
isGet
|
||||
@@ -93,7 +90,6 @@ RestQuery.Method = Object.freeze({
|
||||
* @param className
|
||||
* @param restWhere
|
||||
* @param restOptions
|
||||
* @param clientSDK
|
||||
* @param runAfterFind
|
||||
* @param context
|
||||
*/
|
||||
@@ -103,7 +99,6 @@ function _UnsafeRestQuery(
|
||||
className,
|
||||
restWhere = {},
|
||||
restOptions = {},
|
||||
clientSDK,
|
||||
runAfterFind = true,
|
||||
context,
|
||||
isGet
|
||||
@@ -113,7 +108,6 @@ function _UnsafeRestQuery(
|
||||
this.className = className;
|
||||
this.restWhere = restWhere;
|
||||
this.restOptions = restOptions;
|
||||
this.clientSDK = clientSDK;
|
||||
this.runAfterFind = runAfterFind;
|
||||
this.response = null;
|
||||
this.findOptions = {};
|
||||
@@ -320,7 +314,7 @@ _UnsafeRestQuery.prototype.execute = function (executeOptions) {
|
||||
};
|
||||
|
||||
_UnsafeRestQuery.prototype.each = function (callback) {
|
||||
const { config, auth, className, restWhere, restOptions, clientSDK } = this;
|
||||
const { config, auth, className, restWhere, restOptions } = this;
|
||||
// if the limit is set, use it
|
||||
restOptions.limit = restOptions.limit || 100;
|
||||
restOptions.order = 'objectId';
|
||||
@@ -339,7 +333,6 @@ _UnsafeRestQuery.prototype.each = function (callback) {
|
||||
className,
|
||||
restWhere,
|
||||
restOptions,
|
||||
clientSDK,
|
||||
this.runAfterFind,
|
||||
this.context
|
||||
);
|
||||
|
||||
+2
-6
@@ -11,7 +11,6 @@ var cryptoUtils = require('./cryptoUtils');
|
||||
var passwordCrypto = require('./password');
|
||||
var Parse = require('parse/node');
|
||||
var triggers = require('./triggers');
|
||||
var ClientSDK = require('./ClientSDK');
|
||||
const util = require('util');
|
||||
import RestQuery from './RestQuery';
|
||||
import _ from 'lodash';
|
||||
@@ -29,7 +28,7 @@ import { createSanitizedError } from './Error';
|
||||
// RestWrite will handle objectId, createdAt, and updatedAt for
|
||||
// everything. It also knows to use triggers and special modifications
|
||||
// for the _User class.
|
||||
function RestWrite(config, auth, className, query, data, originalData, clientSDK, context, action) {
|
||||
function RestWrite(config, auth, className, query, data, originalData, context, action) {
|
||||
if (auth.isReadOnly) {
|
||||
throw createSanitizedError(
|
||||
Parse.Error.OPERATION_FORBIDDEN,
|
||||
@@ -40,7 +39,6 @@ function RestWrite(config, auth, className, query, data, originalData, clientSDK
|
||||
this.config = config;
|
||||
this.auth = auth;
|
||||
this.className = className;
|
||||
this.clientSDK = clientSDK;
|
||||
this.storage = {};
|
||||
this.runOptions = {};
|
||||
this.context = context || {};
|
||||
@@ -1897,7 +1895,6 @@ RestWrite.prototype._updateResponseWithData = function (response, data) {
|
||||
if (_.isEmpty(this.storage.fieldsChangedByTrigger)) {
|
||||
return response;
|
||||
}
|
||||
const clientSupportsDelete = ClientSDK.supportsForwardDelete(this.clientSDK);
|
||||
this.storage.fieldsChangedByTrigger.forEach(fieldName => {
|
||||
const dataValue = data[fieldName];
|
||||
|
||||
@@ -1905,10 +1902,9 @@ RestWrite.prototype._updateResponseWithData = function (response, data) {
|
||||
response[fieldName] = dataValue;
|
||||
}
|
||||
|
||||
// Strips operations from responses
|
||||
if (response[fieldName] && response[fieldName].__op) {
|
||||
delete response[fieldName];
|
||||
if (clientSupportsDelete && dataValue.__op == 'Delete') {
|
||||
if (dataValue.__op == 'Delete') {
|
||||
response[fieldName] = dataValue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,6 @@ export class AggregateRouter extends ClassesRouter {
|
||||
this.className(req),
|
||||
body.where,
|
||||
options,
|
||||
req.info.clientSDK,
|
||||
req.info.context
|
||||
);
|
||||
for (const result of response.results) {
|
||||
|
||||
@@ -18,7 +18,6 @@ export class AudiencesRouter extends ClassesRouter {
|
||||
'_Audience',
|
||||
body.where,
|
||||
options,
|
||||
req.info.clientSDK,
|
||||
req.info.context
|
||||
)
|
||||
.then(response => {
|
||||
|
||||
@@ -39,7 +39,6 @@ export class ClassesRouter extends PromiseRouter {
|
||||
this.className(req),
|
||||
body.where,
|
||||
options,
|
||||
req.info.clientSDK,
|
||||
req.info.context
|
||||
)
|
||||
.then(response => {
|
||||
@@ -84,7 +83,6 @@ export class ClassesRouter extends PromiseRouter {
|
||||
this.className(req),
|
||||
req.params.objectId,
|
||||
options,
|
||||
req.info.clientSDK,
|
||||
req.info.context
|
||||
)
|
||||
.then(response => {
|
||||
@@ -119,7 +117,6 @@ export class ClassesRouter extends PromiseRouter {
|
||||
req.auth,
|
||||
this.className(req),
|
||||
req.body || {},
|
||||
req.info.clientSDK,
|
||||
req.info.context
|
||||
);
|
||||
}
|
||||
@@ -132,7 +129,6 @@ export class ClassesRouter extends PromiseRouter {
|
||||
this.className(req),
|
||||
where,
|
||||
req.body || {},
|
||||
req.info.clientSDK,
|
||||
req.info.context
|
||||
);
|
||||
}
|
||||
|
||||
@@ -51,7 +51,6 @@ function getFileForProductIdentifier(productIdentifier, req) {
|
||||
'_Product',
|
||||
{ productIdentifier: productIdentifier },
|
||||
undefined,
|
||||
req.info.clientSDK,
|
||||
req.info.context
|
||||
)
|
||||
.then(function (result) {
|
||||
|
||||
@@ -19,7 +19,6 @@ export class InstallationsRouter extends ClassesRouter {
|
||||
'_Installation',
|
||||
body.where,
|
||||
options,
|
||||
req.info.clientSDK,
|
||||
req.info.context
|
||||
)
|
||||
.then(response => {
|
||||
|
||||
@@ -21,7 +21,6 @@ export class SessionsRouter extends ClassesRouter {
|
||||
'_Session',
|
||||
{ sessionToken },
|
||||
{},
|
||||
req.info.clientSDK,
|
||||
req.info.context
|
||||
);
|
||||
if (
|
||||
@@ -47,7 +46,6 @@ export class SessionsRouter extends ClassesRouter {
|
||||
'_Session',
|
||||
sessionObjectId,
|
||||
{},
|
||||
req.info.clientSDK,
|
||||
req.info.context
|
||||
);
|
||||
if (!response.results || response.results.length == 0) {
|
||||
|
||||
@@ -195,7 +195,6 @@ export class UsersRouter extends ClassesRouter {
|
||||
'_Session',
|
||||
{ sessionToken },
|
||||
{},
|
||||
req.info.clientSDK,
|
||||
req.info.context
|
||||
);
|
||||
if (
|
||||
@@ -214,7 +213,6 @@ export class UsersRouter extends ClassesRouter {
|
||||
'_User',
|
||||
userId,
|
||||
{},
|
||||
req.info.clientSDK,
|
||||
req.info.context
|
||||
);
|
||||
if (!userResponse.results || userResponse.results.length == 0) {
|
||||
@@ -251,7 +249,6 @@ export class UsersRouter extends ClassesRouter {
|
||||
{ objectId: user.objectId },
|
||||
req.body || {},
|
||||
user,
|
||||
req.info.clientSDK,
|
||||
req.info.context
|
||||
),
|
||||
user
|
||||
@@ -438,7 +435,6 @@ export class UsersRouter extends ClassesRouter {
|
||||
'_Session',
|
||||
{ sessionToken: req.info.sessionToken },
|
||||
undefined,
|
||||
req.info.clientSDK,
|
||||
req.info.context
|
||||
);
|
||||
if (records.results && records.results.length) {
|
||||
|
||||
+1
-10
@@ -2,7 +2,6 @@ import AppCache from './cache';
|
||||
import Parse from 'parse/node';
|
||||
import auth from './Auth';
|
||||
import Config from './Config';
|
||||
import ClientSDK from './ClientSDK';
|
||||
import defaultLogger from './logger';
|
||||
import rest from './rest';
|
||||
import MongoStorageAdapter from './Adapters/Storage/Mongo/MongoStorageAdapter';
|
||||
@@ -94,7 +93,6 @@ export async function handleParseHeaders(req, res, next) {
|
||||
javascriptKey: req.get('X-Parse-Javascript-Key'),
|
||||
dotNetKey: req.get('X-Parse-Windows-Key'),
|
||||
restAPIKey: req.get('X-Parse-REST-API-Key'),
|
||||
clientVersion: req.get('X-Parse-Client-Version'),
|
||||
context: context,
|
||||
};
|
||||
|
||||
@@ -149,10 +147,7 @@ export async function handleParseHeaders(req, res, next) {
|
||||
delete req.body._JavaScriptKey;
|
||||
// TODO: test that the REST API formats generated by the other
|
||||
// SDKs are handled ok
|
||||
if (req.body._ClientVersion) {
|
||||
info.clientVersion = req.body._ClientVersion;
|
||||
delete req.body._ClientVersion;
|
||||
}
|
||||
delete req.body._ClientVersion;
|
||||
if (req.body._InstallationId) {
|
||||
info.installationId = req.body._InstallationId;
|
||||
delete req.body._InstallationId;
|
||||
@@ -193,10 +188,6 @@ export async function handleParseHeaders(req, res, next) {
|
||||
info.sessionToken = info.sessionToken.toString();
|
||||
}
|
||||
|
||||
if (info.clientVersion) {
|
||||
info.clientSDK = ClientSDK.fromString(info.clientVersion);
|
||||
}
|
||||
|
||||
if (fileViaJSON && req.body) {
|
||||
req.fileData = req.body.fileData;
|
||||
// We need to repopulate req.body with a buffer
|
||||
|
||||
+5
-11
@@ -30,7 +30,6 @@ async function runFindTriggers(
|
||||
className,
|
||||
restWhere,
|
||||
restOptions,
|
||||
clientSDK,
|
||||
context,
|
||||
options = {}
|
||||
) {
|
||||
@@ -89,7 +88,6 @@ async function runFindTriggers(
|
||||
className,
|
||||
restWhere: refilterWhere,
|
||||
restOptions,
|
||||
clientSDK,
|
||||
context,
|
||||
runBeforeFind: false,
|
||||
runAfterFind: false,
|
||||
@@ -125,7 +123,6 @@ async function runFindTriggers(
|
||||
className,
|
||||
restWhere,
|
||||
restOptions,
|
||||
clientSDK,
|
||||
context,
|
||||
runBeforeFind: false,
|
||||
});
|
||||
@@ -134,7 +131,7 @@ async function runFindTriggers(
|
||||
}
|
||||
|
||||
// Returns a promise for an object with optional keys 'results' and 'count'.
|
||||
const find = async (config, auth, className, restWhere, restOptions, clientSDK, context) => {
|
||||
const find = async (config, auth, className, restWhere, restOptions, context) => {
|
||||
enforceRoleSecurity('find', className, auth, config);
|
||||
return runFindTriggers(
|
||||
config,
|
||||
@@ -142,14 +139,13 @@ const find = async (config, auth, className, restWhere, restOptions, clientSDK,
|
||||
className,
|
||||
restWhere,
|
||||
restOptions,
|
||||
clientSDK,
|
||||
context,
|
||||
{ isGet: false }
|
||||
);
|
||||
};
|
||||
|
||||
// get is just like find but only queries an objectId.
|
||||
const get = async (config, auth, className, objectId, restOptions, clientSDK, context) => {
|
||||
const get = async (config, auth, className, objectId, restOptions, context) => {
|
||||
enforceRoleSecurity('get', className, auth, config);
|
||||
return runFindTriggers(
|
||||
config,
|
||||
@@ -157,7 +153,6 @@ const get = async (config, auth, className, objectId, restOptions, clientSDK, co
|
||||
className,
|
||||
{ objectId },
|
||||
restOptions,
|
||||
clientSDK,
|
||||
context,
|
||||
{ isGet: true }
|
||||
);
|
||||
@@ -263,16 +258,16 @@ function del(config, auth, className, objectId, context) {
|
||||
}
|
||||
|
||||
// Returns a promise for a {response, status, location} object.
|
||||
function create(config, auth, className, restObject, clientSDK, context) {
|
||||
function create(config, auth, className, restObject, context) {
|
||||
enforceRoleSecurity('create', className, auth, config);
|
||||
var write = new RestWrite(config, auth, className, null, restObject, null, clientSDK, context);
|
||||
var write = new RestWrite(config, auth, className, null, restObject, null, context);
|
||||
return write.execute();
|
||||
}
|
||||
|
||||
// Returns a promise that contains the fields of the update that the
|
||||
// REST API is supposed to return.
|
||||
// Usually, this is just updatedAt.
|
||||
function update(config, auth, className, restWhere, restObject, clientSDK, context) {
|
||||
function update(config, auth, className, restWhere, restObject, context) {
|
||||
enforceRoleSecurity('update', className, auth, config);
|
||||
|
||||
return Promise.resolve()
|
||||
@@ -309,7 +304,6 @@ function update(config, auth, className, restWhere, restObject, clientSDK, conte
|
||||
restWhere,
|
||||
restObject,
|
||||
originalRestObject,
|
||||
clientSDK,
|
||||
context,
|
||||
'update'
|
||||
).execute();
|
||||
|
||||
Reference in New Issue
Block a user