Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 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
5 changes: 5 additions & 0 deletions .changeset/lemon-lions-learn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@rocket.chat/meteor": patch
---

fixes the possibility of see new messages without being subscribed to a public channel.
15 changes: 3 additions & 12 deletions apps/meteor/app/lib/server/methods/getChannelHistory.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { Authorization } from '@rocket.chat/core-services';
import type { IMessage, MessageTypesValues } from '@rocket.chat/core-typings';
import type { ServerMethods } from '@rocket.chat/ddp-client';
import { Messages, Subscriptions, Rooms } from '@rocket.chat/models';
import { Messages, Rooms } from '@rocket.chat/models';
import { check } from 'meteor/check';
import { Meteor } from 'meteor/meteor';

import { canAccessRoomAsync } from '../../../authorization/server';
import { hasPermissionAsync } from '../../../authorization/server/functions/hasPermission';
import { settings } from '../../../settings/server/cached';
import { normalizeMessagesForUser } from '../../../utils/server/lib/normalizeMessagesForUser';
import { getHiddenSystemMessages } from '../lib/getHiddenSystemMessages';
Expand Down Expand Up @@ -62,16 +61,8 @@ export const getChannelHistory = async ({
return false;
}

if (!(await canAccessRoomAsync(room, { _id: fromUserId }))) {
return false;
}

// Make sure they can access the room
if (
room.t === 'c' &&
!(await hasPermissionAsync(fromUserId, 'preview-c-room')) &&
!(await Subscriptions.findOneByRoomIdAndUserId(rid, fromUserId, { projection: { _id: 1 } }))
) {
if (!(await Authorization.canReadRoom(room, { _id: fromUserId }))) {
return false;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,15 +102,12 @@ export class NotificationsModule {
}

const canAccess = await Authorization.canAccessRoom(room, { _id: this.userId || '' }, extraData);
Comment thread
tiagoevanp marked this conversation as resolved.
Outdated

if (!canAccess) {
// verify if can preview messages from public channels
if (room.t === 'c' && this.userId) {
return Authorization.hasPermission(this.userId, 'preview-c-room');
}
return false;
}

return true;
return Authorization.canReadRoom(room, { _id: this.userId || '' });
});

this.streamRoomMessage.allowRead('__my_messages__', 'all');
Expand Down
24 changes: 24 additions & 0 deletions apps/meteor/server/services/authorization/canReadRoom.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import type { RoomReadValidator } from '@rocket.chat/core-services';
import { Authorization } from '@rocket.chat/core-services';
import { Subscriptions } from '@rocket.chat/models';

import { canAccessRoom } from './canAccessRoom';

export const canReadRoom: RoomReadValidator = async (...args) => {
if (!(await canAccessRoom(...args))) {
return false;
}

const [room, user] = args;

if (
user?._id &&
room?.t === 'c' &&
!(await Authorization.hasPermission(user._id, 'preview-c-room')) &&
!(await Subscriptions.findOneByRoomIdAndUserId(room?._id, user._id, { projection: { _id: 1 } }))
) {
return false;
}

return true;
};
7 changes: 6 additions & 1 deletion apps/meteor/server/services/authorization/service.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import type { IAuthorization, RoomAccessValidator } from '@rocket.chat/core-services';
import type { IAuthorization, RoomAccessValidator, RoomReadValidator } from '@rocket.chat/core-services';
import { License, ServiceClass } from '@rocket.chat/core-services';
import type { IUser, IRole, IRoom, ISubscription, IRocketChatRecord } from '@rocket.chat/core-typings';
import { Subscriptions, Rooms, Users, Roles, Permissions } from '@rocket.chat/models';
import mem from 'mem';

import { canAccessRoom } from './canAccessRoom';
import { canReadRoom } from './canReadRoom';
import { AuthorizationUtils } from '../../../app/authorization/lib/AuthorizationUtils';

import './canAccessRoomLivechat';
Expand Down Expand Up @@ -80,6 +81,10 @@ export class Authorization extends ServiceClass implements IAuthorization {
return canAccessRoom(...args);
}

async canReadRoom(...args: Parameters<RoomReadValidator>): Promise<boolean> {
return canReadRoom(...args);
}

async canAccessRoomId(rid: IRoom['_id'], uid: IUser['_id']): Promise<boolean> {
const room = await Rooms.findOneById<Pick<IRoom, '_id' | 't' | 'teamId' | 'prid'>>(rid, {
projection: {
Expand Down
3 changes: 2 additions & 1 deletion packages/core-services/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { IAccount, ILoginResult } from './types/IAccount';
import type { IAnalyticsService } from './types/IAnalyticsService';
import { IApiService } from './types/IApiService';
import type { IAppsEngineService } from './types/IAppsEngineService';
import type { IAuthorization, RoomAccessValidator } from './types/IAuthorization';
import type { IAuthorization, RoomAccessValidator, RoomReadValidator } from './types/IAuthorization';
import type { IAuthorizationLivechat } from './types/IAuthorizationLivechat';
import type { IAuthorizationVoip } from './types/IAuthorizationVoip';
import type { IBannerService } from './types/IBannerService';
Expand Down Expand Up @@ -127,6 +127,7 @@ export {
proxify,
ResizeResult,
RoomAccessValidator,
RoomReadValidator,
TelemetryEvents,
TelemetryMap,
VideoConferenceJoinOptions,
Expand Down
6 changes: 6 additions & 0 deletions packages/core-services/src/types/IAuthorization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,17 @@ export type RoomAccessValidator = (
extraData?: Record<string, any>,
) => Promise<boolean>;

type Head<T extends any[]> = T extends [...infer U, any?] ? U : never;
type RemoveLastParameter<T extends (...args: any[]) => any> = (...args: Head<Parameters<T>>) => ReturnType<T>;

export type RoomReadValidator = RemoveLastParameter<RoomAccessValidator>;

export interface IAuthorization {
hasAllPermission(userId: string, permissions: string[], scope?: string): Promise<boolean>;
hasPermission(userId: string, permissionId: string, scope?: string): Promise<boolean>;
hasAtLeastOnePermission(userId: string, permissions: string[], scope?: string): Promise<boolean>;
canAccessRoom: RoomAccessValidator;
canReadRoom: RoomReadValidator;
canAccessRoomId(rid: IRoom['_id'], uid?: IUser['_id']): Promise<boolean>;
getUsersFromPublicRoles(): Promise<(IRocketChatRecord & Pick<IUser, '_id' | 'username' | 'roles'>)[]>;
}