diff --git a/apps/meteor/app/2fa/server/twoFactorRequired.ts b/apps/meteor/app/2fa/server/twoFactorRequired.ts index a3f77add66af3..6db97ef331b17 100644 --- a/apps/meteor/app/2fa/server/twoFactorRequired.ts +++ b/apps/meteor/app/2fa/server/twoFactorRequired.ts @@ -3,11 +3,24 @@ import { Meteor } from 'meteor/meteor'; import type { ITwoFactorOptions } from './code/index'; import { checkCodeForUser } from './code/index'; -export function twoFactorRequired any>( - fn: TFunction, +export type AuthenticatedContext = { + userId: string; + token: string; + connection: { + id: string; + clientAddress: string; + httpHeaders: Record; + }; + twoFactorChecked: boolean; +}; + +export const twoFactorRequired = Promise>( + fn: ThisParameterType extends AuthenticatedContext + ? TFunction + : (this: AuthenticatedContext, ...args: Parameters) => ReturnType, options?: ITwoFactorOptions, -): (this: Meteor.MethodThisType, ...args: Parameters) => Promise> { - return async function (this: Meteor.MethodThisType, ...args: Parameters): Promise> { +) => + async function (this, ...args) { if (!this.userId) { throw new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'twoFactorRequired' }); } @@ -35,5 +48,4 @@ export function twoFactorRequired, ...args: Parameters) => ReturnType; diff --git a/apps/meteor/app/api/server/lib/eraseTeam.spec.ts b/apps/meteor/app/api/server/lib/eraseTeam.spec.ts index 8e5da6b4b59c8..de28fe2c0efa1 100644 --- a/apps/meteor/app/api/server/lib/eraseTeam.spec.ts +++ b/apps/meteor/app/api/server/lib/eraseTeam.spec.ts @@ -126,7 +126,7 @@ describe('eraseTeam (TypeScript) module', () => { await subject.eraseTeam(user, team, []); - sinon.assert.calledWith(eraseRoomStub, team.roomId, 'u1'); + sinon.assert.calledWith(eraseRoomStub, team.roomId, user); }); }); diff --git a/apps/meteor/app/api/server/lib/eraseTeam.ts b/apps/meteor/app/api/server/lib/eraseTeam.ts index 076064ecbf6d3..e8c9a3a6b294c 100644 --- a/apps/meteor/app/api/server/lib/eraseTeam.ts +++ b/apps/meteor/app/api/server/lib/eraseTeam.ts @@ -1,19 +1,19 @@ import { AppEvents, Apps } from '@rocket.chat/apps'; import { MeteorError, Team } from '@rocket.chat/core-services'; -import type { AtLeast, IRoom, ITeam, IUser } from '@rocket.chat/core-typings'; +import type { IRoom, ITeam, IUser, AtLeast } from '@rocket.chat/core-typings'; import { Rooms } from '@rocket.chat/models'; import { eraseRoom } from '../../../../server/lib/eraseRoom'; import { SystemLogger } from '../../../../server/lib/logger/system'; import { deleteRoom } from '../../../lib/server/functions/deleteRoom'; -type eraseRoomFnType = (rid: string, user: AtLeast) => Promise; +type EraseRoomFnType = >(rid: string, user: T) => Promise; -export const eraseTeamShared = async ( - user: AtLeast, +export const eraseTeamShared = async >( + user: T, team: ITeam, roomsToRemove: IRoom['_id'][] = [], - eraseRoomFn: eraseRoomFnType, + eraseRoomFn: EraseRoomFnType, ) => { const rooms: string[] = roomsToRemove.length ? (await Team.getMatchingTeamRooms(team._id, roomsToRemove)).filter((roomId) => roomId !== team.roomId) @@ -41,9 +41,9 @@ export const eraseTeamShared = async ( await Team.deleteById(team._id); }; -export const eraseTeam = async (user: AtLeast, team: ITeam, roomsToRemove: IRoom['_id'][]) => { +export const eraseTeam = async (user: IUser, team: ITeam, roomsToRemove: IRoom['_id'][]) => { await eraseTeamShared(user, team, roomsToRemove, async (rid, user) => { - return eraseRoom(rid, user._id); + return eraseRoom(rid, user); }); }; @@ -54,7 +54,7 @@ export const eraseTeam = async (user: AtLeast => { const deletedRooms = new Set(); - await eraseTeamShared({ _id: 'rocket.cat', username: 'rocket.cat', name: 'Rocket.Cat' }, team, roomsToRemove, async (rid) => { + await eraseTeamShared({ _id: 'rocket.cat', username: 'rocket.cat', name: 'Rocket.Cat' } as IUser, team, roomsToRemove, async (rid) => { const isDeleted = await eraseRoomLooseValidation(rid); if (isDeleted) { deletedRooms.add(rid); diff --git a/apps/meteor/app/api/server/v1/channels.ts b/apps/meteor/app/api/server/v1/channels.ts index 0f654e8822d4a..0aa24f5097b04 100644 --- a/apps/meteor/app/api/server/v1/channels.ts +++ b/apps/meteor/app/api/server/v1/channels.ts @@ -493,7 +493,7 @@ API.v1.addRoute( checkedArchived: false, }); - await eraseRoom(room._id, this.userId); + await eraseRoom(room._id, this.user); return API.v1.success(); }, diff --git a/apps/meteor/app/api/server/v1/chat.ts b/apps/meteor/app/api/server/v1/chat.ts index f289960f4f411..f5a9250fe29b6 100644 --- a/apps/meteor/app/api/server/v1/chat.ts +++ b/apps/meteor/app/api/server/v1/chat.ts @@ -804,7 +804,7 @@ API.v1.addRoute( throw new Meteor.Error('The required "mid" body param is missing.'); } - await followMessage(this.userId, { mid }); + await followMessage(this.user, { mid }); return API.v1.success(); }, @@ -822,7 +822,7 @@ API.v1.addRoute( throw new Meteor.Error('The required "mid" body param is missing.'); } - await unfollowMessage(this.userId, { mid }); + await unfollowMessage(this.user, { mid }); return API.v1.success(); }, diff --git a/apps/meteor/app/api/server/v1/groups.ts b/apps/meteor/app/api/server/v1/groups.ts index a87fd5cc7cd4f..3fbe9c967a8e9 100644 --- a/apps/meteor/app/api/server/v1/groups.ts +++ b/apps/meteor/app/api/server/v1/groups.ts @@ -380,7 +380,7 @@ API.v1.addRoute( checkedArchived: false, }); - await eraseRoom(findResult.rid, this.userId); + await eraseRoom(findResult.rid, this.user); return API.v1.success(); }, diff --git a/apps/meteor/app/api/server/v1/im.ts b/apps/meteor/app/api/server/v1/im.ts index 2e13de8023259..358c6174df4f1 100644 --- a/apps/meteor/app/api/server/v1/im.ts +++ b/apps/meteor/app/api/server/v1/im.ts @@ -155,7 +155,7 @@ const dmDeleteAction = (_path: Path): TypedAction | undefined | null - > => { + const user = await (async () => { if (isUserFromParams(this.bodyParams, this.userId, this.user)) { return Users.findOneById(this.userId); } @@ -1429,7 +1420,7 @@ API.v1.addRoute( let { statusText, status } = user; if (this.bodyParams.message || this.bodyParams.message === '') { - await setStatusText(user._id, this.bodyParams.message, { emit: false }); + await setStatusText(user, this.bodyParams.message, { emit: false }); statusText = this.bodyParams.message; } diff --git a/apps/meteor/app/lib/server/functions/saveUser/saveUser.ts b/apps/meteor/app/lib/server/functions/saveUser/saveUser.ts index b727867b1e818..c44ba338b7030 100644 --- a/apps/meteor/app/lib/server/functions/saveUser/saveUser.ts +++ b/apps/meteor/app/lib/server/functions/saveUser/saveUser.ts @@ -125,7 +125,7 @@ const _saveUser = (session?: ClientSession) => } if (typeof userData.statusText === 'string') { - await setStatusText(userData._id, userData.statusText, { updater, session }); + await setStatusText(oldUserData, userData.statusText, { updater, session }); } if (userData.email) { diff --git a/apps/meteor/app/lib/server/functions/setStatusText.ts b/apps/meteor/app/lib/server/functions/setStatusText.ts index e22805e15c8ad..29b4a8ad72812 100644 --- a/apps/meteor/app/lib/server/functions/setStatusText.ts +++ b/apps/meteor/app/lib/server/functions/setStatusText.ts @@ -7,7 +7,7 @@ import type { ClientSession } from 'mongodb'; import { onceTransactionCommitedSuccessfully } from '../../../../server/database/utils'; export async function setStatusText( - userId: string, + user: Pick, statusText: string, { updater, @@ -19,21 +19,8 @@ export async function setStatusText( emit?: boolean; } = {}, ): Promise { - if (!userId) { - return false; - } - statusText = statusText.trim().substr(0, 120); - const user = await Users.findOneById>(userId, { - projection: { username: 1, name: 1, status: 1, roles: 1, statusText: 1 }, - session, - }); - - if (!user) { - return false; - } - if (user.statusText === statusText) { return true; } diff --git a/apps/meteor/app/lib/server/methods/saveSetting.ts b/apps/meteor/app/lib/server/methods/saveSetting.ts index ed48dc4e9f4fc..044a618dacac0 100644 --- a/apps/meteor/app/lib/server/methods/saveSetting.ts +++ b/apps/meteor/app/lib/server/methods/saveSetting.ts @@ -1,4 +1,4 @@ -import type { SettingValue } from '@rocket.chat/core-typings'; +import type { SettingEditor, SettingValue } from '@rocket.chat/core-typings'; import type { ServerMethods } from '@rocket.chat/ddp-client'; import { Settings } from '@rocket.chat/models'; import { Match, check } from 'meteor/check'; @@ -14,12 +14,12 @@ import { notifyOnSettingChanged } from '../lib/notifyListener'; declare module '@rocket.chat/ddp-client' { // eslint-disable-next-line @typescript-eslint/naming-convention interface ServerMethods { - saveSetting(_id: string, value: SettingValue, editor?: string): Promise; + saveSetting(_id: string, value: SettingValue, editor: SettingEditor): Promise; } } Meteor.methods({ - saveSetting: twoFactorRequired(async function (_id, value, editor) { + saveSetting: twoFactorRequired(async function (_id: string, value: SettingValue, editor: SettingEditor) { const uid = Meteor.userId(); if (!uid) { throw new Meteor.Error('error-action-not-allowed', 'Editing settings is not allowed', { diff --git a/apps/meteor/app/message-pin/server/pinMessage.ts b/apps/meteor/app/message-pin/server/pinMessage.ts index e11e601ce2ba7..204868d9dcda3 100644 --- a/apps/meteor/app/message-pin/server/pinMessage.ts +++ b/apps/meteor/app/message-pin/server/pinMessage.ts @@ -109,7 +109,7 @@ export async function pinMessage(message: IMessage, userId: string, pinnedAt?: D } // App IPostMessagePinned event hook - await Apps.self?.triggerEvent(AppEvents.IPostMessagePinned, originalMessage, await Meteor.userAsync(), originalMessage.pinned); + await Apps.self?.triggerEvent(AppEvents.IPostMessagePinned, originalMessage, me, originalMessage.pinned); const pinMessageType = originalMessage.t === 'e2e' ? 'message_pinned_e2e' : 'message_pinned'; @@ -189,7 +189,7 @@ export const unpinMessage = async (userId: string, message: IMessage) => { } // App IPostMessagePinned event hook - await Apps.self?.triggerEvent(AppEvents.IPostMessagePinned, originalMessage, await Meteor.userAsync(), originalMessage.pinned); + await Apps.self?.triggerEvent(AppEvents.IPostMessagePinned, originalMessage, me, originalMessage.pinned); await Messages.setPinnedByIdAndUserId(originalMessage._id, originalMessage.pinnedBy, originalMessage.pinned); if (settings.get('Message_Read_Receipt_Store_Users')) { diff --git a/apps/meteor/app/slashcommands-status/server/status.ts b/apps/meteor/app/slashcommands-status/server/status.ts index a2ff6483d398e..0a1f02b182571 100644 --- a/apps/meteor/app/slashcommands-status/server/status.ts +++ b/apps/meteor/app/slashcommands-status/server/status.ts @@ -1,5 +1,5 @@ import { api } from '@rocket.chat/core-services'; -import type { SlashCommandCallbackParams } from '@rocket.chat/core-typings'; +import type { SlashCommandCallbackParams, IUser } from '@rocket.chat/core-typings'; import { Users } from '@rocket.chat/models'; import { i18n } from '../../../server/lib/i18n'; @@ -14,11 +14,19 @@ slashCommands.add({ return; } - const user = await Users.findOneById(userId, { projection: { language: 1 } }); + const user = await Users.findOneById>( + userId, + { + projection: { language: 1, username: 1, name: 1, status: 1, roles: 1, statusText: 1 }, + }, + ); const lng = user?.language || settings.get('Language') || 'en'; + if (!user) { + return; + } try { - await setUserStatusMethod(userId, undefined, params); + await setUserStatusMethod(user, undefined, params); void api.broadcast('notify.ephemeralMessage', userId, message.rid, { msg: i18n.t('StatusMessage_Changed_Successfully', { lng }), diff --git a/apps/meteor/app/threads/server/methods/followMessage.ts b/apps/meteor/app/threads/server/methods/followMessage.ts index 88d1b6274002a..ef32595e930a0 100644 --- a/apps/meteor/app/threads/server/methods/followMessage.ts +++ b/apps/meteor/app/threads/server/methods/followMessage.ts @@ -1,5 +1,5 @@ import { Apps, AppEvents } from '@rocket.chat/apps'; -import type { IMessage } from '@rocket.chat/core-typings'; +import type { IMessage, IUser } from '@rocket.chat/core-typings'; import type { ServerMethods } from '@rocket.chat/ddp-client'; import { Messages } from '@rocket.chat/models'; import { check } from 'meteor/check'; @@ -18,7 +18,7 @@ declare module '@rocket.chat/ddp-client' { } } -export const followMessage = async (userId: string, { mid }: { mid: IMessage['_id'] }): Promise => { +export const followMessage = async (user: IUser, { mid }: { mid: IMessage['_id'] }): Promise => { if (mid && !settings.get('Threads_enabled')) { throw new Meteor.Error('error-not-allowed', 'not-allowed', { method: 'followMessage' }); } @@ -30,20 +30,20 @@ export const followMessage = async (userId: string, { mid }: { mid: IMessage['_i }); } - if (!(await canAccessRoomIdAsync(message.rid, userId))) { + if (!(await canAccessRoomIdAsync(message.rid, user._id))) { throw new Meteor.Error('error-not-allowed', 'not-allowed', { method: 'followMessage' }); } const id = message.tmid || message._id; - const followResult = await follow({ tmid: id, uid: userId }); + const followResult = await follow({ tmid: id, uid: user._id }); void notifyOnMessageChange({ id, }); const isFollowed = true; - await Apps.self?.triggerEvent(AppEvents.IPostMessageFollowed, message, await Meteor.userAsync(), isFollowed); + await Apps.self?.triggerEvent(AppEvents.IPostMessageFollowed, message, user, isFollowed); return followResult; }; @@ -52,12 +52,12 @@ Meteor.methods({ async followMessage({ mid }) { check(mid, String); - const uid = Meteor.userId(); - if (!uid) { + const user = (await Meteor.userAsync()) as IUser; + if (!user) { throw new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'followMessage' }); } - return followMessage(uid, { mid }); + return followMessage(user, { mid }); }, }); diff --git a/apps/meteor/app/threads/server/methods/unfollowMessage.ts b/apps/meteor/app/threads/server/methods/unfollowMessage.ts index d19bdf6040051..f5ffaa19fc7af 100644 --- a/apps/meteor/app/threads/server/methods/unfollowMessage.ts +++ b/apps/meteor/app/threads/server/methods/unfollowMessage.ts @@ -1,5 +1,5 @@ import { Apps, AppEvents } from '@rocket.chat/apps'; -import type { IMessage } from '@rocket.chat/core-typings'; +import type { IMessage, IUser } from '@rocket.chat/core-typings'; import type { ServerMethods } from '@rocket.chat/ddp-client'; import { Messages } from '@rocket.chat/models'; import { check } from 'meteor/check'; @@ -18,7 +18,7 @@ declare module '@rocket.chat/ddp-client' { } } -export const unfollowMessage = async (userId: string, { mid }: { mid: IMessage['_id'] }): Promise => { +export const unfollowMessage = async (user: IUser, { mid }: { mid: IMessage['_id'] }): Promise => { if (mid && !settings.get('Threads_enabled')) { throw new Meteor.Error('error-not-allowed', 'not-allowed', { method: 'unfollowMessage' }); } @@ -30,20 +30,20 @@ export const unfollowMessage = async (userId: string, { mid }: { mid: IMessage[' }); } - if (!(await canAccessRoomIdAsync(message.rid, userId))) { + if (!(await canAccessRoomIdAsync(message.rid, user._id))) { throw new Meteor.Error('error-not-allowed', 'not-allowed', { method: 'unfollowMessage' }); } const id = message.tmid || message._id; - const unfollowResult = await unfollow({ rid: message.rid, tmid: id, uid: userId }); + const unfollowResult = await unfollow({ rid: message.rid, tmid: id, uid: user._id }); void notifyOnMessageChange({ id, }); const isFollowed = false; - await Apps.self?.triggerEvent(AppEvents.IPostMessageFollowed, message, await Meteor.userAsync(), isFollowed); + await Apps.self?.triggerEvent(AppEvents.IPostMessageFollowed, message, user, isFollowed); return unfollowResult; }; @@ -52,12 +52,12 @@ Meteor.methods({ async unfollowMessage({ mid }) { check(mid, String); - const uid = Meteor.userId(); - if (!uid) { + const user = (await Meteor.userAsync()) as IUser; + if (!user) { throw new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'unfollowMessage' }); } - return unfollowMessage(uid, { mid }); + return unfollowMessage(user, { mid }); }, }); diff --git a/apps/meteor/app/user-status/server/methods/setUserStatus.ts b/apps/meteor/app/user-status/server/methods/setUserStatus.ts index 0b40e7e37246b..0235c4b681853 100644 --- a/apps/meteor/app/user-status/server/methods/setUserStatus.ts +++ b/apps/meteor/app/user-status/server/methods/setUserStatus.ts @@ -15,14 +15,18 @@ declare module '@rocket.chat/ddp-client' { } } -export const setUserStatusMethod = async (userId: string, statusType: IUser['status'], statusText: IUser['statusText']): Promise => { +export const setUserStatusMethod = async ( + user: Pick, + statusType: IUser['status'], + statusText: IUser['statusText'], +): Promise => { if (statusType) { if (statusType === 'offline' && !settings.get('Accounts_AllowInvisibleStatusOption')) { throw new Meteor.Error('error-status-not-allowed', 'Invisible status is disabled', { method: 'setUserStatus', }); } - await Presence.setStatus(userId, statusType); + await Presence.setStatus(user._id, statusType); } if (statusText || statusText === '') { @@ -34,18 +38,18 @@ export const setUserStatusMethod = async (userId: string, statusType: IUser['sta }); } - await setStatusText(userId, statusText); + await setStatusText(user, statusText); } }; Meteor.methods({ setUserStatus: async (statusType, statusText) => { - const userId = Meteor.userId(); - if (!userId) { + const user = (await Meteor.userAsync()) as IUser; + if (!user) { throw new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'setUserStatus' }); } - await setUserStatusMethod(userId, statusType, statusText); + await setUserStatusMethod(user, statusType, statusText); }, }); diff --git a/apps/meteor/ee/server/api/roles.ts b/apps/meteor/ee/server/api/roles.ts index 5164eb0b31db1..78e94f5b1477b 100644 --- a/apps/meteor/ee/server/api/roles.ts +++ b/apps/meteor/ee/server/api/roles.ts @@ -104,7 +104,7 @@ API.v1.addRoute( throw new Meteor.Error('error-invalid-role-properties', 'The role properties are invalid.'); } - const userId = Meteor.userId(); + const { userId } = this; if (!userId || !(await hasPermissionAsync(userId, 'access-permissions'))) { throw new Meteor.Error('error-action-not-allowed', 'Accessing permissions is not allowed'); diff --git a/apps/meteor/ee/server/apps/communication/rest.ts b/apps/meteor/ee/server/apps/communication/rest.ts index 5f579a0838876..2aaf02f8ec2b4 100644 --- a/apps/meteor/ee/server/apps/communication/rest.ts +++ b/apps/meteor/ee/server/apps/communication/rest.ts @@ -8,7 +8,6 @@ import { License } from '@rocket.chat/license'; import { Logger } from '@rocket.chat/logger'; import { Settings, Users } from '@rocket.chat/models'; import { serverFetch as fetch } from '@rocket.chat/server-fetch'; -import { Meteor } from 'meteor/meteor'; import * as z from 'zod'; import { registerActionButtonsHandler } from './endpoints/actionButtonsHandler'; @@ -355,10 +354,7 @@ export class AppsRestApi { return API.v1.internalError('private_app_install_disabled'); } - const user = orchestrator - ?.getConverters() - ?.get('users') - ?.convertToApp(await Meteor.userAsync()); + const user = orchestrator?.getConverters()?.get('users')?.convertToApp(this.user); const aff = await manager.add(buff, { ...(marketplaceInfo && { marketplaceInfo }), @@ -878,10 +874,7 @@ export class AppsRestApi { return API.v1.failure({ error: 'Cannot_Update_Exempt_App' }); } - const user = orchestrator - ?.getConverters() - ?.get('users') - ?.convertToApp(await Meteor.userAsync()); + const user = orchestrator?.getConverters()?.get('users')?.convertToApp(this.user); const aff = await manager.update(buff, permissionsGranted, { user, loadApp: true }); const info: IAppInfo & { status?: AppStatus } = aff.getAppInfo(); @@ -917,10 +910,7 @@ export class AppsRestApi { return API.v1.notFound(`No App found by the id of: ${this.urlParams.id}`); } - const user = orchestrator - ?.getConverters() - ?.get('users') - .convertToApp(await Meteor.userAsync()); + const user = orchestrator?.getConverters()?.get('users').convertToApp(this.user); const info: IAppInfo & { status?: AppStatus } = prl.getInfo(); try { diff --git a/apps/meteor/imports/personal-access-tokens/server/api/methods/generateToken.ts b/apps/meteor/imports/personal-access-tokens/server/api/methods/generateToken.ts index 15ed90b511703..fdb6067e2eb5d 100644 --- a/apps/meteor/imports/personal-access-tokens/server/api/methods/generateToken.ts +++ b/apps/meteor/imports/personal-access-tokens/server/api/methods/generateToken.ts @@ -14,7 +14,15 @@ declare module '@rocket.chat/ddp-client' { } } -export const generatePersonalAccessTokenOfUser = async ({ bypassTwoFactor, tokenName, userId }: {tokenName: string, userId: string, bypassTwoFactor: boolean}): Promise => { +export const generatePersonalAccessTokenOfUser = async ({ + bypassTwoFactor, + tokenName, + userId, +}: { + tokenName: string; + userId: string; + bypassTwoFactor: boolean; +}): Promise => { if (!(await hasPermissionAsync(userId, 'create-personal-access-tokens'))) { throw new Meteor.Error('not-authorized', 'Not Authorized', { method: 'personalAccessTokens:generateToken', @@ -44,17 +52,23 @@ export const generatePersonalAccessTokenOfUser = async ({ bypassTwoFactor, token }, }); return token; -} +}; Meteor.methods({ - 'personalAccessTokens:generateToken': twoFactorRequired(async function ({ tokenName, bypassTwoFactor }) { + 'personalAccessTokens:generateToken': twoFactorRequired(async function ({ + tokenName, + bypassTwoFactor, + }: { + tokenName: string; + bypassTwoFactor: boolean; + }) { const uid = Meteor.userId(); if (!uid) { throw new Meteor.Error('not-authorized', 'Not Authorized', { method: 'personalAccessTokens:generateToken', }); } - + return generatePersonalAccessTokenOfUser({ tokenName, userId: uid, bypassTwoFactor }); }), }); diff --git a/apps/meteor/imports/personal-access-tokens/server/api/methods/regenerateToken.ts b/apps/meteor/imports/personal-access-tokens/server/api/methods/regenerateToken.ts index 281ed55dc013c..046929a1ad97a 100644 --- a/apps/meteor/imports/personal-access-tokens/server/api/methods/regenerateToken.ts +++ b/apps/meteor/imports/personal-access-tokens/server/api/methods/regenerateToken.ts @@ -44,7 +44,7 @@ export const regeneratePersonalAccessTokenOfUser = async (tokenName: string, use }; Meteor.methods({ - 'personalAccessTokens:regenerateToken': twoFactorRequired(async function ({ tokenName }) { + 'personalAccessTokens:regenerateToken': twoFactorRequired(async function ({ tokenName }: { tokenName: string }) { const uid = Meteor.userId(); if (!uid) { throw new Meteor.Error('not-authorized', 'Not Authorized', { diff --git a/apps/meteor/imports/personal-access-tokens/server/api/methods/removeToken.ts b/apps/meteor/imports/personal-access-tokens/server/api/methods/removeToken.ts index 3bc249143e12d..53048574d8127 100644 --- a/apps/meteor/imports/personal-access-tokens/server/api/methods/removeToken.ts +++ b/apps/meteor/imports/personal-access-tokens/server/api/methods/removeToken.ts @@ -34,10 +34,10 @@ export const removePersonalAccessTokenOfUser = async (tokenName: string, userId: name: tokenName, }, }); -} +}; Meteor.methods({ - 'personalAccessTokens:removeToken': twoFactorRequired(async function ({ tokenName }) { + 'personalAccessTokens:removeToken': twoFactorRequired(async function ({ tokenName }: { tokenName: string }) { const uid = Meteor.userId(); if (!uid) { throw new Meteor.Error('not-authorized', 'Not Authorized', { diff --git a/apps/meteor/server/lib/eraseRoom.ts b/apps/meteor/server/lib/eraseRoom.ts index 72933a1d34a82..5ddcf876e5c7e 100644 --- a/apps/meteor/server/lib/eraseRoom.ts +++ b/apps/meteor/server/lib/eraseRoom.ts @@ -1,6 +1,6 @@ import { AppEvents, Apps } from '@rocket.chat/apps'; import { Message, Team } from '@rocket.chat/core-services'; -import type { IRoom } from '@rocket.chat/core-typings'; +import type { IRoom, IUser, AtLeast } from '@rocket.chat/core-typings'; import { Rooms } from '@rocket.chat/models'; import { Meteor } from 'meteor/meteor'; @@ -8,7 +8,7 @@ import { roomCoordinator } from './rooms/roomCoordinator'; import { hasPermissionAsync } from '../../app/authorization/server/functions/hasPermission'; import { deleteRoom } from '../../app/lib/server/functions/deleteRoom'; -export async function eraseRoom(roomOrId: string | IRoom, uid: string): Promise { +export async function eraseRoom(roomOrId: string | IRoom, user: AtLeast): Promise { const room = typeof roomOrId === 'string' ? await Rooms.findOneById(roomOrId) : roomOrId; if (!room) { @@ -26,7 +26,7 @@ export async function eraseRoom(roomOrId: string | IRoom, uid: string): Promise< if ( !(await roomCoordinator .getRoomDirectives(room.t) - ?.canBeDeleted((permissionId, rid) => hasPermissionAsync(uid, permissionId, rid), room)) + ?.canBeDeleted((permissionId, rid) => hasPermissionAsync(user._id, permissionId, rid), room)) ) { throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'eraseRoom', @@ -34,7 +34,7 @@ export async function eraseRoom(roomOrId: string | IRoom, uid: string): Promise< } const team = room.teamId && (await Team.getOneById(room.teamId, { projection: { roomId: 1 } })); - if (team && !(await hasPermissionAsync(uid, `delete-team-${room.t === 'c' ? 'channel' : 'group'}`, team.roomId))) { + if (team && !(await hasPermissionAsync(user._id, `delete-team-${room.t === 'c' ? 'channel' : 'group'}`, team.roomId))) { throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'eraseRoom', }); @@ -50,10 +50,7 @@ export async function eraseRoom(roomOrId: string | IRoom, uid: string): Promise< await deleteRoom(room._id); if (team) { - const user = await Meteor.userAsync(); - if (user) { - await Message.saveSystemMessage('user-deleted-room-from-team', team.roomId, room.name || '', user); - } + await Message.saveSystemMessage('user-deleted-room-from-team', team.roomId, room.name || '', user); } if (Apps.self?.isLoaded()) { diff --git a/apps/meteor/server/lib/removeOtherTokens.ts b/apps/meteor/server/lib/removeOtherTokens.ts deleted file mode 100644 index 0971c24aba469..0000000000000 --- a/apps/meteor/server/lib/removeOtherTokens.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Users } from '@rocket.chat/models'; -import { Accounts } from 'meteor/accounts-base'; - -export const removeOtherTokens = async function (userId: string, connectionId: string): Promise { - const currentToken = Accounts._getLoginToken(connectionId); - - await Users.removeNonLoginTokensExcept(userId, currentToken); -}; diff --git a/apps/meteor/server/methods/messageSearch.ts b/apps/meteor/server/methods/messageSearch.ts index e3f522048d797..231f952192b92 100644 --- a/apps/meteor/server/methods/messageSearch.ts +++ b/apps/meteor/server/methods/messageSearch.ts @@ -1,6 +1,6 @@ -import type { ISubscription, IUser } from '@rocket.chat/core-typings'; +import type { ISubscription } from '@rocket.chat/core-typings'; import type { ServerMethods } from '@rocket.chat/ddp-client'; -import { Messages, Subscriptions } from '@rocket.chat/models'; +import { Messages, Subscriptions, Users } from '@rocket.chat/models'; import { Match, check } from 'meteor/check'; import { Meteor } from 'meteor/meteor'; @@ -42,7 +42,7 @@ export const messageSearch = async function ( }; } - const user = (await Meteor.userAsync()) as IUser | undefined; + const user = (await Users.findOneById(userId)) || undefined; const { query, options } = parseMessageSearchQuery(text, { user, diff --git a/apps/meteor/server/methods/saveUserProfile.ts b/apps/meteor/server/methods/saveUserProfile.ts index 00115facbf315..f28e0c59f8c62 100644 --- a/apps/meteor/server/methods/saveUserProfile.ts +++ b/apps/meteor/server/methods/saveUserProfile.ts @@ -6,7 +6,7 @@ import { Match, check } from 'meteor/check'; import { Meteor } from 'meteor/meteor'; import type { UpdateFilter } from 'mongodb'; -import { twoFactorRequired } from '../../app/2fa/server/twoFactorRequired'; +import { type AuthenticatedContext, twoFactorRequired } from '../../app/2fa/server/twoFactorRequired'; import { getUserInfo } from '../../app/api/server/helpers/getUserInfo'; import { saveCustomFields } from '../../app/lib/server/functions/saveCustomFields'; import { validateUserEditing } from '../../app/lib/server/functions/saveUser'; @@ -18,13 +18,12 @@ import { settings as rcSettings } from '../../app/settings/server'; import { setUserStatusMethod } from '../../app/user-status/server/methods/setUserStatus'; import { compareUserPassword } from '../lib/compareUserPassword'; import { compareUserPasswordHistory } from '../lib/compareUserPasswordHistory'; -import { removeOtherTokens } from '../lib/removeOtherTokens'; const MAX_BIO_LENGTH = 260; const MAX_NICKNAME_LENGTH = 120; async function saveUserProfile( - this: Meteor.MethodThisType, + this: AuthenticatedContext, settings: { email?: string; username?: string; @@ -62,6 +61,12 @@ async function saveUserProfile( const user = await Users.findOneById(this.userId); + if (!user) { + throw new Meteor.Error('error-invalid-user', 'Invalid user', { + method: 'saveUserProfile', + }); + } + if (settings.realname || settings.username) { if ( !(await saveUserIdentity({ @@ -77,11 +82,11 @@ async function saveUserProfile( } if (settings.statusText || settings.statusText === '') { - await setUserStatusMethod(this.userId, undefined, settings.statusText); + await setUserStatusMethod(user, undefined, settings.statusText); } if (settings.statusType) { - await setUserStatusMethod(this.userId, settings.statusType as UserStatus, undefined); + await setUserStatusMethod(user, settings.statusType as UserStatus, undefined); } if (user && (settings.bio || settings.bio === '')) { @@ -152,7 +157,7 @@ async function saveUserProfile( ); try { - await removeOtherTokens(this.userId, this.connection?.id || ''); + await Users.removeNonLoginTokensExcept(this.userId, this.token); } catch (e) { Accounts._clearAllLoginTokens(this.userId); } @@ -210,7 +215,7 @@ declare module '@rocket.chat/ddp-client' { } export function executeSaveUserProfile( - this: Meteor.MethodThisType, + this: AuthenticatedContext, user: IUser, settings: { email?: string;