chore: replace ids with objects as parameters (#38367)

pull/38279/head
Guilherme Gazzo 4 months ago committed by GitHub
parent 75d089ca40
commit f4d7cc7242
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 24
      apps/meteor/app/2fa/server/twoFactorRequired.ts
  2. 2
      apps/meteor/app/api/server/lib/eraseTeam.spec.ts
  3. 16
      apps/meteor/app/api/server/lib/eraseTeam.ts
  4. 2
      apps/meteor/app/api/server/v1/channels.ts
  5. 4
      apps/meteor/app/api/server/v1/chat.ts
  6. 2
      apps/meteor/app/api/server/v1/groups.ts
  7. 2
      apps/meteor/app/api/server/v1/im.ts
  8. 2
      apps/meteor/app/api/server/v1/rooms.ts
  9. 2
      apps/meteor/app/api/server/v1/teams.ts
  10. 17
      apps/meteor/app/api/server/v1/users.ts
  11. 2
      apps/meteor/app/lib/server/functions/saveUser/saveUser.ts
  12. 15
      apps/meteor/app/lib/server/functions/setStatusText.ts
  13. 6
      apps/meteor/app/lib/server/methods/saveSetting.ts
  14. 4
      apps/meteor/app/message-pin/server/pinMessage.ts
  15. 14
      apps/meteor/app/slashcommands-status/server/status.ts
  16. 16
      apps/meteor/app/threads/server/methods/followMessage.ts
  17. 16
      apps/meteor/app/threads/server/methods/unfollowMessage.ts
  18. 16
      apps/meteor/app/user-status/server/methods/setUserStatus.ts
  19. 2
      apps/meteor/ee/server/api/roles.ts
  20. 16
      apps/meteor/ee/server/apps/communication/rest.ts
  21. 22
      apps/meteor/imports/personal-access-tokens/server/api/methods/generateToken.ts
  22. 2
      apps/meteor/imports/personal-access-tokens/server/api/methods/regenerateToken.ts
  23. 4
      apps/meteor/imports/personal-access-tokens/server/api/methods/removeToken.ts
  24. 13
      apps/meteor/server/lib/eraseRoom.ts
  25. 8
      apps/meteor/server/lib/removeOtherTokens.ts
  26. 6
      apps/meteor/server/methods/messageSearch.ts
  27. 19
      apps/meteor/server/methods/saveUserProfile.ts

@ -3,11 +3,24 @@ import { Meteor } from 'meteor/meteor';
import type { ITwoFactorOptions } from './code/index';
import { checkCodeForUser } from './code/index';
export function twoFactorRequired<TFunction extends (this: Meteor.MethodThisType, ...args: any[]) => any>(
fn: TFunction,
export type AuthenticatedContext = {
userId: string;
token: string;
connection: {
id: string;
clientAddress: string;
httpHeaders: Record<string, string>;
};
twoFactorChecked: boolean;
};
export const twoFactorRequired = <TFunction extends (this: any, ...args: any) => Promise<any>>(
fn: ThisParameterType<TFunction> extends AuthenticatedContext
? TFunction
: (this: AuthenticatedContext, ...args: Parameters<TFunction>) => ReturnType<TFunction>,
options?: ITwoFactorOptions,
): (this: Meteor.MethodThisType, ...args: Parameters<TFunction>) => Promise<ReturnType<TFunction>> {
return async function (this: Meteor.MethodThisType, ...args: Parameters<TFunction>): Promise<ReturnType<TFunction>> {
) =>
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<TFunction extends (this: Meteor.MethodThisType
}
return fn.apply(this, args);
};
}
} as (this: ThisParameterType<TFunction>, ...args: Parameters<TFunction>) => ReturnType<TFunction>;

@ -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);
});
});

@ -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<IUser, '_id' | 'username' | 'name'>) => Promise<boolean | void>;
type EraseRoomFnType = <T extends AtLeast<IUser, '_id' | 'name' | 'username'>>(rid: string, user: T) => Promise<boolean | void>;
export const eraseTeamShared = async (
user: AtLeast<IUser, '_id' | 'username' | 'name'>,
export const eraseTeamShared = async <T extends AtLeast<IUser, '_id' | 'name' | 'username'>>(
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<IUser, '_id' | 'username' | 'name'>, 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<IUser, '_id' | 'username' | 'name'
*/
export const eraseTeamOnRelinquishRoomOwnerships = async (team: ITeam, roomsToRemove: IRoom['_id'][] = []): Promise<string[]> => {
const deletedRooms = new Set<string>();
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);

@ -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();
},

@ -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();
},

@ -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();
},

@ -155,7 +155,7 @@ const dmDeleteAction = <Path extends string>(_path: Path): TypedAction<typeof dm
throw new Meteor.Error('error-not-allowed', 'Not allowed');
}
await eraseRoom(room._id, this.userId);
await eraseRoom(room._id, this.user);
return API.v1.success();
};

@ -148,7 +148,7 @@ API.v1.addRoute(
});
}
await eraseRoom(room, this.userId);
await eraseRoom(room, this.user);
return API.v1.success();
},

