Skip to content

Commit

Permalink
fix: imported fixes (#32878)
Browse files Browse the repository at this point in the history
Co-authored-by: Diego Sampaio <[email protected]>
  • Loading branch information
dionisio-bot[bot] and sampaiodiego committed Jul 24, 2024
1 parent 1ae7b59 commit c7df7df
Show file tree
Hide file tree
Showing 14 changed files with 552 additions and 29 deletions.
5 changes: 5 additions & 0 deletions .changeset/witty-penguins-rush.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@rocket.chat/meteor': patch
---

Security Hotfix (https://docs.rocket.chat/guides/security/security-updates)
4 changes: 4 additions & 0 deletions apps/meteor/app/api/server/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ interface IAPIDefaultFieldsToExclude {
statusDefault: number;
_updatedAt: number;
settings: number;
inviteToken: number;
}

type RateLimiterOptions = {
Expand Down Expand Up @@ -148,6 +149,7 @@ export class APIClass<TBasePath extends string = ''> extends Restivus {

public limitedUserFieldsToExcludeIfIsPrivilegedUser: {
services: number;
inviteToken: number;
};

constructor(properties: IAPIProperties) {
Expand Down Expand Up @@ -175,10 +177,12 @@ export class APIClass<TBasePath extends string = ''> extends Restivus {
statusDefault: 0,
_updatedAt: 0,
settings: 0,
inviteToken: 0,
};
this.limitedUserFieldsToExclude = this.defaultLimitedUserFieldsToExclude;
this.limitedUserFieldsToExcludeIfIsPrivilegedUser = {
services: 0,
inviteToken: 0,
};
}

Expand Down
2 changes: 1 addition & 1 deletion apps/meteor/app/livechat/server/api/v1/message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ API.v1.addRoute(
throw new Error('invalid-room');
}

let message = await Messages.findOneById(_id);
let message = await Messages.findOneByRoomIdAndMessageId(rid, _id);
if (!message) {
throw new Error('invalid-message');
}
Expand Down
9 changes: 6 additions & 3 deletions apps/meteor/app/livechat/server/methods/loadHistory.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { IMessage } from '@rocket.chat/core-typings';
import { LivechatVisitors, LivechatRooms } from '@rocket.chat/models';
import type { ServerMethods } from '@rocket.chat/ui-contexts';
import { check, Match } from 'meteor/check';
import { Meteor } from 'meteor/meteor';

import { loadMessageHistory } from '../../../lib/server/functions/loadMessageHistory';
Expand All @@ -23,9 +24,11 @@ Meteor.methods<ServerMethods>({
async 'livechat:loadHistory'({ token, rid, end, limit = 20, ls }) {
methodDeprecationLogger.method('livechat:loadHistory', '7.0.0');

if (!token || typeof token !== 'string') {
return;
}
check(token, String);
check(rid, String);
check(end, Date);
check(ls, Match.OneOf(String, Date));
check(limit, Number);

const visitor = await LivechatVisitors.getVisitorByToken(token, { projection: { _id: 1 } });

Expand Down
1 change: 1 addition & 0 deletions apps/meteor/app/livechat/server/methods/loginByToken.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ declare module '@rocket.chat/ui-contexts' {
Meteor.methods<ServerMethods>({
async 'livechat:loginByToken'(token) {
methodDeprecationLogger.method('livechat:loginByToken', '7.0.0');
check(token, String);
const visitor = await LivechatVisitors.getVisitorByToken(token, { projection: { _id: 1 } });

if (!visitor) {
Expand Down
9 changes: 9 additions & 0 deletions apps/meteor/app/slashcommands-inviteall/server/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { Meteor } from 'meteor/meteor';

import { isTruthy } from '../../../lib/isTruthy';
import { i18n } from '../../../server/lib/i18n';
import { canAccessRoomAsync } from '../../authorization/server';
import { addUsersToRoomMethod } from '../../lib/server/methods/addUsersToRoom';
import { createChannelMethod } from '../../lib/server/methods/createChannel';
import { createPrivateGroupMethod } from '../../lib/server/methods/createPrivateGroup';
Expand Down Expand Up @@ -55,6 +56,14 @@ function inviteAll<T extends string>(type: T): SlashCommand<T>['callback'] {
});
return;
}

if (!(await canAccessRoomAsync(baseChannel, user))) {
void api.broadcast('notify.ephemeralMessage', userId, message.rid, {
msg: i18n.t('Room_not_exist_or_not_permission', { lng }),
});
return;
}

const cursor = Subscriptions.findByRoomIdWhenUsernameExists(baseChannel._id, {
projection: { 'u.username': 1 },
});
Expand Down
8 changes: 4 additions & 4 deletions apps/meteor/server/models/raw/Team.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,10 @@ export class TeamRaw extends BaseRaw<ITeam> implements ITeamModel {
query?: Filter<ITeam>,
): FindCursor<P> | FindCursor<ITeam> {
if (options === undefined) {
return this.find({ _id: { $in: ids }, ...query });
return this.find({ ...query, _id: { $in: ids } });
}

return this.find({ _id: { $in: ids }, ...query }, options);
return this.find({ ...query, _id: { $in: ids } }, options);
}

findByIdsPaginated(
Expand All @@ -57,10 +57,10 @@ export class TeamRaw extends BaseRaw<ITeam> implements ITeamModel {
query?: Filter<ITeam>,
): FindPaginated<FindCursor<ITeam>> {
if (options === undefined) {
return this.findPaginated({ _id: { $in: ids }, ...query });
return this.findPaginated({ ...query, _id: { $in: ids } });
}

return this.findPaginated({ _id: { $in: ids }, ...query }, options);
return this.findPaginated({ ...query, _id: { $in: ids } }, options);
}

findByIdsAndType(ids: Array<string>, type: TEAM_TYPE): FindCursor<ITeam>;
Expand Down
4 changes: 4 additions & 0 deletions apps/meteor/tests/data/api-data.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ export function methodCall(methodName) {
return api(`method.call/${methodName}`);
}

export function methodCallAnon(methodName) {
return api(`method.callAnon/${methodName}`);
}

export function log(res) {
console.log(res.req.path);
console.log({
Expand Down
113 changes: 106 additions & 7 deletions apps/meteor/tests/end-to-end/api/01-users.js
Original file line number Diff line number Diff line change
Expand Up @@ -795,6 +795,10 @@ describe('[Users]', function () {
let deactivatedUser;
let user2;
let user2Credentials;
let user3;
let user3Credentials;
let group;
let inviteToken;

before(async () => {
const username = `deactivated_${Date.now()}${apiUsername}`;
Expand Down Expand Up @@ -853,18 +857,49 @@ describe('[Users]', function () {
before(async () => {
user2 = await createUser({ joinDefaultChannels: false });
user2Credentials = await login(user2.username, password);
user3 = await createUser({ joinDefaultChannels: false });
user3Credentials = await login(user3.username, password);
});

after(async () => {
await deleteUser(deactivatedUser);
await deleteUser(user);
await deleteUser(user2);
user2 = undefined;
before('Create a group', async () => {
group = (
await createRoom({
type: 'p',
name: `group.test.${Date.now()}-${Math.random()}`,
})
).body.group;
});

await updatePermission('view-outside-room', ['admin', 'owner', 'moderator', 'user']);
await updateSetting('API_Apply_permission_view-outside-room_on_users-list', false);
before('Create invite link', async () => {
inviteToken = (
await request.post(api('findOrCreateInvite')).set(credentials).send({
rid: group._id,
days: 0,
maxUses: 0,
})
).body._id;
});

after('Remove invite link', async () =>
request
.delete(api(`removeInvite/${inviteToken}`))
.set(credentials)
.send(),
);

after(() =>
Promise.all([
clearCustomFields(),
deleteUser(deactivatedUser),
deleteUser(user),
deleteUser(user2),
deleteUser(user3),
deleteRoom({ type: 'p', roomId: group._id }),
updatePermission('view-outside-room', ['admin', 'owner', 'moderator', 'user']),
updateSetting('API_Apply_permission_view-outside-room_on_users-list', false),
]),
);

it('should query all users in the system', (done) => {
request
.get(api('users.list'))
Expand Down Expand Up @@ -982,6 +1017,70 @@ describe('[Users]', function () {

await request.get(api('users.list')).set(user2Credentials).expect('Content-Type', 'application/json').expect(403);
});

it('should exclude inviteToken in the user item for privileged users even when fields={inviteToken:1} is specified', async () => {
await request
.post(api('useInviteToken'))
.set(user2Credentials)
.send({ token: inviteToken })
.expect(200)
.expect('Content-Type', 'application/json')
.expect((res) => {
expect(res.body).to.have.property('success', true);
expect(res.body).to.have.property('room');
expect(res.body.room).to.have.property('rid', group._id);
});

await request
.get(api('users.list'))
.set(credentials)
.expect('Content-Type', 'application/json')
.query({
fields: JSON.stringify({ inviteToken: 1 }),
sort: JSON.stringify({ inviteToken: -1 }),
count: 100,
})
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
expect(res.body).to.have.property('users');
res.body.users.forEach((user) => {
expect(user).to.not.have.property('inviteToken');
});
});
});

it('should exclude inviteToken in the user item for normal users even when fields={inviteToken:1} is specified', async () => {
await updateSetting('API_Apply_permission_view-outside-room_on_users-list', false);
await request
.post(api('useInviteToken'))
.set(user3Credentials)
.send({ token: inviteToken })
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
expect(res.body).to.have.property('room');
expect(res.body.room).to.have.property('rid', group._id);
});

await request
.get(api('users.list'))
.set(user3Credentials)
.expect('Content-Type', 'application/json')
.query({
fields: JSON.stringify({ inviteToken: 1 }),
sort: JSON.stringify({ inviteToken: -1 }),
count: 100,
})
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
expect(res.body).to.have.property('users');
res.body.users.forEach((user) => {
expect(user).to.not.have.property('inviteToken');
});
});
});
});

describe('[/users.setAvatar]', () => {
Expand Down
Loading

0 comments on commit c7df7df

Please sign in to comment.