diff --git a/apps/meteor/app/api/server/v1/permissions.ts b/apps/meteor/app/api/server/v1/permissions.ts index 4b860d6e1eac..3613cc171354 100644 --- a/apps/meteor/app/api/server/v1/permissions.ts +++ b/apps/meteor/app/api/server/v1/permissions.ts @@ -4,6 +4,7 @@ import { isBodyParamsValidPermissionUpdate } from '@rocket.chat/rest-typings'; import { Meteor } from 'meteor/meteor'; import { hasPermissionAsync } from '../../../authorization/server/functions/hasPermission'; +import { notifyOnPermissionChangedById } from '../../../lib/server/lib/notifyListener'; import { API } from '../api'; API.v1.addRoute( @@ -70,6 +71,7 @@ API.v1.addRoute( for await (const permission of bodyParams.permissions) { await Permissions.setRoles(permission._id, permission.roles); + void notifyOnPermissionChangedById(permission._id); } const result = (await Meteor.callAsync('permissions/get')) as IPermission[]; diff --git a/apps/meteor/app/api/server/v1/roles.ts b/apps/meteor/app/api/server/v1/roles.ts index 6727f4f970cb..66c6677a9eed 100644 --- a/apps/meteor/app/api/server/v1/roles.ts +++ b/apps/meteor/app/api/server/v1/roles.ts @@ -9,7 +9,7 @@ import { getUsersInRolePaginated } from '../../../authorization/server/functions import { hasPermissionAsync } from '../../../authorization/server/functions/hasPermission'; import { hasRoleAsync, hasAnyRoleAsync } from '../../../authorization/server/functions/hasRole'; import { apiDeprecationLogger } from '../../../lib/server/lib/deprecationWarningLogger'; -import { notifyListenerOnRoleChanges } from '../../../lib/server/lib/notifyListenerOnRoleChanges'; +import { notifyOnRoleChanged } from '../../../lib/server/lib/notifyListener'; import { settings } from '../../../settings/server/index'; import { API } from '../api'; import { getPaginationItems } from '../helpers/getPaginationItems'; @@ -180,7 +180,7 @@ API.v1.addRoute( await Roles.removeById(role._id); - void notifyListenerOnRoleChanges(role._id, 'removed', role); + void notifyOnRoleChanged(role, 'removed'); return API.v1.success(); }, diff --git a/apps/meteor/app/authorization/server/methods/addPermissionToRole.ts b/apps/meteor/app/authorization/server/methods/addPermissionToRole.ts index cb6422a03142..13a114732bd2 100644 --- a/apps/meteor/app/authorization/server/methods/addPermissionToRole.ts +++ b/apps/meteor/app/authorization/server/methods/addPermissionToRole.ts @@ -2,6 +2,7 @@ import { Permissions } from '@rocket.chat/models'; import type { ServerMethods } from '@rocket.chat/ui-contexts'; import { Meteor } from 'meteor/meteor'; +import { notifyOnPermissionChangedById } from '../../../lib/server/lib/notifyListener'; import { CONSTANTS, AuthorizationUtils } from '../../lib'; import { hasPermissionAsync } from '../functions/hasPermission'; @@ -41,11 +42,15 @@ Meteor.methods({ action: 'Adding_permission', }); } + // for setting-based-permissions, authorize the group access as well if (permission.groupPermissionId) { await Permissions.addRole(permission.groupPermissionId, role); + void notifyOnPermissionChangedById(permission.groupPermissionId); } await Permissions.addRole(permission._id, role); + + void notifyOnPermissionChangedById(permission._id); }, }); diff --git a/apps/meteor/app/authorization/server/methods/removeRoleFromPermission.ts b/apps/meteor/app/authorization/server/methods/removeRoleFromPermission.ts index 30a1b2a759b6..91a4df1eddf7 100644 --- a/apps/meteor/app/authorization/server/methods/removeRoleFromPermission.ts +++ b/apps/meteor/app/authorization/server/methods/removeRoleFromPermission.ts @@ -2,6 +2,7 @@ import { Permissions } from '@rocket.chat/models'; import type { ServerMethods } from '@rocket.chat/ui-contexts'; import { Meteor } from 'meteor/meteor'; +import { notifyOnPermissionChangedById } from '../../../lib/server/lib/notifyListener'; import { CONSTANTS } from '../../lib'; import { hasPermissionAsync } from '../functions/hasPermission'; @@ -36,10 +37,12 @@ Meteor.methods({ // for setting based permissions, revoke the group permission once all setting permissions // related to this group have been removed - if (permission.groupPermissionId) { await Permissions.removeRole(permission.groupPermissionId, role); + void notifyOnPermissionChangedById(permission.groupPermissionId); } + await Permissions.removeRole(permission._id, role); + void notifyOnPermissionChangedById(permission._id); }, }); diff --git a/apps/meteor/app/lib/server/lib/notifyListener.ts b/apps/meteor/app/lib/server/lib/notifyListener.ts index c2e16117854c..9ec4bbf6be1b 100644 --- a/apps/meteor/app/lib/server/lib/notifyListener.ts +++ b/apps/meteor/app/lib/server/lib/notifyListener.ts @@ -1,6 +1,6 @@ import { api, dbWatchersDisabled } from '@rocket.chat/core-services'; -import type { IPbxEvent, IRocketChatRecord, IRoom } from '@rocket.chat/core-typings'; -import { PbxEvents, Rooms } from '@rocket.chat/models'; +import type { IPermission, IRocketChatRecord, IRoom, ISetting, IPbxEvent, IRole } from '@rocket.chat/core-typings'; +import { Rooms, Permissions, Settings, PbxEvents, Roles } from '@rocket.chat/models'; type ClientAction = 'inserted' | 'updated' | 'removed'; @@ -66,6 +66,43 @@ export async function notifyOnRoomChangedByUserDM( } } +export async function notifyOnSettingChanged(setting: ISetting, clientAction: ClientAction = 'updated'): Promise { + if (!dbWatchersDisabled) { + return; + } + + void api.broadcast('watch.settings', { clientAction, setting }); +} + +export async function notifyOnPermissionChanged(permission: IPermission, clientAction: ClientAction = 'updated'): Promise { + if (!dbWatchersDisabled) { + return; + } + + void api.broadcast('permission.changed', { clientAction, data: permission }); + + if (permission.level === 'settings' && permission.settingId) { + const setting = await Settings.findOneNotHiddenById(permission.settingId); + if (!setting) { + return; + } + void notifyOnSettingChanged(setting, 'updated'); + } +} + +export async function notifyOnPermissionChangedById(pid: IPermission['_id'], clientAction: ClientAction = 'updated'): Promise { + if (!dbWatchersDisabled) { + return; + } + + const permission = await Permissions.findOneById(pid); + if (!permission) { + return; + } + + return notifyOnPermissionChanged(permission, clientAction); +} + export async function notifyOnPbxEventChangedById( id: T['_id'], clientAction: ClientAction = 'updated', @@ -80,3 +117,27 @@ export async function notifyOnPbxEventChangedById( void api.broadcast('watch.pbxevents', { clientAction, id, data: item }); } } + +export async function notifyOnRoleChanged(role: T, clientAction: 'removed' | 'changed' = 'changed'): Promise { + if (!dbWatchersDisabled) { + return; + } + + void api.broadcast('watch.roles', { clientAction, role }); +} + +export async function notifyOnRoleChangedById( + id: T['_id'], + clientAction: 'removed' | 'changed' = 'changed', +): Promise { + if (!dbWatchersDisabled) { + return; + } + + const role = await Roles.findOneById(id); + if (!role) { + return; + } + + void notifyOnRoleChanged(role, clientAction); +} diff --git a/apps/meteor/app/lib/server/lib/notifyListenerOnRoleChanges.ts b/apps/meteor/app/lib/server/lib/notifyListenerOnRoleChanges.ts deleted file mode 100644 index b0a2bfb459f4..000000000000 --- a/apps/meteor/app/lib/server/lib/notifyListenerOnRoleChanges.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { api, dbWatchersDisabled } from '@rocket.chat/core-services'; -import type { IRole } from '@rocket.chat/core-typings'; -import { Roles } from '@rocket.chat/models'; - -type ClientAction = 'inserted' | 'updated' | 'removed'; - -export async function notifyListenerOnRoleChanges( - rid: IRole['_id'], - clientAction: ClientAction = 'updated', - existingRoleData?: IRole, -): Promise { - if (!dbWatchersDisabled) { - return; - } - - const role = existingRoleData || (await Roles.findOneById(rid)); - if (!role) { - return; - } - - void api.broadcast('watch.roles', { - clientAction, - role, - }); -} diff --git a/apps/meteor/ee/server/lib/roles/insertRole.ts b/apps/meteor/ee/server/lib/roles/insertRole.ts index 23cb394a913c..321490055c03 100644 --- a/apps/meteor/ee/server/lib/roles/insertRole.ts +++ b/apps/meteor/ee/server/lib/roles/insertRole.ts @@ -2,7 +2,7 @@ import { api, MeteorError } from '@rocket.chat/core-services'; import type { IRole } from '@rocket.chat/core-typings'; import { Roles } from '@rocket.chat/models'; -import { notifyListenerOnRoleChanges } from '../../../../app/lib/server/lib/notifyListenerOnRoleChanges'; +import { notifyOnRoleChanged } from '../../../../app/lib/server/lib/notifyListener'; import { isValidRoleScope } from '../../../../lib/roles/isValidRoleScope'; type InsertRoleOptions = { @@ -22,7 +22,7 @@ export const insertRoleAsync = async (roleData: Omit, options: Ins const role = await Roles.createWithRandomId(name, scope, description, false, mandatory2fa); - void notifyListenerOnRoleChanges(role._id, 'inserted', role); + void notifyOnRoleChanged(role); if (options.broadcastUpdate) { void api.broadcast('user.roleUpdate', { diff --git a/apps/meteor/ee/server/lib/roles/updateRole.ts b/apps/meteor/ee/server/lib/roles/updateRole.ts index 976abbd8921f..0cde11cd0a7a 100644 --- a/apps/meteor/ee/server/lib/roles/updateRole.ts +++ b/apps/meteor/ee/server/lib/roles/updateRole.ts @@ -2,7 +2,7 @@ import { api, MeteorError } from '@rocket.chat/core-services'; import type { IRole } from '@rocket.chat/core-typings'; import { Roles } from '@rocket.chat/models'; -import { notifyListenerOnRoleChanges } from '../../../../app/lib/server/lib/notifyListenerOnRoleChanges'; +import { notifyOnRoleChangedById } from '../../../../app/lib/server/lib/notifyListener'; import { isValidRoleScope } from '../../../../lib/roles/isValidRoleScope'; type UpdateRoleOptions = { @@ -39,7 +39,7 @@ export const updateRole = async (roleId: IRole['_id'], roleData: Omit 0) { diff --git a/apps/meteor/server/lib/roles/createOrUpdateProtectedRole.ts b/apps/meteor/server/lib/roles/createOrUpdateProtectedRole.ts index 487c74c0f76b..cdc43cdad93a 100644 --- a/apps/meteor/server/lib/roles/createOrUpdateProtectedRole.ts +++ b/apps/meteor/server/lib/roles/createOrUpdateProtectedRole.ts @@ -1,7 +1,7 @@ import type { IRole, AtLeast } from '@rocket.chat/core-typings'; import { Roles } from '@rocket.chat/models'; -import { notifyListenerOnRoleChanges } from '../../../app/lib/server/lib/notifyListenerOnRoleChanges'; +import { notifyOnRoleChanged, notifyOnRoleChangedById } from '../../../app/lib/server/lib/notifyListener'; export const createOrUpdateProtectedRoleAsync = async ( roleId: string, @@ -20,12 +20,12 @@ export const createOrUpdateProtectedRoleAsync = async ( roleData.mandatory2fa || role.mandatory2fa, ); - void notifyListenerOnRoleChanges(roleId, 'updated', updatedRole); + void notifyOnRoleChanged(updatedRole); return; } - const insertedRole = await Roles.insertOne({ + await Roles.insertOne({ _id: roleId, scope: 'Users', description: '', @@ -34,5 +34,5 @@ export const createOrUpdateProtectedRoleAsync = async ( protected: true, }); - void notifyListenerOnRoleChanges(insertedRole.insertedId, 'inserted'); + void notifyOnRoleChangedById(roleId); };