@ -133,7 +133,7 @@ API.v1.addRoute(
if (rooms.length) {
for await (const room of rooms) {
await eraseRoom(room, this.userId);
await eraseRoom(room, this.user);
}
}

@ -31,7 +31,6 @@ import { regeneratePersonalAccessTokenOfUser } from '../../../../imports/persona
import { removePersonalAccessTokenOfUser } from '../../../../imports/personal-access-tokens/server/api/methods/removeToken';
import { UserChangedAuditStore } from '../../../../server/lib/auditServerEvents/userChanged';
import { i18n } from '../../../../server/lib/i18n';
import { removeOtherTokens } from '../../../../server/lib/removeOtherTokens';
import { resetUserE2EEncriptionKey } from '../../../../server/lib/resetUserE2EKey';
import { registerUser } from '../../../../server/methods/registerUser';
import { requestDataDownload } from '../../../../server/methods/requestDataDownload';
@ -187,13 +186,7 @@ API.v1.addRoute(
twoFactorMethod: 'password',
};
await executeSaveUserProfile.call(
this as unknown as Meteor.MethodThisType,
this.user,
userData,
this.bodyParams.customFields,
twoFactorOptions,
);
await executeSaveUserProfile.call(this, this.user, userData, this.bodyParams.customFields, twoFactorOptions);
return API.v1.success({
user: await Users.findOneById(this.userId, { projection: API.v1.defaultFieldsToExclude }),
@ -1239,7 +1232,7 @@ API.v1.addRoute(
{ authRequired: true },
{
async post() {
return API.v1.success(await removeOtherTokens(this.userId, this.connection.id));
return API.v1.success(await Users.removeNonLoginTokensExcept(this.userId, this.token));
},
},
);
@ -1410,9 +1403,7 @@ API.v1.addRoute(
});
}
const user = await (async (): Promise<
Pick<IUser, '_id' | 'username' | 'name' | 'status' | 'statusText' | 'roles'> | 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;
}

@ -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) {

@ -7,7 +7,7 @@ import type { ClientSession } from 'mongodb';
import { onceTransactionCommitedSuccessfully } from '../../../../server/database/utils';
export async function setStatusText(
userId: string,
user: Pick<IUser, '_id' | 'username' | 'name' | 'status' | 'roles' | 'statusText'>,
statusText: string,
{
updater,
@ -19,21 +19,8 @@ export async function setStatusText(
emit?: boolean;
} = {},
): Promise<boolean> {
if (!userId) {
return false;
}
statusText = statusText.trim().substr(0, 120);
const user = await Users.findOneById<Pick<IUser, '_id' | 'username' | 'name' | 'status' | 'roles' | 'statusText'>>(userId, {
projection: { username: 1, name: 1, status: 1, roles: 1, statusText: 1 },
session,
});
if (!user) {
return false;
}
if (user.statusText === statusText) {
return true;
}

@ -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<boolean>;
saveSetting(_id: string, value: SettingValue, editor: SettingEditor): Promise<boolean>;
}
}
Meteor.methods<ServerMethods>({
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', {

@ -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')) {

@ -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<Pick<IUser, '_id' | 'username' | 'name' | 'status' | 'roles' | 'statusText' | 'language'>>(
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 }),

@ -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<false | undefined> => {
export const followMessage = async (user: IUser, { mid }: { mid: IMessage['_id'] }): Promise<false | undefined> => {
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<ServerMethods>({
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 });
},
});

@ -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<false | undefined> => {
export const unfollowMessage = async (user: IUser, { mid }: { mid: IMessage['_id'] }): Promise<false | undefined> => {
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<ServerMethods>({
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 });
},
});

@ -15,14 +15,18 @@ declare module '@rocket.chat/ddp-client' {
}
}
export const setUserStatusMethod = async (userId: string, statusType: IUser['status'], statusText: IUser['statusText']): Promise<void> => {
export const setUserStatusMethod = async (
user: Pick<IUser, '_id' | 'username' | 'name' | 'status' | 'roles' | 'statusText'>,
statusType: IUser['status'],
statusText: IUser['statusText'],
): Promise<void> => {
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<ServerMethods>({
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);
},
});

@ -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');

@ -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 {

@ -14,7 +14,15 @@ declare module '@rocket.chat/ddp-client' {
}
}
export const generatePersonalAccessTokenOfUser = async ({ bypassTwoFactor, tokenName, userId }: {tokenName: string, userId: string, bypassTwoFactor: boolean}): Promise<string> => {
export const generatePersonalAccessTokenOfUser = async ({
bypassTwoFactor,
tokenName,
userId,
}: {
tokenName: string;
userId: string;
bypassTwoFactor: boolean;
}): Promise<string> => {
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<ServerMethods>({
'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 });
}),
});

@ -44,7 +44,7 @@ export const regeneratePersonalAccessTokenOfUser = async (tokenName: string, use
};
Meteor.methods<ServerMethods>({
'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', {

@ -34,10 +34,10 @@ export const removePersonalAccessTokenOfUser = async (tokenName: string, userId:
name: tokenName,
},
});
}
};
Meteor.methods<ServerMethods>({
'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', {

@ -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<void> {
export async function eraseRoom(roomOrId: string | IRoom, user: AtLeast<IUser, '_id' | 'name' | 'username'>): Promise<void> {
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()) {

@ -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<void> {
const currentToken = Accounts._getLoginToken(connectionId);
await Users.removeNonLoginTokensExcept(userId, currentToken);
};

@ -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,

@ -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;

Loading…
Cancel
Save