-
Notifications
You must be signed in to change notification settings - Fork 13.7k
feat: migrate batch4 client DDP callers + add 6 REST endpoints #40728
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
29d71a2
53ee70c
9bfa117
7401c7e
3eacd95
e62bf04
df1d4e7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| '@rocket.chat/meteor': minor | ||
| --- | ||
|
|
||
| Moved the post-logout cleanup hook (`afterLogoutCleanUpCallback` + `Apps.IPostUserLoggedOut`) into a server-side `Accounts.onLogout` handler and into `POST /v1/users.logout`. Both DDP and REST logout paths now fire those callbacks server-side; the client no longer needs to invoke `logoutCleanUp` after detecting a logout, and the deprecated DDP method keeps its registration with a deprecation log pointing at `/v1/users.logout`. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| --- | ||
| '@rocket.chat/rest-typings': minor | ||
| '@rocket.chat/meteor': minor | ||
| --- | ||
|
|
||
| Added `POST /v1/cloud.connectWorkspace` (replaces the deprecated `cloud:connectWorkspace` DDP method). Body is `{ token }`; auth-gated with `manage-cloud` permission. The legacy DDP method remains registered with a deprecation log pointing at the new route. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| --- | ||
| '@rocket.chat/rest-typings': minor | ||
| '@rocket.chat/meteor': minor | ||
| --- | ||
|
|
||
| Added `POST /v1/integrations.history.clear` and `POST /v1/integrations.outgoing.replay` (replace the deprecated `clearIntegrationHistory` and `replayOutgoingIntegration` DDP methods). Bodies `{ integrationId }` and `{ integrationId, historyId }` respectively. Permissions (`manage-outgoing-integrations` or `manage-own-outgoing-integrations`) are enforced the same way the DDP methods did. Legacy DDP methods remain registered with deprecation logs pointing at the new routes. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| --- | ||
| '@rocket.chat/rest-typings': minor | ||
| '@rocket.chat/meteor': minor | ||
| --- | ||
|
|
||
| Added `POST /v1/permissions.addRole` and `POST /v1/permissions.removeRole` (replace the deprecated `authorization:addPermissionToRole` and `authorization:removeRoleFromPermission` DDP methods). Body is `{ permissionId, role }` on both. The same per-user permission checks (`access-permissions`, `access-setting-permissions`) the DDP methods enforced are reused. Legacy DDP methods remain registered with deprecation logs pointing at the new routes. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| '@rocket.chat/meteor': minor | ||
| --- | ||
|
|
||
| Extended `POST /v1/users.setAvatar` to accept an optional `service` multipart field. When provided, the value is stored as the user's `avatarOrigin`, matching what the deprecated `setAvatarFromService` DDP method did. The legacy DDP method remains registered with a deprecation log pointing at the new route. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| --- | ||
| '@rocket.chat/rest-typings': minor | ||
| '@rocket.chat/meteor': minor | ||
| --- | ||
|
|
||
| Added `POST /v1/users.verifyEmail` (replaces the two-call DDP flow of `verifyEmail` + `afterVerifyEmail`). Body is `{ token }`; the server resolves the user, marks the email verified, and runs the anonymous→user role swap in a single request. The deprecated `afterVerifyEmail` DDP method keeps its registration with a deprecation log pointing at the new route. |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -9,6 +9,7 @@ import { | |||||||||||||||||||
| } from '@rocket.chat/rest-typings'; | ||||||||||||||||||||
| import { Meteor } from 'meteor/meteor'; | ||||||||||||||||||||
|
|
||||||||||||||||||||
| import { addPermissionToRoleMethod, removeRoleFromPermissionMethod } from '../../../authorization/server/functions/permissionRole'; | ||||||||||||||||||||
| import { permissionsGetMethod } from '../../../authorization/server/streamer/permissions'; | ||||||||||||||||||||
| import { notifyOnPermissionChangedById } from '../../../lib/server/lib/notifyListener'; | ||||||||||||||||||||
| import type { ExtractRoutesFromAPI } from '../ApiClass'; | ||||||||||||||||||||
|
|
@@ -62,6 +63,25 @@ const isPermissionsListAll = ajvQuery.compile<PermissionsListAllProps>(permissio | |||||||||||||||||||
|
|
||||||||||||||||||||
| const isBodyParamsValidPermissionUpdate = ajv.compile<PermissionsUpdateProps>(permissionUpdatePropsSchema); | ||||||||||||||||||||
|
|
||||||||||||||||||||
| type PermissionRolePayload = { permissionId: string; role: string }; | ||||||||||||||||||||
|
|
||||||||||||||||||||
| const isPermissionRolePayload = ajv.compile<PermissionRolePayload>({ | ||||||||||||||||||||
| type: 'object', | ||||||||||||||||||||
| properties: { | ||||||||||||||||||||
| permissionId: { type: 'string', minLength: 1 }, | ||||||||||||||||||||
| role: { type: 'string', minLength: 1 }, | ||||||||||||||||||||
| }, | ||||||||||||||||||||
| required: ['permissionId', 'role'], | ||||||||||||||||||||
| additionalProperties: false, | ||||||||||||||||||||
| }); | ||||||||||||||||||||
|
|
||||||||||||||||||||
| const voidPermissionResponse = ajv.compile<void>({ | ||||||||||||||||||||
| type: 'object', | ||||||||||||||||||||
| properties: { success: { type: 'boolean', enum: [true] } }, | ||||||||||||||||||||
| required: ['success'], | ||||||||||||||||||||
| additionalProperties: false, | ||||||||||||||||||||
| }); | ||||||||||||||||||||
|
|
||||||||||||||||||||
| const permissionsEndpoints = API.v1 | ||||||||||||||||||||
| .get( | ||||||||||||||||||||
| 'permissions.listAll', | ||||||||||||||||||||
|
|
@@ -185,6 +205,42 @@ const permissionsEndpoints = API.v1 | |||||||||||||||||||
| permissions: result, | ||||||||||||||||||||
| }); | ||||||||||||||||||||
| }, | ||||||||||||||||||||
| ) | ||||||||||||||||||||
| .post( | ||||||||||||||||||||
| 'permissions.addRole', | ||||||||||||||||||||
| { | ||||||||||||||||||||
| authRequired: true, | ||||||||||||||||||||
| body: isPermissionRolePayload, | ||||||||||||||||||||
|
Comment on lines
+210
to
+213
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: Add a route-level (Based on your team's feedback about permission checks at public API entry points.) Prompt for AI agents
Suggested change
|
||||||||||||||||||||
| response: { | ||||||||||||||||||||
| 200: voidPermissionResponse, | ||||||||||||||||||||
| 400: validateBadRequestErrorResponse, | ||||||||||||||||||||
| 401: validateUnauthorizedErrorResponse, | ||||||||||||||||||||
| 403: validateForbiddenErrorResponse, | ||||||||||||||||||||
| }, | ||||||||||||||||||||
| }, | ||||||||||||||||||||
| async function action() { | ||||||||||||||||||||
| const { permissionId, role } = this.bodyParams; | ||||||||||||||||||||
| await addPermissionToRoleMethod(this.userId, permissionId, role); | ||||||||||||||||||||
| return API.v1.success(); | ||||||||||||||||||||
| }, | ||||||||||||||||||||
| ) | ||||||||||||||||||||
| .post( | ||||||||||||||||||||
| 'permissions.removeRole', | ||||||||||||||||||||
| { | ||||||||||||||||||||
| authRequired: true, | ||||||||||||||||||||
| body: isPermissionRolePayload, | ||||||||||||||||||||
|
Comment on lines
+228
to
+231
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: Add a route-level (Based on your team's feedback about permission checks at public API entry points.) Prompt for AI agents
Suggested change
|
||||||||||||||||||||
| response: { | ||||||||||||||||||||
| 200: voidPermissionResponse, | ||||||||||||||||||||
| 400: validateBadRequestErrorResponse, | ||||||||||||||||||||
| 401: validateUnauthorizedErrorResponse, | ||||||||||||||||||||
| 403: validateForbiddenErrorResponse, | ||||||||||||||||||||
| }, | ||||||||||||||||||||
| }, | ||||||||||||||||||||
| async function action() { | ||||||||||||||||||||
| const { permissionId, role } = this.bodyParams; | ||||||||||||||||||||
| await removeRoleFromPermissionMethod(this.userId, permissionId, role); | ||||||||||||||||||||
| return API.v1.success(); | ||||||||||||||||||||
| }, | ||||||||||||||||||||
| ); | ||||||||||||||||||||
|
|
||||||||||||||||||||
| export type PermissionsEndpoints = ExtractRoutesFromAPI<typeof permissionsEndpoints>; | ||||||||||||||||||||
|
|
||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -38,10 +38,12 @@ import type { Filter } from 'mongodb'; | |||||||||||
| import { generatePersonalAccessTokenOfUser } from '../../../../imports/personal-access-tokens/server/api/methods/generateToken'; | ||||||||||||
| import { regeneratePersonalAccessTokenOfUser } from '../../../../imports/personal-access-tokens/server/api/methods/regenerateToken'; | ||||||||||||
| import { removePersonalAccessTokenOfUser } from '../../../../imports/personal-access-tokens/server/api/methods/removeToken'; | ||||||||||||
| import { runUserLogoutCleanUp } from '../../../../server/hooks/userLogoutCleanUp'; | ||||||||||||
| import { UserChangedAuditStore } from '../../../../server/lib/auditServerEvents/userChanged'; | ||||||||||||
| import { i18n } from '../../../../server/lib/i18n'; | ||||||||||||
| import { SystemLogger } from '../../../../server/lib/logger/system'; | ||||||||||||
| import { resetUserE2EEncriptionKey } from '../../../../server/lib/resetUserE2EKey'; | ||||||||||||
| import { runAfterVerifyEmail } from '../../../../server/lib/users/runAfterVerifyEmail'; | ||||||||||||
| import { registerUser } from '../../../../server/methods/registerUser'; | ||||||||||||
| import { requestDataDownload } from '../../../../server/methods/requestDataDownload'; | ||||||||||||
| import { resetAvatar } from '../../../../server/methods/resetAvatar'; | ||||||||||||
|
|
@@ -343,7 +345,9 @@ API.v1 | |||||||||||
| } | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| await setUserAvatar(user, fileBuffer, mimetype, 'rest'); | ||||||||||||
| const service = typeof fields.service === 'string' && fields.service.length > 0 ? fields.service : 'rest'; | ||||||||||||
|
|
||||||||||||
| await setUserAvatar(user, fileBuffer, mimetype, service as 'rest'); | ||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P1: Unsafe type assertion Prompt for AI agents
Suggested change
|
||||||||||||
|
|
||||||||||||
| return API.v1.success(); | ||||||||||||
| }, | ||||||||||||
|
|
@@ -1877,6 +1881,8 @@ API.v1 | |||||||||||
| return API.v1.forbidden(); | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| const user = await Users.findOneById(userId); | ||||||||||||
|
|
||||||||||||
| // this method logs the user out automatically, if successful returns 1, otherwise 0 | ||||||||||||
| if (!(await Users.unsetLoginTokens(userId))) { | ||||||||||||
| throw new Meteor.Error('error-invalid-user-id', 'Invalid user id'); | ||||||||||||
|
|
@@ -1886,6 +1892,10 @@ API.v1 | |||||||||||
|
|
||||||||||||
| void notifyOnUserChange({ clientAction: 'updated', id: userId, diff: { 'services.resume.loginTokens': [] } }); | ||||||||||||
|
|
||||||||||||
| if (user) { | ||||||||||||
| await runUserLogoutCleanUp(user); | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| return API.v1.success({ | ||||||||||||
| message: `User ${userId} has been logged out!`, | ||||||||||||
| }); | ||||||||||||
|
|
@@ -2080,6 +2090,38 @@ API.v1 | |||||||||||
| }, | ||||||||||||
| ); | ||||||||||||
|
|
||||||||||||
| API.v1.post( | ||||||||||||
| 'users.verifyEmail', | ||||||||||||
| { | ||||||||||||
| authRequired: false, | ||||||||||||
| body: ajv.compile<{ token: string }>({ | ||||||||||||
| type: 'object', | ||||||||||||
| properties: { | ||||||||||||
| token: { type: 'string', minLength: 1 }, | ||||||||||||
| }, | ||||||||||||
| required: ['token'], | ||||||||||||
| additionalProperties: false, | ||||||||||||
| }), | ||||||||||||
| response: { | ||||||||||||
| 200: voidSuccessResponse, | ||||||||||||
| 400: validateBadRequestErrorResponse, | ||||||||||||
| }, | ||||||||||||
| }, | ||||||||||||
| async function action() { | ||||||||||||
| const { token } = this.bodyParams; | ||||||||||||
|
|
||||||||||||
| const user = await Users.findOne<Pick<IUser, '_id'>>({ 'services.email.verificationTokens.token': token }, { projection: { _id: 1 } }); | ||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: The user lookup should occur after Prompt for AI agents |
||||||||||||
|
|
||||||||||||
| await Meteor.callAsync('verifyEmail', token); | ||||||||||||
|
|
||||||||||||
| if (user) { | ||||||||||||
| await runAfterVerifyEmail(user._id); | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| return API.v1.success(); | ||||||||||||
| }, | ||||||||||||
|
Comment on lines
+2110
to
+2122
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔴 High: Missing authorization check in users.update API allows account takeover and privilege escalation The Tracegraph TD
subgraph SG0 ["apps/meteor/app/2fa/server/code/index.ts"]
getUserForCheck["Retrieves user data required for two-factor authentication checks."]
end
style SG0 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG1 ["apps/meteor/app/2fa/server/functions/resetTOTP.ts"]
sendResetNotification_2["sendResetNotification"]
resetTOTP["Resets a user's TOTP configuration, optionally notifying the user via email."]
end
style SG1 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG2 ["apps/meteor/app/api/server/ApiClass.ts"]
APIClass.success["Returns a successful API response."]
APIClass.failure["Returns a failure API response."]
APIClass.forbidden["Returns a 403 Forbidden API response."]
APIClass.this.parseJsonQuery["Parses JSON query parameters for an API context."]
end
style SG2 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG3 ["apps/meteor/app/api/server/helpers/getPaginationItems.ts"]
getPaginationItems["Calculates pagination offset and count based on request parameters and system settings."]
end
style SG3 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG4 ["apps/meteor/app/api/server/helpers/getUserFromParams.ts"]
getUserFromParams["Retrieves a user object based on userId or username parameters from an API request."]
end
style SG4 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG5 ["apps/meteor/app/api/server/helpers/getUserInfo.ts"]
isVerifiedEmail["isVerifiedEmail"]
getUserPreferences["getUserPreferences"]
filterOutdatedVersionUpdateBanners["filterOutdatedVersionUpdateBanners"]
getUserCalendar["getUserCalendar"]
getUserInfo["Constructs and returns a comprehensive user information object for API responses, including preferences and calendar settings."]
end
style SG5 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG6 ["apps/meteor/app/api/server/helpers/isUserFromParams.ts"]
isUserFromParams["Validates if the provided parameters identify the currently logged-in user."]
end
style SG6 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG7 ["apps/meteor/app/api/server/lib/eraseTeam.ts"]
eraseTeamOnRelinquishRoomOwnerships["eraseTeamOnRelinquishRoomOwnerships"]
eraseRoomLooseValidation["eraseRoomLooseValidation"]
end
style SG7 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG8 ["apps/meteor/app/api/server/lib/getUploadFormData.ts"]
getUploadFormData["Parses multipart/form-data from an HTTP request to extract file data and fields."]
end
style SG8 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG9 ["apps/meteor/app/api/server/lib/isValidQuery.ts"]
._Rocket.Chat_apps_meteor_app_api_server_lib_isValidQuery.ts["Top-level logic providing a utility to validate query objects against allowed attributes and operations."]
end
style SG9 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG10 ["apps/meteor/app/api/server/lib/users.ts"]
findUsersToAutocomplete["Provides autocomplete suggestions for users based on search terms and access permissions."]
getInclusiveFields["Filters a query object to retain only inclusive fields."]
getNonEmptyFields["Returns default fields if the provided fields object is empty or invalid."]
getNonEmptyQuery["Returns a default query if the provided query object is empty, optionally including email searches."]
findPaginatedUsersByStatus["Retrieves a paginated list of users filtered by status, roles, and other criteria."]
end
style SG10 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG11 ["apps/meteor/app/api/server/v1/users.ts"]
get["get"]
action{{"action"}}
end
style SG11 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG12 ["apps/meteor/app/authentication/server/startup/index.js"]
Accounts.insertUserDoc["Accounts.insertUserDoc"]
end
style SG12 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG13 ["apps/meteor/app/authorization/server/functions/hasPermission.ts"]
hasPermissionAsync["Checks if a user has a specific permission, optionally within a room scope."]
end
style SG13 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG14 ["apps/meteor/app/authorization/server/index.ts"]
._Rocket.Chat_apps_meteor_app_authorization_server_index.ts["Exports authorization-related functions and registers server methods."]
end
style SG14 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG15 ["apps/meteor/app/file-upload/server/lib/FileUpload.ts"]
FileUpload.getStore["Retrieves a file storage handler by model name."]
FileUpload.getStoreByName["FileUpload.getStoreByName"]
FileUpload.get["FileUpload.get"]
FileUpload.removeFilesByRoomId["FileUpload.removeFilesByRoomId"]
FileUploadClass.deleteById["FileUploadClass.deleteById"]
end
style SG15 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG16 ["apps/meteor/app/file/server/file.server.ts"]
RocketChatFile.dataURIParse["RocketChatFile.dataURIParse"]
end
style SG16 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG17 ["apps/meteor/app/invites/server/functions/validateInviteToken.ts"]
validateInviteToken["validateInviteToken"]
end
style SG17 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG18 ["apps/meteor/app/lib/server/functions/addUserToDefaultChannels.ts"]
addUserToDefaultChannels["addUserToDefaultChannels"]
end
style SG18 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG19 ["apps/meteor/app/lib/server/functions/addUserToRoom.ts"]
addUserToRoom["addUserToRoom"]
end
style SG19 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG20 ["apps/meteor/app/lib/server/functions/checkEmailAvailability.ts"]
checkEmailAvailability["Checks if an email address is available in the database."]
end
style SG20 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG21 ["apps/meteor/app/lib/server/functions/checkUsernameAvailability.ts"]
toRegExp["toRegExp"]
usernameIsBlocked["usernameIsBlocked"]
checkUsernameAvailabilityWithValidation["Checks if a username is available with validation logic for user editing."]
checkUsernameAvailability["Checks if a username is available in the system, considering blocked lists and existing users/teams."]
end
style SG21 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG22 ["apps/meteor/app/lib/server/functions/deleteRoom.ts"]
deleteRoom["deleteRoom"]
end
style SG22 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG23 ["apps/meteor/app/lib/server/functions/deleteUser.ts"]
deleteUser["Deletes a user account, cleans up associated data (messages, subscriptions, files, roles), and triggers cleanup callbacks."]
end
style SG23 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG24 ["apps/meteor/app/lib/server/functions/getAvatarSuggestionForUser.ts"]
getAvatarSuggestionForUser["Fetches and processes potential user avatar URLs from various social/OAuth providers and Gravatar."]
end
style SG24 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG25 ["apps/meteor/app/lib/server/functions/getDefaultChannels.ts"]
getDefaultChannels["getDefaultChannels"]
end
style SG25 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG26 ["apps/meteor/app/lib/server/functions/getFullUserData.ts"]
getCustomFields["getCustomFields"]
getFields["getFields"]
findTargetUser["findTargetUser"]
getFullUserDataByUniqueSearchTerm["Retrieves a full user object based on a unique search term, enforcing authorization checks and filtering sensitive fields."]
end
style SG26 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG27 ["apps/meteor/app/lib/server/functions/getRoomsWithSingleOwner.ts"]
shouldRemoveOrChangeOwner["shouldRemoveOrChangeOwner"]
getSubscribedRoomsForUserWithDetails["getSubscribedRoomsForUserWithDetails"]
end
style SG27 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG28 ["apps/meteor/app/lib/server/functions/getUserSingleOwnedRooms.ts"]
getUserSingleOwnedRooms["getUserSingleOwnedRooms"]
end
style SG28 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG29 ["apps/meteor/app/lib/server/functions/getUsernameSuggestion.ts"]
slug["slug"]
usernameIsAvailable["usernameIsAvailable"]
name["name"]
generateUsernameSuggestion["Generates a unique username suggestion for a user based on their name, email, or OAuth services."]
end
style SG29 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG30 ["apps/meteor/app/lib/server/functions/joinDefaultChannels.ts"]
joinDefaultChannels["joinDefaultChannels"]
end
style SG30 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG31 ["apps/meteor/app/lib/server/functions/relinquishRoomOwnerships.ts"]
bulkTeamCleanup["bulkTeamCleanup"]
bulkRoomCleanUp["bulkRoomCleanUp"]
relinquishRoomOwnerships["relinquishRoomOwnerships"]
end
style SG31 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG32 ["apps/meteor/app/lib/server/functions/saveCustomFields.ts"]
saveCustomFields["Validates and saves custom user profile fields to the database."]
end
style SG32 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG33 ["apps/meteor/app/lib/server/functions/saveCustomFieldsWithoutValidation.ts"]
getCustomFieldsMeta["getCustomFieldsMeta"]
saveCustomFieldsWithoutValidation["Saves custom user fields to the database without performing additional validation."]
end
style SG33 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG34 ["apps/meteor/app/lib/server/functions/saveUser/index.ts"]
._Rocket.Chat_apps_meteor_app_lib_server_functions_saveUser_index.ts["Exports core user saving and validation functions for use in other modules."]
end
style SG34 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG35 ["apps/meteor/app/lib/server/functions/saveUser/sendUserEmail.ts"]
sendUserEmail["sendUserEmail"]
sendWelcomeEmail["Sends a welcome email to a new user upon registration."]
end
style SG35 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG36 ["apps/meteor/app/lib/server/functions/saveUser/validateUserEditing.ts"]
canEditExtension["Validates if a specific VoIP extension can be assigned to a user."]
end
style SG36 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG37 ["apps/meteor/app/lib/server/functions/saveUserIdentity.ts"]
saveUserIdentity["saveUserIdentity"]
updateUsernameReferences["updateUsernameReferences"]
end
style SG37 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG38 ["apps/meteor/app/lib/server/functions/setRealName.ts"]
setRealName["setRealName"]
end
style SG38 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG39 ["apps/meteor/app/lib/server/functions/setStatusText.ts"]
setStatusText["Updates a user's status text, truncates it to 120 characters, persists to the database, and broadcasts the update."]
end
style SG39 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG40 ["apps/meteor/app/lib/server/functions/setUserAvatar.ts"]
setAvatarFromServiceWithValidation["setAvatarFromServiceWithValidation"]
setUserAvatar["Sets a user's avatar from a data URI, URL, or REST input, handling file storage and database updates."]
end
style SG40 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG41 ["apps/meteor/app/lib/server/functions/setUsername.ts"]
isUserInFederatedRooms["isUserInFederatedRooms"]
setUsernameWithValidation["Validates and updates a user's username, ensuring uniqueness and compliance with federation rules."]
setUsername["_setUsername"]
end
style SG41 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG42 ["apps/meteor/app/lib/server/functions/updateGroupDMsName.ts"]
getFname["getFname"]
getName["getName"]
getUsersWhoAreInTheSameGroupDMsAs["getUsersWhoAreInTheSameGroupDMsAs"]
updateGroupDMsName["updateGroupDMsName"]
getMembers["getMembers"]
end
style SG42 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG43 ["apps/meteor/app/lib/server/functions/validateCustomFields.js"]
validateCustomFields["Validates user-defined custom fields against configured schema, ensuring required fields, types, and lengths are respected."]
end
style SG43 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG44 ["apps/meteor/app/lib/server/functions/validateName.ts"]
validateName["validateName"]
end
style SG44 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG45 ["apps/meteor/app/lib/server/functions/validateNameChars.ts"]
validateNameChars["Validates a name string for invalid characters, including URI-decoded checks."]
end
style SG45 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG46 ["apps/meteor/app/lib/server/functions/validateUsername.ts"]
validateUsername["Validates a username string against a configurable regular expression pattern."]
end
style SG46 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG47 ["apps/meteor/app/lib/server/index.ts"]
._Rocket.Chat_apps_meteor_app_lib_server_index.ts["./Rocket.Chat/apps/meteor/app/lib/server/index.ts"]
end
style SG47 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG48 ["apps/meteor/app/lib/server/lib/deprecationWarningLogger.ts"]
compareVersions["Compares a version string against the threshold for throwing deprecation errors."]
method["Logs deprecation warnings for methods, including replacement information and metrics."]
warn["Logs a generic deprecation warning."]
end
style SG48 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG49 ["apps/meteor/app/lib/server/lib/notifyListener.ts"]
notifyOnRoomChangedById["notifyOnRoomChangedById"]
notifyOnRoomChangedByUsernamesOrUids["notifyOnRoomChangedByUsernamesOrUids"]
notifyOnIntegrationChangedByUserId["notifyOnIntegrationChangedByUserId"]
notifyOnLivechatDepartmentAgentChanged["notifyOnLivechatDepartmentAgentChanged"]
notifyOnSettingChanged["notifyOnSettingChanged"]
notifyOnSettingChangedById["notifyOnSettingChangedById"]
notifyOnUserChange["Broadcasts a notification about a user record change."]
notifyOnUserChangeAsync["Executes a callback and notifies on user change if watchers are disabled."]
notifyOnSubscriptionChanged["Broadcasts a notification when a subscription is changed."]
notifyOnSubscriptionChangedByRoomIdAndUserId["Broadcasts a notification for a subscription identified by room ID and user ID."]
notifyOnSubscriptionChangedById["notifyOnSubscriptionChangedById"]
notifyOnSubscriptionChangedByUserPreferences["notifyOnSubscriptionChangedByUserPreferences"]
notifyOnSubscriptionChangedByRoomId["notifyOnSubscriptionChangedByRoomId"]
notifyOnSubscriptionChangedByAutoTranslateAndUserId["notifyOnSubscriptionChangedByAutoTranslateAndUserId"]
notifyOnSubscriptionChangedByUserIdAndRoomType["notifyOnSubscriptionChangedByUserIdAndRoomType"]
notifyOnSubscriptionChangedByNameAndRoomType["notifyOnSubscriptionChangedByNameAndRoomType"]
notifyOnSubscriptionChangedByUserId["notifyOnSubscriptionChangedByUserId"]
end
style SG49 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG50 ["apps/meteor/app/lib/server/methods/createToken.ts"]
generateAccessToken["Generates an access token for a given user if the provided secret matches the environment variable."]
end
style SG50 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG51 ["apps/meteor/app/lib/server/methods/deleteUserOwnAccount.ts"]
deleteUserOwnAccount["Handles the deletion of a user's own account after verifying their password and system settings."]
end
style SG51 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG52 ["apps/meteor/app/mailer/server/api.ts"]
replacekey["replacekey"]
translate["translate"]
replace["replace"]
replaceEscaped["replaceEscaped"]
wrap["wrap"]
checkAddressFormat["checkAddressFormat"]
sendNoWrap["sendNoWrap"]
send["send"]
end
style SG52 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG53 ["apps/meteor/app/utils/lib/getDefaultSubscriptionPref.ts"]
getDefaultSubscriptionPref["getDefaultSubscriptionPref"]
end
style SG53 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG54 ["apps/meteor/app/utils/lib/getURL.ts"]
getCloudUrl["getCloudUrl"]
getURL["_getURL"]
getURLWithoutSettings["getURLWithoutSettings"]
end
style SG54 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG55 ["apps/meteor/app/utils/lib/mimeTypes.ts"]
getMimeTypeFromFileName["getMimeTypeFromFileName"]
getMimeType["getMimeType"]
end
style SG55 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG56 ["apps/meteor/app/utils/server/functions/isSMTPConfigured.ts"]
isSMTPConfigured["Checks if SMTP is configured by verifying the MAIL_URL environment variable or SMTP_Host setting."]
end
style SG56 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG57 ["apps/meteor/app/utils/server/getURL.ts"]
getURL_2["Generates a URL for a given path, incorporating site URL and CDN settings."]
end
style SG57 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG58 ["apps/meteor/app/utils/server/lib/getUserPreference.ts"]
getUserPreference["getUserPreference"]
end
style SG58 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG59 ["apps/meteor/client/meteor/overrides/userAndUsers.ts"]
Meteor.userId["Overrides Meteor.userId to return the current user ID from the local store."]
end
style SG59 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG60 ["apps/meteor/client/meteor/user.ts"]
watchUserId["Watches and returns the current user ID."]
end
style SG60 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG61 ["apps/meteor/client/meteor/watch.ts"]
watch["watch"]
end
style SG61 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG62 ["apps/meteor/imports/personal-access-tokens/server/api/methods/generateToken.ts"]
generatePersonalAccessTokenOfUser["Generates a new personal access token for a user after checking permissions and ensuring uniqueness."]
end
style SG62 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG63 ["apps/meteor/imports/personal-access-tokens/server/api/methods/regenerateToken.ts"]
regeneratePersonalAccessTokenOfUser["Regenerates a personal access token for a user after verifying authorization and token existence."]
end
style SG63 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG64 ["apps/meteor/imports/personal-access-tokens/server/api/methods/removeToken.ts"]
removePersonalAccessTokenOfUser["Removes a personal access token for a user after verifying authorization."]
end
style SG64 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG65 ["apps/meteor/lib/roles/calculateRoomRolePriorityFromRoles.ts"]
getRoomRolePriorityForRole["getRoomRolePriorityForRole"]
calculateRoomRolePriorityFromRoles["calculateRoomRolePriorityFromRoles"]
end
style SG65 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG66 ["apps/meteor/lib/utils/isObject.ts"]
isObject["isObject"]
end
style SG66 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG67 ["apps/meteor/lib/utils/parseCSV.ts"]
parseCSV["parseCSV"]
end
style SG67 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG68 ["apps/meteor/lib/utils/stringUtils.ts"]
makeString["makeString"]
defaultToWhiteSpace["defaultToWhiteSpace"]
trim["trim"]
ltrim["ltrim"]
rtrim["rtrim"]
strLeft["strLeft"]
strRightBack["strRightBack"]
end
style SG68 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG69 ["apps/meteor/server/database/utils.ts"]
isExtendedSession["isExtendedSession"]
onceTransactionCommitedSuccessfully["onceTransactionCommitedSuccessfully"]
withError["withError"]
end
style SG69 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG70 ["apps/meteor/server/hooks/userLogoutCleanUp.ts"]
runUserLogoutCleanUp["Triggers cleanup operations after a user logs out."]
end
style SG70 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG71 ["apps/meteor/server/lib/getSubscriptionAutotranslateDefaultConfig.ts"]
getSubscriptionAutotranslateDefaultConfig["getSubscriptionAutotranslateDefaultConfig"]
end
style SG71 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG72 ["apps/meteor/server/lib/isUserIdFederated.ts"]
isUserIdFederated["isUserIdFederated"]
end
style SG72 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG73 ["apps/meteor/server/lib/resetUserE2EKey.ts"]
sendResetNotification["sendResetNotification"]
resetUserE2EEncriptionKey["Resets a user's E2E encryption key and forces a re-login."]
end
style SG73 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG74 ["apps/meteor/server/lib/roles/addUserRoles.ts"]
addUserRolesAsync["Adds roles to a user, optionally scoped to a specific room."]
end
style SG74 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG75 ["apps/meteor/server/lib/roles/removeUserFromRoles.ts"]
removeUserFromRolesAsync["Removes specified roles from a user, optionally scoped to a room."]
end
style SG75 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG76 ["apps/meteor/server/lib/roles/syncRoomRolePriority.ts"]
syncRoomRolePriorityForUserAndRoom["Synchronizes the room role priority for a user in a specific room."]
updateRolePriority["updateRolePriority"]
end
style SG76 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG77 ["apps/meteor/server/lib/roles/validateRoleList.ts"]
validateRoleList["Validates a list of role IDs against existing roles in the database."]
end
style SG77 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG78 ["apps/meteor/server/lib/rooms/roomCoordinator.ts"]
RoomCoordinatorServer.allowMemberAction["RoomCoordinatorServer.allowMemberAction"]
RoomCoordinatorServer.getRoomDirectives["Retrieves the server-side directives for a specific room type."]
end
style SG78 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG79 ["apps/meteor/server/lib/users/runAfterVerifyEmail.ts"]
runAfterVerifyEmail["Updates user roles after email verification."]
end
style SG79 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG80 ["apps/meteor/server/methods/registerUser.ts"]
registerUser["Registers a new user, handles anonymous access, and validates registration requirements."]
end
style SG80 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG81 ["apps/meteor/server/methods/requestDataDownload.ts"]
requestDataDownload["Requests a data export operation for the user."]
end
style SG81 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG82 ["apps/meteor/server/methods/resetAvatar.ts"]
resetAvatar["Resets a user's avatar after authorization checks."]
userId["userId"]
end
style SG82 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG83 ["apps/meteor/server/methods/saveUserPreferences.ts"]
updateNotificationPreferences["updateNotificationPreferences"]
saveUserPreferences["Updates user preferences and propagates notification changes."]
end
style SG83 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG84 ["apps/meteor/server/methods/sendConfirmationEmail.ts"]
sendConfirmationEmail["Sends a verification email to a user based on their email address."]
end
style SG84 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG85 ["apps/meteor/server/methods/sendForgotPasswordEmail.ts"]
sendForgotPasswordEmail["Sends a password reset email to a user if they exist."]
end
style SG85 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG86 ["apps/meteor/server/methods/setUserActiveStatus.ts"]
executeSetUserActiveStatus["Updates the active status of a user, requiring administrative permissions."]
setUserActiveStatus["setUserActiveStatus"]
end
style SG86 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG87 ["apps/meteor/server/services/authorization/service.ts"]
Authorization.hasPermission["Checks if a user has a specific permission, optionally scoped to a room."]
Authorization.all["Authorization.all"]
end
style SG87 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG88 ["apps/meteor/server/services/user/lib/getNewUserRoles.ts"]
getNewUserRoles["getNewUserRoles"]
end
style SG88 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG89 ["ee/apps/account-service/src/lib/utils.ts"]
generateStampedLoginToken["_generateStampedLoginToken"]
hashLoginToken["Hashes a login token using SHA-256 for secure storage."]
end
style SG89 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG90 ["packages/models/src/models/BaseRaw.ts"]
BaseRaw.doNotMixInclusionAndExclusionFields["BaseRaw.doNotMixInclusionAndExclusionFields"]
BaseRaw.ensureDefaultFields["BaseRaw.ensureDefaultFields"]
BaseRaw.find["BaseRaw.find"]
BaseRaw.updateOne["BaseRaw.updateOne"]
BaseRaw.updateMany["BaseRaw.updateMany"]
BaseRaw.deleteMany["BaseRaw.deleteMany"]
BaseRaw.setUpdatedAt["BaseRaw.setUpdatedAt"]
end
style SG90 fill:#2a2a2a,stroke:#444,color:#aaa
subgraph SG91 ["packages/models/src/models/LivechatDepartmentAgents.ts"]
LivechatDepartmentAgentsRaw.findByAgentId["LivechatDepartmentAgentsRaw.findByAgentId"]
LivechatDepartmentAgentsRaw.removeByAgentId["LivechatDepartmentAgentsRaw.removeByAgentId"]
LivechatDepartmentAgentsRaw.replaceUsernameOfAgentByUserId["LivechatDepartmentAgentsRaw.replaceUsernameOfAgentByUserId"]
end
style SG91 fill:#2a2a2a,stroke:#444,color:#aaa
action --> hashLoginToken
action --> getFullUserDataByUniqueSearchTerm
action --> deleteUser
action --> generateUsernameSuggestion
action --> validateCustomFields
action --> saveCustomFields
action --> getAvatarSuggestionForUser
action --> checkUsernameAvailabilityWithValidation
action --> checkUsernameAvailability
action --> validateUsername
action --> validateNameChars
action --> saveCustomFieldsWithoutValidation
action --> canEditExtension
action --> ._Rocket.Chat_apps_meteor_app_lib_server_functions_saveUser_index.ts
action --> sendWelcomeEmail
action --> setUserAvatar
action --> setStatusText
action --> checkEmailAvailability
action --> setUsernameWithValidation
action --> notifyOnUserChange
action --> notifyOnUserChangeAsync
action --> deleteUserOwnAccount
action --> generateAccessToken
action --> resetUserE2EEncriptionKey
action --> sendForgotPasswordEmail
action --> executeSetUserActiveStatus
action --> resetAvatar
action --> sendConfirmationEmail
action --> requestDataDownload
action --> registerUser
action --> saveUserPreferences
action --> removePersonalAccessTokenOfUser
action --> generatePersonalAccessTokenOfUser
action --> regeneratePersonalAccessTokenOfUser
action --> resetTOTP
action --> getUserForCheck
action --> isSMTPConfigured
action --> hasPermissionAsync
action --> findUsersToAutocomplete
action --> findPaginatedUsersByStatus
action --> ._Rocket.Chat_apps_meteor_app_api_server_lib_isValidQuery.ts
action --> getUploadFormData
action --> APIClass.success
action --> APIClass.failure
action --> APIClass.forbidden
action --> APIClass.this.parseJsonQuery
action --> getUserInfo
action --> getPaginationItems
action --> getUserFromParams
action --> isUserFromParams
action --> runUserLogoutCleanUp
action --> runAfterVerifyEmail
action --> get
getFullUserDataByUniqueSearchTerm --> getFields
getFullUserDataByUniqueSearchTerm --> findTargetUser
getFullUserDataByUniqueSearchTerm --> hasPermissionAsync
deleteUser --> shouldRemoveOrChangeOwner
deleteUser --> getSubscribedRoomsForUserWithDetails
deleteUser --> getUserSingleOwnedRooms
deleteUser --> updateGroupDMsName
deleteUser --> relinquishRoomOwnerships
deleteUser --> notifyOnRoomChangedById
deleteUser --> notifyOnIntegrationChangedByUserId
deleteUser --> notifyOnLivechatDepartmentAgentChanged
deleteUser --> notifyOnUserChange
deleteUser --> FileUpload.getStore
deleteUser --> LivechatDepartmentAgentsRaw.findByAgentId
deleteUser --> LivechatDepartmentAgentsRaw.removeByAgentId
generateUsernameSuggestion --> slug
generateUsernameSuggestion --> usernameIsAvailable
generateUsernameSuggestion --> name
validateCustomFields --> trim
saveCustomFields --> validateCustomFields
saveCustomFields --> saveCustomFieldsWithoutValidation
saveCustomFields --> trim
checkUsernameAvailabilityWithValidation --> checkUsernameAvailability
checkUsernameAvailability --> toRegExp
checkUsernameAvailability --> usernameIsBlocked
checkUsernameAvailability --> validateName
saveCustomFieldsWithoutValidation --> getCustomFieldsMeta
saveCustomFieldsWithoutValidation --> notifyOnSubscriptionChangedByUserIdAndRoomType
saveCustomFieldsWithoutValidation --> onceTransactionCommitedSuccessfully
saveCustomFieldsWithoutValidation --> trim
sendWelcomeEmail --> sendUserEmail
setUserAvatar --> onceTransactionCommitedSuccessfully
setUserAvatar --> FileUpload.getStore
setUserAvatar --> RocketChatFile.dataURIParse
setStatusText --> onceTransactionCommitedSuccessfully
setUsernameWithValidation --> checkUsernameAvailability
setUsernameWithValidation --> saveUserIdentity
setUsernameWithValidation --> validateUsername
setUsernameWithValidation --> joinDefaultChannels
setUsernameWithValidation --> isUserInFederatedRooms
setUsernameWithValidation --> notifyOnUserChange
notifyOnUserChangeAsync --> notifyOnUserChange
deleteUserOwnAccount --> deleteUser
deleteUserOwnAccount --> method
deleteUserOwnAccount --> deleteUserOwnAccount
deleteUserOwnAccount --> trim
deleteUserOwnAccount --> Meteor.userId
generateAccessToken --> generateStampedLoginToken
resetUserE2EEncriptionKey --> isUserIdFederated
resetUserE2EEncriptionKey --> notifyOnUserChange
resetUserE2EEncriptionKey --> notifyOnSubscriptionChangedByUserId
resetUserE2EEncriptionKey --> sendResetNotification
sendForgotPasswordEmail --> sendForgotPasswordEmail
executeSetUserActiveStatus --> setUserActiveStatus
executeSetUserActiveStatus --> hasPermissionAsync
resetAvatar --> method
resetAvatar --> resetAvatar
resetAvatar --> userId
resetAvatar --> hasPermissionAsync
requestDataDownload --> method
requestDataDownload --> requestDataDownload
registerUser --> generateStampedLoginToken
registerUser --> ._Rocket.Chat_apps_meteor_app_lib_server_index.ts
registerUser --> Accounts.insertUserDoc
registerUser --> registerUser
registerUser --> validateInviteToken
registerUser --> trim
saveUserPreferences --> notifyOnUserChange
saveUserPreferences --> notifyOnSubscriptionChangedByAutoTranslateAndUserId
saveUserPreferences --> notifyOnSubscriptionChangedByUserId
saveUserPreferences --> method
saveUserPreferences --> updateNotificationPreferences
saveUserPreferences --> saveUserPreferences
saveUserPreferences --> Meteor.userId
removePersonalAccessTokenOfUser --> removePersonalAccessTokenOfUser
removePersonalAccessTokenOfUser --> hasPermissionAsync
generatePersonalAccessTokenOfUser --> hashLoginToken
generatePersonalAccessTokenOfUser --> hasPermissionAsync
regeneratePersonalAccessTokenOfUser --> removePersonalAccessTokenOfUser
regeneratePersonalAccessTokenOfUser --> generatePersonalAccessTokenOfUser
regeneratePersonalAccessTokenOfUser --> hasPermissionAsync
resetTOTP --> isUserIdFederated
resetTOTP --> notifyOnUserChange
resetTOTP --> sendResetNotification_2
hasPermissionAsync --> Authorization.hasPermission
findUsersToAutocomplete --> hasPermissionAsync
findPaginatedUsersByStatus --> hasPermissionAsync
getUploadFormData --> getMimeType
APIClass.success --> isObject
APIClass.failure --> isObject
APIClass.this.parseJsonQuery --> APIClass.this.parseJsonQuery
getUserInfo --> getURL_2
getUserInfo --> isVerifiedEmail
getUserInfo --> getUserPreferences
getUserInfo --> filterOutdatedVersionUpdateBanners
getUserInfo --> getUserCalendar
runAfterVerifyEmail --> removeUserFromRolesAsync
runAfterVerifyEmail --> addUserRolesAsync
get --> getURL_2
get --> hasPermissionAsync
get --> getInclusiveFields
get --> getNonEmptyFields
get --> getNonEmptyQuery
get --> ._Rocket.Chat_apps_meteor_app_api_server_lib_isValidQuery.ts
get --> APIClass.success
get --> APIClass.forbidden
get --> APIClass.this.parseJsonQuery
get --> getPaginationItems
get --> getUserFromParams
get --> get
getFields --> getCustomFields
getSubscribedRoomsForUserWithDetails --> ._Rocket.Chat_apps_meteor_app_authorization_server_index.ts
updateGroupDMsName --> getFname
updateGroupDMsName --> getName
updateGroupDMsName --> getUsersWhoAreInTheSameGroupDMsAs
updateGroupDMsName --> getMembers
updateGroupDMsName --> notifyOnSubscriptionChangedByRoomId
relinquishRoomOwnerships --> bulkRoomCleanUp
relinquishRoomOwnerships --> addUserRolesAsync
FileUpload.getStore --> FileUpload.getStoreByName
FileUpload.getStore --> FileUpload.get
LivechatDepartmentAgentsRaw.findByAgentId --> BaseRaw.find
LivechatDepartmentAgentsRaw.removeByAgentId --> BaseRaw.deleteMany
name --> slug
trim --> makeString
trim --> defaultToWhiteSpace
onceTransactionCommitedSuccessfully --> isExtendedSession
onceTransactionCommitedSuccessfully --> withError
sendUserEmail --> send
saveUserIdentity --> updateUsernameReferences
saveUserIdentity --> validateName
saveUserIdentity --> setRealName
saveUserIdentity --> setUsername
saveUserIdentity --> onceTransactionCommitedSuccessfully
joinDefaultChannels --> addUserToDefaultChannels
method --> compareVersions
method --> warn
Meteor.userId --> watchUserId
sendResetNotification --> send
setUserActiveStatus --> executeSetUserActiveStatus
setUserActiveStatus --> Meteor.userId
Accounts.insertUserDoc --> getAvatarSuggestionForUser
Accounts.insertUserDoc --> setAvatarFromServiceWithValidation
Accounts.insertUserDoc --> joinDefaultChannels
Accounts.insertUserDoc --> notifyOnSettingChangedById
Accounts.insertUserDoc --> addUserRolesAsync
Accounts.insertUserDoc --> getNewUserRoles
Accounts.insertUserDoc --> parseCSV
updateNotificationPreferences --> notifyOnSubscriptionChangedByUserPreferences
sendResetNotification_2 --> send
Authorization.hasPermission --> Authorization.all
getMimeType --> getMimeTypeFromFileName
getURL_2 --> getURLWithoutSettings
getUserPreferences --> getUserPreference
removeUserFromRolesAsync --> notifyOnSubscriptionChangedByRoomIdAndUserId
removeUserFromRolesAsync --> syncRoomRolePriorityForUserAndRoom
removeUserFromRolesAsync --> validateRoleList
addUserRolesAsync --> notifyOnSubscriptionChangedByRoomIdAndUserId
addUserRolesAsync --> syncRoomRolePriorityForUserAndRoom
addUserRolesAsync --> validateRoleList
bulkRoomCleanUp --> bulkTeamCleanup
bulkRoomCleanUp --> notifyOnSubscriptionChanged
bulkRoomCleanUp --> FileUpload.removeFilesByRoomId
bulkRoomCleanUp --> eraseRoomLooseValidation
FileUpload.get --> FileUpload.getStoreByName
FileUpload.get --> FileUpload.get
BaseRaw.find --> BaseRaw.doNotMixInclusionAndExclusionFields
BaseRaw.find --> BaseRaw.find
BaseRaw.deleteMany --> BaseRaw.find
BaseRaw.deleteMany --> BaseRaw.updateOne
BaseRaw.deleteMany --> BaseRaw.deleteMany
defaultToWhiteSpace --> makeString
send --> replace
send --> wrap
send --> sendNoWrap
updateUsernameReferences --> updateGroupDMsName
updateUsernameReferences --> notifyOnRoomChangedByUsernamesOrUids
updateUsernameReferences --> notifyOnSubscriptionChangedByNameAndRoomType
updateUsernameReferences --> notifyOnSubscriptionChangedByUserId
updateUsernameReferences --> FileUpload.getStore
updateUsernameReferences --> LivechatDepartmentAgentsRaw.replaceUsernameOfAgentByUserId
setRealName --> onceTransactionCommitedSuccessfully
setUsername --> addUserToRoom
setUsername --> getAvatarSuggestionForUser
setUsername --> checkUsernameAvailability
setUsername --> validateUsername
setUsername --> setUserAvatar
setUsername --> isUserInFederatedRooms
setUsername --> onceTransactionCommitedSuccessfully
addUserToDefaultChannels --> getDefaultChannels
addUserToDefaultChannels --> notifyOnSubscriptionChangedById
addUserToDefaultChannels --> getSubscriptionAutotranslateDefaultConfig
addUserToDefaultChannels --> getDefaultSubscriptionPref
warn --> compareVersions
warn --> warn
watchUserId --> watch
setAvatarFromServiceWithValidation --> setUserAvatar
setAvatarFromServiceWithValidation --> hasPermissionAsync
getNewUserRoles --> parseCSV
getURLWithoutSettings --> getURL
syncRoomRolePriorityForUserAndRoom --> updateRolePriority
syncRoomRolePriorityForUserAndRoom --> calculateRoomRolePriorityFromRoles
bulkTeamCleanup --> eraseTeamOnRelinquishRoomOwnerships
FileUpload.removeFilesByRoomId --> FileUpload.getStore
FileUpload.removeFilesByRoomId --> FileUploadClass.deleteById
eraseRoomLooseValidation --> deleteRoom
BaseRaw.doNotMixInclusionAndExclusionFields --> BaseRaw.ensureDefaultFields
BaseRaw.updateOne --> BaseRaw.updateOne
BaseRaw.updateOne --> BaseRaw.setUpdatedAt
replace --> replacekey
replace --> translate
replace --> replace
replace --> strLeft
replace --> strRightBack
wrap --> replace
wrap --> replaceEscaped
sendNoWrap --> notifyOnSettingChanged
sendNoWrap --> checkAddressFormat
LivechatDepartmentAgentsRaw.replaceUsernameOfAgentByUserId --> BaseRaw.updateMany
addUserToRoom --> notifyOnRoomChangedById
addUserToRoom --> notifyOnSubscriptionChanged
addUserToRoom --> RoomCoordinatorServer.allowMemberAction
addUserToRoom --> RoomCoordinatorServer.getRoomDirectives
getURL --> getCloudUrl
getURL --> trim
getURL --> ltrim
getURL --> rtrim
updateRolePriority --> calculateRoomRolePriorityFromRoles
calculateRoomRolePriorityFromRoles --> getRoomRolePriorityForRole
eraseTeamOnRelinquishRoomOwnerships --> eraseRoomLooseValidation
FileUploadClass.deleteById --> FileUpload.getStoreByName
deleteRoom --> notifyOnRoomChangedById
deleteRoom --> notifyOnSubscriptionChanged
deleteRoom --> FileUpload.getStore
deleteRoom --> FileUpload.removeFilesByRoomId
BaseRaw.setUpdatedAt --> BaseRaw.setUpdatedAt
replacekey --> replace
strLeft --> makeString
strRightBack --> makeString
replaceEscaped --> replace
BaseRaw.updateMany --> BaseRaw.updateMany
BaseRaw.updateMany --> BaseRaw.setUpdatedAt
getCloudUrl --> ltrim
getCloudUrl --> rtrim
ltrim --> makeString
ltrim --> defaultToWhiteSpace
rtrim --> makeString
rtrim --> defaultToWhiteSpace
Fix with AITriage: Reply |
||||||||||||
| ); | ||||||||||||
|
Comment on lines
+2093
to
+2123
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. User lookup should occur after The user is looked up before Consider moving the user lookup after the Proposed fix async function action() {
const { token } = this.bodyParams;
- const user = await Users.findOne<Pick<IUser, '_id'>>({ 'services.email.verificationTokens.token': token }, { projection: { _id: 1 } });
-
await Meteor.callAsync('verifyEmail', token);
+ const user = await Users.findOne<Pick<IUser, '_id'>>({ 'emails.verified': true, 'services.email.verificationTokens.token': { $exists: false } }, { projection: { _id: 1 } });
+ // Alternative: lookup by the token that was just consumed (if Meteor stores it differently post-verification)
+ // Or pass userId from verifyEmail if it returns it
+
if (user) {
await runAfterVerifyEmail(user._id);
}
return API.v1.success();
}Note: The exact query after verification depends on how 🤖 Prompt for AI Agents |
||||||||||||
|
|
||||||||||||
| settings.watch<number>('Rate_Limiter_Limit_RegisterUser', (value) => { | ||||||||||||
| const userRegisterRoute = '/api/v1/users.registerpost'; | ||||||||||||
|
|
||||||||||||
|
|
||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,78 @@ | ||
| import { License } from '@rocket.chat/core-services'; | ||
| import { Permissions } from '@rocket.chat/models'; | ||
| import { Meteor } from 'meteor/meteor'; | ||
|
|
||
| import { hasPermissionAsync } from './hasPermission'; | ||
| import { notifyOnPermissionChangedById } from '../../../lib/server/lib/notifyListener'; | ||
| import { CONSTANTS, AuthorizationUtils } from '../../lib'; | ||
|
|
||
| export const addPermissionToRoleMethod = async (uid: string | null, permissionId: string, role: string): Promise<void> => { | ||
| if (role === 'guest' && !AuthorizationUtils.hasRestrictionsToRole(role) && (await License.hasValidLicense())) { | ||
| AuthorizationUtils.addRolePermissionWhiteList(role, await License.getGuestPermissions()); | ||
| } | ||
|
|
||
| if (AuthorizationUtils.isPermissionRestrictedForRole(permissionId, role)) { | ||
| throw new Meteor.Error('error-action-not-allowed', 'Permission is restricted', { | ||
| method: 'authorization:addPermissionToRole', | ||
| action: 'Adding_permission', | ||
| }); | ||
| } | ||
|
|
||
| const permission = await Permissions.findOneById(permissionId); | ||
|
|
||
| if (!permission) { | ||
| throw new Meteor.Error('error-invalid-permission', 'Permission does not exist', { | ||
| method: 'authorization:addPermissionToRole', | ||
| action: 'Adding_permission', | ||
| }); | ||
| } | ||
|
|
||
| if ( | ||
| !uid || | ||
| !(await hasPermissionAsync(uid, 'access-permissions')) || | ||
| (permission.level === CONSTANTS.SETTINGS_LEVEL && !(await hasPermissionAsync(uid, 'access-setting-permissions'))) | ||
| ) { | ||
| throw new Meteor.Error('error-action-not-allowed', 'Adding permission is not allowed', { | ||
| method: 'authorization:addPermissionToRole', | ||
| action: 'Adding_permission', | ||
| }); | ||
| } | ||
|
|
||
| if (permission.groupPermissionId) { | ||
| await Permissions.addRole(permission.groupPermissionId, role); | ||
| void notifyOnPermissionChangedById(permission.groupPermissionId); | ||
| } | ||
|
|
||
| await Permissions.addRole(permission._id, role); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: Validate the role exists before writing it to permission roles, otherwise invalid role IDs can be persisted. Prompt for AI agents |
||
|
|
||
| void notifyOnPermissionChangedById(permission._id); | ||
| }; | ||
|
|
||
| export const removeRoleFromPermissionMethod = async (uid: string | null, permissionId: string, role: string): Promise<void> => { | ||
| const permission = await Permissions.findOneById(permissionId); | ||
|
|
||
| if (!permission) { | ||
| throw new Meteor.Error('error-permission-not-found', 'Permission not found', { | ||
| method: 'authorization:removeRoleFromPermission', | ||
| }); | ||
| } | ||
|
|
||
| if ( | ||
| !uid || | ||
| !(await hasPermissionAsync(uid, 'access-permissions')) || | ||
| (permission.level === CONSTANTS.SETTINGS_LEVEL && !(await hasPermissionAsync(uid, 'access-setting-permissions'))) | ||
| ) { | ||
| throw new Meteor.Error('error-action-not-allowed', 'Removing permission is not allowed', { | ||
| method: 'authorization:removeRoleFromPermission', | ||
| action: 'Removing_permission', | ||
| }); | ||
| } | ||
|
|
||
| if (permission.groupPermissionId) { | ||
| await Permissions.removeRole(permission.groupPermissionId, role); | ||
| void notifyOnPermissionChangedById(permission.groupPermissionId); | ||
| } | ||
|
|
||
| await Permissions.removeRole(permission._id, role); | ||
| void notifyOnPermissionChangedById(permission._id); | ||
| }; | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P1: The new
cloud.connectWorkspaceroute ignores the boolean result ofconnectWorkspaceand always returns success, so failed workspace connections are incorrectly reported as successful.Prompt for AI agents