Skip to content

Commit

Permalink
Merge pull request #8408 from RocketChat/rest-api-improve-json-query-…
Browse files Browse the repository at this point in the history
…helper

[FIX] Duplicate code in rest api letting in a few bugs with the rest api
  • Loading branch information
rodrigok committed Oct 9, 2017
1 parent cc6fad4 commit 17472d8
Show file tree
Hide file tree
Showing 7 changed files with 73 additions and 46 deletions.
19 changes: 18 additions & 1 deletion packages/rocketchat-api/server/api.js
Expand Up @@ -5,11 +5,28 @@ class API extends Restivus {
this.logger = new Logger(`API ${ properties.version ? properties.version : 'default' } Logger`, {});
this.authMethods = [];
this.helperMethods = new Map();
this.fieldSeparator = '.';
this.defaultFieldsToExclude = {
joinCode: 0,
$loki: 0,
meta: 0,
members: 0
members: 0,
importIds: 0
};
this.limitedUserFieldsToExclude = {
avatarOrigin: 0,
emails: 0,
phone: 0,
statusConnection: 0,
createdAt: 0,
lastLogin: 0,
services: 0,
requirePasswordChange: 0,
requirePasswordChangeReason: 0,
roles: 0,
statusDefault: 0,
_updatedAt: 0,
customFields: 0
};

this._config.defaultOptionsEndpoint = function() {
Expand Down
10 changes: 5 additions & 5 deletions packages/rocketchat-api/server/v1/channels.js
Expand Up @@ -191,7 +191,7 @@ RocketChat.API.v1.addRoute('channels.files', { authRequired: true }, {
sort: sort ? sort : { name: 1 },
skip: offset,
limit: count,
fields: Object.assign({}, fields, RocketChat.API.v1.defaultFieldsToExclude)
fields
}).fetch();

return RocketChat.API.v1.success({
Expand Down Expand Up @@ -235,7 +235,7 @@ RocketChat.API.v1.addRoute('channels.getIntegrations', { authRequired: true }, {
sort: sort ? sort : { _createdAt: 1 },
skip: offset,
limit: count,
fields: Object.assign({}, fields, RocketChat.API.v1.defaultFieldsToExclude)
fields
}).fetch();

return RocketChat.API.v1.success({
Expand Down Expand Up @@ -381,7 +381,7 @@ RocketChat.API.v1.addRoute('channels.list', { authRequired: true }, {
sort: sort ? sort : { name: 1 },
skip: offset,
limit: count,
fields: Object.assign({}, fields, RocketChat.API.v1.defaultFieldsToExclude)
fields
}).fetch();

return RocketChat.API.v1.success({
Expand All @@ -405,7 +405,7 @@ RocketChat.API.v1.addRoute('channels.list.joined', { authRequired: true }, {
sort: sort ? sort : { name: 1 },
skip: offset,
limit: count,
fields: Object.assign({}, fields, RocketChat.API.v1.defaultFieldsToExclude)
fields
});

return RocketChat.API.v1.success({
Expand Down Expand Up @@ -461,7 +461,7 @@ RocketChat.API.v1.addRoute('channels.messages', { authRequired: true }, {
sort: sort ? sort : { ts: -1 },
skip: offset,
limit: count,
fields: Object.assign({}, fields, RocketChat.API.v1.defaultFieldsToExclude)
fields
}).fetch();

return RocketChat.API.v1.success({
Expand Down
10 changes: 5 additions & 5 deletions packages/rocketchat-api/server/v1/groups.js
Expand Up @@ -167,7 +167,7 @@ RocketChat.API.v1.addRoute('groups.files', { authRequired: true }, {
sort: sort ? sort : { name: 1 },
skip: offset,
limit: count,
fields: Object.assign({}, fields, RocketChat.API.v1.defaultFieldsToExclude)
fields
}).fetch();

return RocketChat.API.v1.success({
Expand Down Expand Up @@ -205,7 +205,7 @@ RocketChat.API.v1.addRoute('groups.getIntegrations', { authRequired: true }, {
sort: sort ? sort : { _createdAt: 1 },
skip: offset,
limit: count,
fields: Object.assign({}, fields, RocketChat.API.v1.defaultFieldsToExclude)
fields
}).fetch();

return RocketChat.API.v1.success({
Expand Down Expand Up @@ -323,7 +323,7 @@ RocketChat.API.v1.addRoute('groups.list', { authRequired: true }, {
sort: sort ? sort : { name: 1 },
skip: offset,
limit: count,
fields: Object.assign({}, fields, RocketChat.API.v1.defaultFieldsToExclude)
fields
});

return RocketChat.API.v1.success({
Expand All @@ -350,7 +350,7 @@ RocketChat.API.v1.addRoute('groups.listAll', { authRequired: true }, {
sort: sort ? sort : { name: 1 },
skip: offset,
limit: count,
fields: Object.assign({}, fields, RocketChat.API.v1.defaultFieldsToExclude)
fields
});

return RocketChat.API.v1.success({
Expand Down Expand Up @@ -398,7 +398,7 @@ RocketChat.API.v1.addRoute('groups.messages', { authRequired: true }, {
sort: sort ? sort : { ts: -1 },
skip: offset,
limit: count,
fields: Object.assign({}, fields, RocketChat.API.v1.defaultFieldsToExclude)
fields
}).fetch();

return RocketChat.API.v1.success({
Expand Down
34 changes: 34 additions & 0 deletions packages/rocketchat-api/server/v1/helpers/parseJsonQuery.js
Expand Up @@ -19,6 +19,26 @@ RocketChat.API.v1.helperMethods.set('parseJsonQuery', function _parseJsonQuery()
}
}

// Verify the user's selected fields only contains ones which their role allows
if (typeof fields === 'object') {
let nonSelectableFields = Object.keys(RocketChat.API.v1.defaultFieldsToExclude);
if (!RocketChat.authz.hasPermission(this.userId, 'view-full-other-user-info') && this.request.route.includes('/v1/users.')) {
nonSelectableFields = nonSelectableFields.concat(Object.keys(RocketChat.API.v1.limitedUserFieldsToExclude));
}

Object.keys(fields).forEach((k) => {
if (nonSelectableFields.includes(k) || nonSelectableFields.includes(k.split(RocketChat.API.v1.fieldSeparator)[0])) {
delete fields[k];
}
});
}

// Limit the fields by default
fields = Object.assign({}, fields, RocketChat.API.v1.defaultFieldsToExclude);
if (!RocketChat.authz.hasPermission(this.userId, 'view-full-other-user-info') && this.request.route.includes('/v1/users.')) {
fields = Object.assign(fields, RocketChat.API.v1.limitedUserFieldsToExclude);
}

let query;
if (this.queryParams.query) {
try {
Expand All @@ -29,6 +49,20 @@ RocketChat.API.v1.helperMethods.set('parseJsonQuery', function _parseJsonQuery()
}
}

// Verify the user has permission to query the fields they are
if (typeof query === 'object') {
let nonQuerableFields = Object.keys(RocketChat.API.v1.defaultFieldsToExclude);
if (!RocketChat.authz.hasPermission(this.userId, 'view-full-other-user-info') && this.request.route.includes('/v1/users.')) {
nonQuerableFields = nonQuerableFields.concat(Object.keys(RocketChat.API.v1.limitedUserFieldsToExclude));
}

Object.keys(query).forEach((k) => {
if (nonQuerableFields.includes(k) || nonQuerableFields.includes(k.split(RocketChat.API.v1.fieldSeparator)[0])) {
delete query[k];
}
});
}

return {
sort,
fields,
Expand Down
10 changes: 5 additions & 5 deletions packages/rocketchat-api/server/v1/im.js
Expand Up @@ -60,7 +60,7 @@ RocketChat.API.v1.addRoute(['dm.files', 'im.files'], { authRequired: true }, {
sort: sort ? sort : { name: 1 },
skip: offset,
limit: count,
fields: Object.assign({}, fields, RocketChat.API.v1.defaultFieldsToExclude)
fields
}).fetch();

return RocketChat.API.v1.success({
Expand Down Expand Up @@ -160,7 +160,7 @@ RocketChat.API.v1.addRoute(['dm.messages', 'im.messages'], { authRequired: true
sort: sort ? sort : { ts: -1 },
skip: offset,
limit: count,
fields: Object.assign({}, fields, RocketChat.API.v1.defaultFieldsToExclude)
fields
}).fetch();

return RocketChat.API.v1.success({
Expand Down Expand Up @@ -200,7 +200,7 @@ RocketChat.API.v1.addRoute(['dm.messages.others', 'im.messages.others'], { authR
sort: sort ? sort : { ts: -1 },
skip: offset,
limit: count,
fields: Object.assign({}, fields, RocketChat.API.v1.defaultFieldsToExclude)
fields
}).fetch();

return RocketChat.API.v1.success({
Expand All @@ -223,7 +223,7 @@ RocketChat.API.v1.addRoute(['dm.list', 'im.list'], { authRequired: true }, {
sort: sort ? sort : { name: 1 },
skip: offset,
limit: count,
fields: Object.assign({}, fields, RocketChat.API.v1.defaultFieldsToExclude)
fields
});

return RocketChat.API.v1.success({
Expand All @@ -250,7 +250,7 @@ RocketChat.API.v1.addRoute(['dm.list.everyone', 'im.list.everyone'], { authRequi
sort: sort ? sort : { name: 1 },
skip: offset,
limit: count,
fields: Object.assign({}, fields, RocketChat.API.v1.defaultFieldsToExclude)
fields
}).fetch();

return RocketChat.API.v1.success({
Expand Down
8 changes: 3 additions & 5 deletions packages/rocketchat-api/server/v1/stats.js
Expand Up @@ -25,20 +25,18 @@ RocketChat.API.v1.addRoute('statistics.list', { authRequired: true }, {
const { offset, count } = this.getPaginationItems();
const { sort, fields, query } = this.parseJsonQuery();

const ourQuery = Object.assign({}, query);

const statistics = RocketChat.models.Statistics.find(ourQuery, {
const statistics = RocketChat.models.Statistics.find(query, {
sort: sort ? sort : { name: 1 },
skip: offset,
limit: count,
fields: Object.assign({}, fields, RocketChat.API.v1.defaultFieldsToExclude)
fields
}).fetch();

return RocketChat.API.v1.success({
statistics,
count: statistics.length,
offset,
total: RocketChat.models.Statistics.find(ourQuery).count()
total: RocketChat.models.Statistics.find(query).count()
});
}
});
28 changes: 3 additions & 25 deletions packages/rocketchat-api/server/v1/users.js
Expand Up @@ -117,40 +117,18 @@ RocketChat.API.v1.addRoute('users.list', { authRequired: true }, {
const { offset, count } = this.getPaginationItems();
const { sort, fields, query } = this.parseJsonQuery();

let fieldsToKeepFromRegularUsers;
if (!RocketChat.authz.hasPermission(this.userId, 'view-full-other-user-info')) {
fieldsToKeepFromRegularUsers = {
avatarOrigin: 0,
emails: 0,
phone: 0,
statusConnection: 0,
createdAt: 0,
lastLogin: 0,
services: 0,
requirePasswordChange: 0,
requirePasswordChangeReason: 0,
roles: 0,
statusDefault: 0,
_updatedAt: 0,
customFields: 0
};
}

const ourQuery = Object.assign({}, query);
const ourFields = Object.assign({}, fields, fieldsToKeepFromRegularUsers, RocketChat.API.v1.defaultFieldsToExclude);

const users = RocketChat.models.Users.find(ourQuery, {
const users = RocketChat.models.Users.find(query, {
sort: sort ? sort : { username: 1 },
skip: offset,
limit: count,
fields: ourFields
fields
}).fetch();

return RocketChat.API.v1.success({
users,
count: users.length,
offset,
total: RocketChat.models.Users.find(ourQuery).count()
total: RocketChat.models.Users.find(query).count()
});
}
});
Expand Down

0 comments on commit 17472d8

Please sign in to comment.