Skip to content

Commit 0524014

Browse files
fix: imported fixes (#32881)
Co-authored-by: Diego Sampaio <chinello@gmail.com>
1 parent 8bd698c commit 0524014

File tree

14 files changed

+558
-30
lines changed

14 files changed

+558
-30
lines changed

.changeset/witty-penguins-rush.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@rocket.chat/meteor': patch
3+
---
4+
5+
Security Hotfix (https://docs.rocket.chat/guides/security/security-updates)

apps/meteor/app/api/server/api.ts

+4
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ interface IAPIDefaultFieldsToExclude {
6262
statusDefault: number;
6363
_updatedAt: number;
6464
settings: number;
65+
inviteToken: number;
6566
}
6667

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

149150
public limitedUserFieldsToExcludeIfIsPrivilegedUser: {
150151
services: number;
152+
inviteToken: number;
151153
};
152154

153155
constructor(properties: IAPIProperties) {
@@ -175,10 +177,12 @@ export class APIClass<TBasePath extends string = ''> extends Restivus {
175177
statusDefault: 0,
176178
_updatedAt: 0,
177179
settings: 0,
180+
inviteToken: 0,
178181
};
179182
this.limitedUserFieldsToExclude = this.defaultLimitedUserFieldsToExclude;
180183
this.limitedUserFieldsToExcludeIfIsPrivilegedUser = {
181184
services: 0,
185+
inviteToken: 0,
182186
};
183187
}
184188

apps/meteor/app/livechat/server/api/v1/message.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ API.v1.addRoute(
9898
throw new Error('invalid-room');
9999
}
100100

101-
let message = await Messages.findOneById(_id);
101+
let message = await Messages.findOneByRoomIdAndMessageId(rid, _id);
102102
if (!message) {
103103
throw new Error('invalid-message');
104104
}

apps/meteor/app/livechat/server/methods/loadHistory.ts

+6-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type { IMessage } from '@rocket.chat/core-typings';
22
import { LivechatVisitors, LivechatRooms } from '@rocket.chat/models';
33
import type { ServerMethods } from '@rocket.chat/ui-contexts';
4+
import { check, Match } from 'meteor/check';
45
import { Meteor } from 'meteor/meteor';
56

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

26-
if (!token || typeof token !== 'string') {
27-
return;
28-
}
27+
check(token, String);
28+
check(rid, String);
29+
check(end, Date);
30+
check(ls, Match.OneOf(String, Date));
31+
check(limit, Number);
2932

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

apps/meteor/app/livechat/server/methods/loginByToken.ts

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ declare module '@rocket.chat/ui-contexts' {
1414
Meteor.methods<ServerMethods>({
1515
async 'livechat:loginByToken'(token) {
1616
methodDeprecationLogger.method('livechat:loginByToken', '7.0.0');
17+
check(token, String);
1718
const visitor = await LivechatVisitors.getVisitorByToken(token, { projection: { _id: 1 } });
1819

1920
if (!visitor) {

apps/meteor/app/slashcommands-inviteall/server/server.ts

+9
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { Meteor } from 'meteor/meteor';
1010

1111
import { isTruthy } from '../../../lib/isTruthy';
1212
import { i18n } from '../../../server/lib/i18n';
13+
import { canAccessRoomAsync } from '../../authorization/server';
1314
import { addUsersToRoomMethod } from '../../lib/server/methods/addUsersToRoom';
1415
import { createChannelMethod } from '../../lib/server/methods/createChannel';
1516
import { createPrivateGroupMethod } from '../../lib/server/methods/createPrivateGroup';
@@ -55,6 +56,14 @@ function inviteAll<T extends string>(type: T): SlashCommand<T>['callback'] {
5556
});
5657
return;
5758
}
59+
60+
if (!(await canAccessRoomAsync(baseChannel, user))) {
61+
void api.broadcast('notify.ephemeralMessage', userId, message.rid, {
62+
msg: i18n.t('Room_not_exist_or_not_permission', { lng }),
63+
});
64+
return;
65+
}
66+
5867
const cursor = Subscriptions.findByRoomIdWhenUsernameExists(baseChannel._id, {
5968
projection: { 'u.username': 1 },
6069
});

apps/meteor/server/models/raw/Team.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,10 @@ export class TeamRaw extends BaseRaw<ITeam> implements ITeamModel {
4545
query?: Filter<ITeam>,
4646
): FindCursor<P> | FindCursor<ITeam> {
4747
if (options === undefined) {
48-
return this.find({ _id: { $in: ids }, ...query });
48+
return this.find({ ...query, _id: { $in: ids } });
4949
}
5050

51-
return this.find({ _id: { $in: ids }, ...query }, options);
51+
return this.find({ ...query, _id: { $in: ids } }, options);
5252
}
5353

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

63-
return this.findPaginated({ _id: { $in: ids }, ...query }, options);
63+
return this.findPaginated({ ...query, _id: { $in: ids } }, options);
6464
}
6565

6666
findByIdsAndType(ids: Array<string>, type: TEAM_TYPE): FindCursor<ITeam>;

apps/meteor/tests/data/api-data.js

+4
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ export function methodCall(methodName) {
4848
return api(`method.call/${methodName}`);
4949
}
5050

51+
export function methodCallAnon(methodName) {
52+
return api(`method.callAnon/${methodName}`);
53+
}
54+
5155
export function log(res) {
5256
console.log(res.req.path);
5357
console.log({

apps/meteor/tests/end-to-end/api/01-users.js

+106-7
Original file line numberDiff line numberDiff line change
@@ -636,6 +636,10 @@ describe('[Users]', function () {
636636
let deactivatedUser;
637637
let user2;
638638
let user2Credentials;
639+
let user3;
640+
let user3Credentials;
641+
let group;
642+
let inviteToken;
639643

640644
before(async () => {
641645
const username = `deactivated_${Date.now()}${apiUsername}`;
@@ -694,18 +698,49 @@ describe('[Users]', function () {
694698
before(async () => {
695699
user2 = await createUser({ joinDefaultChannels: false });
696700
user2Credentials = await login(user2.username, password);
701+
user3 = await createUser({ joinDefaultChannels: false });
702+
user3Credentials = await login(user3.username, password);
697703
});
698704

699-
after(async () => {
700-
await deleteUser(deactivatedUser);
701-
await deleteUser(user);
702-
await deleteUser(user2);
703-
user2 = undefined;
705+
before('Create a group', async () => {
706+
group = (
707+
await createRoom({
708+
type: 'p',
709+
name: `group.test.${Date.now()}-${Math.random()}`,
710+
})
711+
).body.group;
712+
});
704713

705-
await updatePermission('view-outside-room', ['admin', 'owner', 'moderator', 'user']);
706-
await updateSetting('API_Apply_permission_view-outside-room_on_users-list', false);
714+
before('Create invite link', async () => {
715+
inviteToken = (
716+
await request.post(api('findOrCreateInvite')).set(credentials).send({
717+
rid: group._id,
718+
days: 0,
719+
maxUses: 0,
720+
})
721+
).body._id;
707722
});
708723

724+
after('Remove invite link', async () =>
725+
request
726+
.delete(api(`removeInvite/${inviteToken}`))
727+
.set(credentials)
728+
.send(),
729+
);
730+
731+
after(() =>
732+
Promise.all([
733+
clearCustomFields(),
734+
deleteUser(deactivatedUser),
735+
deleteUser(user),
736+
deleteUser(user2),
737+
deleteUser(user3),
738+
deleteRoom({ type: 'p', roomId: group._id }),
739+
updatePermission('view-outside-room', ['admin', 'owner', 'moderator', 'user']),
740+
updateSetting('API_Apply_permission_view-outside-room_on_users-list', false),
741+
]),
742+
);
743+
709744
it('should query all users in the system', (done) => {
710745
request
711746
.get(api('users.list'))
@@ -823,6 +858,70 @@ describe('[Users]', function () {
823858

824859
await request.get(api('users.list')).set(user2Credentials).expect('Content-Type', 'application/json').expect(403);
825860
});
861+
862+
it('should exclude inviteToken in the user item for privileged users even when fields={inviteToken:1} is specified', async () => {
863+
await request
864+
.post(api('useInviteToken'))
865+
.set(user2Credentials)
866+
.send({ token: inviteToken })
867+
.expect(200)
868+
.expect('Content-Type', 'application/json')
869+
.expect((res) => {
870+
expect(res.body).to.have.property('success', true);
871+
expect(res.body).to.have.property('room');
872+
expect(res.body.room).to.have.property('rid', group._id);
873+
});
874+
875+
await request
876+
.get(api('users.list'))
877+
.set(credentials)
878+
.expect('Content-Type', 'application/json')
879+
.query({
880+
fields: JSON.stringify({ inviteToken: 1 }),
881+
sort: JSON.stringify({ inviteToken: -1 }),
882+
count: 100,
883+
})
884+
.expect(200)
885+
.expect((res) => {
886+
expect(res.body).to.have.property('success', true);
887+
expect(res.body).to.have.property('users');
888+
res.body.users.forEach((user) => {
889+
expect(user).to.not.have.property('inviteToken');
890+
});
891+
});
892+
});
893+
894+
it('should exclude inviteToken in the user item for normal users even when fields={inviteToken:1} is specified', async () => {
895+
await updateSetting('API_Apply_permission_view-outside-room_on_users-list', false);
896+
await request
897+
.post(api('useInviteToken'))
898+
.set(user3Credentials)
899+
.send({ token: inviteToken })
900+
.expect(200)
901+
.expect((res) => {
902+
expect(res.body).to.have.property('success', true);
903+
expect(res.body).to.have.property('room');
904+
expect(res.body.room).to.have.property('rid', group._id);
905+
});
906+
907+
await request
908+
.get(api('users.list'))
909+
.set(user3Credentials)
910+
.expect('Content-Type', 'application/json')
911+
.query({
912+
fields: JSON.stringify({ inviteToken: 1 }),
913+
sort: JSON.stringify({ inviteToken: -1 }),
914+
count: 100,
915+
})
916+
.expect(200)
917+
.expect((res) => {
918+
expect(res.body).to.have.property('success', true);
919+
expect(res.body).to.have.property('users');
920+
res.body.users.forEach((user) => {
921+
expect(user).to.not.have.property('inviteToken');
922+
});
923+
});
924+
});
826925
});
827926

828927
describe('[/users.setAvatar]', () => {

0 commit comments

Comments
 (0)