diff --git a/.changeset/brave-snakes-scream.md b/.changeset/brave-snakes-scream.md new file mode 100644 index 000000000000..914f248cd821 --- /dev/null +++ b/.changeset/brave-snakes-scream.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +Fixed an issue where broadcasted events were published twice within the same instance diff --git a/.changeset/bump-patch-1694827499043.md b/.changeset/bump-patch-1694827499043.md new file mode 100644 index 000000000000..e1eaa7980afb --- /dev/null +++ b/.changeset/bump-patch-1694827499043.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Bump @rocket.chat/meteor version. diff --git a/.changeset/bump-patch-1695163548038.md b/.changeset/bump-patch-1695163548038.md new file mode 100644 index 000000000000..e1eaa7980afb --- /dev/null +++ b/.changeset/bump-patch-1695163548038.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Bump @rocket.chat/meteor version. diff --git a/.changeset/bump-patch-1695165575069.md b/.changeset/bump-patch-1695165575069.md new file mode 100644 index 000000000000..e1eaa7980afb --- /dev/null +++ b/.changeset/bump-patch-1695165575069.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Bump @rocket.chat/meteor version. diff --git a/.changeset/fluffy-monkeys-sing.md b/.changeset/fluffy-monkeys-sing.md new file mode 100644 index 000000000000..db93491b0ecd --- /dev/null +++ b/.changeset/fluffy-monkeys-sing.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +Changed the name of the administration Logs page to "Records", implemented a tab layout in this page and added a new tab called "Analytic reports" that shows the most recent result of the statistics endpoint. diff --git a/.changeset/heavy-zebras-wonder.md b/.changeset/heavy-zebras-wonder.md new file mode 100644 index 000000000000..a1904a81c514 --- /dev/null +++ b/.changeset/heavy-zebras-wonder.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Show correct date for last day time diff --git a/.changeset/kind-books-love.md b/.changeset/kind-books-love.md new file mode 100644 index 000000000000..40ce15453ff4 --- /dev/null +++ b/.changeset/kind-books-love.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +Fixed message disappearing from room after erased even if "Show Deleted Status" is enabled diff --git a/.changeset/pre.json b/.changeset/pre.json index bf2911665af5..3bc535a4b50f 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -57,6 +57,9 @@ "bright-snakes-vanish", "brown-clouds-add", "bump-patch-1694741499930", + "bump-patch-1694827499043", + "bump-patch-1695163548038", + "bump-patch-1695165575069", "chilled-flies-fold", "chilled-phones-give", "cool-students-tan", @@ -86,6 +89,7 @@ "grumpy-candles-rule", "heavy-baboons-laugh", "heavy-cougars-marry", + "heavy-zebras-wonder", "hip-hounds-ring", "hip-mugs-promise", "honest-glasses-roll", @@ -139,7 +143,9 @@ "strong-laws-pump", "swift-birds-build", "swift-walls-protect", + "tall-pumpkins-cross", "tame-pens-occur", + "three-ants-give", "three-birds-tickle", "tidy-bears-camp", "tiny-turkeys-burn", diff --git a/.changeset/strange-papayas-yell.md b/.changeset/strange-papayas-yell.md new file mode 100644 index 000000000000..ca194dd2f9d4 --- /dev/null +++ b/.changeset/strange-papayas-yell.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +fix: Disables GenericMenu without any sections or items diff --git a/.changeset/thirty-pumpkins-fix.md b/.changeset/thirty-pumpkins-fix.md new file mode 100644 index 000000000000..11b92b064e15 --- /dev/null +++ b/.changeset/thirty-pumpkins-fix.md @@ -0,0 +1,8 @@ +--- +'@rocket.chat/core-typings': minor +'@rocket.chat/rest-typings': minor +'@rocket.chat/tools': minor +'@rocket.chat/meteor': minor +--- + +Added option to select between two script engine options for the integrations diff --git a/.github/workflows/ci-code-check.yml b/.github/workflows/ci-code-check.yml index 5a556a1a8e29..57cdac047423 100644 --- a/.github/workflows/ci-code-check.yml +++ b/.github/workflows/ci-code-check.yml @@ -44,6 +44,17 @@ jobs: - uses: dtinth/setup-github-actions-caching-for-turbo@v1 + - name: Cache TypeCheck + uses: actions/cache@v3 + if: matrix.check == 'ts' + with: + path: ./apps/meteor/tsconfig.typecheck.tsbuildinfo + key: typecheck-cache-${{ runner.OS }}-${{ hashFiles('yarn.lock') }}-${{ github.event.issue.number }} + restore-keys: | + typecheck-cache-${{ runner.OS }}-${{ hashFiles('yarn.lock') }} + typecheck-cache-${{ runner.OS }} + typecheck-cache + - name: TS TypeCheck if: matrix.check == 'ts' run: yarn turbo run typecheck diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 22250705ea58..31c2c42718b6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -356,13 +356,16 @@ jobs: echo finished deploy: - name: 🚀 Publish build and update our registry + name: 🚀 Publish build assets runs-on: ubuntu-20.04 if: github.event_name == 'release' || github.ref == 'refs/heads/develop' needs: [build-gh-docker, release-versions] steps: - - uses: actions/checkout@v3 + - uses: Bhacaz/checkout-files@v2 + with: + files: package.json + branch: ${{ github.ref }} - name: Restore build uses: actions/download-artifact@v3 @@ -376,32 +379,17 @@ jobs: AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} AWS_DEFAULT_REGION: 'us-east-1' GPG_PASSWORD: ${{ secrets.GPG_PASSWORD }} - REDHAT_REGISTRY_PID: ${{ secrets.REDHAT_REGISTRY_PID }} - REDHAT_REGISTRY_KEY: ${{ secrets.REDHAT_REGISTRY_KEY }} - UPDATE_TOKEN: ${{ secrets.UPDATE_TOKEN }} run: | REPO_VERSION=$(node -p "require('./package.json').version") + if [[ '${{ github.event_name }}' = 'release' ]]; then GIT_TAG="${GITHUB_REF#*tags/}" - GIT_BRANCH="" ARTIFACT_NAME="${REPO_VERSION}" - RC_VERSION=$GIT_TAG - - if [[ '${{ needs.release-versions.outputs.release }}' = 'release-candidate' ]]; then - SNAP_CHANNEL=candidate - RC_RELEASE=candidate - elif [[ '${{ needs.release-versions.outputs.release }}' = 'latest' ]]; then - SNAP_CHANNEL=stable - RC_RELEASE=stable - fi else GIT_TAG="" - GIT_BRANCH="${GITHUB_REF#*heads/}" ARTIFACT_NAME="${REPO_VERSION}.$GITHUB_SHA" - RC_VERSION="${REPO_VERSION}" - SNAP_CHANNEL=edge - RC_RELEASE=develop fi; + ROCKET_DEPLOY_DIR="/tmp/deploy" FILENAME="$ROCKET_DEPLOY_DIR/rocket.chat-$ARTIFACT_NAME.tgz"; @@ -419,22 +407,6 @@ jobs: aws s3 cp $ROCKET_DEPLOY_DIR/ s3://download.rocket.chat/build/ --recursive - curl -H "Content-Type: application/json" -H "X-Update-Token: $UPDATE_TOKEN" -d \ - "{\"nodeVersion\": \"${{ needs.release-versions.outputs.node-version }}\", \"compatibleMongoVersions\": [\"4.4\", \"5.0\", \"6.0\"], \"commit\": \"$GITHUB_SHA\", \"tag\": \"$RC_VERSION\", \"branch\": \"$GIT_BRANCH\", \"artifactName\": \"$ARTIFACT_NAME\", \"releaseType\": \"$RC_RELEASE\"}" \ - https://releases.rocket.chat/update - - # Makes build fail if the release isn't there - curl --fail https://releases.rocket.chat/$RC_VERSION/info - - if [[ $GIT_TAG ]]; then - curl -X POST \ - https://connect.redhat.com/api/v2/projects/$REDHAT_REGISTRY_PID/build \ - -H "Authorization: Bearer $REDHAT_REGISTRY_KEY" \ - -H 'Cache-Control: no-cache' \ - -H 'Content-Type: application/json' \ - -d '{"tag":"'$GIT_TAG'"}' - fi - build-docker-preview: name: 🚢 Build Docker Image (preview) runs-on: ubuntu-20.04 @@ -665,6 +637,66 @@ jobs: echo "::endgroup::" + notify-services: + name: 🚀 Notify external services + runs-on: ubuntu-20.04 + needs: + - services-docker-image-publish + - docker-image-publish + - release-versions + steps: + - uses: Bhacaz/checkout-files@v2 + with: + files: package.json + branch: ${{ github.ref }} + + - name: Releases service + env: + UPDATE_TOKEN: ${{ secrets.UPDATE_TOKEN }} + run: | + REPO_VERSION=$(node -p "require('./package.json').version") + + if [[ '${{ github.event_name }}' = 'release' ]]; then + GIT_TAG="${GITHUB_REF#*tags/}" + GIT_BRANCH="" + ARTIFACT_NAME="${REPO_VERSION}" + RC_VERSION=$GIT_TAG + + if [[ '${{ needs.release-versions.outputs.release }}' = 'release-candidate' ]]; then + RC_RELEASE=candidate + elif [[ '${{ needs.release-versions.outputs.release }}' = 'latest' ]]; then + RC_RELEASE=stable + fi + else + GIT_TAG="" + GIT_BRANCH="${GITHUB_REF#*heads/}" + ARTIFACT_NAME="${REPO_VERSION}.$GITHUB_SHA" + RC_VERSION="${REPO_VERSION}" + RC_RELEASE=develop + fi; + + curl -H "Content-Type: application/json" -H "X-Update-Token: $UPDATE_TOKEN" -d \ + "{\"nodeVersion\": \"${{ needs.release-versions.outputs.node-version }}\", \"compatibleMongoVersions\": [\"4.4\", \"5.0\", \"6.0\"], \"commit\": \"$GITHUB_SHA\", \"tag\": \"$RC_VERSION\", \"branch\": \"$GIT_BRANCH\", \"artifactName\": \"$ARTIFACT_NAME\", \"releaseType\": \"$RC_RELEASE\"}" \ + https://releases.rocket.chat/update + + # Makes build fail if the release isn't there + curl --fail https://releases.rocket.chat/$RC_VERSION/info + + - name: RedHat Registry + if: github.event_name == 'release' + env: + REDHAT_REGISTRY_PID: ${{ secrets.REDHAT_REGISTRY_PID }} + REDHAT_REGISTRY_KEY: ${{ secrets.REDHAT_REGISTRY_KEY }} + run: | + GIT_TAG="${GITHUB_REF#*tags/}" + + curl -X POST \ + https://connect.redhat.com/api/v2/projects/$REDHAT_REGISTRY_PID/build \ + -H "Authorization: Bearer $REDHAT_REGISTRY_KEY" \ + -H 'Cache-Control: no-cache' \ + -H 'Content-Type: application/json' \ + -d '{"tag":"'$GIT_TAG'"}' + trigger-dependent-workflows: runs-on: ubuntu-latest if: github.event_name == 'release' diff --git a/.yarn/patches/mongodb-npm-4.17.1-a2fe811ff1.patch b/.yarn/patches/mongodb-npm-4.17.1-a2fe811ff1.patch new file mode 100644 index 000000000000..501881370244 --- /dev/null +++ b/.yarn/patches/mongodb-npm-4.17.1-a2fe811ff1.patch @@ -0,0 +1,13 @@ +diff --git a/mongodb.d.ts b/mongodb.d.ts +index dd080b553309594c28093365ea101adec5c0a20c..20a616de8c97ec68629c01a848ea8df4fe122bf2 100644 +--- a/mongodb.d.ts ++++ b/mongodb.d.ts +@@ -5539,7 +5539,7 @@ export declare interface MonitorOptions extends Omit = Depth['length'] extends 8 ? [] : Type extends string | number | boolean | Date | RegExp | Buffer | Uint8Array | ((...args: any[]) => any) | { ++export declare type NestedPaths = Depth['length'] extends 1 ? [] : Type extends string | number | boolean | Date | RegExp | Buffer | Uint8Array | ((...args: any[]) => any) | { + _bsontype: string; + } ? [] : Type extends ReadonlyArray ? [] | [number, ...NestedPaths] : Type extends Map ? [string] : Type extends object ? { + [Key in Extract]: Type[Key] extends Type ? [Key] : Type extends Type[Key] ? [Key] : Type[Key] extends ReadonlyArray ? Type extends ArrayType ? [Key] : ArrayType extends Type ? [Key] : [ diff --git a/apps/meteor/.docker/Dockerfile.alpine b/apps/meteor/.docker/Dockerfile.alpine index 62a0476d9077..003baa57aa8b 100644 --- a/apps/meteor/.docker/Dockerfile.alpine +++ b/apps/meteor/.docker/Dockerfile.alpine @@ -15,6 +15,11 @@ RUN set -x \ && npm install sharp@0.30.4 \ && mv node_modules/sharp npm/node_modules/sharp \ # End hack for sharp + # Start hack for isolated-vm... + && rm -rf npm/node_modules/isolated-vm \ + && npm install isolated-vm@4.4.2 \ + && mv node_modules/isolated-vm npm/node_modules/isolated-vm \ + # End hack for isolated-vm && cd npm \ && npm rebuild bcrypt --build-from-source \ && npm cache clear --force \ diff --git a/apps/meteor/.gitignore b/apps/meteor/.gitignore index 287cb313c174..a9fd54ab8711 100644 --- a/apps/meteor/.gitignore +++ b/apps/meteor/.gitignore @@ -87,4 +87,5 @@ out.txt dist *-session.json matrix-federation-config/* -.eslintcache \ No newline at end of file +.eslintcache +tsconfig.typecheck.tsbuildinfo diff --git a/apps/meteor/.meteor/packages b/apps/meteor/.meteor/packages index 97836558ab28..ae788af78034 100644 --- a/apps/meteor/.meteor/packages +++ b/apps/meteor/.meteor/packages @@ -25,7 +25,7 @@ accounts-password@2.3.4 accounts-twitter@1.5.0 pauli:accounts-linkedin -google-oauth@1.4.3 +google-oauth@1.4.4 oauth@2.2.0 oauth2@1.3.2 @@ -39,7 +39,7 @@ meteor-base@1.5.1 ddp-common@1.4.0 webapp@1.13.5 -mongo@1.16.6 +mongo@1.16.7 reload@1.3.1 service-configuration@1.3.1 diff --git a/apps/meteor/.meteor/release b/apps/meteor/.meteor/release index e8cfc7ec4c01..6641d0478a10 100644 --- a/apps/meteor/.meteor/release +++ b/apps/meteor/.meteor/release @@ -1 +1 @@ -METEOR@2.12 +METEOR@2.13.3 diff --git a/apps/meteor/.meteor/versions b/apps/meteor/.meteor/versions index da6de9efbde1..66f61e2cd8cc 100644 --- a/apps/meteor/.meteor/versions +++ b/apps/meteor/.meteor/versions @@ -22,7 +22,7 @@ ddp@1.4.1 ddp-client@2.6.1 ddp-common@1.4.0 ddp-rate-limiter@1.2.0 -ddp-server@2.6.1 +ddp-server@2.6.2 diff-sequence@1.1.2 dispatch:run-as-user@1.1.1 dynamic-import@0.7.3 @@ -38,7 +38,7 @@ facts-base@1.0.1 fetch@0.1.3 geojson-utils@1.0.11 github-oauth@1.4.1 -google-oauth@1.4.3 +google-oauth@1.4.4 hot-code-push@1.0.4 http@2.0.0 id-map@1.1.1 @@ -47,7 +47,7 @@ jquery@3.0.0 kadira:flow-router@2.12.1 localstorage@1.2.0 logging@1.3.2 -meteor@1.11.2 +meteor@1.11.3 meteor-base@1.5.1 meteor-developer-oauth@1.3.2 meteorhacks:inject-initial@1.0.5 @@ -56,7 +56,7 @@ minimongo@1.9.3 modern-browsers@0.1.9 modules@0.19.0 modules-runtime@0.13.1 -mongo@1.16.6 +mongo@1.16.7 mongo-decimal@0.1.3 mongo-dev-server@1.1.0 mongo-id@1.0.8 @@ -92,7 +92,7 @@ shell-server@0.5.0 socket-stream-client@0.5.1 standard-minifier-css@1.9.2 tracker@1.3.2 -twitter-oauth@1.3.2 +twitter-oauth@1.3.3 typescript@4.9.4 underscore@1.0.13 url@1.3.2 diff --git a/apps/meteor/CHANGELOG.md b/apps/meteor/CHANGELOG.md index db7855b84991..18e6e45e8f48 100644 --- a/apps/meteor/CHANGELOG.md +++ b/apps/meteor/CHANGELOG.md @@ -1,5 +1,84 @@ # @rocket.chat/meteor +## 6.4.0-rc.4 + +### Patch Changes + +- Bump @rocket.chat/meteor version. + - @rocket.chat/core-typings@6.4.0-rc.4 + - @rocket.chat/rest-typings@6.4.0-rc.4 + - @rocket.chat/api-client@0.1.8-rc.4 + - @rocket.chat/omnichannel-services@0.0.14-rc.4 + - @rocket.chat/pdf-worker@0.0.14-rc.4 + - @rocket.chat/presence@0.0.14-rc.4 + - @rocket.chat/core-services@0.2.0-rc.4 + - @rocket.chat/cron@0.0.10-rc.4 + - @rocket.chat/gazzodown@2.0.0-rc.4 + - @rocket.chat/model-typings@0.1.0-rc.4 + - @rocket.chat/ui-contexts@2.0.0-rc.4 + - @rocket.chat/fuselage-ui-kit@2.0.0-rc.4 + - @rocket.chat/models@0.0.14-rc.4 + - @rocket.chat/ui-theming@0.1.0-rc.0 + - @rocket.chat/ui-client@2.0.0-rc.4 + - @rocket.chat/ui-video-conf@2.0.0-rc.4 + - @rocket.chat/web-ui-registration@2.0.0-rc.4 + - @rocket.chat/instance-status@0.0.14-rc.4 + +## 6.4.0-rc.3 + +### Patch Changes + +- Bump @rocket.chat/meteor version. +- 614a9b8fc8: Show correct date for last day time +- 61a106fbf2: Increase cron job check delay to 1 min from 5s. + + This reduces MongoDB requests introduced on 6.3. + +- Updated dependencies [d9a150000d] +- Updated dependencies [61a106fbf2] + - @rocket.chat/presence@0.0.13-rc.3 + - @rocket.chat/cron@0.0.9-rc.3 + - @rocket.chat/core-typings@6.4.0-rc.3 + - @rocket.chat/rest-typings@6.4.0-rc.3 + - @rocket.chat/api-client@0.1.7-rc.3 + - @rocket.chat/omnichannel-services@0.0.13-rc.3 + - @rocket.chat/pdf-worker@0.0.13-rc.3 + - @rocket.chat/core-services@0.2.0-rc.3 + - @rocket.chat/gazzodown@2.0.0-rc.3 + - @rocket.chat/model-typings@0.1.0-rc.3 + - @rocket.chat/ui-contexts@2.0.0-rc.3 + - @rocket.chat/fuselage-ui-kit@2.0.0-rc.3 + - @rocket.chat/models@0.0.13-rc.3 + - @rocket.chat/ui-theming@0.1.0-rc.0 + - @rocket.chat/ui-client@2.0.0-rc.3 + - @rocket.chat/ui-video-conf@2.0.0-rc.3 + - @rocket.chat/web-ui-registration@2.0.0-rc.3 + - @rocket.chat/instance-status@0.0.13-rc.3 + +## 6.4.0-rc.2 + +### Patch Changes + +- Bump @rocket.chat/meteor version. + - @rocket.chat/core-typings@6.4.0-rc.2 + - @rocket.chat/rest-typings@6.4.0-rc.2 + - @rocket.chat/api-client@0.1.7-rc.2 + - @rocket.chat/omnichannel-services@0.0.13-rc.2 + - @rocket.chat/pdf-worker@0.0.13-rc.2 + - @rocket.chat/presence@0.0.13-rc.2 + - @rocket.chat/core-services@0.2.0-rc.2 + - @rocket.chat/cron@0.0.9-rc.2 + - @rocket.chat/gazzodown@2.0.0-rc.2 + - @rocket.chat/model-typings@0.1.0-rc.2 + - @rocket.chat/ui-contexts@2.0.0-rc.2 + - @rocket.chat/fuselage-ui-kit@2.0.0-rc.2 + - @rocket.chat/models@0.0.13-rc.2 + - @rocket.chat/ui-theming@0.1.0-rc.0 + - @rocket.chat/ui-client@2.0.0-rc.2 + - @rocket.chat/ui-video-conf@2.0.0-rc.2 + - @rocket.chat/web-ui-registration@2.0.0-rc.2 + - @rocket.chat/instance-status@0.0.13-rc.2 + ## 6.4.0-rc.1 ### Patch Changes @@ -186,6 +265,39 @@ - @rocket.chat/random@1.2.1 - @rocket.chat/sha256@1.0.9 - @rocket.chat/ui-composer@0.0.1 + +## 6.3.7 + +### Patch Changes + +- f1e36a5e46: Bump @rocket.chat/meteor version. +- Bump @rocket.chat/meteor version. +- e1acdda0a3: User information crashing for some locales +- deffcb187c: Increase cron job check delay to 1 min from 5s. + + This reduces MongoDB requests introduced on 6.3. + +- Updated dependencies [c655be17ca] +- Updated dependencies [deffcb187c] + - @rocket.chat/presence@0.0.13 + - @rocket.chat/cron@0.0.9 + - @rocket.chat/core-typings@6.3.7 + - @rocket.chat/rest-typings@6.3.7 + - @rocket.chat/api-client@0.1.7 + - @rocket.chat/omnichannel-services@0.0.13 + - @rocket.chat/pdf-worker@0.0.13 + - @rocket.chat/core-services@0.1.7 + - @rocket.chat/gazzodown@1.0.7 + - @rocket.chat/model-typings@0.0.13 + - @rocket.chat/ui-contexts@1.0.7 + - @rocket.chat/fuselage-ui-kit@1.0.7 + - @rocket.chat/models@0.0.13 + - @rocket.chat/ui-theming@0.0.1 + - @rocket.chat/ui-client@1.0.7 + - @rocket.chat/ui-video-conf@1.0.7 + - @rocket.chat/web-ui-registration@1.0.7 + - @rocket.chat/instance-status@0.0.13 + ## 6.3.6 ### Patch Changes diff --git a/apps/meteor/app/api/server/v1/channels.ts b/apps/meteor/app/api/server/v1/channels.ts index 70b7fc875082..4a7aec073442 100644 --- a/apps/meteor/app/api/server/v1/channels.ts +++ b/apps/meteor/app/api/server/v1/channels.ts @@ -1,4 +1,4 @@ -import { Team } from '@rocket.chat/core-services'; +import { Team, Room } from '@rocket.chat/core-services'; import type { IRoom, ISubscription, IUser, RoomType } from '@rocket.chat/core-typings'; import { Integrations, Messages, Rooms, Subscriptions, Uploads, Users } from '@rocket.chat/models'; import { @@ -31,7 +31,6 @@ import { saveRoomSettings } from '../../../channel-settings/server/methods/saveR import { mountIntegrationQueryBasedOnPermissions } from '../../../integrations/server/lib/mountQueriesBasedOnPermission'; import { addUsersToRoomMethod } from '../../../lib/server/methods/addUsersToRoom'; import { createChannelMethod } from '../../../lib/server/methods/createChannel'; -import { joinRoomMethod } from '../../../lib/server/methods/joinRoom'; import { leaveRoomMethod } from '../../../lib/server/methods/leaveRoom'; import { settings } from '../../../settings/server'; import { normalizeMessagesForUser } from '../../../utils/server/lib/normalizeMessagesForUser'; @@ -209,7 +208,7 @@ API.v1.addRoute( const { joinCode, ...params } = this.bodyParams; const findResult = await findChannelByIdOrName({ params }); - await joinRoomMethod(this.userId, findResult._id, joinCode); + await Room.join({ room: findResult, user: this.user, joinCode }); return API.v1.success({ channel: await findChannelByIdOrName({ params, userId: this.userId }), diff --git a/apps/meteor/app/autotranslate/server/msTranslate.ts b/apps/meteor/app/autotranslate/server/msTranslate.ts index 3e9c9dbd8a35..f885a23b8e6b 100644 --- a/apps/meteor/app/autotranslate/server/msTranslate.ts +++ b/apps/meteor/app/autotranslate/server/msTranslate.ts @@ -87,7 +87,7 @@ class MsAutoTranslate extends AutoTranslate { if (this.supportedLanguages[target]) { return this.supportedLanguages[target]; } - const request = await fetch(this.apiEndPointUrl); + const request = await fetch(this.apiGetLanguages); if (!request.ok) { throw new Error(request.statusText); } diff --git a/apps/meteor/app/cloud/server/functions/checkUserHasCloudLogin.ts b/apps/meteor/app/cloud/server/functions/checkUserHasCloudLogin.ts index 033f2e3b94da..a17c71d80dc9 100644 --- a/apps/meteor/app/cloud/server/functions/checkUserHasCloudLogin.ts +++ b/apps/meteor/app/cloud/server/functions/checkUserHasCloudLogin.ts @@ -3,9 +3,9 @@ import { Users } from '@rocket.chat/models'; import { retrieveRegistrationStatus } from './retrieveRegistrationStatus'; export async function checkUserHasCloudLogin(userId: string) { - const { connectToCloud, workspaceRegistered } = await retrieveRegistrationStatus(); + const { workspaceRegistered } = await retrieveRegistrationStatus(); - if (!connectToCloud || !workspaceRegistered) { + if (!workspaceRegistered) { return false; } diff --git a/apps/meteor/app/cloud/server/functions/connectWorkspace.ts b/apps/meteor/app/cloud/server/functions/connectWorkspace.ts index 3c8a587fa558..8223522e2723 100644 --- a/apps/meteor/app/cloud/server/functions/connectWorkspace.ts +++ b/apps/meteor/app/cloud/server/functions/connectWorkspace.ts @@ -1,18 +1,11 @@ -import { Settings } from '@rocket.chat/models'; import { serverFetch as fetch } from '@rocket.chat/server-fetch'; import { SystemLogger } from '../../../../server/lib/logger/system'; import { settings } from '../../../settings/server'; import { getRedirectUri } from './getRedirectUri'; -import { retrieveRegistrationStatus } from './retrieveRegistrationStatus'; import { saveRegistrationData } from './saveRegistrationData'; export async function connectWorkspace(token: string) { - const { connectToCloud } = await retrieveRegistrationStatus(); - if (!connectToCloud) { - await Settings.updateValueById('Register_Server', true); - } - // shouldn't get here due to checking this on the method // but this is just to double check if (!token) { diff --git a/apps/meteor/app/cloud/server/functions/disconnectWorkspace.ts b/apps/meteor/app/cloud/server/functions/disconnectWorkspace.ts deleted file mode 100644 index c72a96297f37..000000000000 --- a/apps/meteor/app/cloud/server/functions/disconnectWorkspace.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { Settings } from '@rocket.chat/models'; - -import { retrieveRegistrationStatus } from './retrieveRegistrationStatus'; -import { syncWorkspace } from './syncWorkspace'; - -export async function disconnectWorkspace() { - const { connectToCloud } = await retrieveRegistrationStatus(); - if (!connectToCloud) { - return true; - } - - await Settings.updateValueById('Register_Server', false); - - await syncWorkspace(true); - - return true; -} diff --git a/apps/meteor/app/cloud/server/functions/getUserCloudAccessToken.ts b/apps/meteor/app/cloud/server/functions/getUserCloudAccessToken.ts index d7d87417e349..bf39a50b6234 100644 --- a/apps/meteor/app/cloud/server/functions/getUserCloudAccessToken.ts +++ b/apps/meteor/app/cloud/server/functions/getUserCloudAccessToken.ts @@ -11,9 +11,9 @@ import { retrieveRegistrationStatus } from './retrieveRegistrationStatus'; import { userLoggedOut } from './userLoggedOut'; export async function getUserCloudAccessToken(userId: string, forceNew = false, scope = '', save = true) { - const { connectToCloud, workspaceRegistered } = await retrieveRegistrationStatus(); + const { workspaceRegistered } = await retrieveRegistrationStatus(); - if (!connectToCloud || !workspaceRegistered) { + if (!workspaceRegistered) { return ''; } diff --git a/apps/meteor/app/cloud/server/functions/getWorkspaceAccessToken.ts b/apps/meteor/app/cloud/server/functions/getWorkspaceAccessToken.ts index 1a69d108ae4c..2b731ef82757 100644 --- a/apps/meteor/app/cloud/server/functions/getWorkspaceAccessToken.ts +++ b/apps/meteor/app/cloud/server/functions/getWorkspaceAccessToken.ts @@ -11,9 +11,9 @@ import { retrieveRegistrationStatus } from './retrieveRegistrationStatus'; * @returns string */ export async function getWorkspaceAccessToken(forceNew = false, scope = '', save = true) { - const { connectToCloud, workspaceRegistered } = await retrieveRegistrationStatus(); + const { workspaceRegistered } = await retrieveRegistrationStatus(); - if (!connectToCloud || !workspaceRegistered) { + if (!workspaceRegistered) { return ''; } diff --git a/apps/meteor/app/cloud/server/functions/getWorkspaceAccessTokenWithScope.ts b/apps/meteor/app/cloud/server/functions/getWorkspaceAccessTokenWithScope.ts index 4a0c4b5fe394..351b4cba20e5 100644 --- a/apps/meteor/app/cloud/server/functions/getWorkspaceAccessTokenWithScope.ts +++ b/apps/meteor/app/cloud/server/functions/getWorkspaceAccessTokenWithScope.ts @@ -8,11 +8,11 @@ import { removeWorkspaceRegistrationInfo } from './removeWorkspaceRegistrationIn import { retrieveRegistrationStatus } from './retrieveRegistrationStatus'; export async function getWorkspaceAccessTokenWithScope(scope = '') { - const { connectToCloud, workspaceRegistered } = await retrieveRegistrationStatus(); + const { workspaceRegistered } = await retrieveRegistrationStatus(); const tokenResponse = { token: '', expiresAt: new Date() }; - if (!connectToCloud || !workspaceRegistered) { + if (!workspaceRegistered) { return tokenResponse; } diff --git a/apps/meteor/app/cloud/server/functions/getWorkspaceKey.ts b/apps/meteor/app/cloud/server/functions/getWorkspaceKey.ts index f3b6dfc4238a..639f29402fe9 100644 --- a/apps/meteor/app/cloud/server/functions/getWorkspaceKey.ts +++ b/apps/meteor/app/cloud/server/functions/getWorkspaceKey.ts @@ -2,9 +2,9 @@ import { settings } from '../../../settings/server'; import { retrieveRegistrationStatus } from './retrieveRegistrationStatus'; export async function getWorkspaceKey() { - const { connectToCloud, workspaceRegistered } = await retrieveRegistrationStatus(); + const { workspaceRegistered } = await retrieveRegistrationStatus(); - if (!connectToCloud || !workspaceRegistered) { + if (!workspaceRegistered) { return false; } diff --git a/apps/meteor/app/cloud/server/functions/retrieveRegistrationStatus.ts b/apps/meteor/app/cloud/server/functions/retrieveRegistrationStatus.ts index 55698f4d27af..0291534ac637 100644 --- a/apps/meteor/app/cloud/server/functions/retrieveRegistrationStatus.ts +++ b/apps/meteor/app/cloud/server/functions/retrieveRegistrationStatus.ts @@ -3,7 +3,6 @@ import { Users } from '@rocket.chat/models'; import { settings } from '../../../settings/server'; export async function retrieveRegistrationStatus(): Promise<{ - connectToCloud: boolean; workspaceRegistered: boolean; workspaceId: string; uniqueId: string; @@ -11,7 +10,6 @@ export async function retrieveRegistrationStatus(): Promise<{ email: string; }> { const info = { - connectToCloud: settings.get('Register_Server'), workspaceRegistered: !!settings.get('Cloud_Workspace_Client_Id') && !!settings.get('Cloud_Workspace_Client_Secret'), workspaceId: settings.get('Cloud_Workspace_Id'), uniqueId: settings.get('uniqueID'), diff --git a/apps/meteor/app/cloud/server/functions/startRegisterWorkspace.ts b/apps/meteor/app/cloud/server/functions/startRegisterWorkspace.ts index de9fafc99065..af74fcd7d211 100644 --- a/apps/meteor/app/cloud/server/functions/startRegisterWorkspace.ts +++ b/apps/meteor/app/cloud/server/functions/startRegisterWorkspace.ts @@ -8,8 +8,8 @@ import { retrieveRegistrationStatus } from './retrieveRegistrationStatus'; import { syncWorkspace } from './syncWorkspace'; export async function startRegisterWorkspace(resend = false) { - const { workspaceRegistered, connectToCloud } = await retrieveRegistrationStatus(); - if ((workspaceRegistered && connectToCloud) || process.env.TEST_MODE) { + const { workspaceRegistered } = await retrieveRegistrationStatus(); + if (workspaceRegistered || process.env.TEST_MODE) { await syncWorkspace(true); return true; diff --git a/apps/meteor/app/cloud/server/functions/syncWorkspace.ts b/apps/meteor/app/cloud/server/functions/syncWorkspace.ts index 9337fd0a0172..c8a323e40f95 100644 --- a/apps/meteor/app/cloud/server/functions/syncWorkspace.ts +++ b/apps/meteor/app/cloud/server/functions/syncWorkspace.ts @@ -10,9 +10,9 @@ import { getWorkspaceAccessToken } from './getWorkspaceAccessToken'; import { getWorkspaceLicense } from './getWorkspaceLicense'; import { retrieveRegistrationStatus } from './retrieveRegistrationStatus'; -export async function syncWorkspace(reconnectCheck = false) { - const { workspaceRegistered, connectToCloud } = await retrieveRegistrationStatus(); - if (!workspaceRegistered || (!connectToCloud && !reconnectCheck)) { +export async function syncWorkspace(_reconnectCheck = false) { + const { workspaceRegistered } = await retrieveRegistrationStatus(); + if (!workspaceRegistered) { return false; } diff --git a/apps/meteor/app/cloud/server/functions/userLogout.ts b/apps/meteor/app/cloud/server/functions/userLogout.ts index e03f96df679d..7dd4aa094535 100644 --- a/apps/meteor/app/cloud/server/functions/userLogout.ts +++ b/apps/meteor/app/cloud/server/functions/userLogout.ts @@ -7,9 +7,9 @@ import { retrieveRegistrationStatus } from './retrieveRegistrationStatus'; import { userLoggedOut } from './userLoggedOut'; export async function userLogout(userId: string): Promise { - const { connectToCloud, workspaceRegistered } = await retrieveRegistrationStatus(); + const { workspaceRegistered } = await retrieveRegistrationStatus(); - if (!connectToCloud || !workspaceRegistered) { + if (!workspaceRegistered) { return ''; } diff --git a/apps/meteor/app/cloud/server/index.ts b/apps/meteor/app/cloud/server/index.ts index 4bb1f634978e..c7e783d4d5aa 100644 --- a/apps/meteor/app/cloud/server/index.ts +++ b/apps/meteor/app/cloud/server/index.ts @@ -2,7 +2,6 @@ import { cronJobs } from '@rocket.chat/cron'; import { Meteor } from 'meteor/meteor'; import { SystemLogger } from '../../../server/lib/logger/system'; -import { settings } from '../../settings/server'; import { connectWorkspace } from './functions/connectWorkspace'; import { getWorkspaceAccessToken } from './functions/getWorkspaceAccessToken'; import { getWorkspaceAccessTokenWithScope } from './functions/getWorkspaceAccessTokenWithScope'; @@ -13,24 +12,6 @@ import './methods'; const licenseCronName = 'Cloud Workspace Sync'; Meteor.startup(async () => { - // run token/license sync if registered - let TroubleshootDisableWorkspaceSync: boolean; - settings.watch('Troubleshoot_Disable_Workspace_Sync', async (value) => { - if (TroubleshootDisableWorkspaceSync === value) { - return; - } - TroubleshootDisableWorkspaceSync = value; - - if (value) { - return cronJobs.remove(licenseCronName); - } - - setImmediate(() => syncWorkspace()); - await cronJobs.add(licenseCronName, '0 */12 * * *', async () => { - await syncWorkspace(); - }); - }); - const { workspaceRegistered } = await retrieveRegistrationStatus(); if (process.env.REG_TOKEN && process.env.REG_TOKEN !== '' && !workspaceRegistered) { @@ -43,9 +24,14 @@ Meteor.startup(async () => { console.log('Successfully registered with token provided by REG_TOKEN!'); } catch (e: any) { - SystemLogger.error('An error occured registering with token.', e.message); + SystemLogger.error('An error occurred registering with token.', e.message); } } + + setImmediate(() => syncWorkspace()); + await cronJobs.add(licenseCronName, '0 */12 * * *', async () => { + await syncWorkspace(); + }); }); export { getWorkspaceAccessToken, getWorkspaceAccessTokenWithScope }; diff --git a/apps/meteor/app/cloud/server/methods.ts b/apps/meteor/app/cloud/server/methods.ts index d2fbac1af881..89e7b99e7146 100644 --- a/apps/meteor/app/cloud/server/methods.ts +++ b/apps/meteor/app/cloud/server/methods.ts @@ -6,7 +6,6 @@ import { hasPermissionAsync } from '../../authorization/server/functions/hasPerm import { buildWorkspaceRegistrationData } from './functions/buildRegistrationData'; import { checkUserHasCloudLogin } from './functions/checkUserHasCloudLogin'; import { connectWorkspace } from './functions/connectWorkspace'; -import { disconnectWorkspace } from './functions/disconnectWorkspace'; import { finishOAuthAuthorization } from './functions/finishOAuthAuthorization'; import { getOAuthAuthorizationUrl } from './functions/getOAuthAuthorizationUrl'; import { reconnectWorkspace } from './functions/reconnectWorkspace'; @@ -19,7 +18,6 @@ declare module '@rocket.chat/ui-contexts' { // eslint-disable-next-line @typescript-eslint/naming-convention interface ServerMethods { 'cloud:checkRegisterStatus': () => { - connectToCloud: boolean; workspaceRegistered: boolean; workspaceId: string; uniqueId: string; @@ -137,22 +135,6 @@ Meteor.methods({ return connectWorkspace(token); }, - async 'cloud:disconnectWorkspace'() { - const uid = Meteor.userId(); - if (!uid) { - throw new Meteor.Error('error-invalid-user', 'Invalid user', { - method: 'cloud:connectServer', - }); - } - - if (!(await hasPermissionAsync(uid, 'manage-cloud'))) { - throw new Meteor.Error('error-not-authorized', 'Not authorized', { - method: 'cloud:connectServer', - }); - } - - return disconnectWorkspace(); - }, async 'cloud:reconnectWorkspace'() { const uid = Meteor.userId(); if (!uid) { diff --git a/apps/meteor/app/discussion/server/hooks/joinDiscussionOnMessage.ts b/apps/meteor/app/discussion/server/hooks/joinDiscussionOnMessage.ts deleted file mode 100644 index b953d4658c85..000000000000 --- a/apps/meteor/app/discussion/server/hooks/joinDiscussionOnMessage.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { Subscriptions } from '@rocket.chat/models'; - -import { callbacks } from '../../../../lib/callbacks'; -import { joinRoomMethod } from '../../../lib/server/methods/joinRoom'; - -callbacks.add( - 'beforeSaveMessage', - async (message, room) => { - // abort if room is not a discussion - if (!room?.prid) { - return message; - } - - // check if user already joined the discussion - const sub = await Subscriptions.findOneByRoomIdAndUserId(room._id, message.u._id, { - projection: { _id: 1 }, - }); - - if (sub) { - return message; - } - - await joinRoomMethod(message.u._id, room._id); - - return message; - }, - callbacks.priority.MEDIUM, - 'joinDiscussionOnMessage', -); diff --git a/apps/meteor/app/integrations/server/api/api.js b/apps/meteor/app/integrations/server/api/api.js index e1db46729011..5162fa54ad9c 100644 --- a/apps/meteor/app/integrations/server/api/api.js +++ b/apps/meteor/app/integrations/server/api/api.js @@ -1,114 +1,21 @@ import { Integrations, Users } from '@rocket.chat/models'; -import * as Models from '@rocket.chat/models'; import { Random } from '@rocket.chat/random'; -import { Livechat } from 'meteor/rocketchat:livechat'; -import moment from 'moment'; import _ from 'underscore'; -import { VM, VMScript } from 'vm2'; -import * as s from '../../../../lib/utils/stringUtils'; -import { deasyncPromise } from '../../../../server/deasync/deasync'; -import { httpCall } from '../../../../server/lib/http/call'; import { API, APIClass, defaultRateLimiterOptions } from '../../../api/server'; import { processWebhookMessage } from '../../../lib/server/functions/processWebhookMessage'; import { settings } from '../../../settings/server'; +import { IsolatedVMScriptEngine } from '../lib/isolated-vm/isolated-vm'; +import { VM2ScriptEngine } from '../lib/vm2/vm2'; import { incomingLogger } from '../logger'; import { addOutgoingIntegration } from '../methods/outgoing/addOutgoingIntegration'; import { deleteOutgoingIntegration } from '../methods/outgoing/deleteOutgoingIntegration'; -const DISABLE_INTEGRATION_SCRIPTS = ['yes', 'true'].includes(String(process.env.DISABLE_INTEGRATION_SCRIPTS).toLowerCase()); +const vm2Engine = new VM2ScriptEngine(true); +const ivmEngine = new IsolatedVMScriptEngine(true); -export const forbiddenModelMethods = ['registerModel', 'getCollectionName']; - -const compiledScripts = {}; -function buildSandbox(store = {}) { - const httpAsync = async (method, url, options) => { - try { - return { - result: await httpCall(method, url, options), - }; - } catch (error) { - return { error }; - } - }; - - const sandbox = { - scriptTimeout(reject) { - return setTimeout(() => reject('timed out'), 3000); - }, - _, - s, - console, - moment, - Promise, - Livechat, - Store: { - set(key, val) { - store[key] = val; - return val; - }, - get(key) { - return store[key]; - }, - }, - HTTP: (method, url, options) => { - // TODO: deprecate, track and alert - return deasyncPromise(httpAsync(method, url, options)); - }, - // TODO: Export fetch as the non deprecated method - }; - Object.keys(Models) - .filter((k) => !forbiddenModelMethods.includes(k)) - .forEach((k) => { - sandbox[k] = Models[k]; - }); - return { store, sandbox }; -} - -function getIntegrationScript(integration) { - if (DISABLE_INTEGRATION_SCRIPTS) { - throw API.v1.failure('integration-scripts-disabled'); - } - - const compiledScript = compiledScripts[integration._id]; - if (compiledScript && +compiledScript._updatedAt === +integration._updatedAt) { - return compiledScript.script; - } - - const script = integration.scriptCompiled; - const { sandbox, store } = buildSandbox(); - try { - incomingLogger.info({ msg: 'Will evaluate script of Trigger', integration: integration.name }); - incomingLogger.debug(script); - - const vmScript = new VMScript(`${script}; Script;`, 'script.js'); - const vm = new VM({ - sandbox, - }); - - const ScriptClass = vm.run(vmScript); - - if (ScriptClass) { - compiledScripts[integration._id] = { - script: new ScriptClass(), - store, - _updatedAt: integration._updatedAt, - }; - - return compiledScripts[integration._id].script; - } - } catch (err) { - incomingLogger.error({ - msg: 'Error evaluating Script in Trigger', - integration: integration.name, - script, - err, - }); - throw API.v1.failure('error-evaluating-script'); - } - - incomingLogger.error({ msg: 'Class "Script" not in Trigger', integration: integration.name }); - throw API.v1.failure('class-script-not-found'); +function getEngine(integration) { + return integration.scriptEngine === 'isolated-vm' ? ivmEngine : vm2Engine; } async function createIntegration(options, user) { @@ -178,20 +85,9 @@ async function executeIntegrationRest() { emoji: this.integration.emoji, }; - if ( - !DISABLE_INTEGRATION_SCRIPTS && - this.integration.scriptEnabled && - this.integration.scriptCompiled && - this.integration.scriptCompiled.trim() !== '' - ) { - let script; - try { - script = getIntegrationScript(this.integration); - } catch (e) { - incomingLogger.error(e); - return API.v1.failure(e.message); - } + const scriptEngine = getEngine(this.integration); + if (scriptEngine.integrationHasValidScript(this.integration)) { this.request.setEncoding('utf8'); const content_raw = this.request.read(); @@ -216,37 +112,12 @@ async function executeIntegrationRest() { }, }; - try { - const { sandbox } = buildSandbox(compiledScripts[this.integration._id].store); - sandbox.script = script; - sandbox.request = request; - - const vm = new VM({ - timeout: 3000, - sandbox, - }); - - const result = await new Promise((resolve, reject) => { - process.nextTick(async () => { - try { - const scriptResult = await vm.run(` - new Promise((resolve, reject) => { - scriptTimeout(reject); - try { - resolve(script.process_incoming_request({ request: request })); - } catch(e) { - reject(e); - } - }).catch((error) => { throw new Error(error); }); - `); - - resolve(scriptResult); - } catch (e) { - reject(e); - } - }); - }); + const result = await scriptEngine.processIncomingRequest({ + integration: this.integration, + request, + }); + try { if (!result) { incomingLogger.debug({ msg: 'Process Incoming Request result of Trigger has no data', diff --git a/apps/meteor/app/integrations/server/lib/ScriptEngine.ts b/apps/meteor/app/integrations/server/lib/ScriptEngine.ts new file mode 100644 index 000000000000..e46984a893ef --- /dev/null +++ b/apps/meteor/app/integrations/server/lib/ScriptEngine.ts @@ -0,0 +1,385 @@ +import type { + IUser, + IRoom, + IMessage, + IOutgoingIntegration, + IIncomingIntegration, + IIntegration, + IIntegrationHistory, +} from '@rocket.chat/core-typings'; +import type { Logger } from '@rocket.chat/logger'; +import type { serverFetch } from '@rocket.chat/server-fetch'; +import { wrapExceptions } from '@rocket.chat/tools'; + +import { incomingLogger, outgoingLogger } from '../logger'; +import type { IScriptClass, CompiledScript } from './definition'; +import { updateHistory } from './updateHistory'; + +type OutgoingRequestBaseData = { + token: IOutgoingIntegration['token']; + bot: false; + trigger_word: string; +}; + +type OutgoingRequestSendMessageData = OutgoingRequestBaseData & { + channel_id: string; + channel_name: string; + message_id: string; + timestamp: Date; + user_id: string; + user_name: string; + text: string; + siteUrl: string; + alias?: string; + bot?: boolean; + isEdited?: true; + tmid?: string; +}; + +type OutgoingRequestUploadedFileData = OutgoingRequestBaseData & { + channel_id: string; + channel_name: string; + message_id: string; + timestamp: Date; + user_id: string; + user_name: string; + text: string; + + user: IUser; + room: IRoom; + message: IMessage; + + alias?: string; + bot?: boolean; +}; + +type OutgoingRequestRoomCreatedData = OutgoingRequestBaseData & { + channel_id: string; + channel_name: string; + timestamp: Date; + user_id: string; + user_name: string; + owner: IUser; + room: IRoom; +}; + +type OutgoingRequestRoomData = OutgoingRequestBaseData & { + channel_id: string; + channel_name: string; + timestamp: Date; + user_id: string; + user_name: string; + owner: IUser; + room: IRoom; + bot?: boolean; +}; + +type OutgoingRequestUserCreatedData = OutgoingRequestBaseData & { + timestamp: Date; + user_id: string; + user_name: string; + user: IUser; + bot?: boolean; +}; + +type OutgoingRequestData = + | OutgoingRequestSendMessageData + | OutgoingRequestUploadedFileData + | OutgoingRequestRoomCreatedData + | OutgoingRequestRoomData + | OutgoingRequestUserCreatedData; + +type OutgoingRequest = { + params: Record; + method: 'POST'; + url: string; + data: OutgoingRequestData; + auth: undefined; + headers: Record; +}; + +type OutgoingRequestFromScript = { + url?: string; + headers?: Record; + method?: string; + message?: { + text?: string; + channel?: string; + attachments?: { + color?: string; + author_name?: string; + author_link?: string; + author_icon?: string; + title?: string; + title_link?: string; + text?: string; + fields?: { + title?: string; + value?: string; + short?: boolean; + }[]; + image_url?: string; + thumb_url?: string; + }[]; + }; + + auth?: string; + data?: Record; +}; + +type OutgoingRequestContext = { + integration: IOutgoingIntegration; + data: OutgoingRequestData; + historyId: IIntegrationHistory['_id']; + url: string; +}; + +type ProcessedOutgoingRequest = OutgoingRequest | OutgoingRequestFromScript; + +type OutgoingResponseContext = { + integration: IOutgoingIntegration; + request: ProcessedOutgoingRequest; + response: Awaited>; + content: string; + historyId: IIntegrationHistory['_id']; +}; + +type IncomingIntegrationRequest = { + url: { + hash: string | null | undefined; + search: string | null | undefined; + query: Record; + pathname: string | null | undefined; + path: string | null | undefined; + }; + url_raw: string; + url_params: Record; + content: Record; + content_raw: string; + headers: Record; + body: Record; + user: Pick, '_id' | 'name' | 'username'>; +}; + +export abstract class IntegrationScriptEngine { + protected compiledScripts: Record; + + public get disabled(): boolean { + return this.isDisabled(); + } + + public get incoming(): IsIncoming { + return this.isIncoming; + } + + constructor(private isIncoming: IsIncoming) { + this.compiledScripts = {}; + } + + public integrationHasValidScript(integration: IIntegration): boolean { + return Boolean(!this.disabled && integration.scriptEnabled && integration.scriptCompiled && integration.scriptCompiled.trim() !== ''); + } + + // PrepareOutgoingRequest will execute a script to build the request object that will be used for the actual integration request + // It may also return a message object to be sent to the room where the integration was triggered + public async prepareOutgoingRequest({ integration, data, historyId, url }: OutgoingRequestContext): Promise { + const request: OutgoingRequest = { + params: {}, + method: 'POST', + url, + data, + auth: undefined, + headers: { + 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2227.0 Safari/537.36', + }, + }; + + if (!(await this.hasScriptAndMethod(integration, 'prepare_outgoing_request'))) { + return request; + } + + return this.executeOutgoingScript(integration, 'prepare_outgoing_request', { request }, historyId); + } + + public async processOutgoingResponse({ + integration, + request, + response, + content, + historyId, + }: OutgoingResponseContext): Promise { + if (!(await this.hasScriptAndMethod(integration, 'process_outgoing_response'))) { + return; + } + + const sandbox = { + request, + response: { + error: null, + status_code: response.status, + content, + content_raw: content, + headers: Object.fromEntries(response.headers), + }, + }; + + const scriptResult = await this.executeOutgoingScript(integration, 'process_outgoing_response', sandbox, historyId); + + if (scriptResult === false) { + return scriptResult; + } + + if (scriptResult?.content) { + return scriptResult.content; + } + } + + public async processIncomingRequest({ + integration, + request, + }: { + integration: IIncomingIntegration; + request: IncomingIntegrationRequest; + }): Promise { + return this.executeIncomingScript(integration, 'process_incoming_request', { request }); + } + + protected get logger(): ReturnType { + if (this.isIncoming) { + return incomingLogger; + } + + return outgoingLogger; + } + + protected async executeOutgoingScript( + integration: IOutgoingIntegration, + method: keyof IScriptClass, + params: Record, + historyId: IIntegrationHistory['_id'], + ): Promise { + if (this.disabled) { + return; + } + + const script = await wrapExceptions(() => this.getIntegrationScript(integration)).suppress((e: any) => + updateHistory({ + historyId, + step: 'execute-script-getting-script', + error: true, + errorStack: e, + }), + ); + + if (!script) { + return; + } + + if (!script[method]) { + this.logger.error(`Method "${method}" not found in the Integration "${integration.name}"`); + await updateHistory({ historyId, step: `execute-script-no-method-${method}` }); + return; + } + + try { + await updateHistory({ historyId, step: `execute-script-before-running-${method}` }); + + const result = await this.runScriptMethod({ + integrationId: integration._id, + script, + method, + params, + }); + + this.logger.debug({ + msg: `Script method "${method}" result of the Integration "${integration.name}" is:`, + result, + }); + + return result; + } catch (err: any) { + await updateHistory({ + historyId, + step: `execute-script-error-running-${method}`, + error: true, + errorStack: err.stack.replace(/^/gm, ' '), + }); + this.logger.error({ + msg: 'Error running Script in the Integration', + integration: integration.name, + err, + }); + this.logger.debug({ + msg: 'Error running Script in the Integration', + integration: integration.name, + script: integration.scriptCompiled, + }); + } + } + + protected async executeIncomingScript( + integration: IIncomingIntegration, + method: keyof IScriptClass, + params: Record, + ): Promise { + if (!this.integrationHasValidScript(integration)) { + return; + } + + const script = await wrapExceptions(() => this.getIntegrationScript(integration)).catch((e) => { + this.logger.error(e); + throw e; + }); + + if (!script[method]) { + this.logger.error(`Method "${method}" not found in the Integration "${integration.name}"`); + return; + } + + return wrapExceptions(() => + this.runScriptMethod({ + integrationId: integration._id, + script, + method, + params, + }), + ).catch((err: any) => { + this.logger.error({ + msg: 'Error running Script in Trigger', + integration: integration.name, + script: integration.scriptCompiled, + err, + }); + throw new Error('error-running-script'); + }); + } + + protected async hasScriptAndMethod(integration: IIntegration, method: keyof IScriptClass): Promise { + const script = await this.getScriptSafely(integration); + return typeof script?.[method] === 'function'; + } + + protected async getScriptSafely(integration: IIntegration): Promise | undefined> { + if (this.disabled || integration.scriptEnabled !== true || !integration.scriptCompiled || integration.scriptCompiled.trim() === '') { + return; + } + + return wrapExceptions(() => this.getIntegrationScript(integration)).suppress(); + } + + protected abstract isDisabled(): boolean; + + protected abstract runScriptMethod({ + integrationId, + script, + method, + params, + }: { + integrationId: IIntegration['_id']; + script: IScriptClass; + method: keyof IScriptClass; + params: Record; + }): Promise; + + protected abstract getIntegrationScript(integration: IIntegration): Promise>; +} diff --git a/apps/meteor/app/integrations/server/lib/definition.ts b/apps/meteor/app/integrations/server/lib/definition.ts new file mode 100644 index 000000000000..b4d11b9f4e8b --- /dev/null +++ b/apps/meteor/app/integrations/server/lib/definition.ts @@ -0,0 +1,19 @@ +import type { IIntegration } from '@rocket.chat/core-typings'; + +export interface IScriptClass { + prepare_outgoing_request?: (params: Record) => any; + process_outgoing_response?: (params: Record) => any; + process_incoming_request?: (params: Record) => any; +} + +export type FullScriptClass = Required; + +export type CompiledScript = { + script: Partial; + store: Record; + _updatedAt: IIntegration['_updatedAt']; +}; + +export type CompatibilityScriptResult = IScriptClass & { + availableFunctions: (keyof IScriptClass)[]; +}; diff --git a/apps/meteor/app/integrations/server/lib/isolated-vm/buildSandbox.ts b/apps/meteor/app/integrations/server/lib/isolated-vm/buildSandbox.ts new file mode 100644 index 000000000000..1bbefb6a2ee7 --- /dev/null +++ b/apps/meteor/app/integrations/server/lib/isolated-vm/buildSandbox.ts @@ -0,0 +1,127 @@ +import { EventEmitter } from 'events'; + +import { serverFetch as fetch, Response } from '@rocket.chat/server-fetch'; +import ivm, { type Context } from 'isolated-vm'; + +import * as s from '../../../../../lib/utils/stringUtils'; + +const proxyObject = (obj: Record, forbiddenKeys: string[] = []): Record => { + return copyObject({ + isProxy: true, + get: (key: string) => { + if (forbiddenKeys.includes(key)) { + return undefined; + } + + const value = obj[key]; + + if (typeof value === 'function') { + return new ivm.Reference(async (...args: any[]) => { + const result = (obj[key] as any)(...args); + + if (result && result instanceof Promise) { + return new Promise(async (resolve, reject) => { + try { + const awaitedResult = await result; + resolve(makeTransferable(awaitedResult)); + } catch (e) { + reject(e); + } + }); + } + + return makeTransferable(result); + }); + } + + return makeTransferable(value); + }, + }); +}; + +const copyObject = (obj: Record | any[]): Record | any[] => { + if (Array.isArray(obj)) { + return obj.map((data) => copyData(data)); + } + + if (obj instanceof Response) { + return proxyObject(obj, ['clone']); + } + + if (isSemiTransferable(obj)) { + return obj; + } + + if (typeof obj[Symbol.iterator as any] === 'function') { + return copyObject(Array.from(obj as any)); + } + + if (obj instanceof EventEmitter) { + return {}; + } + + const keys = Object.keys(obj); + + return { + ...Object.fromEntries( + keys.map((key) => { + const data = obj[key]; + + if (typeof data === 'function') { + return [key, new ivm.Callback((...args: any[]) => obj[key](...args))]; + } + + return [key, copyData(data)]; + }), + ), + }; +}; + +// Transferable data can be passed to isolates directly +const isTransferable = (data: any): data is ivm.Transferable => { + const dataType = typeof data; + + if (data === ivm) { + return true; + } + + if (['null', 'undefined', 'string', 'number', 'boolean', 'function'].includes(dataType)) { + return true; + } + + if (dataType !== 'object') { + return false; + } + + return ( + data instanceof ivm.Isolate || + data instanceof ivm.Context || + data instanceof ivm.Script || + data instanceof ivm.ExternalCopy || + data instanceof ivm.Callback || + data instanceof ivm.Reference + ); +}; + +// Semi-transferable data can be copied with an ivm.ExternalCopy without needing any manipulation. +const isSemiTransferable = (data: any) => data instanceof ArrayBuffer; + +const copyData = | any[]>(data: T) => (isTransferable(data) ? data : copyObject(data)); +const makeTransferable = (data: any) => (isTransferable(data) ? data : new ivm.ExternalCopy(copyObject(data)).copyInto()); + +export const buildSandbox = (context: Context) => { + const { global: jail } = context; + jail.setSync('global', jail.derefInto()); + jail.setSync('ivm', ivm); + + jail.setSync('s', makeTransferable(s)); + jail.setSync('console', makeTransferable(console)); + + jail.setSync( + 'serverFetch', + new ivm.Reference(async (url: string, ...args: any[]) => { + const result = await fetch(url, ...args); + return makeTransferable(result); + }), + ); +}; diff --git a/apps/meteor/app/integrations/server/lib/isolated-vm/getCompatibilityScript.ts b/apps/meteor/app/integrations/server/lib/isolated-vm/getCompatibilityScript.ts new file mode 100644 index 000000000000..77ce2475e8c2 --- /dev/null +++ b/apps/meteor/app/integrations/server/lib/isolated-vm/getCompatibilityScript.ts @@ -0,0 +1,60 @@ +export const getCompatibilityScript = (customScript?: string) => ` + const Store = (function() { + const store = {}; + return { + set(key, val) { + store[key] = val; + return val; + }, + get(key) { + return store[key]; + }, + }; + })(); + + const reproxy = (reference) => { + return new Proxy(reference, { + get(target, p, receiver) { + if (target !== reference || p === 'then') { + return Reflect.get(target, p, receiver); + } + + const data = reference.get(p); + + if (typeof data === 'object' && data instanceof ivm.Reference && data.typeof === 'function') { + return (...args) => data.apply(undefined, args, { arguments: { copy: true }, result: { promise: true } }); + } + + return data; + } + }); + }; + + //url, options, allowSelfSignedCertificate + const fetch = async (...args) => { + const result = await serverFetch.apply(undefined, args, { arguments: { copy: true }, result: { promise: true } }); + + if (result && typeof result === 'object' && result.isProxy) { + return reproxy(result); + } + + return result; + }; + + ${customScript} + + (function() { + const instance = new Script(); + + const functions = { + ...(typeof instance['prepare_outgoing_request'] === 'function' ? { prepare_outgoing_request : (...args) => instance.prepare_outgoing_request(...args) } : {}), + ...(typeof instance['process_outgoing_response'] === 'function' ? { process_outgoing_response : (...args) => instance.process_outgoing_response(...args) } : {}), + ...(typeof instance['process_incoming_request'] === 'function' ? { process_incoming_request : (...args) => instance.process_incoming_request(...args) } : {}), + }; + + return { + ...functions, + availableFunctions: Object.keys(functions), + } + })(); +`; diff --git a/apps/meteor/app/integrations/server/lib/isolated-vm/isolated-vm.ts b/apps/meteor/app/integrations/server/lib/isolated-vm/isolated-vm.ts new file mode 100644 index 000000000000..2c78b6d98a7c --- /dev/null +++ b/apps/meteor/app/integrations/server/lib/isolated-vm/isolated-vm.ts @@ -0,0 +1,99 @@ +import type { IIntegration, ValueOf } from '@rocket.chat/core-typings'; +import { pick } from '@rocket.chat/tools'; +import ivm, { type Reference } from 'isolated-vm'; + +import { IntegrationScriptEngine } from '../ScriptEngine'; +import type { IScriptClass, CompatibilityScriptResult, FullScriptClass } from '../definition'; +import { buildSandbox } from './buildSandbox'; +import { getCompatibilityScript } from './getCompatibilityScript'; + +const DISABLE_INTEGRATION_SCRIPTS = ['yes', 'true', 'ivm'].includes(String(process.env.DISABLE_INTEGRATION_SCRIPTS).toLowerCase()); + +export class IsolatedVMScriptEngine extends IntegrationScriptEngine { + protected isDisabled(): boolean { + return DISABLE_INTEGRATION_SCRIPTS; + } + + protected async callScriptFunction( + scriptReference: Reference>, + ...params: Parameters> + ): Promise { + return scriptReference.applySync(undefined, params, { + arguments: { copy: true }, + result: { copy: true, promise: true }, + }); + } + + protected async runScriptMethod({ + script, + method, + params, + }: { + integrationId: IIntegration['_id']; + script: Partial; + method: keyof IScriptClass; + params: Record; + }): Promise { + const fn = script[method]; + + if (typeof fn !== 'function') { + throw new Error('integration-method-not-found'); + } + + return fn(params); + } + + protected async getIntegrationScript(integration: IIntegration): Promise> { + if (this.disabled) { + throw new Error('integration-scripts-disabled'); + } + + const compiledScript = this.compiledScripts[integration._id]; + if (compiledScript && +compiledScript._updatedAt === +integration._updatedAt) { + return compiledScript.script; + } + + const script = integration.scriptCompiled; + try { + this.logger.info({ msg: 'Will evaluate the integration script', integration: pick(integration, 'name', '_id') }); + this.logger.debug(script); + + const isolate = new ivm.Isolate({ memoryLimit: 8 }); + + const ivmScript = await isolate.compileScript(getCompatibilityScript(script)); + + const ivmContext = isolate.createContextSync(); + buildSandbox(ivmContext); + + const ivmResult: Reference = await ivmScript.run(ivmContext, { + reference: true, + timeout: 3000, + }); + + const availableFunctions = await ivmResult.get('availableFunctions', { copy: true }); + const scriptFunctions = Object.fromEntries( + availableFunctions.map((functionName) => { + const fnReference = ivmResult.getSync(functionName, { reference: true }); + return [functionName, (...params: Parameters>) => this.callScriptFunction(fnReference, ...params)]; + }), + ) as Partial; + + this.compiledScripts[integration._id] = { + script: scriptFunctions, + store: {}, + _updatedAt: integration._updatedAt, + }; + + return scriptFunctions; + } catch (err: any) { + this.logger.error({ + msg: 'Error evaluating integration script', + integration: integration.name, + script, + err, + }); + + throw new Error('error-evaluating-script'); + } + } +} diff --git a/apps/meteor/app/integrations/server/lib/triggerHandler.js b/apps/meteor/app/integrations/server/lib/triggerHandler.js index b122b22ff355..b5050b8c4716 100644 --- a/apps/meteor/app/integrations/server/lib/triggerHandler.js +++ b/apps/meteor/app/integrations/server/lib/triggerHandler.js @@ -1,30 +1,25 @@ -import { Integrations, IntegrationHistory, Users, Rooms, Messages } from '@rocket.chat/models'; -import * as Models from '@rocket.chat/models'; -import { Random } from '@rocket.chat/random'; +import { Integrations, Users, Rooms, Messages } from '@rocket.chat/models'; import { serverFetch as fetch } from '@rocket.chat/server-fetch'; +import { wrapExceptions } from '@rocket.chat/tools'; import { Meteor } from 'meteor/meteor'; -import moment from 'moment'; import _ from 'underscore'; -import { VM, VMScript } from 'vm2'; -import { omit } from '../../../../lib/utils/omit'; -import * as s from '../../../../lib/utils/stringUtils'; -import { deasyncPromise } from '../../../../server/deasync/deasync'; -import { httpCall } from '../../../../server/lib/http/call'; import { getRoomByNameOrIdWithOptionToJoin } from '../../../lib/server/functions/getRoomByNameOrIdWithOptionToJoin'; import { processWebhookMessage } from '../../../lib/server/functions/processWebhookMessage'; import { settings } from '../../../settings/server'; import { outgoingEvents } from '../../lib/outgoingEvents'; -import { forbiddenModelMethods } from '../api/api'; import { outgoingLogger } from '../logger'; - -const DISABLE_INTEGRATION_SCRIPTS = ['yes', 'true'].includes(String(process.env.DISABLE_INTEGRATION_SCRIPTS).toLowerCase()); +import { IsolatedVMScriptEngine } from './isolated-vm/isolated-vm'; +import { updateHistory } from './updateHistory'; +import { VM2ScriptEngine } from './vm2/vm2'; class RocketChatIntegrationHandler { constructor() { this.successResults = [200, 201, 202]; this.compiledScripts = {}; this.triggers = {}; + this.vm2Engine = new VM2ScriptEngine(false); + this.ivmEngine = new IsolatedVMScriptEngine(false); } addIntegration(record) { @@ -51,6 +46,10 @@ class RocketChatIntegrationHandler { } } + getEngine(integration) { + return integration.scriptEngine === 'isolated-vm' ? this.ivmEngine : this.vm2Engine; + } + removeIntegration(record) { for (const trigger of Object.values(this.triggers)) { delete trigger[record._id]; @@ -67,114 +66,6 @@ class RocketChatIntegrationHandler { return false; } - async updateHistory({ - historyId, - step, - integration, - event, - data, - triggerWord, - ranPrepareScript, - prepareSentMessage, - processSentMessage, - resultMessage, - finished, - url, - httpCallData, - httpError, - httpResult, - error, - errorStack, - }) { - const history = { - type: 'outgoing-webhook', - step, - }; - - // Usually is only added on initial insert - if (integration) { - history.integration = integration; - } - - // Usually is only added on initial insert - if (event) { - history.event = event; - } - - if (data) { - history.data = { ...data }; - - if (data.user) { - history.data.user = omit(data.user, 'services'); - } - - if (data.room) { - history.data.room = data.room; - } - } - - if (triggerWord) { - history.triggerWord = triggerWord; - } - - if (typeof ranPrepareScript !== 'undefined') { - history.ranPrepareScript = ranPrepareScript; - } - - if (prepareSentMessage) { - history.prepareSentMessage = prepareSentMessage; - } - - if (processSentMessage) { - history.processSentMessage = processSentMessage; - } - - if (resultMessage) { - history.resultMessage = resultMessage; - } - - if (typeof finished !== 'undefined') { - history.finished = finished; - } - - if (url) { - history.url = url; - } - - if (typeof httpCallData !== 'undefined') { - history.httpCallData = httpCallData; - } - - if (httpError) { - history.httpError = httpError; - } - - if (typeof httpResult !== 'undefined') { - history.httpResult = JSON.stringify(httpResult, null, 2); - } - - if (typeof error !== 'undefined') { - history.error = error; - } - - if (typeof errorStack !== 'undefined') { - history.errorStack = errorStack; - } - - if (historyId) { - await IntegrationHistory.updateOne({ _id: historyId }, { $set: history }); - return historyId; - } - - history._createdAt = new Date(); - - const _id = Random.id(); - - await IntegrationHistory.insertOne({ _id, ...history }); - - return _id; - } - // Trigger is the trigger, nameOrId is a string which is used to try and find a room, room is a room, message is a message, and data contains "user_name" if trigger.impersonateUser is truthful. async sendMessage({ trigger, nameOrId = '', room, message, data }) { let user; @@ -229,199 +120,6 @@ class RocketChatIntegrationHandler { return message; } - buildSandbox(store = {}) { - const httpAsync = async (method, url, options) => { - try { - return { - result: await httpCall(method, url, options), - }; - } catch (error) { - return { error }; - } - }; - - const sandbox = { - scriptTimeout(reject) { - return setTimeout(() => reject('timed out'), 3000); - }, - _, - s, - console, - moment, - Promise, - Store: { - set: (key, val) => { - store[key] = val; - }, - get: (key) => store[key], - }, - HTTP: (method, url, options) => { - // TODO: deprecate, track and alert - return deasyncPromise(httpAsync(method, url, options)); - }, - // TODO: Export fetch as the non deprecated method - }; - - Object.keys(Models) - .filter((k) => !forbiddenModelMethods.includes(k)) - .forEach((k) => { - sandbox[k] = Models[k]; - }); - - return { store, sandbox }; - } - - getIntegrationScript(integration) { - if (DISABLE_INTEGRATION_SCRIPTS) { - throw new Meteor.Error('integration-scripts-disabled'); - } - - const compiledScript = this.compiledScripts[integration._id]; - if (compiledScript && +compiledScript._updatedAt === +integration._updatedAt) { - return compiledScript.script; - } - - const script = integration.scriptCompiled; - const { store, sandbox } = this.buildSandbox(); - - try { - outgoingLogger.info({ msg: 'Will evaluate script of Trigger', integration: integration.name }); - outgoingLogger.debug(script); - - const vmScript = new VMScript(`${script}; Script;`, 'script.js'); - const vm = new VM({ - sandbox, - }); - - const ScriptClass = vm.run(vmScript); - - if (ScriptClass) { - this.compiledScripts[integration._id] = { - script: new ScriptClass(), - store, - _updatedAt: integration._updatedAt, - }; - - return this.compiledScripts[integration._id].script; - } - } catch (err) { - outgoingLogger.error({ - msg: 'Error evaluating Script in Trigger', - integration: integration.name, - script, - err, - }); - throw new Meteor.Error('error-evaluating-script'); - } - - outgoingLogger.error(`Class "Script" not in Trigger ${integration.name}:`); - throw new Meteor.Error('class-script-not-found'); - } - - hasScriptAndMethod(integration, method) { - if ( - DISABLE_INTEGRATION_SCRIPTS || - integration.scriptEnabled !== true || - !integration.scriptCompiled || - integration.scriptCompiled.trim() === '' - ) { - return false; - } - - let script; - try { - script = this.getIntegrationScript(integration); - } catch (e) { - return false; - } - - return typeof script[method] !== 'undefined'; - } - - async executeScript(integration, method, params, historyId) { - if (DISABLE_INTEGRATION_SCRIPTS) { - return; - } - - let script; - try { - script = this.getIntegrationScript(integration); - } catch (e) { - await this.updateHistory({ - historyId, - step: 'execute-script-getting-script', - error: true, - errorStack: e, - }); - return; - } - - if (!script[method]) { - outgoingLogger.error(`Method "${method}" no found in the Integration "${integration.name}"`); - await this.updateHistory({ historyId, step: `execute-script-no-method-${method}` }); - return; - } - - try { - const { sandbox } = this.buildSandbox(this.compiledScripts[integration._id].store); - sandbox.script = script; - sandbox.method = method; - sandbox.params = params; - - await this.updateHistory({ historyId, step: `execute-script-before-running-${method}` }); - - const vm = new VM({ - timeout: 3000, - sandbox, - }); - - const result = await new Promise((resolve, reject) => { - process.nextTick(async () => { - try { - const scriptResult = await vm.run(` - new Promise((resolve, reject) => { - scriptTimeout(reject); - try { - resolve(script[method](params)) - } catch(e) { - reject(e); - } - }).catch((error) => { throw new Error(error); }); - `); - - resolve(scriptResult); - } catch (e) { - reject(e); - } - }); - }); - - outgoingLogger.debug({ - msg: `Script method "${method}" result of the Integration "${integration.name}" is:`, - result, - }); - - return result; - } catch (err) { - await this.updateHistory({ - historyId, - step: `execute-script-error-running-${method}`, - error: true, - errorStack: err.stack.replace(/^/gm, ' '), - }); - outgoingLogger.error({ - msg: 'Error running Script in the Integration', - integration: integration.name, - err, - }); - outgoingLogger.debug({ - msg: 'Error running Script in the Integration', - integration: integration.name, - script: integration.scriptCompiled, - }); // Only output the compiled script if debugging is enabled, so the logs don't get spammed. - } - } - eventNameArgumentsToObject(...args) { const argObject = { event: args[0], @@ -680,6 +378,17 @@ class RocketChatIntegrationHandler { } } + // Ensure that any errors thrown by the script engine will contibue to be compatible with Meteor.Error + async wrapScriptEngineCall(getter) { + return wrapExceptions(getter).catch((error) => { + if (error instanceof Error) { + throw new Meteor.Error(error.message); + } + + throw error; + }); + } + async executeTriggerUrl(url, trigger, { event, message, room, owner, user }, theHistoryId, tries = 0) { if (!this.isTriggerEnabled(trigger)) { outgoingLogger.warn(`The trigger "${trigger.name}" is no longer enabled, stopping execution of it at try: ${tries}`); @@ -715,7 +424,7 @@ class RocketChatIntegrationHandler { return; } - const historyId = await this.updateHistory({ + const historyId = await updateHistory({ step: 'start-execute-trigger-url', integration: trigger, event, @@ -731,36 +440,32 @@ class RocketChatIntegrationHandler { } this.mapEventArgsToData(data, { trigger, event, message, room, owner, user }); - await this.updateHistory({ historyId, step: 'mapped-args-to-data', data, triggerWord: word }); + await updateHistory({ historyId, step: 'mapped-args-to-data', data, triggerWord: word }); outgoingLogger.info(`Will be executing the Integration "${trigger.name}" to the url: ${url}`); outgoingLogger.debug({ data }); - let opts = { - params: {}, - method: 'POST', - url, - data, - auth: undefined, - headers: { - 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2227.0 Safari/537.36', - }, - }; + const scriptEngine = this.getEngine(trigger); - if (this.hasScriptAndMethod(trigger, 'prepare_outgoing_request')) { - opts = await this.executeScript(trigger, 'prepare_outgoing_request', { request: opts }, historyId); - } + const opts = await this.wrapScriptEngineCall(() => + scriptEngine.prepareOutgoingRequest({ + integration: trigger, + data, + url, + historyId, + }), + ); - await this.updateHistory({ historyId, step: 'after-maybe-ran-prepare', ranPrepareScript: true }); + await updateHistory({ historyId, step: 'after-maybe-ran-prepare', ranPrepareScript: true }); if (!opts) { - await this.updateHistory({ historyId, step: 'after-prepare-no-opts', finished: true }); + await updateHistory({ historyId, step: 'after-prepare-no-opts', finished: true }); return; } if (opts.message) { const prepareMessage = await this.sendMessage({ trigger, room, message: opts.message, data }); - await this.updateHistory({ + await updateHistory({ historyId, step: 'after-prepare-send-message', prepareSentMessage: prepareMessage, @@ -768,7 +473,7 @@ class RocketChatIntegrationHandler { } if (!opts.url || !opts.method) { - await this.updateHistory({ historyId, step: 'after-prepare-no-url_or_method', finished: true }); + await updateHistory({ historyId, step: 'after-prepare-no-url_or_method', finished: true }); return; } @@ -782,7 +487,7 @@ class RocketChatIntegrationHandler { opts.headers.Authorization = `Basic ${base64}`; } - await this.updateHistory({ + await updateHistory({ historyId, step: 'pre-http-call', url: opts.url, @@ -823,47 +528,42 @@ class RocketChatIntegrationHandler { } })(); - await this.updateHistory({ + await updateHistory({ historyId, step: 'after-http-call', httpError: null, httpResult: content, }); - if (this.hasScriptAndMethod(trigger, 'process_outgoing_response')) { - const sandbox = { + const responseContent = await this.wrapScriptEngineCall(() => + scriptEngine.processOutgoingResponse({ + integration: trigger, request: opts, - response: { - error: null, - status_code: res.status, // These values will be undefined to close issues #4175, #5762, and #5896 - content, - content_raw: content, - headers: Object.fromEntries(res.headers), - }, - }; - - const scriptResult = await this.executeScript(trigger, 'process_outgoing_response', sandbox, historyId); - - if (scriptResult && scriptResult.content) { - const resultMessage = await this.sendMessage({ - trigger, - room, - message: scriptResult.content, - data, - }); - await this.updateHistory({ - historyId, - step: 'after-process-send-message', - processSentMessage: resultMessage, - finished: true, - }); - return; - } + response: res, + content, + historyId, + }), + ); + + if (responseContent) { + const resultMessage = await this.sendMessage({ + trigger, + room, + message: responseContent, + data, + }); + await updateHistory({ + historyId, + step: 'after-process-send-message', + processSentMessage: resultMessage, + finished: true, + }); + return; + } - if (scriptResult === false) { - await this.updateHistory({ historyId, step: 'after-process-false-result', finished: true }); - return; - } + if (responseContent === false) { + await updateHistory({ historyId, step: 'after-process-false-result', finished: true }); + return; } // if the result contained nothing or wasn't a successful statusCode @@ -875,14 +575,14 @@ class RocketChatIntegrationHandler { }); if (res.status === 410) { - await this.updateHistory({ historyId, step: 'after-process-http-status-410', error: true }); + await updateHistory({ historyId, step: 'after-process-http-status-410', error: true }); outgoingLogger.error(`Disabling the Integration "${trigger.name}" because the status code was 401 (Gone).`); await Integrations.updateOne({ _id: trigger._id }, { $set: { enabled: false } }); return; } if (res.status === 500) { - await this.updateHistory({ historyId, step: 'after-process-http-status-500', error: true }); + await updateHistory({ historyId, step: 'after-process-http-status-500', error: true }); outgoingLogger.error({ msg: `Error "500" for the Integration "${trigger.name}" to ${url}.`, content, @@ -893,7 +593,7 @@ class RocketChatIntegrationHandler { if (trigger.retryFailedCalls) { if (tries < trigger.retryCount && trigger.retryDelay) { - await this.updateHistory({ historyId, error: true, step: `going-to-retry-${tries + 1}` }); + await updateHistory({ historyId, error: true, step: `going-to-retry-${tries + 1}` }); let waitTime; @@ -912,7 +612,7 @@ class RocketChatIntegrationHandler { break; default: const er = new Error("The integration's retryDelay setting is invalid."); - await this.updateHistory({ + await updateHistory({ historyId, step: 'failed-and-retry-delay-is-invalid', error: true, @@ -926,10 +626,10 @@ class RocketChatIntegrationHandler { void this.executeTriggerUrl(url, trigger, { event, message, room, owner, user }, historyId, tries + 1); }, waitTime); } else { - await this.updateHistory({ historyId, step: 'too-many-retries', error: true }); + await updateHistory({ historyId, step: 'too-many-retries', error: true }); } } else { - await this.updateHistory({ + await updateHistory({ historyId, step: 'failed-and-not-configured-to-retry', error: true, @@ -943,7 +643,7 @@ class RocketChatIntegrationHandler { if (content && this.successResults.includes(res.status)) { if (data?.text || data?.attachments) { const resultMsg = await this.sendMessage({ trigger, room, message: data, data }); - await this.updateHistory({ + await updateHistory({ historyId, step: 'url-response-sent-message', resultMessage: resultMsg, @@ -954,7 +654,7 @@ class RocketChatIntegrationHandler { }) .catch(async (error) => { outgoingLogger.error(error); - await this.updateHistory({ + await updateHistory({ historyId, step: 'after-http-call', httpError: error, diff --git a/apps/meteor/app/integrations/server/lib/updateHistory.ts b/apps/meteor/app/integrations/server/lib/updateHistory.ts new file mode 100644 index 000000000000..9f7a3017108d --- /dev/null +++ b/apps/meteor/app/integrations/server/lib/updateHistory.ts @@ -0,0 +1,96 @@ +import type { IIntegrationHistory, IIntegration, IMessage, AtLeast } from '@rocket.chat/core-typings'; +import { IntegrationHistory } from '@rocket.chat/models'; +import { Random } from '@rocket.chat/random'; + +import { omit } from '../../../../lib/utils/omit'; + +export const updateHistory = async ({ + historyId, + step, + integration, + event, + data, + triggerWord, + ranPrepareScript, + prepareSentMessage, + processSentMessage, + resultMessage, + finished, + url, + httpCallData, + httpError, + httpResult, + error, + errorStack, +}: { + historyId: IIntegrationHistory['_id']; + step: IIntegrationHistory['step']; + integration?: IIntegration; + event?: string; + triggerWord?: string; + ranPrepareScript?: boolean; + prepareSentMessage?: { channel: string; message: Partial }[]; + processSentMessage?: { channel: string; message: Partial }[]; + resultMessage?: { channel: string; message: Partial }[]; + finished?: boolean; + url?: string; + httpCallData?: Record; // ProcessedOutgoingRequest.data + httpError?: any; // null or whatever error type `fetch` may throw + httpResult?: string | null; + + error?: boolean; + errorStack?: any; // Error | Error['stack'] + + data?: Record; +}) => { + const { user: userData, room: roomData, ...fullData } = data || {}; + + const history: AtLeast = { + type: 'outgoing-webhook', + step, + + // Usually is only added on initial insert + ...(integration ? { integration } : {}), + // Usually is only added on initial insert + ...(event ? { event } : {}), + ...(fullData + ? { + data: { + ...fullData, + ...(userData ? { user: omit(userData, 'services') } : {}), + ...(roomData ? { room: roomData } : {}), + }, + } + : {}), + ...(triggerWord ? { triggerWord } : {}), + ...(typeof ranPrepareScript !== 'undefined' ? { ranPrepareScript } : {}), + ...(prepareSentMessage ? { prepareSentMessage } : {}), + ...(processSentMessage ? { processSentMessage } : {}), + ...(resultMessage ? { resultMessage } : {}), + ...(typeof finished !== 'undefined' ? { finished } : {}), + ...(url ? { url } : {}), + ...(typeof httpCallData !== 'undefined' ? { httpCallData } : {}), + ...(httpError ? { httpError } : {}), + ...(typeof httpResult !== 'undefined' ? { httpResult: JSON.stringify(httpResult, null, 2) } : {}), + ...(typeof error !== 'undefined' ? { error } : {}), + ...(typeof errorStack !== 'undefined' ? { errorStack } : {}), + }; + + if (historyId) { + await IntegrationHistory.updateOne({ _id: historyId }, { $set: history }); + return historyId; + } + + // Can't create a new history without there being an integration + if (!history.integration) { + throw new Error('error-invalid-integration'); + } + + history._createdAt = new Date(); + + const _id = Random.id(); + + await IntegrationHistory.insertOne({ _id, ...history } as IIntegrationHistory); + + return _id; +}; diff --git a/apps/meteor/app/integrations/server/lib/validateOutgoingIntegration.ts b/apps/meteor/app/integrations/server/lib/validateOutgoingIntegration.ts index d9c2db78b62e..398f81161279 100644 --- a/apps/meteor/app/integrations/server/lib/validateOutgoingIntegration.ts +++ b/apps/meteor/app/integrations/server/lib/validateOutgoingIntegration.ts @@ -1,19 +1,18 @@ import type { IUser, INewOutgoingIntegration, IOutgoingIntegration, IUpdateOutgoingIntegration } from '@rocket.chat/core-typings'; import { Subscriptions, Users, Rooms } from '@rocket.chat/models'; +import { pick } from '@rocket.chat/tools'; import { Babel } from 'meteor/babel-compiler'; import { Match } from 'meteor/check'; import { Meteor } from 'meteor/meteor'; -import _ from 'underscore'; import { parseCSV } from '../../../../lib/utils/parseCSV'; import { hasPermissionAsync, hasAllPermissionAsync } from '../../../authorization/server/functions/hasPermission'; import { outgoingEvents } from '../../lib/outgoingEvents'; +import { isScriptEngineFrozen } from './validateScriptEngine'; const scopedChannels = ['all_public_channels', 'all_private_groups', 'all_direct_messages']; const validChannelChars = ['@', '#']; -const FREEZE_INTEGRATION_SCRIPTS = ['yes', 'true'].includes(String(process.env.FREEZE_INTEGRATION_SCRIPTS).toLowerCase()); - function _verifyRequiredFields(integration: INewOutgoingIntegration | IUpdateOutgoingIntegration): void { if ( !integration.event || @@ -152,6 +151,7 @@ export const validateOutgoingIntegration = async function ( const integrationData: IOutgoingIntegration = { ...integration, + scriptEngine: integration.scriptEngine ?? 'isolated-vm', type: 'webhook-outgoing', channel: channels, userId: user._id, @@ -171,7 +171,13 @@ export const validateOutgoingIntegration = async function ( delete integrationData.triggerWords; } - if (!FREEZE_INTEGRATION_SCRIPTS && integration.scriptEnabled === true && integration.script && integration.script.trim() !== '') { + // Only compile the script if it is enabled and using a sandbox that is not frozen + if ( + !isScriptEngineFrozen(integrationData.scriptEngine) && + integration.scriptEnabled === true && + integration.script && + integration.script.trim() !== '' + ) { try { const babelOptions = Object.assign(Babel.getDefaultOptions({ runtime: false }), { compact: true, @@ -183,7 +189,7 @@ export const validateOutgoingIntegration = async function ( integrationData.scriptError = undefined; } catch (e) { integrationData.scriptCompiled = undefined; - integrationData.scriptError = e instanceof Error ? _.pick(e, 'name', 'message', 'stack') : undefined; + integrationData.scriptError = e instanceof Error ? pick(e, 'name', 'message', 'stack') : undefined; } } diff --git a/apps/meteor/app/integrations/server/lib/validateScriptEngine.ts b/apps/meteor/app/integrations/server/lib/validateScriptEngine.ts new file mode 100644 index 000000000000..c20dc9c59427 --- /dev/null +++ b/apps/meteor/app/integrations/server/lib/validateScriptEngine.ts @@ -0,0 +1,26 @@ +import type { IntegrationScriptEngine } from '@rocket.chat/core-typings'; +import { wrapExceptions } from '@rocket.chat/tools'; + +const FREEZE_INTEGRATION_SCRIPTS_VALUE = String(process.env.FREEZE_INTEGRATION_SCRIPTS).toLowerCase(); +const FREEZE_INTEGRATION_SCRIPTS = ['yes', 'true'].includes(FREEZE_INTEGRATION_SCRIPTS_VALUE); + +export const validateScriptEngine = (engine?: IntegrationScriptEngine) => { + if (FREEZE_INTEGRATION_SCRIPTS) { + throw new Error('integration-scripts-disabled'); + } + + const engineCode = engine === 'isolated-vm' ? 'ivm' : 'vm2'; + + if (engineCode === FREEZE_INTEGRATION_SCRIPTS_VALUE) { + if (engineCode === 'ivm') { + throw new Error('integration-scripts-isolated-vm-disabled'); + } + + throw new Error('integration-scripts-vm2-disabled'); + } + + return true; +}; + +export const isScriptEngineFrozen = (engine?: IntegrationScriptEngine) => + wrapExceptions(() => !validateScriptEngine(engine)).catch(() => true); diff --git a/apps/meteor/app/integrations/server/lib/vm2/buildSandbox.ts b/apps/meteor/app/integrations/server/lib/vm2/buildSandbox.ts new file mode 100644 index 000000000000..9ba74404cf26 --- /dev/null +++ b/apps/meteor/app/integrations/server/lib/vm2/buildSandbox.ts @@ -0,0 +1,88 @@ +import * as Models from '@rocket.chat/models'; +import moment from 'moment'; +import _ from 'underscore'; + +import * as s from '../../../../../lib/utils/stringUtils'; +import { deasyncPromise } from '../../../../../server/deasync/deasync'; +import { httpCall } from '../../../../../server/lib/http/call'; + +const forbiddenModelMethods: readonly (keyof typeof Models)[] = ['registerModel', 'getCollectionName']; + +type ModelName = Exclude; + +export type Vm2Sandbox = { + scriptTimeout: (reject: (reason?: any) => void) => ReturnType; + _: typeof _; + s: typeof s; + console: typeof console; + moment: typeof moment; + Promise: typeof Promise; + Store: { + set: IsIncoming extends true ? (key: string, value: any) => any : (key: string, value: any) => void; + get: (key: string) => any; + }; + HTTP: (method: string, url: string, options: Record) => unknown; +} & (IsIncoming extends true ? { Livechat: undefined } : never) & + Record; + +export const buildSandbox = ( + store: Record, + isIncoming?: IsIncoming, +): { + store: Record; + sandbox: Vm2Sandbox; +} => { + const httpAsync = async (method: string, url: string, options: Record) => { + try { + return { + result: await httpCall(method, url, options), + }; + } catch (error) { + return { error }; + } + }; + + const sandbox = { + scriptTimeout(reject: (reason?: any) => void) { + return setTimeout(() => reject('timed out'), 3000); + }, + _, + s, + console, + moment, + Promise, + // There's a small difference between the sandbox that is sent to incoming and to outgoing scripts + // Technically we could unify this but since we're deprecating vm2 anyway I'm keeping this old behavior here until the feature is removed completely + ...(isIncoming + ? { + Livechat: undefined, + Store: { + set: (key: string, val: any): any => { + store[key] = val; + return val; + }, + get: (key: string) => store[key], + }, + } + : { + Store: { + set: (key: string, val: any): void => { + store[key] = val; + }, + get: (key: string) => store[key], + }, + }), + HTTP: (method: string, url: string, options: Record) => { + // TODO: deprecate, track and alert + return deasyncPromise(httpAsync(method, url, options)); + }, + } as Vm2Sandbox; + + (Object.keys(Models) as ModelName[]) + .filter((k) => !forbiddenModelMethods.includes(k)) + .forEach((k) => { + sandbox[k] = Models[k]; + }); + + return { store, sandbox }; +}; diff --git a/apps/meteor/app/integrations/server/lib/vm2/vm2.ts b/apps/meteor/app/integrations/server/lib/vm2/vm2.ts new file mode 100644 index 000000000000..5f7519d69346 --- /dev/null +++ b/apps/meteor/app/integrations/server/lib/vm2/vm2.ts @@ -0,0 +1,111 @@ +import type { IIntegration } from '@rocket.chat/core-typings'; +import { VM, VMScript } from 'vm2'; + +import { IntegrationScriptEngine } from '../ScriptEngine'; +import type { IScriptClass } from '../definition'; +import { buildSandbox, type Vm2Sandbox } from './buildSandbox'; + +const DISABLE_INTEGRATION_SCRIPTS = ['yes', 'true', 'vm2'].includes(String(process.env.DISABLE_INTEGRATION_SCRIPTS).toLowerCase()); + +export class VM2ScriptEngine extends IntegrationScriptEngine { + protected isDisabled(): boolean { + return DISABLE_INTEGRATION_SCRIPTS; + } + + protected buildSandbox(store: Record = {}): { store: Record; sandbox: Vm2Sandbox } { + return buildSandbox(store, this.incoming); + } + + protected async runScriptMethod({ + integrationId, + script, + method, + params, + }: { + integrationId: IIntegration['_id']; + script: IScriptClass; + method: keyof IScriptClass; + params: Record; + }): Promise { + const { sandbox } = this.buildSandbox(this.compiledScripts[integrationId].store); + + const vm = new VM({ + timeout: 3000, + sandbox: { + ...sandbox, + script, + method, + params, + ...(this.incoming && 'request' in params ? { request: params.request } : {}), + }, + }); + + return new Promise((resolve, reject) => { + process.nextTick(async () => { + try { + const scriptResult = await vm.run(` + new Promise((resolve, reject) => { + scriptTimeout(reject); + try { + resolve(script[method](params)) + } catch(e) { + reject(e); + } + }).catch((error) => { throw new Error(error); }); + `); + + resolve(scriptResult); + } catch (e) { + reject(e); + } + }); + }); + } + + protected async getIntegrationScript(integration: IIntegration): Promise> { + if (this.disabled) { + throw new Error('integration-scripts-disabled'); + } + + const compiledScript = this.compiledScripts[integration._id]; + if (compiledScript && +compiledScript._updatedAt === +integration._updatedAt) { + return compiledScript.script; + } + + const script = integration.scriptCompiled; + const { store, sandbox } = this.buildSandbox(); + + try { + this.logger.info({ msg: 'Will evaluate script of Trigger', integration: integration.name }); + this.logger.debug(script); + + const vmScript = new VMScript(`${script}; Script;`, 'script.js'); + const vm = new VM({ + sandbox, + }); + + const ScriptClass = vm.run(vmScript); + + if (ScriptClass) { + this.compiledScripts[integration._id] = { + script: new ScriptClass(), + store, + _updatedAt: integration._updatedAt, + }; + + return this.compiledScripts[integration._id].script; + } + } catch (err) { + this.logger.error({ + msg: 'Error evaluating Script in Trigger', + integration: integration.name, + script, + err, + }); + throw new Error('error-evaluating-script'); + } + + this.logger.error({ msg: 'Class "Script" not in Trigger', integration: integration.name }); + throw new Error('class-script-not-found'); + } +} diff --git a/apps/meteor/app/integrations/server/methods/incoming/addIncomingIntegration.ts b/apps/meteor/app/integrations/server/methods/incoming/addIncomingIntegration.ts index bf84957ba8ea..45548a17a565 100644 --- a/apps/meteor/app/integrations/server/methods/incoming/addIncomingIntegration.ts +++ b/apps/meteor/app/integrations/server/methods/incoming/addIncomingIntegration.ts @@ -8,11 +8,10 @@ import { Meteor } from 'meteor/meteor'; import _ from 'underscore'; import { hasPermissionAsync, hasAllPermissionAsync } from '../../../../authorization/server/functions/hasPermission'; +import { validateScriptEngine, isScriptEngineFrozen } from '../../lib/validateScriptEngine'; const validChannelChars = ['@', '#']; -const FREEZE_INTEGRATION_SCRIPTS = ['yes', 'true'].includes(String(process.env.FREEZE_INTEGRATION_SCRIPTS).toLowerCase()); - declare module '@rocket.chat/ui-contexts' { // eslint-disable-next-line @typescript-eslint/naming-convention interface ServerMethods { @@ -32,6 +31,7 @@ export const addIncomingIntegration = async (userId: string, integration: INewIn alias: Match.Maybe(String), emoji: Match.Maybe(String), scriptEnabled: Boolean, + scriptEngine: Match.Maybe(String), overrideDestinationChannelEnabled: Match.Maybe(Boolean), script: Match.Maybe(String), avatar: Match.Maybe(String), @@ -76,8 +76,8 @@ export const addIncomingIntegration = async (userId: string, integration: INewIn }); } - if (FREEZE_INTEGRATION_SCRIPTS && integration.script?.trim()) { - throw new Meteor.Error('integration-scripts-disabled'); + if (integration.script?.trim()) { + validateScriptEngine(integration.scriptEngine ?? 'isolated-vm'); } const user = await Users.findOne({ username: integration.username }); @@ -90,6 +90,7 @@ export const addIncomingIntegration = async (userId: string, integration: INewIn const integrationData: IIncomingIntegration = { ...integration, + scriptEngine: integration.scriptEngine ?? 'isolated-vm', type: 'webhook-incoming', channel: channels, overrideDestinationChannelEnabled: integration.overrideDestinationChannelEnabled ?? false, @@ -99,7 +100,13 @@ export const addIncomingIntegration = async (userId: string, integration: INewIn _createdBy: await Users.findOne({ _id: userId }, { projection: { username: 1 } }), }; - if (integration.scriptEnabled === true && integration.script && integration.script.trim() !== '') { + // Only compile the script if it is enabled and using a sandbox that is not frozen + if ( + !isScriptEngineFrozen(integrationData.scriptEngine) && + integration.scriptEnabled === true && + integration.script && + integration.script.trim() !== '' + ) { try { let babelOptions = Babel.getDefaultOptions({ runtime: false }); babelOptions = _.extend(babelOptions, { compact: true, minified: true, comments: false }); diff --git a/apps/meteor/app/integrations/server/methods/incoming/updateIncomingIntegration.ts b/apps/meteor/app/integrations/server/methods/incoming/updateIncomingIntegration.ts index b865c72e0cca..5358e3233ce7 100644 --- a/apps/meteor/app/integrations/server/methods/incoming/updateIncomingIntegration.ts +++ b/apps/meteor/app/integrations/server/methods/incoming/updateIncomingIntegration.ts @@ -1,16 +1,16 @@ import type { IIntegration, INewIncomingIntegration, IUpdateIncomingIntegration } from '@rocket.chat/core-typings'; import { Integrations, Roles, Subscriptions, Users, Rooms } from '@rocket.chat/models'; +import { wrapExceptions } from '@rocket.chat/tools'; import type { ServerMethods } from '@rocket.chat/ui-contexts'; import { Babel } from 'meteor/babel-compiler'; import { Meteor } from 'meteor/meteor'; import _ from 'underscore'; import { hasAllPermissionAsync, hasPermissionAsync } from '../../../../authorization/server/functions/hasPermission'; +import { isScriptEngineFrozen, validateScriptEngine } from '../../lib/validateScriptEngine'; const validChannelChars = ['@', '#']; -const FREEZE_INTEGRATION_SCRIPTS = ['yes', 'true'].includes(String(process.env.FREEZE_INTEGRATION_SCRIPTS).toLowerCase()); - declare module '@rocket.chat/ui-contexts' { // eslint-disable-next-line @typescript-eslint/naming-convention interface ServerMethods { @@ -66,11 +66,20 @@ Meteor.methods({ }); } - if (FREEZE_INTEGRATION_SCRIPTS) { - if (currentIntegration.script?.trim() !== integration.script?.trim()) { - throw new Meteor.Error('integration-scripts-disabled'); - } - } else { + const oldScriptEngine = currentIntegration.scriptEngine ?? 'vm2'; + const scriptEngine = integration.scriptEngine ?? oldScriptEngine; + if ( + integration.script?.trim() && + (scriptEngine !== oldScriptEngine || integration.script?.trim() !== currentIntegration.script?.trim()) + ) { + wrapExceptions(() => validateScriptEngine(scriptEngine)).catch((e) => { + throw new Meteor.Error(e.message); + }); + } + + const isFrozen = isScriptEngineFrozen(scriptEngine); + + if (!isFrozen) { let scriptCompiled: string | undefined; let scriptError: Pick | undefined; @@ -165,11 +174,12 @@ Meteor.methods({ emoji: integration.emoji, alias: integration.alias, channel: channels, - ...(FREEZE_INTEGRATION_SCRIPTS + ...(isFrozen ? {} : { script: integration.script, scriptEnabled: integration.scriptEnabled, + scriptEngine, }), ...(typeof integration.overrideDestinationChannelEnabled !== 'undefined' && { overrideDestinationChannelEnabled: integration.overrideDestinationChannelEnabled, diff --git a/apps/meteor/app/integrations/server/methods/outgoing/addOutgoingIntegration.ts b/apps/meteor/app/integrations/server/methods/outgoing/addOutgoingIntegration.ts index 9e5d29261b36..59879f99d475 100644 --- a/apps/meteor/app/integrations/server/methods/outgoing/addOutgoingIntegration.ts +++ b/apps/meteor/app/integrations/server/methods/outgoing/addOutgoingIntegration.ts @@ -6,6 +6,7 @@ import { Meteor } from 'meteor/meteor'; import { hasPermissionAsync } from '../../../../authorization/server/functions/hasPermission'; import { validateOutgoingIntegration } from '../../lib/validateOutgoingIntegration'; +import { validateScriptEngine } from '../../lib/validateScriptEngine'; declare module '@rocket.chat/ui-contexts' { // eslint-disable-next-line @typescript-eslint/naming-convention @@ -14,8 +15,6 @@ declare module '@rocket.chat/ui-contexts' { } } -const FREEZE_INTEGRATION_SCRIPTS = ['yes', 'true'].includes(String(process.env.FREEZE_INTEGRATION_SCRIPTS).toLowerCase()); - export const addOutgoingIntegration = async (userId: string, integration: INewOutgoingIntegration): Promise => { check( integration, @@ -29,6 +28,7 @@ export const addOutgoingIntegration = async (userId: string, integration: INewOu emoji: Match.Maybe(String), scriptEnabled: Boolean, script: Match.Maybe(String), + scriptEngine: Match.Maybe(String), urls: Match.Maybe([String]), event: Match.Maybe(String), triggerWords: Match.Maybe([String]), @@ -52,8 +52,8 @@ export const addOutgoingIntegration = async (userId: string, integration: INewOu throw new Meteor.Error('not_authorized'); } - if (FREEZE_INTEGRATION_SCRIPTS && integration.script?.trim()) { - throw new Meteor.Error('integration-scripts-disabled'); + if (integration.script?.trim()) { + validateScriptEngine(integration.scriptEngine ?? 'isolated-vm'); } const integrationData = await validateOutgoingIntegration(integration, userId); diff --git a/apps/meteor/app/integrations/server/methods/outgoing/updateOutgoingIntegration.ts b/apps/meteor/app/integrations/server/methods/outgoing/updateOutgoingIntegration.ts index 166badee823d..9e62561ebf9a 100644 --- a/apps/meteor/app/integrations/server/methods/outgoing/updateOutgoingIntegration.ts +++ b/apps/meteor/app/integrations/server/methods/outgoing/updateOutgoingIntegration.ts @@ -1,10 +1,12 @@ import type { IIntegration, INewOutgoingIntegration, IUpdateOutgoingIntegration } from '@rocket.chat/core-typings'; import { Integrations, Users } from '@rocket.chat/models'; +import { wrapExceptions } from '@rocket.chat/tools'; import type { ServerMethods } from '@rocket.chat/ui-contexts'; import { Meteor } from 'meteor/meteor'; import { hasPermissionAsync } from '../../../../authorization/server/functions/hasPermission'; import { validateOutgoingIntegration } from '../../lib/validateOutgoingIntegration'; +import { isScriptEngineFrozen, validateScriptEngine } from '../../lib/validateScriptEngine'; declare module '@rocket.chat/ui-contexts' { // eslint-disable-next-line @typescript-eslint/naming-convention @@ -16,8 +18,6 @@ declare module '@rocket.chat/ui-contexts' { } } -const FREEZE_INTEGRATION_SCRIPTS = ['yes', 'true'].includes(String(process.env.FREEZE_INTEGRATION_SCRIPTS).toLowerCase()); - Meteor.methods({ async updateOutgoingIntegration(integrationId, _integration) { if (!this.userId) { @@ -53,10 +53,19 @@ Meteor.methods({ throw new Meteor.Error('invalid_integration', '[methods] updateOutgoingIntegration -> integration not found'); } - if (FREEZE_INTEGRATION_SCRIPTS && integration.script?.trim() !== currentIntegration.script?.trim()) { - throw new Meteor.Error('integration-scripts-disabled'); + const oldScriptEngine = currentIntegration.scriptEngine ?? 'vm2'; + const scriptEngine = integration.scriptEngine ?? oldScriptEngine; + if ( + integration.script?.trim() && + (scriptEngine !== oldScriptEngine || integration.script?.trim() !== currentIntegration.script?.trim()) + ) { + wrapExceptions(() => validateScriptEngine(scriptEngine)).catch((e) => { + throw new Meteor.Error(e.message); + }); } + const isFrozen = isScriptEngineFrozen(scriptEngine); + await Integrations.updateOne( { _id: integrationId }, { @@ -74,11 +83,12 @@ Meteor.methods({ userId: integration.userId, urls: integration.urls, token: integration.token, - ...(FREEZE_INTEGRATION_SCRIPTS + ...(isFrozen ? {} : { script: integration.script, scriptEnabled: integration.scriptEnabled, + scriptEngine, ...(integration.scriptCompiled ? { scriptCompiled: integration.scriptCompiled } : { scriptError: integration.scriptError }), }), triggerWords: integration.triggerWords, @@ -90,7 +100,7 @@ Meteor.methods({ _updatedAt: new Date(), _updatedBy: await Users.findOne({ _id: this.userId }, { projection: { username: 1 } }), }, - ...(FREEZE_INTEGRATION_SCRIPTS + ...(isFrozen ? {} : { $unset: { diff --git a/apps/meteor/app/lib/server/functions/notifications/index.ts b/apps/meteor/app/lib/server/functions/notifications/index.ts index 934014b794a1..11e4418c4510 100644 --- a/apps/meteor/app/lib/server/functions/notifications/index.ts +++ b/apps/meteor/app/lib/server/functions/notifications/index.ts @@ -5,7 +5,6 @@ import { escapeRegExp } from '@rocket.chat/string-helpers'; import { callbacks } from '../../../../../lib/callbacks'; import { i18n } from '../../../../../server/lib/i18n'; import { settings } from '../../../../settings/server'; -import { joinRoomMethod } from '../../methods/joinRoom'; /** * This function returns a string ready to be shown in the notification @@ -66,7 +65,3 @@ export function messageContainsHighlight(message: IMessage, highlights: string[] return regexp.test(message.msg); }); } - -export async function callJoinRoom(userId: string, rid: string): Promise { - await joinRoomMethod(userId, rid); -} diff --git a/apps/meteor/app/lib/server/functions/sendMessage.js b/apps/meteor/app/lib/server/functions/sendMessage.js index a1399b5b19e9..72247d4b1870 100644 --- a/apps/meteor/app/lib/server/functions/sendMessage.js +++ b/apps/meteor/app/lib/server/functions/sendMessage.js @@ -1,3 +1,4 @@ +import { Message } from '@rocket.chat/core-services'; import { Messages } from '@rocket.chat/models'; import { Match, check } from 'meteor/check'; @@ -247,6 +248,8 @@ export const sendMessage = async function (user, message, room, upsert = false, parseUrlsInMessage(message, previewUrls); + message = await Message.beforeSave({ message, room, user }); + message = await callbacks.run('beforeSaveMessage', message, room); if (message) { if (message.t === 'otr') { diff --git a/apps/meteor/app/lib/server/functions/updateMessage.ts b/apps/meteor/app/lib/server/functions/updateMessage.ts index 05c17906374e..9c544bd9a333 100644 --- a/apps/meteor/app/lib/server/functions/updateMessage.ts +++ b/apps/meteor/app/lib/server/functions/updateMessage.ts @@ -1,3 +1,4 @@ +import { Message } from '@rocket.chat/core-services'; import type { IEditedMessage, IMessage, IUser, AtLeast } from '@rocket.chat/core-typings'; import { Messages, Rooms } from '@rocket.chat/models'; import { Meteor } from 'meteor/meteor'; @@ -48,6 +49,14 @@ export const updateMessage = async function ( parseUrlsInMessage(message, previewUrls); + const room = await Rooms.findOneById(message.rid); + if (!room) { + return; + } + + // TODO remove type cast + message = await Message.beforeSave({ message: message as IMessage, room, user }); + message = await callbacks.run('beforeSaveMessage', message); const { _id, ...editedMessage } = message; @@ -67,12 +76,6 @@ export const updateMessage = async function ( }, ); - const room = await Rooms.findOneById(message.rid); - - if (!room) { - return; - } - if (Apps?.isLoaded()) { // This returns a promise, but it won't mutate anything about the message // so, we don't really care if it is successful or fails diff --git a/apps/meteor/app/lib/server/index.ts b/apps/meteor/app/lib/server/index.ts index 597d03752dcc..8fa779ec9644 100644 --- a/apps/meteor/app/lib/server/index.ts +++ b/apps/meteor/app/lib/server/index.ts @@ -23,7 +23,6 @@ import './methods/deleteUserOwnAccount'; import './methods/executeSlashCommandPreview'; import './startup/filterATAllTag'; import './startup/filterATHereTag'; -import './methods/filterBadWords'; import './methods/getChannelHistory'; import './methods/getRoomJoinCode'; import './methods/getRoomRoles'; diff --git a/apps/meteor/app/lib/server/lib/sendNotificationsOnMessage.js b/apps/meteor/app/lib/server/lib/sendNotificationsOnMessage.js index 17296d8f374a..ce262e4e6756 100644 --- a/apps/meteor/app/lib/server/lib/sendNotificationsOnMessage.js +++ b/apps/meteor/app/lib/server/lib/sendNotificationsOnMessage.js @@ -1,3 +1,4 @@ +import { Room } from '@rocket.chat/core-services'; import { Subscriptions, Users } from '@rocket.chat/models'; import { Meteor } from 'meteor/meteor'; import moment from 'moment'; @@ -7,12 +8,7 @@ import { roomCoordinator } from '../../../../server/lib/rooms/roomCoordinator'; import { hasPermissionAsync } from '../../../authorization/server/functions/hasPermission'; import { Notification } from '../../../notification-queue/server/NotificationQueue'; import { settings } from '../../../settings/server'; -import { - callJoinRoom, - messageContainsHighlight, - parseMessageTextPerUser, - replaceMentionedUsernamesWithFullNames, -} from '../functions/notifications'; +import { messageContainsHighlight, parseMessageTextPerUser, replaceMentionedUsernamesWithFullNames } from '../functions/notifications'; import { notifyDesktopUser, shouldNotifyDesktop } from '../functions/notifications/desktop'; import { getEmailData, shouldNotifyEmail } from '../functions/notifications/email'; import { getPushData, shouldNotifyMobile } from '../functions/notifications/mobile'; @@ -365,7 +361,7 @@ export async function sendAllNotifications(message, room) { const users = await Promise.all( mentions.map(async (userId) => { - await callJoinRoom(userId, room._id); + await Room.join({ room, user: { _id: userId } }); return userId; }), diff --git a/apps/meteor/app/lib/server/methods/filterBadWords.ts b/apps/meteor/app/lib/server/methods/filterBadWords.ts deleted file mode 100644 index 3db0ee76e997..000000000000 --- a/apps/meteor/app/lib/server/methods/filterBadWords.ts +++ /dev/null @@ -1,65 +0,0 @@ -import type { IMessage } from '@rocket.chat/core-typings'; -import Filter from 'bad-words'; -import { Meteor } from 'meteor/meteor'; -import { Tracker } from 'meteor/tracker'; - -import { callbacks } from '../../../../lib/callbacks'; -import { settings } from '../../../settings/server'; - -const Dep = new Tracker.Dependency(); -Meteor.startup(() => { - settings.watchMultiple(['Message_AllowBadWordsFilter', 'Message_BadWordsFilterList', 'Message_BadWordsWhitelist'], () => { - Dep.changed(); - }); - Tracker.autorun(() => { - Dep.depend(); - const allowBadWordsFilter = settings.get('Message_AllowBadWordsFilter'); - - callbacks.remove('beforeSaveMessage', 'filterBadWords'); - - if (!allowBadWordsFilter) { - return; - } - - const badWordsList = settings.get('Message_BadWordsFilterList') as string | undefined; - const whiteList = settings.get('Message_BadWordsWhitelist') as string | undefined; - - const options = { - list: - badWordsList - ?.split(',') - .map((word) => word.trim()) - .filter(Boolean) || [], - // library definition does not allow optional definition - exclude: undefined, - splitRegex: undefined, - placeHolder: undefined, - regex: undefined, - replaceRegex: undefined, - emptyList: undefined, - }; - - const filter = new Filter(options); - - if (whiteList?.length) { - filter.removeWords(...whiteList.split(',').map((word) => word.trim())); - } - - callbacks.add( - 'beforeSaveMessage', - (message: IMessage) => { - if (!message.msg) { - return message; - } - try { - message.msg = filter.clean(message.msg); - } finally { - // eslint-disable-next-line no-unsafe-finally - return message; - } - }, - callbacks.priority.HIGH, - 'filterBadWords', - ); - }); -}); diff --git a/apps/meteor/app/lib/server/methods/joinRoom.ts b/apps/meteor/app/lib/server/methods/joinRoom.ts index 355fd49916ae..0fa3ac0b3c3b 100644 --- a/apps/meteor/app/lib/server/methods/joinRoom.ts +++ b/apps/meteor/app/lib/server/methods/joinRoom.ts @@ -1,63 +1,31 @@ -import type { IRoom, IRoomWithJoinCode, IUser } from '@rocket.chat/core-typings'; -import { Rooms, Users } from '@rocket.chat/models'; +import { Room } from '@rocket.chat/core-services'; +import type { IRoom } from '@rocket.chat/core-typings'; +import { Rooms } from '@rocket.chat/models'; import type { ServerMethods } from '@rocket.chat/ui-contexts'; import { check } from 'meteor/check'; import { Meteor } from 'meteor/meteor'; -import { RoomMemberActions } from '../../../../definition/IRoomTypeConfig'; -import { roomCoordinator } from '../../../../server/lib/rooms/roomCoordinator'; -import { canAccessRoomAsync } from '../../../authorization/server'; -import { hasPermissionAsync } from '../../../authorization/server/functions/hasPermission'; -import { addUserToRoom } from '../functions/addUserToRoom'; - declare module '@rocket.chat/ui-contexts' { // eslint-disable-next-line @typescript-eslint/naming-convention interface ServerMethods { - joinRoom(rid: IRoom['_id'], code?: unknown): boolean | undefined; + joinRoom(rid: IRoom['_id'], code?: string): boolean | undefined; } } -export const joinRoomMethod = async (userId: IUser['_id'], rid: IRoom['_id'], code?: unknown): Promise => { - check(rid, String); - - const user = await Users.findOneById(userId); - - if (!user) { - throw new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'joinRoom' }); - } - - const room = await Rooms.findOneById(rid); - - if (!room) { - throw new Meteor.Error('error-invalid-room', 'Invalid room', { method: 'joinRoom' }); - } - - if (!(await roomCoordinator.getRoomDirectives(room.t)?.allowMemberAction(room, RoomMemberActions.JOIN, user._id))) { - throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'joinRoom' }); - } - - if (!(await canAccessRoomAsync(room, user))) { - throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'joinRoom' }); - } - if (room.joinCodeRequired === true && code !== room.joinCode && !(await hasPermissionAsync(user._id, 'join-without-join-code'))) { - throw new Meteor.Error('error-code-invalid', 'Invalid Room Password', { - method: 'joinRoom', - }); - } - - return addUserToRoom(rid, user); -}; - Meteor.methods({ async joinRoom(rid, code) { check(rid, String); const userId = await Meteor.userId(); - if (!userId) { throw new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'joinRoom' }); } - return joinRoomMethod(userId, rid, code); + const room = await Rooms.findOneById(rid); + if (!room) { + throw new Meteor.Error('error-invalid-room', 'Invalid room', { method: 'joinRoom' }); + } + + return Room.join({ room, user: { _id: userId }, ...(code ? { joinCode: code } : {}) }); }, }); diff --git a/apps/meteor/app/message-pin/server/pinMessage.ts b/apps/meteor/app/message-pin/server/pinMessage.ts index a36883abb0a5..906f0c98c181 100644 --- a/apps/meteor/app/message-pin/server/pinMessage.ts +++ b/apps/meteor/app/message-pin/server/pinMessage.ts @@ -1,6 +1,6 @@ import { Message } from '@rocket.chat/core-services'; -import { isQuoteAttachment } from '@rocket.chat/core-typings'; -import type { IMessage, IUser, MessageAttachment, MessageQuoteAttachment } from '@rocket.chat/core-typings'; +import { isQuoteAttachment, isRegisterUser } from '@rocket.chat/core-typings'; +import type { IMessage, MessageAttachment, MessageQuoteAttachment } from '@rocket.chat/core-typings'; import { Messages, Rooms, Subscriptions, Users, ReadReceipts } from '@rocket.chat/models'; import type { ServerMethods } from '@rocket.chat/ui-contexts'; import { check } from 'meteor/check'; @@ -82,15 +82,13 @@ Meteor.methods({ throw new Meteor.Error('not-authorized', 'Not Authorized', { method: 'pinMessage' }); } - const me = await Users.findOneById>>(userId, { - projection: { username: 1, name: 1 }, - }); + const me = await Users.findOneById(userId); if (!me) { throw new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'pinMessage' }); } // If we keep history of edits, insert a new message to store history information - if (settings.get('Message_KeepHistory') && me.username) { + if (settings.get('Message_KeepHistory') && isRegisterUser(me)) { await Messages.cloneAndSaveAsHistoryById(message._id, me); } @@ -110,6 +108,8 @@ Meteor.methods({ username: me.username, }; + originalMessage = await Message.beforeSave({ message: originalMessage, room, user: me }); + originalMessage = await callbacks.run('beforeSaveMessage', originalMessage); await Messages.setPinnedByIdAndUserId(originalMessage._id, originalMessage.pinnedBy, originalMessage.pinned); @@ -186,15 +186,13 @@ Meteor.methods({ throw new Meteor.Error('not-authorized', 'Not Authorized', { method: 'unpinMessage' }); } - const me = await Users.findOneById>>(userId, { - projection: { username: 1, name: 1 }, - }); + const me = await Users.findOneById(userId); if (!me) { throw new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'unpinMessage' }); } // If we keep history of edits, insert a new message to store history information - if (settings.get('Message_KeepHistory') && me.username) { + if (settings.get('Message_KeepHistory') && isRegisterUser(me)) { await Messages.cloneAndSaveAsHistoryById(originalMessage._id, me); } @@ -203,7 +201,6 @@ Meteor.methods({ _id: userId, username: me.username, }; - originalMessage = await callbacks.run('beforeSaveMessage', originalMessage); const room = await Rooms.findOneById(originalMessage.rid, { projection: { ...roomAccessAttributes, lastMessage: 1 } }); if (!room) { @@ -214,6 +211,10 @@ Meteor.methods({ throw new Meteor.Error('not-authorized', 'Not Authorized', { method: 'unpinMessage' }); } + originalMessage = await Message.beforeSave({ message: originalMessage, room, user: me }); + + originalMessage = await callbacks.run('beforeSaveMessage', originalMessage); + if (isTheLastMessage(room, message)) { await Rooms.setLastMessagePinned(room._id, originalMessage.pinnedBy, originalMessage.pinned); } diff --git a/apps/meteor/app/slashcommands-join/server/server.ts b/apps/meteor/app/slashcommands-join/server/server.ts index dfe27d8d5dc4..33d0278f81a3 100644 --- a/apps/meteor/app/slashcommands-join/server/server.ts +++ b/apps/meteor/app/slashcommands-join/server/server.ts @@ -1,10 +1,9 @@ -import { api } from '@rocket.chat/core-services'; +import { api, Room } from '@rocket.chat/core-services'; import type { SlashCommandCallbackParams } from '@rocket.chat/core-typings'; import { Rooms, Subscriptions } from '@rocket.chat/models'; import { Meteor } from 'meteor/meteor'; import { i18n } from '../../../server/lib/i18n'; -import { joinRoomMethod } from '../../lib/server/methods/joinRoom'; import { settings } from '../../settings/server'; import { slashCommands } from '../../utils/lib/slashCommand'; @@ -16,13 +15,13 @@ slashCommands.add({ return; } - channel = channel.replace('#', ''); - const room = await Rooms.findOneByNameAndType(channel, 'c'); - if (!userId) { return; } + channel = channel.replace('#', ''); + + const room = await Rooms.findOneByNameAndType(channel, 'c'); if (!room) { void api.broadcast('notify.ephemeralMessage', userId, message.rid, { msg: i18n.t('Channel_doesnt_exist', { @@ -44,7 +43,7 @@ slashCommands.add({ }); } - await joinRoomMethod(userId, room._id); + await Room.join({ room, user: { _id: userId } }); }, options: { description: 'Join_the_given_channel', diff --git a/apps/meteor/client/components/ActionManagerBusyState.tsx b/apps/meteor/client/components/ActionManagerBusyState.tsx index dcf82342917c..0374254a7de9 100644 --- a/apps/meteor/client/components/ActionManagerBusyState.tsx +++ b/apps/meteor/client/components/ActionManagerBusyState.tsx @@ -1,3 +1,4 @@ +import { css } from '@rocket.chat/css-in-js'; import { Box } from '@rocket.chat/fuselage'; import { useTranslation } from '@rocket.chat/ui-contexts'; import React, { useEffect, useState } from 'react'; @@ -23,10 +24,23 @@ const ActionManagerBusyState = () => { if (busy) { return ( - - - {t('Loading')} - + + {t('Loading')} ); } diff --git a/apps/meteor/client/components/GenericMenu/GenericMenu.tsx b/apps/meteor/client/components/GenericMenu/GenericMenu.tsx index e02d6dc4e746..f660b4b85f35 100644 --- a/apps/meteor/client/components/GenericMenu/GenericMenu.tsx +++ b/apps/meteor/client/components/GenericMenu/GenericMenu.tsx @@ -1,5 +1,4 @@ -import type { IconButton } from '@rocket.chat/fuselage'; -import { MenuItem, MenuSection, MenuV2 } from '@rocket.chat/fuselage'; +import { IconButton, MenuItem, MenuSection, MenuV2 } from '@rocket.chat/fuselage'; import { useTranslation } from '@rocket.chat/ui-contexts'; import type { ComponentProps, ReactNode } from 'react'; import React from 'react'; @@ -43,6 +42,12 @@ const GenericMenu = ({ title, icon = 'menu', onAction, ...props }: GenericMenuPr const handleItems = (items: GenericMenuItemProps[]) => hasIcon ? items.map((item) => ({ ...item, gap: !item.icon && !item.status })) : items; + const isMenuEmpty = !(sections && sections.length > 0) && !(items && items.length > 0); + + if (isMenuEmpty) { + return ; + } + return ( <> {sections && ( diff --git a/apps/meteor/client/hooks/useAppTranslations.ts b/apps/meteor/client/hooks/useAppTranslations.ts index ad8ca5966c2b..bf4f83e48d85 100644 --- a/apps/meteor/client/hooks/useAppTranslations.ts +++ b/apps/meteor/client/hooks/useAppTranslations.ts @@ -65,7 +65,7 @@ export const useAppTranslations = () => { // Translations keys must be scoped under app id const scopedTranslations = Object.entries(translations).reduce>((acc, [key, value]) => { acc[Utilities.getI18nKeyForApp(key, appId)] = value; - return translations; + return acc; }, {}); i18n.addResourceBundle(normalizedLanguage, 'core', scopedTranslations); diff --git a/apps/meteor/client/hooks/useTimeAgo.ts b/apps/meteor/client/hooks/useTimeAgo.ts index 2b661ae89cf3..724f61d8c7c8 100644 --- a/apps/meteor/client/hooks/useTimeAgo.ts +++ b/apps/meteor/client/hooks/useTimeAgo.ts @@ -14,7 +14,7 @@ export const useTimeAgo = (): ((time: Date | number | string) => string) => { (time) => { return moment(time).calendar(null, { sameDay: format, - lastDay: moment().calendar('lastDay').replace('LT', format), + lastDay: moment(time).calendar('lastDay').replace('LT', format), lastWeek: `dddd ${format}`, sameElse: 'LL', }); diff --git a/apps/meteor/client/lib/chats/data.ts b/apps/meteor/client/lib/chats/data.ts index bd6e01458863..f2c049ad04b1 100644 --- a/apps/meteor/client/lib/chats/data.ts +++ b/apps/meteor/client/lib/chats/data.ts @@ -217,7 +217,6 @@ export const createDataAPI = ({ rid, tmid }: { rid: IRoom['_id']; tmid: IMessage const deleteMessage = async (mid: IMessage['_id']): Promise => { await sdk.call('deleteMessage', { _id: mid }); - Messages.remove({ _id: mid }); }; const drafts = new Map(); diff --git a/apps/meteor/client/startup/startup.ts b/apps/meteor/client/startup/startup.ts index 440b55ce5e6d..6b2b66ec69d7 100644 --- a/apps/meteor/client/startup/startup.ts +++ b/apps/meteor/client/startup/startup.ts @@ -72,11 +72,11 @@ Meteor.startup(() => { } const { - registrationStatus: { connectToCloud, workspaceRegistered }, + registrationStatus: { workspaceRegistered }, } = await sdk.rest.get('/v1/cloud.registrationStatus'); c.stop(); - if (connectToCloud === true && workspaceRegistered !== true) { + if (workspaceRegistered !== true) { banners.open({ id: 'cloud-registration', title: () => t('Cloud_registration_pending_title'), diff --git a/apps/meteor/client/views/admin/cloud/RegisterWorkspace.tsx b/apps/meteor/client/views/admin/cloud/RegisterWorkspace.tsx index 694d437de8d3..e3e1f474cb91 100644 --- a/apps/meteor/client/views/admin/cloud/RegisterWorkspace.tsx +++ b/apps/meteor/client/views/admin/cloud/RegisterWorkspace.tsx @@ -16,7 +16,6 @@ const RegisterWorkspace = () => { const { data: registrationStatusData, isLoading, isError, refetch } = useRegistrationStatus(); const isWorkspaceRegistered = registrationStatusData?.registrationStatus?.workspaceRegistered ?? false; - const isConnectedToCloud = registrationStatusData?.registrationStatus?.connectToCloud ?? false; if (isLoading || isError) { return null; @@ -40,32 +39,11 @@ const RegisterWorkspace = () => { setModal(); }; - const handleRegistrationTag = () => { - if (!isWorkspaceRegistered && !isConnectedToCloud) { - return {t('RegisterWorkspace_NotRegistered_Title')}; - } - if (isWorkspaceRegistered && !isConnectedToCloud) { - return {t('RegisterWorkspace_NotConnected_Title')}; - } - return {t('Workspace_registered')}; - }; - - const handleCardsTitle = () => { - if (!isWorkspaceRegistered && !isConnectedToCloud) { - return t('RegisterWorkspace_NotRegistered_Subtitle'); - } - if (isWorkspaceRegistered && !isConnectedToCloud) { - return t('RegisterWorkspace_NotConnected_Subtitle'); - } - return t('RegisterWorkspace_Registered_Description'); - }; - return ( { - {handleRegistrationTag()} + + {!isWorkspaceRegistered && {t('RegisterWorkspace_NotRegistered_Title')}} + {isWorkspaceRegistered && {t('Workspace_registered')}} + - {handleCardsTitle()} + {isWorkspaceRegistered && t('RegisterWorkspace_NotRegistered_Subtitle')} + {!isWorkspaceRegistered && t('RegisterWorkspace_Registered_Description')} diff --git a/apps/meteor/client/views/admin/cloud/components/RegisterWorkspaceMenu.tsx b/apps/meteor/client/views/admin/cloud/components/RegisterWorkspaceMenu.tsx index d5b0ec7cf771..9163e5e30af5 100644 --- a/apps/meteor/client/views/admin/cloud/components/RegisterWorkspaceMenu.tsx +++ b/apps/meteor/client/views/admin/cloud/components/RegisterWorkspaceMenu.tsx @@ -8,7 +8,6 @@ import RegisteredWorkspaceModal from '../modals/RegisteredWorkspaceModal'; type RegisterWorkspaceMenuProps = { isWorkspaceRegistered: boolean | string; - isConnectedToCloud: boolean | string; onClick: () => void; onClickOfflineRegistration: () => void; onStatusChange?: () => void; @@ -16,7 +15,6 @@ type RegisterWorkspaceMenuProps = { const RegisterWorkspaceMenu = ({ isWorkspaceRegistered, - isConnectedToCloud, onClick, onClickOfflineRegistration, onStatusChange, @@ -33,7 +31,7 @@ const RegisterWorkspaceMenu = ({ return ( - {isWorkspaceRegistered && isConnectedToCloud && ( + {isWorkspaceRegistered && ( <> - )} {!isWorkspaceRegistered && ( <> diff --git a/apps/meteor/client/views/admin/cloud/modals/DisconnectWorkspaceModal.tsx b/apps/meteor/client/views/admin/cloud/modals/DisconnectWorkspaceModal.tsx deleted file mode 100644 index 44846ffe24c5..000000000000 --- a/apps/meteor/client/views/admin/cloud/modals/DisconnectWorkspaceModal.tsx +++ /dev/null @@ -1,79 +0,0 @@ -import { Box, Button, ButtonGroup, Modal } from '@rocket.chat/fuselage'; -import { useMethod, useSetModal, useToastMessageDispatch, useTranslation } from '@rocket.chat/ui-contexts'; -import React from 'react'; - -import useFeatureBullets from '../hooks/useFeatureBullets'; -import RegisteredWorkspaceModal from './RegisteredWorkspaceModal'; - -type DisconnectWorkspaceModalProps = { - onClose: () => void; - onStatusChange?: () => void; -}; - -const DisconnectWorkspaceModal = ({ onClose, onStatusChange, ...props }: DisconnectWorkspaceModalProps) => { - const t = useTranslation(); - const setModal = useSetModal(); - const bulletFeatures = useFeatureBullets(); - const dispatchToastMessage = useToastMessageDispatch(); - - const disconnectWorkspace = useMethod('cloud:disconnectWorkspace'); - - const handleCancelAction = (): void => { - const handleModalClose = (): void => setModal(null); - setModal(); - }; - - const handleUnregister = async () => { - try { - const success = await disconnectWorkspace(); - - if (!success) { - throw Error(t('RegisterWorkspace_Disconnect_Error')); - } - - dispatchToastMessage({ type: 'success', message: t('Disconnected') }); - - setModal(null); - } catch (error) { - dispatchToastMessage({ type: 'error', message: error }); - } finally { - await (onStatusChange && onStatusChange()); - } - }; - - return ( - - - - {t('Are_you_sure')} - - - - - - {`${t('RegisterWorkspace_Disconnect_Subtitle')}: `} -
    - {bulletFeatures.map((item, index) => ( -
  • - {item.title} - - {item.disconnect} - -
  • - ))} -
-
-
- - - - - - -
- ); -}; - -export default DisconnectWorkspaceModal; diff --git a/apps/meteor/client/views/admin/cloud/modals/RegisteredWorkspaceModal.tsx b/apps/meteor/client/views/admin/cloud/modals/RegisteredWorkspaceModal.tsx index 1a77893548f2..050411075c74 100644 --- a/apps/meteor/client/views/admin/cloud/modals/RegisteredWorkspaceModal.tsx +++ b/apps/meteor/client/views/admin/cloud/modals/RegisteredWorkspaceModal.tsx @@ -4,7 +4,6 @@ import { useMethod, useSetModal, useToastMessageDispatch, useTranslation } from import React, { useState } from 'react'; import useFeatureBullets from '../hooks/useFeatureBullets'; -import DisconnectWorkspaceModal from './DisconnectWorkspaceModal'; type RegisteredWorkspaceModalProps = { onClose: () => void; @@ -20,11 +19,6 @@ const RegisteredWorkspaceModal = ({ onClose, onStatusChange, ...props }: Registe const syncWorkspace = useMethod('cloud:syncWorkspace'); - const handleDisconnect = (): void => { - const handleModalClose = (): void => setModal(null); - setModal(); - }; - const handleSyncAction = async () => { setSyncing(true); @@ -40,7 +34,7 @@ const RegisteredWorkspaceModal = ({ onClose, onStatusChange, ...props }: Registe } catch (error) { dispatchToastMessage({ type: 'error', message: error }); } finally { - await (onStatusChange && onStatusChange()); + onStatusChange?.(); setSyncing(false); } }; @@ -70,9 +64,6 @@ const RegisteredWorkspaceModal = ({ onClose, onStatusChange, ...props }: Registe - diff --git a/apps/meteor/client/views/admin/integrations/IncomingWebhookForm.js b/apps/meteor/client/views/admin/integrations/IncomingWebhookForm.js index 94bbd156b86c..ae4d4fa411b5 100644 --- a/apps/meteor/client/views/admin/integrations/IncomingWebhookForm.js +++ b/apps/meteor/client/views/admin/integrations/IncomingWebhookForm.js @@ -1,4 +1,4 @@ -import { Field, TextInput, Box, ToggleSwitch, Icon, TextAreaInput, FieldGroup, Margins } from '@rocket.chat/fuselage'; +import { Field, TextInput, Box, ToggleSwitch, Icon, TextAreaInput, FieldGroup, Margins, Select } from '@rocket.chat/fuselage'; import { useAbsoluteUrl, useTranslation } from '@rocket.chat/ui-contexts'; import React, { useMemo, useCallback } from 'react'; @@ -11,7 +11,8 @@ export default function IncomingWebhookForm({ formValues, formHandlers, extraDat const absoluteUrl = useAbsoluteUrl(); - const { enabled, channel, username, name, alias, avatar, emoji, scriptEnabled, script, overrideDestinationChannelEnabled } = formValues; + const { enabled, channel, username, name, alias, avatar, emoji, scriptEnabled, script, scriptEngine, overrideDestinationChannelEnabled } = + formValues; const { handleEnabled, @@ -24,6 +25,7 @@ export default function IncomingWebhookForm({ formValues, formHandlers, extraDat handleScriptEnabled, handleOverrideDestinationChannelEnabled, handleScript, + handleScriptEngine, } = formHandlers; const url = absoluteUrl(`hooks/${extraData._id}/${extraData.token}`); @@ -42,6 +44,14 @@ export default function IncomingWebhookForm({ formValues, formHandlers, extraDat url, }); + const scriptEngineOptions = useMemo( + () => [ + ['vm2', t('Script_Engine_vm2')], + ['isolated-vm', t('Script_Engine_isolated_vm')], + ], + [t], + ); + const hilightedExampleJson = useHighlightedCode('json', JSON.stringify(exampleData, null, 2)); return ( @@ -172,6 +182,18 @@ export default function IncomingWebhookForm({ formValues, formHandlers, extraDat ), [t, scriptEnabled, handleScriptEnabled], )} + {useMemo( + () => ( + + {t('Script_Engine')} + + + + {t('Script_Engine_Description')} + + ), + [scriptEngine, scriptEngineOptions, handleScriptEngine, t], + )} {useMemo( () => ( diff --git a/apps/meteor/client/views/admin/integrations/edit/EditIncomingWebhook.js b/apps/meteor/client/views/admin/integrations/edit/EditIncomingWebhook.js index cbe3c3e5377d..e785f63ca29d 100644 --- a/apps/meteor/client/views/admin/integrations/edit/EditIncomingWebhook.js +++ b/apps/meteor/client/views/admin/integrations/edit/EditIncomingWebhook.js @@ -17,6 +17,7 @@ const getInitialValue = (data) => { avatar: data.avatar ?? '', emoji: data.emoji ?? '', scriptEnabled: data.scriptEnabled, + scriptEngine: data.scriptEngine ?? 'vm2', overrideDestinationChannelEnabled: data.overrideDestinationChannelEnabled, script: data.script, }; diff --git a/apps/meteor/client/views/admin/integrations/edit/EditOutgoingWebhook.js b/apps/meteor/client/views/admin/integrations/edit/EditOutgoingWebhook.js index 1734f32968c9..383b9209519d 100644 --- a/apps/meteor/client/views/admin/integrations/edit/EditOutgoingWebhook.js +++ b/apps/meteor/client/views/admin/integrations/edit/EditOutgoingWebhook.js @@ -24,6 +24,7 @@ const getInitialValue = (data) => { avatar: data.avatar ?? '', emoji: data.emoji ?? '', scriptEnabled: data.scriptEnabled ?? false, + scriptEngine: data.scriptEngine ?? 'vm2', script: data.script ?? '', retryFailedCalls: data.retryFailedCalls ?? true, retryCount: data.retryCount ?? 5, diff --git a/apps/meteor/client/views/admin/integrations/new/NewIncomingWebhook.js b/apps/meteor/client/views/admin/integrations/new/NewIncomingWebhook.js index 019dc6d0d730..7b4e0880e57f 100644 --- a/apps/meteor/client/views/admin/integrations/new/NewIncomingWebhook.js +++ b/apps/meteor/client/views/admin/integrations/new/NewIncomingWebhook.js @@ -15,6 +15,7 @@ const initialState = { avatar: '', emoji: '', scriptEnabled: false, + scriptEngine: 'isolated-vm', overrideDestinationChannelEnabled: false, script: '', }; diff --git a/apps/meteor/client/views/admin/integrations/new/NewOutgoingWebhook.js b/apps/meteor/client/views/admin/integrations/new/NewOutgoingWebhook.js index 818082f5f5de..153dc4c6eb7f 100644 --- a/apps/meteor/client/views/admin/integrations/new/NewOutgoingWebhook.js +++ b/apps/meteor/client/views/admin/integrations/new/NewOutgoingWebhook.js @@ -23,6 +23,7 @@ const defaultData = { avatar: '', emoji: '', scriptEnabled: false, + scriptEngine: 'isolated-vm', script: '', retryFailedCalls: true, retryCount: 6, diff --git a/apps/meteor/client/views/admin/routes.tsx b/apps/meteor/client/views/admin/routes.tsx index fa418b986cc1..a25bea5affaa 100644 --- a/apps/meteor/client/views/admin/routes.tsx +++ b/apps/meteor/client/views/admin/routes.tsx @@ -70,8 +70,8 @@ declare module '@rocket.chat/ui-contexts' { pattern: '/admin/registration/:page?'; }; 'admin-view-logs': { - pathname: '/admin/logs'; - pattern: '/admin/logs'; + pathname: '/admin/records'; + pattern: '/admin/records'; }; 'federation-dashboard': { pathname: '/admin/federation'; @@ -193,7 +193,7 @@ registerAdminRoute('/registration/:page?', { component: lazy(() => import('./cloud/CloudRoute')), }); -registerAdminRoute('/logs', { +registerAdminRoute('/records', { name: 'admin-view-logs', component: lazy(() => import('./viewLogs/ViewLogsRoute')), }); diff --git a/apps/meteor/client/views/admin/sidebarItems.ts b/apps/meteor/client/views/admin/sidebarItems.ts index c397e28e6db1..50a3284b5ed1 100644 --- a/apps/meteor/client/views/admin/sidebarItems.ts +++ b/apps/meteor/client/views/admin/sidebarItems.ts @@ -112,8 +112,8 @@ export const { permissionGranted: (): boolean => hasPermission('run-import'), }, { - href: '/admin/logs', - i18nLabel: 'Logs', + href: '/admin/records', + i18nLabel: 'Records', icon: 'post', permissionGranted: (): boolean => hasPermission('view-logs'), }, diff --git a/apps/meteor/client/views/admin/viewLogs/AnalyticsReports.tsx b/apps/meteor/client/views/admin/viewLogs/AnalyticsReports.tsx new file mode 100644 index 000000000000..7771298ceb73 --- /dev/null +++ b/apps/meteor/client/views/admin/viewLogs/AnalyticsReports.tsx @@ -0,0 +1,38 @@ +import { Box, Icon, Skeleton } from '@rocket.chat/fuselage'; +import { useTranslation } from '@rocket.chat/ui-contexts'; +import React from 'react'; + +import { useAnalyticsObject } from './hooks/useAnalyticsObject'; + +const AnalyticsReports = () => { + const t = useTranslation(); + + const { data, isLoading, isSuccess, isError } = useAnalyticsObject(); + + return ( + <> + + + + + + {t('How_and_why_we_collect_usage_data')} + + {t('Analytics_page_briefing')} + + + {isSuccess &&
{JSON.stringify(data, null, '\t')}
} + {isError && t('Something_went_wrong_try_again_later')} + {isLoading && ( + <> + + + + + )} +
+ + ); +}; + +export default AnalyticsReports; diff --git a/apps/meteor/client/views/admin/viewLogs/ViewLogsPage.tsx b/apps/meteor/client/views/admin/viewLogs/ViewLogsPage.tsx index a75c22da19b0..4463fec8f5bf 100644 --- a/apps/meteor/client/views/admin/viewLogs/ViewLogsPage.tsx +++ b/apps/meteor/client/views/admin/viewLogs/ViewLogsPage.tsx @@ -1,18 +1,30 @@ +import { Tabs } from '@rocket.chat/fuselage'; import { useTranslation } from '@rocket.chat/ui-contexts'; import type { ReactElement } from 'react'; -import React from 'react'; +import React, { useState } from 'react'; import Page from '../../../components/Page'; +import AnalyticsReports from './AnalyticsReports'; import ServerLogs from './ServerLogs'; const ViewLogsPage = (): ReactElement => { const t = useTranslation(); + const [tab, setTab] = useState('Logs'); + return ( - + - + + setTab('Logs')} selected={tab === 'Logs'}> + {t('Logs')} + + setTab('Analytics')} selected={tab === 'Analytics'}> + {t('Analytic_reports')} + + + {tab === 'Logs' ? : } ); diff --git a/apps/meteor/client/views/admin/viewLogs/hooks/useAnalyticsObject.ts b/apps/meteor/client/views/admin/viewLogs/hooks/useAnalyticsObject.ts new file mode 100644 index 000000000000..8aad0e605964 --- /dev/null +++ b/apps/meteor/client/views/admin/viewLogs/hooks/useAnalyticsObject.ts @@ -0,0 +1,8 @@ +import { useEndpoint } from '@rocket.chat/ui-contexts'; +import { useQuery } from '@tanstack/react-query'; + +export const useAnalyticsObject = () => { + const getAnalytics = useEndpoint('GET', '/v1/statistics'); + + return useQuery(['analytics'], () => getAnalytics({}), { staleTime: 10 * 60 * 1000 }); +}; diff --git a/apps/meteor/client/views/omnichannel/contactHistory/ContactHistory.tsx b/apps/meteor/client/views/omnichannel/contactHistory/ContactHistory.tsx index 5c40b36417ce..955c1918be05 100644 --- a/apps/meteor/client/views/omnichannel/contactHistory/ContactHistory.tsx +++ b/apps/meteor/client/views/omnichannel/contactHistory/ContactHistory.tsx @@ -11,7 +11,7 @@ const ContactHistory = () => { return ( <> {chatId && chatId !== '' ? ( - + ) : ( )} diff --git a/apps/meteor/client/views/omnichannel/currentChats/CurrentChatsPage.tsx b/apps/meteor/client/views/omnichannel/currentChats/CurrentChatsPage.tsx index 1c3a79f30f9e..d82498ff1e50 100644 --- a/apps/meteor/client/views/omnichannel/currentChats/CurrentChatsPage.tsx +++ b/apps/meteor/client/views/omnichannel/currentChats/CurrentChatsPage.tsx @@ -117,7 +117,7 @@ const currentChatQuery: useQueryType = ( return query; }; -const CurrentChatsRoute = ({ id, onRowClick }: { id?: string; onRowClick: (_id: string) => void }): ReactElement => { +const CurrentChatsPage = ({ id, onRowClick }: { id?: string; onRowClick: (_id: string) => void }): ReactElement => { const { sortBy, sortDirection, setSort } = useSort<'fname' | 'departmentId' | 'servedBy' | 'priorityWeight' | 'ts' | 'lm' | 'open'>( 'ts', 'desc', @@ -347,4 +347,4 @@ const CurrentChatsRoute = ({ id, onRowClick }: { id?: string; onRowClick: (_id: ); }; -export default memo(CurrentChatsRoute); +export default memo(CurrentChatsPage); diff --git a/apps/meteor/client/views/omnichannel/currentChats/CurrentChatsRoute.tsx b/apps/meteor/client/views/omnichannel/currentChats/CurrentChatsRoute.tsx index 7d2694d242c9..842a1ad6227d 100644 --- a/apps/meteor/client/views/omnichannel/currentChats/CurrentChatsRoute.tsx +++ b/apps/meteor/client/views/omnichannel/currentChats/CurrentChatsRoute.tsx @@ -26,7 +26,7 @@ const CurrentChatsRoute = (): ReactElement => { } // TODO: Missing error state - return ; + return ; }; export default memo(CurrentChatsRoute); diff --git a/apps/meteor/ee/server/local-services/instance/service.ts b/apps/meteor/ee/server/local-services/instance/service.ts index 0fc4fd33a9b1..85c021f74769 100644 --- a/apps/meteor/ee/server/local-services/instance/service.ts +++ b/apps/meteor/ee/server/local-services/instance/service.ts @@ -96,6 +96,12 @@ export class InstanceService extends ServiceClassInternal implements IInstanceSe events: { broadcast(ctx: any) { const { eventName, streamName, args } = ctx.params; + const { nodeID } = ctx; + + const fromLocalNode = nodeID === InstanceStatus.id(); + if (fromLocalNode) { + return; + } const instance = StreamerCentral.instances[streamName]; if (!instance) { diff --git a/apps/meteor/ee/server/models/raw/LivechatRooms.ts b/apps/meteor/ee/server/models/raw/LivechatRooms.ts index 70824c7d7130..5c3bbb1296e0 100644 --- a/apps/meteor/ee/server/models/raw/LivechatRooms.ts +++ b/apps/meteor/ee/server/models/raw/LivechatRooms.ts @@ -357,7 +357,10 @@ export class LivechatRoomsRawEE extends LivechatRoomsRaw implements ILivechatRoo }, { $group: { - _id: '$source', + _id: { + type: '$source.type', + alias: '$source.alias', + }, value: { $sum: 1 }, }, }, diff --git a/apps/meteor/ee/server/services/CHANGELOG.md b/apps/meteor/ee/server/services/CHANGELOG.md index 6d032b37f4ae..cb58d45affa3 100644 --- a/apps/meteor/ee/server/services/CHANGELOG.md +++ b/apps/meteor/ee/server/services/CHANGELOG.md @@ -1,6 +1,36 @@ # rocketchat-services -## 1.1.7-rc.1 +## 1.1.8-rc.4 + +### Patch Changes + +- @rocket.chat/core-typings@6.4.0-rc.4 +- @rocket.chat/rest-typings@6.4.0-rc.4 +- @rocket.chat/core-services@0.2.0-rc.4 +- @rocket.chat/model-typings@0.1.0-rc.4 +- @rocket.chat/models@0.0.14-rc.4 + +## 1.1.8-rc.3 + +### Patch Changes + +- @rocket.chat/core-typings@6.4.0-rc.3 +- @rocket.chat/rest-typings@6.4.0-rc.3 +- @rocket.chat/core-services@0.2.0-rc.3 +- @rocket.chat/model-typings@0.1.0-rc.3 +- @rocket.chat/models@0.0.13-rc.3 + +## 1.1.8-rc.2 + +### Patch Changes + +- @rocket.chat/core-typings@6.4.0-rc.2 +- @rocket.chat/rest-typings@6.4.0-rc.2 +- @rocket.chat/core-services@0.2.0-rc.2 +- @rocket.chat/model-typings@0.1.0-rc.2 +- @rocket.chat/models@0.0.13-rc.2 + +## 1.1.8-rc.1 ### Patch Changes @@ -10,7 +40,7 @@ - @rocket.chat/model-typings@0.1.0-rc.1 - @rocket.chat/models@0.0.11-rc.1 -## 1.1.7-rc.0 +## 1.1.8-rc.0 ### Patch Changes @@ -37,6 +67,17 @@ - @rocket.chat/model-typings@0.1.0-rc.0 - @rocket.chat/core-services@0.2.0-rc.0 - @rocket.chat/models@0.0.11-rc.0 + +## 1.1.7 + +### Patch Changes + +- @rocket.chat/core-typings@6.3.7 +- @rocket.chat/rest-typings@6.3.7 +- @rocket.chat/core-services@0.1.7 +- @rocket.chat/model-typings@0.0.13 +- @rocket.chat/models@0.0.13 + ## 1.1.6 ### Patch Changes diff --git a/apps/meteor/ee/server/services/Dockerfile b/apps/meteor/ee/server/services/Dockerfile index 6b55a5c35aca..e1a1074fcb60 100644 --- a/apps/meteor/ee/server/services/Dockerfile +++ b/apps/meteor/ee/server/services/Dockerfile @@ -10,6 +10,7 @@ COPY ./yarn.lock . COPY ./.yarnrc.yml . COPY ./.yarn/plugins .yarn/plugins COPY ./.yarn/releases .yarn/releases +COPY ./.yarn/patches .yarn/patches COPY ./packages/core-services packages/core-services COPY ./packages/core-typings packages/core-typings @@ -56,6 +57,7 @@ COPY ./yarn.lock . COPY ./.yarnrc.yml . COPY ./.yarn/plugins .yarn/plugins COPY ./.yarn/releases .yarn/releases +COPY ./.yarn/patches .yarn/patches COPY ./apps/meteor/ee/server/services/package.json ./apps/meteor/ee/server/services/package.json ENV NODE_ENV=production \ diff --git a/apps/meteor/ee/server/services/package.json b/apps/meteor/ee/server/services/package.json index 3466067fd742..98658d1ab681 100644 --- a/apps/meteor/ee/server/services/package.json +++ b/apps/meteor/ee/server/services/package.json @@ -1,7 +1,7 @@ { "name": "rocketchat-services", "private": true, - "version": "1.1.7-rc.1", + "version": "1.1.8-rc.4", "description": "Rocket.Chat Authorization service", "main": "index.js", "scripts": { @@ -41,7 +41,7 @@ "jaeger-client": "^3.19.0", "mem": "^8.1.1", "moleculer": "^0.14.29", - "mongodb": "^4.12.1", + "mongodb": "^4.17.1", "nats": "^2.6.1", "pino": "^8.15.0", "sodium-native": "^3.3.0", diff --git a/apps/meteor/package.json b/apps/meteor/package.json index 030b77fd7814..5dea47ff3a10 100644 --- a/apps/meteor/package.json +++ b/apps/meteor/package.json @@ -347,6 +347,7 @@ "imap": "^0.8.19", "ip-range-check": "^0.2.0", "is-svg": "^4.3.2", + "isolated-vm": "4.4.2", "jquery": "^3.6.0", "jschardet": "^3.0.0", "jsdom": "^16.7.0", @@ -371,8 +372,7 @@ "moment": "^2.29.4", "moment-timezone": "^0.5.43", "mongo-message-queue": "^1.0.0", - "mongodb": "^4.12.1", - "mongodb-memory-server": "^7.6.3", + "mongodb": "^4.17.1", "nats": "^2.6.1", "node-abort-controller": "^3.1.1", "node-dogstatsd": "^0.0.7", diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.json index 7d27aa05eb75..cd8b88fe4058 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.json @@ -417,6 +417,7 @@ "Also_send_to_channel": "Also send to channel", "Always_open_in_new_window": "Always Open in New Window", "Always_show_thread_replies_in_main_channel": "Always show thread replies in main channel", + "Analytic_reports": "Analytic reports", "Analytics": "Analytics", "Analytics_Description": "See how users interact with your workspace.", "Analytics_features_enabled": "Features Enabled", @@ -425,6 +426,7 @@ "Analytics_features_users_Description": "Tracks custom events related to actions related to users (password reset times, profile picture change, etc).", "Analytics_Google": "Google Analytics", "Analytics_Google_id": "Tracking ID", + "Analytics_page_briefing": "Rocket.Chat collects anonymous usage data to identify how many instances are deployed and to improve the product for all users. We take your privacy seriously, so the usage data is encrypted and stored securely.", "Analyze_practical_usage": "Analyze practical usage statistics about users, messages and channels", "and": "and", "And_more": "And {{length}} more", @@ -2476,6 +2478,7 @@ "Hospitality_Businness": "Hospitality Business", "hours": "hours", "Hours": "Hours", + "How_and_why_we_collect_usage_data": "How and why we collect usage data", "How_friendly_was_the_chat_agent": "How friendly was the chat agent?", "How_knowledgeable_was_the_chat_agent": "How knowledgeable was the chat agent?", "How_long_to_wait_after_agent_goes_offline": "How Long to Wait After Agent Goes Offline", @@ -2615,6 +2618,8 @@ "Integration_Incoming_WebHook": "Incoming WebHook Integration", "Integration_New": "New Integration", "integration-scripts-disabled": "Integration Scripts are Disabled", + "integration-scripts-isolated-vm-disabled": "The \"Secure Sandbox\" may not be used on new or modified scripts.", + "integration-scripts-vm2-disabled": "The \"Compatible Sandbox\" may not be used on new or modified scripts.", "Integration_Outgoing_WebHook": "Outgoing WebHook Integration", "Integration_Outgoing_WebHook_History": "Outgoing WebHook Integration History", "Integration_Outgoing_WebHook_History_Data_Passed_To_Trigger": "Data Passed to Integration", @@ -3326,6 +3331,11 @@ "Members_List": "Members List", "mention-all": "Mention All", "mention-all_description": "Permission to use the @all mention", + "Mentions_all_room_members": "Mentions all room members", + "Mentions_online_room_members": "Mentions online room members", + "Mentions_user": "Mentions user", + "Mentions_channel": "Mentions channel", + "Mentions_you": "Mentions you", "mention-here": "Mention Here", "mention-here_description": "Permission to use the @here mention", "Mentions": "Mentions", @@ -4164,6 +4174,7 @@ "Receive_Login_Detection_Emails_Description": "Receive an email each time a new login is detected on your account.", "Recent_Import_History": "Recent Import History", "Record": "Record", + "Records": "Records", "recording": "recording", "Redirect_URI": "Redirect URI", "Redirect_URL_does_not_match": "Redirect URL does not match", @@ -4521,6 +4532,10 @@ "Screen_Share": "Screen Share", "Script": "Script", "Script_Enabled": "Script Enabled", + "Script_Engine": "Script Sandbox", + "Script_Engine_Description": "Older scripts may require the compatible sandbox to run properly, but all new scripts should try to use the secure sandbox instead.", + "Script_Engine_vm2": "Compatible Sandbox (Deprecated)", + "Script_Engine_isolated_vm": "Secure Sandbox", "Search": "Search", "Searchable": "Searchable", "Search_Apps": "Search apps", @@ -5180,10 +5195,6 @@ "Troubleshoot_Disable_Presence_Broadcast_Alert": "This setting prevents all instances form sending the status changes of the users to their clients keeping all the users with their presence status from the first load!", "Troubleshoot_Disable_Sessions_Monitor": "Disable Sessions Monitor", "Troubleshoot_Disable_Sessions_Monitor_Alert": "This setting stops the processing of user sessions causing the statistics to stop working correctly!", - "Troubleshoot_Disable_Statistics_Generator": "Disable Statistics Generator", - "Troubleshoot_Disable_Statistics_Generator_Alert": "This setting stops the processing all statistics making the info page outdated until someone clicks on the refresh button and may cause other missing information around the system!", - "Troubleshoot_Disable_Workspace_Sync": "Disable Workspace Sync", - "Troubleshoot_Disable_Workspace_Sync_Alert": "This setting stops the sync of this server with Rocket.Chat's cloud and may cause issues with marketplace and enteprise licenses!", "Troubleshoot_Disable_Teams_Mention": "Disable Teams mention", "Troubleshoot_Disable_Teams_Mention_Alert": "This setting disables the teams mention feature. User's won't be able to mention a Team by name in a message and get its members notified.", "True": "True", @@ -5854,7 +5865,7 @@ "onboarding.component.form.action.confirm": "Confirm", "onboarding.component.form.termsAndConditions": "I agree with <1>Terms and Conditions and <3>Privacy Policy", "onboarding.component.emailCodeFallback": "Didn’t receive email? <1>Resend or <3>Change email", - "onboarding.page.form.title": "Let's <1>Launch Your Workspace", + "onboarding.page.form.title": "Let's launch your workspace", "onboarding.page.awaitingConfirmation.title": "Awaiting confirmation", "onboarding.page.awaitingConfirmation.subtitle": "We have sent you an email to {{emailAddress}} with a confirmation link. Please verify that the security code below matches the one in the email.", "onboarding.page.emailConfirmed.title": "Email Confirmed!", @@ -5881,10 +5892,8 @@ "onboarding.page.requestTrial.subtitle": "Try our best Enterprise Edition plan for 30 days for free", "onboarding.page.magicLinkEmail.title": "We emailed you a login link", "onboarding.page.magicLinkEmail.subtitle": "Click the link in the email we just sent you to sign in to your workspace. <1>The link will expire in 30 minutes.", - "onboarding.page.organizationInfoPage.title": "A few more details...", - "onboarding.page.organizationInfoPage.subtitle": "These will help us to personalize your workspace.", "onboarding.form.adminInfoForm.title": "Admin Info", - "onboarding.form.adminInfoForm.subtitle": "We need this to create an admin profile inside your workspace", + "onboarding.form.adminInfoForm.subtitle": "We need this information to create an admin profile for your workspace.", "onboarding.form.adminInfoForm.fields.fullName.label": "Full name", "onboarding.form.adminInfoForm.fields.fullName.placeholder": "First and last name", "onboarding.form.adminInfoForm.fields.username.label": "Username", @@ -5895,7 +5904,7 @@ "onboarding.form.adminInfoForm.fields.password.placeholder": "Create password", "onboarding.form.adminInfoForm.fields.keepPosted.label": "Keep me posted about Rocket.Chat updates", "onboarding.form.organizationInfoForm.title": "Organization Info", - "onboarding.form.organizationInfoForm.subtitle": "Please, bear with us. This info will help us personalize your workspace", + "onboarding.form.organizationInfoForm.subtitle": "We need to know who you are.", "onboarding.form.organizationInfoForm.fields.organizationName.label": "Organization name", "onboarding.form.organizationInfoForm.fields.organizationName.placeholder": "Organization name", "onboarding.form.organizationInfoForm.fields.organizationType.label": "Organization type", @@ -5906,17 +5915,16 @@ "onboarding.form.organizationInfoForm.fields.organizationSize.placeholder": "Select", "onboarding.form.organizationInfoForm.fields.country.label": "Country", "onboarding.form.organizationInfoForm.fields.country.placeholder": "Select", - "onboarding.form.registeredServerForm.title": "Register Your Server", + "onboarding.form.registeredServerForm.title": "Register your workspace", "onboarding.form.registeredServerForm.included.push": "Mobile push notifications", "onboarding.form.registeredServerForm.included.externalProviders": "Integration with external providers (WhatsApp, Facebook, Telegram, Twitter)", "onboarding.form.registeredServerForm.included.apps": "Access to marketplace apps", - "onboarding.form.registeredServerForm.fields.accountEmail.inputLabel": "Cloud account email", - "onboarding.form.registeredServerForm.fields.accountEmail.tooltipLabel": "To register your server, we need to connect it to your cloud account. If you already have one - we will link it automatically. Otherwise, a new account will be created", - "onboarding.form.registeredServerForm.fields.accountEmail.inputPlaceholder": "Please enter your Email", + "onboarding.form.registeredServerForm.fields.accountEmail.inputLabel": "Admin email", + "onboarding.form.registeredServerForm.fields.accountEmail.inputPlaceholder": "Insert your email to continue", "onboarding.form.registeredServerForm.keepInformed": "Keep me informed about news and events", "onboarding.form.registeredServerForm.registerLater": "Register later", "onboarding.form.registeredServerForm.notConnectedToInternet": "The server is not connected to the internet, so you’ll have to do an offline registration for this workspace.", - "onboarding.form.registeredServerForm.agreeToReceiveUpdates": "By registering I agree to receive relevant product and security updates", + "onboarding.form.registeredServerForm.registrationEngagement": "Registration allows automatic license updates, notifications of critical vulnerabilities and access to Rocket.Chat Cloud services. No sensitive workspace data is shared; statistics sent to Rocket.Chat is made visible to you within the administration area.", "onboarding.form.standaloneServerForm.title": "Standalone Server Confirmation", "onboarding.form.standaloneServerForm.servicesUnavailable": "Some of the services will be unavailable or will require manual setup", "onboarding.form.standaloneServerForm.publishOwnApp": "In order to send push notitications you need to compile and publish your own app to Google Play and App Store", @@ -5943,6 +5951,7 @@ "Theme_match_system_description": "Automatically match the appearance of your system.", "Theme_high_contrast": "High contrast", "Theme_high_contrast_description": "Maximum tonal differentiation with bold colors and sharp contrasts provide enhanced accessibility.", + "Highlighted_chosen_word": "Highlighted chosen word", "High_contrast_upsell_title": "Enable high contrast theme", "High_contrast_upsell_subtitle": "Enhance your team’s reading experience", "High_contrast_upsell_description": "Especially designed for individuals with visual impairments or conditions such as color vision deficiency, low vision, or sensitivity to low contrast.\n\nThis theme increases contrast between text and background elements, making content more distinguishable and easier to read.", diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/fi.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/fi.i18n.json index ccdec04a7bec..34c7ca9fdda4 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/fi.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/fi.i18n.json @@ -5757,4 +5757,4 @@ "Uninstall_grandfathered_app": "Poistetaanko {{appName}}?", "App_will_lose_grandfathered_status": "**Tämä {{context}}sovellus menettää aikaisemmin käytetössä olleen sovelluksen tilansa.** \n \nYhteisöversion työtiloissa voi olla käytössä enintään {{limit}} {{context}} sovellusta. aikaisemmin Aikaisemmin käytössä olleet sovellukset lasketaan mukaan rajoitukseen, mutta rajoitusta ei sovelleta niihin.", "Theme_Appearence": "Teeman ulkoasu" -} +} \ No newline at end of file diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/hu.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/hu.i18n.json index d939e8ad16bb..e54f69c81052 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/hu.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/hu.i18n.json @@ -5438,4 +5438,4 @@ "Join_your_team": "Csatlakozás csapathoz", "Create_an_account": "Fiók létrehozása", "RegisterWorkspace_Features_Marketplace_Title": "Piactér" -} +} \ No newline at end of file diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/pt-BR.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/pt-BR.i18n.json index 1b24ab3c4129..80d17019855c 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/pt-BR.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/pt-BR.i18n.json @@ -4705,14 +4705,14 @@ "VoIP_Server_Websocket_Port": "Porta do webSocket", "VoIP_Server_Name": "Nome do servidor", "VoIP_Server_Websocket_Path": "URL do webSocket", + "VoIP_Retry_Count": "Número de tentativas", + "VoIP_Retry_Count_Description": "Define quantas vezes o cliente tentará se reconectar ao servidor VoIP caso a conexão seja perdida.", "VoIP_Management_Server": "Servidor de gerenciamento de VoIP", "VoIP_Management_Server_Host": "Host de servidor", "VoIP_Management_Server_Port": "Porta do servidor", "VoIP_Management_Server_Name": "Nome do servidor", "VoIP_Management_Server_Username": "Nome de usuário", "VoIP_Management_Server_Password": "Senha", - "VoIP_Retry_Count": "Número de tentativas", - "VoIP_Retry_Count_Description": "Define quantas vezes o cliente tentará se reconectar ao servidor VoIP caso a conexão seja perdida.", "Voip_call_started": "Chamada iniciada às", "Voip_call_duration": "Chamada com duração de {{duration}}", "Voip_call_declined": "Chamada finalizada pelo agente", diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/sv.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/sv.i18n.json index 35792cce086a..bea75b85c976 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/sv.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/sv.i18n.json @@ -5762,4 +5762,4 @@ "Uninstall_grandfathered_app": "Avinstallera {{appName}}?", "App_will_lose_grandfathered_status": "**Denna {{context}}-app kommer att förlora sin status som gammal app.** \n \nArbetsytorna i Community Edition kan ha upp till {{limit}} __kontext__-appar aktiverade. Gamla appar inkluderas i gränsen, men gränsen tillämpas inte på dem.", "Theme_Appearence": "Utseende för tema" -} +} \ No newline at end of file diff --git a/apps/meteor/server/cron/statistics.ts b/apps/meteor/server/cron/statistics.ts index b6f58b66d383..27c1fc064e25 100644 --- a/apps/meteor/server/cron/statistics.ts +++ b/apps/meteor/server/cron/statistics.ts @@ -32,28 +32,10 @@ async function generateStatistics(logger: Logger): Promise { } export async function statsCron(logger: Logger): Promise { - if (settings.get('Troubleshoot_Disable_Statistics_Generator')) { - return; - } - const name = 'Generate and save statistics'; + await generateStatistics(logger); - let previousValue: boolean; - settings.watch('Troubleshoot_Disable_Statistics_Generator', async (value) => { - if (value === previousValue) { - return; - } - previousValue = value; - - if (value) { - await cronJobs.remove(name); - return; - } - - await generateStatistics(logger); - - const now = new Date(); + const now = new Date(); - await cronJobs.add(name, `12 ${now.getHours()} * * *`, async () => generateStatistics(logger)); - }); + await cronJobs.add(name, `12 ${now.getHours()} * * *`, async () => generateStatistics(logger)); } diff --git a/apps/meteor/server/lib/rooms/roomTypes/direct.ts b/apps/meteor/server/lib/rooms/roomTypes/direct.ts index b18418258cb3..ad1913345b85 100644 --- a/apps/meteor/server/lib/rooms/roomTypes/direct.ts +++ b/apps/meteor/server/lib/rooms/roomTypes/direct.ts @@ -1,4 +1,4 @@ -import type { IRoom, AtLeast } from '@rocket.chat/core-typings'; +import type { AtLeast } from '@rocket.chat/core-typings'; import { isRoomFederated } from '@rocket.chat/core-typings'; import { Subscriptions } from '@rocket.chat/models'; import { Meteor } from 'meteor/meteor'; @@ -42,7 +42,7 @@ roomCoordinator.add(DirectMessageRoomType, { } }, - async allowMemberAction(room: IRoom, action, userId) { + async allowMemberAction(room, action, userId) { if (isRoomFederated(room)) { return Federation.actionAllowed(room, action, userId); } diff --git a/apps/meteor/server/services/messages/hooks/badwords.ts b/apps/meteor/server/services/messages/hooks/badwords.ts new file mode 100644 index 000000000000..17641d8f9c7f --- /dev/null +++ b/apps/meteor/server/services/messages/hooks/badwords.ts @@ -0,0 +1,26 @@ +export async function configureBadWords(badWordsList?: string, goodWordsList?: string) { + const { default: Filter } = await import('bad-words'); + + const options = { + list: + badWordsList + ?.split(',') + .map((word) => word.trim()) + .filter(Boolean) || [], + // library definition does not allow optional definition + exclude: undefined, + splitRegex: undefined, + placeHolder: undefined, + regex: undefined, + replaceRegex: undefined, + emptyList: undefined, + }; + + const badWords = new Filter(options); + + if (goodWordsList?.length) { + badWords.removeWords(...goodWordsList.split(',').map((word) => word.trim())); + } + + return badWords; +} diff --git a/apps/meteor/server/services/messages/service.ts b/apps/meteor/server/services/messages/service.ts index 48f7ad42276c..f981422727f7 100644 --- a/apps/meteor/server/services/messages/service.ts +++ b/apps/meteor/server/services/messages/service.ts @@ -2,6 +2,7 @@ import type { IMessageService } from '@rocket.chat/core-services'; import { ServiceClassInternal } from '@rocket.chat/core-services'; import type { IMessage, MessageTypesValues, IUser, IRoom } from '@rocket.chat/core-typings'; import { Messages } from '@rocket.chat/models'; +import type BadWordsFilter from 'bad-words'; import { deleteMessage } from '../../../app/lib/server/functions/deleteMessage'; import { sendMessage } from '../../../app/lib/server/functions/sendMessage'; @@ -9,10 +10,30 @@ import { updateMessage } from '../../../app/lib/server/functions/updateMessage'; import { executeSendMessage } from '../../../app/lib/server/methods/sendMessage'; import { executeSetReaction } from '../../../app/reactions/server/setReaction'; import { settings } from '../../../app/settings/server'; +import { configureBadWords } from './hooks/badwords'; export class MessageService extends ServiceClassInternal implements IMessageService { protected name = 'message'; + private badWordsFilter?: BadWordsFilter; + + async created() { + await this.configureBadWords(); + } + + private async configureBadWords() { + settings.watchMultiple( + ['Message_AllowBadWordsFilter', 'Message_BadWordsFilterList', 'Message_BadWordsWhitelist'], + async ([enabled, badWordsList, whiteList]) => { + if (!enabled) { + this.badWordsFilter = undefined; + return; + } + this.badWordsFilter = await configureBadWords(badWordsList as string, whiteList as string); + }, + ); + } + async sendMessage({ fromId, rid, msg }: { fromId: string; rid: string; msg: string }): Promise { return executeSendMessage(fromId, { rid, msg }); } @@ -55,4 +76,61 @@ export class MessageService extends ServiceClassInternal implements IMessageServ return result.insertedId; } + + async beforeSave({ + message, + room: _room, + user: _user, + }: { + message: IMessage; + room: IRoom; + user: Pick; + }): Promise { + // TODO looks like this one was not being used (so I'll left it commented) + // await this.joinDiscussionOnMessage({ message, room, user }); + + // conditionals here should be fast, so they won't add up for each message + if (this.isBadWordsFilterEnabled()) { + message = await this.filterBadWords(message); + } + + return message; + } + + private isBadWordsFilterEnabled() { + return !!settings.get('Message_AllowBadWordsFilter'); + } + + private async filterBadWords(message: IMessage): Promise { + if (!message.msg || !this.badWordsFilter) { + return message; + } + + try { + message.msg = this.badWordsFilter.clean(message.msg); + } catch (error) { + // ignore + } + + return message; + } + + // joinDiscussionOnMessage + // private async joinDiscussionOnMessage({ message, room, user }: { message: IMessage; room: IRoom; user: IUser }) { + // // abort if room is not a discussion + // if (!room.prid) { + // return; + // } + + // // check if user already joined the discussion + // const sub = await Subscriptions.findOneByRoomIdAndUserId(room._id, message.u._id, { + // projection: { _id: 1 }, + // }); + + // if (sub) { + // return; + // } + + // await Room.join({ room, user }); + // } } diff --git a/apps/meteor/server/services/room/service.ts b/apps/meteor/server/services/room/service.ts index ac978da88c77..61b5bfeee504 100644 --- a/apps/meteor/server/services/room/service.ts +++ b/apps/meteor/server/services/room/service.ts @@ -1,6 +1,6 @@ -import { ServiceClassInternal, Authorization } from '@rocket.chat/core-services'; +import { ServiceClassInternal, Authorization, MeteorError } from '@rocket.chat/core-services'; import type { ICreateRoomParams, IRoomService } from '@rocket.chat/core-services'; -import type { AtLeast, IRoom, IUser } from '@rocket.chat/core-typings'; +import { type AtLeast, type IRoom, type IUser, isRoomWithJoinCode } from '@rocket.chat/core-typings'; import { Users } from '@rocket.chat/models'; import { saveRoomTopic } from '../../../app/channel-settings/server/functions/saveRoomTopic'; @@ -8,6 +8,7 @@ import { addUserToRoom } from '../../../app/lib/server/functions/addUserToRoom'; import { createRoom } from '../../../app/lib/server/functions/createRoom'; // TODO remove this import import { removeUserFromRoom } from '../../../app/lib/server/functions/removeUserFromRoom'; import { getValidRoomName } from '../../../app/utils/server/lib/getValidRoomName'; +import { RoomMemberActions } from '../../../definition/IRoomTypeConfig'; import { roomCoordinator } from '../../lib/rooms/roomCoordinator'; import { createDirectMessage } from '../../methods/createDirectMessage'; @@ -94,4 +95,29 @@ export class RoomService extends ServiceClassInternal implements IRoomService { async getRouteLink(room: AtLeast): Promise { return roomCoordinator.getRouteLink(room.t as string, { rid: room._id, name: room.name }); } + + /** + * Method called by users to join a room. + */ + async join({ room, user, joinCode }: { room: IRoom; user: Pick; joinCode?: string }) { + if (!(await roomCoordinator.getRoomDirectives(room.t)?.allowMemberAction(room, RoomMemberActions.JOIN, user._id))) { + throw new MeteorError('error-not-allowed', 'Not allowed', { method: 'joinRoom' }); + } + + if (!(await Authorization.canAccessRoom(room, user))) { + throw new MeteorError('error-not-allowed', 'Not allowed', { method: 'joinRoom' }); + } + + if ( + isRoomWithJoinCode(room) && + (!joinCode || joinCode !== room.joinCode) && + !(await Authorization.hasPermission(user._id, 'join-without-join-code')) + ) { + throw new MeteorError('error-code-invalid', 'Invalid Room Password', { + method: 'joinRoom', + }); + } + + return addUserToRoom(room._id, user); + } } diff --git a/apps/meteor/server/settings/troubleshoot.ts b/apps/meteor/server/settings/troubleshoot.ts index bc1cd1484301..bfecb1a344f6 100644 --- a/apps/meteor/server/settings/troubleshoot.ts +++ b/apps/meteor/server/settings/troubleshoot.ts @@ -32,20 +32,30 @@ export const createTroubleshootSettings = () => type: 'boolean', i18nDescription: 'Troubleshoot_Disable_Livechat_Activity_Monitor_Alert', }); - await this.add('Troubleshoot_Disable_Statistics_Generator', false, { - type: 'boolean', - i18nDescription: 'Troubleshoot_Disable_Statistics_Generator_Alert', - }); + await this.add('Troubleshoot_Disable_Data_Exporter_Processor', false, { type: 'boolean', i18nDescription: 'Troubleshoot_Disable_Data_Exporter_Processor_Alert', }); - await this.add('Troubleshoot_Disable_Workspace_Sync', false, { - type: 'boolean', - i18nDescription: 'Troubleshoot_Disable_Workspace_Sync_Alert', - }); await this.add('Troubleshoot_Disable_Teams_Mention', false, { type: 'boolean', i18nDescription: 'Troubleshoot_Disable_Teams_Mention_Alert', }); + + // TODO: remove this setting at next major (7.0.0) + await this.add('Troubleshoot_Disable_Statistics_Generator', false, { + type: 'boolean', + i18nDescription: 'Troubleshoot_Disable_Statistics_Generator_Alert', + private: true, + hidden: true, + readonly: true, + }); + // TODO: remove this setting at next major (7.0.0) + await this.add('Troubleshoot_Disable_Workspace_Sync', false, { + type: 'boolean', + i18nDescription: 'Troubleshoot_Disable_Workspace_Sync_Alert', + private: true, + hidden: true, + readonly: true, + }); }); diff --git a/apps/meteor/tests/e2e/forgot-password.spec.ts b/apps/meteor/tests/e2e/forgot-password.spec.ts index ee531d59cdfa..441944f5b227 100644 --- a/apps/meteor/tests/e2e/forgot-password.spec.ts +++ b/apps/meteor/tests/e2e/forgot-password.spec.ts @@ -2,7 +2,7 @@ import { Registration } from './page-objects'; import { test, expect } from './utils/test'; test.describe.parallel('Forgot Password', () => { - let poRegistration: Registration; + let poRegistration: Registration; test.beforeEach(async ({ page }) => { poRegistration = new Registration(page); @@ -11,7 +11,7 @@ test.describe.parallel('Forgot Password', () => { await poRegistration.btnForgotPassword.click(); }); - test('Email validation', async () => { + test('Send email to recover account', async () => { await test.step('expect trigger a validation error if no email is provided', async () => { await poRegistration.btnSendInstructions.click(); await expect(poRegistration.inputEmail).toBeInvalid(); @@ -31,11 +31,16 @@ test.describe.parallel('Forgot Password', () => { await expect(poRegistration.inputEmail).toBeInvalid(); }); - await test.step('expect to show a success toast if a valid email is provided', async () => { + await test.step('expect to show a success callout if a valid email is provided', async () => { await poRegistration.inputEmail.fill('mail@mail.com'); await poRegistration.btnSendInstructions.click(); await expect(poRegistration.forgotPasswordEmailCallout).toBeVisible(); }); }); + + test('should not have any accessibility violations', async ({ makeAxeBuilder }) => { + const results = await makeAxeBuilder().analyze(); + expect(results.violations).toEqual([]); + }) }); diff --git a/apps/meteor/tests/e2e/page-objects/auth.ts b/apps/meteor/tests/e2e/page-objects/auth.ts index 26537f183113..9b47d2e44adc 100644 --- a/apps/meteor/tests/e2e/page-objects/auth.ts +++ b/apps/meteor/tests/e2e/page-objects/auth.ts @@ -11,6 +11,11 @@ export class Registration { return this.page.locator('role=button[name="Send instructions"]'); } + get btnReset(): Locator { + return this.page.locator('role=button[name="Reset"]'); + } + + get btnLogin(): Locator { return this.page.locator('role=button[name="Login"]'); } @@ -19,10 +24,6 @@ export class Registration { return this.page.locator('role=link[name="Create an account"]'); } - get main(): Locator { - return this.page.locator('role=main'); - } - get backToLogin(): Locator { return this.page.locator('role=link[name="Back to Login"]'); } @@ -63,10 +64,6 @@ export class Registration { return this.page.locator('[name=passwordConfirmation]'); } - // get textErrorPasswordConfirm(): Locator { - // return this.page.locator('[name=confirm-pass]~.input-error'); - // } - get forgotPasswordEmailCallout(): Locator { return this.page.locator('role=status'); } diff --git a/apps/meteor/tests/e2e/page-objects/utils.ts b/apps/meteor/tests/e2e/page-objects/utils.ts index d71eaf55daab..066c5eac153f 100644 --- a/apps/meteor/tests/e2e/page-objects/utils.ts +++ b/apps/meteor/tests/e2e/page-objects/utils.ts @@ -7,6 +7,10 @@ export class Utils { this.page = page; } + get mainContent(): Locator { + return this.page.locator('main.main-content'); + } + get toastBar(): Locator { return this.page.locator('.rcx-toastbar'); } diff --git a/apps/meteor/tests/e2e/register.spec.ts b/apps/meteor/tests/e2e/register.spec.ts index 6d62ace5e7d3..1709b8414e6b 100644 --- a/apps/meteor/tests/e2e/register.spec.ts +++ b/apps/meteor/tests/e2e/register.spec.ts @@ -1,14 +1,16 @@ import { faker } from '@faker-js/faker'; -import { Registration } from './page-objects'; +import { Utils, Registration } from './page-objects'; import { test, expect } from './utils/test'; -test.describe.serial('register', () => { +test.describe.parallel('register', () => { let poRegistration: Registration; + let poUtils: Utils; test.describe('Registration default flow', async () => { test.beforeEach(async ({ page }) => { poRegistration = new Registration(page); + poUtils = new Utils(page); }); test('Successfully Registration flow', async ({ page }) => { await test.step('expect trigger a validation error if no data is provided on register', async () => { @@ -37,7 +39,7 @@ test.describe.serial('register', () => { await test.step('expect successfully register a new user', async () => { await poRegistration.inputPasswordConfirm.fill('any_password'); await poRegistration.btnRegister.click(); - await expect(poRegistration.main).toBeHidden(); + await expect(poUtils.mainContent).toBeVisible(); }); }); @@ -70,7 +72,7 @@ test.describe.serial('register', () => { await poRegistration.inputPassword.fill('any_password'); await poRegistration.btnRegister.click(); - await expect(poRegistration.main).toBeHidden(); + await expect(poUtils.mainContent).toBeVisible(); }); }); }); @@ -137,6 +139,7 @@ test.describe.serial('register', () => { test.describe('Registration for secret password', async () => { test.beforeEach(async ({ api, page }) => { poRegistration = new Registration(page); + poUtils = new Utils(page); const result = await api.post('/settings/Accounts_RegistrationForm', { value: 'Secret URL' }); await api.post('/settings/Accounts_RegistrationForm_SecretURL', { value: 'secret' }); await expect(result.ok()).toBeTruthy(); @@ -173,8 +176,7 @@ test.describe.serial('register', () => { await poRegistration.inputPassword.fill('any_password'); await poRegistration.inputPasswordConfirm.fill('any_password'); await poRegistration.btnRegister.click(); - await page.waitForSelector('role=main'); - await expect(poRegistration.main).toBeVisible(); + await expect(poUtils.mainContent).toBeVisible(); }); }); diff --git a/apps/meteor/tests/e2e/reset-password.spec.ts b/apps/meteor/tests/e2e/reset-password.spec.ts new file mode 100644 index 000000000000..fc5e0b703784 --- /dev/null +++ b/apps/meteor/tests/e2e/reset-password.spec.ts @@ -0,0 +1,35 @@ +import { Registration } from './page-objects'; +import { setSettingValueById } from './utils/setSettingValueById'; +import { test, expect } from './utils/test'; + +test.describe.parallel('Reset Password', () => { + let poRegistration: Registration; + + test.beforeEach(async ({ api, page }) => { + poRegistration = new Registration(page); + await setSettingValueById(api, 'Accounts_RequirePasswordConfirmation', true); + + await page.goto('/reset-password/someToken'); + }); + + test.afterAll(async ({ api }) => { + await setSettingValueById(api, 'Accounts_RequirePasswordConfirmation', true); + }) + + test('should confirm password be invalid', async () => { + await poRegistration.inputPassword.fill('123456'); + await poRegistration.inputPasswordConfirm.fill('123455'); + await poRegistration.btnReset.click(); + await expect(poRegistration.inputPasswordConfirm).toBeInvalid(); + }); + + test('should confirm password not be visible', async ({ api }) => { + await setSettingValueById(api, 'Accounts_RequirePasswordConfirmation', false); + await expect(poRegistration.inputPasswordConfirm).not.toBeVisible(); + }) + + test('should not have any accessibility violations', async ({ makeAxeBuilder }) => { + const results = await makeAxeBuilder().analyze(); + expect(results.violations).toEqual([]); + }) +}); diff --git a/apps/meteor/tsconfig.typecheck.json b/apps/meteor/tsconfig.typecheck.json index e5a34906c8ce..33699e98affb 100644 --- a/apps/meteor/tsconfig.typecheck.json +++ b/apps/meteor/tsconfig.typecheck.json @@ -2,7 +2,12 @@ "extends": "./tsconfig.json", "compilerOptions": { "skipLibCheck": true, - "noEmit": true + "noEmit": true, + "incremental": true, + "allowImportingTsExtensions": true, + "paths": { + "mongodb": ["node_modules/mongodb"] + } }, "exclude": [".meteor", "./packages", "./imports/client", "./ee/server/services", "public/", "private"] } diff --git a/ee/apps/account-service/CHANGELOG.md b/ee/apps/account-service/CHANGELOG.md index 269ce5961b3f..2b8f68d82542 100644 --- a/ee/apps/account-service/CHANGELOG.md +++ b/ee/apps/account-service/CHANGELOG.md @@ -1,6 +1,36 @@ # @rocket.chat/account-service -## 0.2.7-rc.1 +## 0.2.8-rc.4 + +### Patch Changes + +- @rocket.chat/core-typings@6.4.0-rc.4 +- @rocket.chat/rest-typings@6.4.0-rc.4 +- @rocket.chat/core-services@0.2.0-rc.4 +- @rocket.chat/model-typings@0.1.0-rc.4 +- @rocket.chat/models@0.0.14-rc.4 + +## 0.2.8-rc.3 + +### Patch Changes + +- @rocket.chat/core-typings@6.4.0-rc.3 +- @rocket.chat/rest-typings@6.4.0-rc.3 +- @rocket.chat/core-services@0.2.0-rc.3 +- @rocket.chat/model-typings@0.1.0-rc.3 +- @rocket.chat/models@0.0.11-rc.3 + +## 0.2.8-rc.2 + +### Patch Changes + +- @rocket.chat/core-typings@6.5.0-rc.2 +- @rocket.chat/rest-typings@6.5.0-rc.2 +- @rocket.chat/core-services@0.2.0-rc.2 +- @rocket.chat/model-typings@0.2.0-rc.2 +- @rocket.chat/models@0.0.11-rc.2 + +## 0.2.8-rc.1 ### Patch Changes @@ -10,7 +40,7 @@ - @rocket.chat/model-typings@0.1.0-rc.1 - @rocket.chat/models@0.0.11-rc.1 -## 0.2.7-rc.0 +## 0.2.8-rc.0 ### Patch Changes @@ -37,6 +67,17 @@ - @rocket.chat/model-typings@0.1.0-rc.0 - @rocket.chat/core-services@0.2.0-rc.0 - @rocket.chat/models@0.0.11-rc.0 + +## 0.2.7 + +### Patch Changes + +- @rocket.chat/core-typings@6.3.7 +- @rocket.chat/rest-typings@6.3.7 +- @rocket.chat/core-services@0.1.7 +- @rocket.chat/model-typings@0.0.13 +- @rocket.chat/models@0.0.13 + ## 0.2.6 ### Patch Changes diff --git a/ee/apps/account-service/Dockerfile b/ee/apps/account-service/Dockerfile index e59c9f672f8b..d7ccb734071b 100644 --- a/ee/apps/account-service/Dockerfile +++ b/ee/apps/account-service/Dockerfile @@ -29,6 +29,7 @@ COPY ./yarn.lock . COPY ./.yarnrc.yml . COPY ./.yarn/plugins .yarn/plugins COPY ./.yarn/releases .yarn/releases +COPY ./.yarn/patches .yarn/patches COPY ./ee/apps/${SERVICE}/package.json ee/apps/${SERVICE}/package.json ENV NODE_ENV=production \ diff --git a/ee/apps/account-service/package.json b/ee/apps/account-service/package.json index 5eaf101e2561..5828b25ebcd3 100644 --- a/ee/apps/account-service/package.json +++ b/ee/apps/account-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/account-service", "private": true, - "version": "0.2.7-rc.1", + "version": "0.2.8-rc.4", "description": "Rocket.Chat Account service", "scripts": { "build": "tsc -p tsconfig.json", @@ -31,7 +31,7 @@ "gc-stats": "^1.4.0", "mem": "^8.1.1", "moleculer": "^0.14.29", - "mongodb": "^4.12.1", + "mongodb": "^4.17.1", "nats": "^2.4.0", "pino": "^8.15.0", "polka": "^0.5.2", diff --git a/ee/apps/authorization-service/CHANGELOG.md b/ee/apps/authorization-service/CHANGELOG.md index 469f334a1914..c88f11bdaca0 100644 --- a/ee/apps/authorization-service/CHANGELOG.md +++ b/ee/apps/authorization-service/CHANGELOG.md @@ -1,6 +1,36 @@ # @rocket.chat/authorization-service -## 0.2.7-rc.1 +## 0.2.8-rc.4 + +### Patch Changes + +- @rocket.chat/core-typings@6.4.0-rc.4 +- @rocket.chat/rest-typings@6.4.0-rc.4 +- @rocket.chat/core-services@0.2.0-rc.4 +- @rocket.chat/model-typings@0.1.0-rc.4 +- @rocket.chat/models@0.0.14-rc.4 + +## 0.2.8-rc.3 + +### Patch Changes + +- @rocket.chat/core-typings@6.4.0-rc.3 +- @rocket.chat/rest-typings@6.4.0-rc.3 +- @rocket.chat/core-services@0.2.0-rc.3 +- @rocket.chat/model-typings@0.1.0-rc.3 +- @rocket.chat/models@0.0.13-rc.3 + +## 0.2.8-rc.2 + +### Patch Changes + +- @rocket.chat/core-typings@6.4.0-rc.2 +- @rocket.chat/rest-typings@6.4.0-rc.2 +- @rocket.chat/core-services@0.2.0-rc.2 +- @rocket.chat/model-typings@0.1.0-rc.2 +- @rocket.chat/models@0.0.13-rc.2 + +## 0.2.8-rc.1 ### Patch Changes @@ -10,7 +40,7 @@ - @rocket.chat/model-typings@0.1.0-rc.1 - @rocket.chat/models@0.0.11-rc.1 -## 0.2.7-rc.0 +## 0.2.8-rc.0 ### Patch Changes @@ -37,6 +67,17 @@ - @rocket.chat/model-typings@0.1.0-rc.0 - @rocket.chat/core-services@0.2.0-rc.0 - @rocket.chat/models@0.0.11-rc.0 + +## 0.2.7 + +### Patch Changes + +- @rocket.chat/core-typings@6.3.7 +- @rocket.chat/rest-typings@6.3.7 +- @rocket.chat/core-services@0.1.7 +- @rocket.chat/model-typings@0.0.13 +- @rocket.chat/models@0.0.13 + ## 0.2.6 ### Patch Changes diff --git a/ee/apps/authorization-service/Dockerfile b/ee/apps/authorization-service/Dockerfile index e59c9f672f8b..d7ccb734071b 100644 --- a/ee/apps/authorization-service/Dockerfile +++ b/ee/apps/authorization-service/Dockerfile @@ -29,6 +29,7 @@ COPY ./yarn.lock . COPY ./.yarnrc.yml . COPY ./.yarn/plugins .yarn/plugins COPY ./.yarn/releases .yarn/releases +COPY ./.yarn/patches .yarn/patches COPY ./ee/apps/${SERVICE}/package.json ee/apps/${SERVICE}/package.json ENV NODE_ENV=production \ diff --git a/ee/apps/authorization-service/package.json b/ee/apps/authorization-service/package.json index 67541bcffc22..9eac1c8b04fc 100644 --- a/ee/apps/authorization-service/package.json +++ b/ee/apps/authorization-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/authorization-service", "private": true, - "version": "0.2.7-rc.1", + "version": "0.2.8-rc.4", "description": "Rocket.Chat Authorization service", "scripts": { "build": "tsc -p tsconfig.json", @@ -30,7 +30,7 @@ "gc-stats": "^1.4.0", "mem": "^8.1.1", "moleculer": "^0.14.29", - "mongodb": "^4.12.1", + "mongodb": "^4.17.1", "nats": "^2.4.0", "pino": "^8.15.0", "polka": "^0.5.2" diff --git a/ee/apps/ddp-streamer/CHANGELOG.md b/ee/apps/ddp-streamer/CHANGELOG.md index 31ecba3b2705..1054c42ff2de 100644 --- a/ee/apps/ddp-streamer/CHANGELOG.md +++ b/ee/apps/ddp-streamer/CHANGELOG.md @@ -1,6 +1,42 @@ # @rocket.chat/ddp-streamer -## 0.1.7-rc.1 +## 0.1.8-rc.4 + +### Patch Changes + +- @rocket.chat/core-typings@6.4.0-rc.4 +- @rocket.chat/rest-typings@6.4.0-rc.4 +- @rocket.chat/core-services@0.2.0-rc.4 +- @rocket.chat/model-typings@0.1.0-rc.4 +- @rocket.chat/ui-contexts@2.0.0-rc.4 +- @rocket.chat/models@0.0.14-rc.4 +- @rocket.chat/instance-status@0.0.14-rc.4 + +## 0.1.8-rc.3 + +### Patch Changes + +- @rocket.chat/core-typings@6.4.0-rc.3 +- @rocket.chat/rest-typings@6.4.0-rc.3 +- @rocket.chat/core-services@0.2.0-rc.3 +- @rocket.chat/model-typings@0.1.0-rc.3 +- @rocket.chat/ui-contexts@2.0.0-rc.3 +- @rocket.chat/models@0.0.13-rc.3 +- @rocket.chat/instance-status@0.0.13-rc.3 + +## 0.1.8-rc.2 + +### Patch Changes + +- @rocket.chat/core-typings@6.4.0-rc.2 +- @rocket.chat/rest-typings@6.4.0-rc.2 +- @rocket.chat/core-services@0.2.0-rc.2 +- @rocket.chat/model-typings@0.1.0-rc.2 +- @rocket.chat/ui-contexts@2.0.0-rc.2 +- @rocket.chat/models@0.0.13-rc.2 +- @rocket.chat/instance-status@0.0.13-rc.2 + +## 0.1.8-rc.1 ### Patch Changes @@ -12,7 +48,7 @@ - @rocket.chat/models@0.0.11-rc.1 - @rocket.chat/instance-status@0.0.11-rc.1 -## 0.1.7-rc.0 +## 0.1.8-rc.0 ### Patch Changes @@ -43,6 +79,19 @@ - @rocket.chat/ui-contexts@2.0.0-rc.0 - @rocket.chat/models@0.0.11-rc.0 - @rocket.chat/instance-status@0.0.11-rc.0 + +## 0.1.7 + +### Patch Changes + +- @rocket.chat/core-typings@6.3.7 +- @rocket.chat/rest-typings@6.3.7 +- @rocket.chat/core-services@0.1.7 +- @rocket.chat/model-typings@0.0.13 +- @rocket.chat/ui-contexts@1.0.7 +- @rocket.chat/models@0.0.13 +- @rocket.chat/instance-status@0.0.13 + ## 0.1.6 ### Patch Changes diff --git a/ee/apps/ddp-streamer/Dockerfile b/ee/apps/ddp-streamer/Dockerfile index 9a3f9ef9c582..5250e48bf106 100644 --- a/ee/apps/ddp-streamer/Dockerfile +++ b/ee/apps/ddp-streamer/Dockerfile @@ -41,6 +41,7 @@ COPY ./yarn.lock . COPY ./.yarnrc.yml . COPY ./.yarn/plugins .yarn/plugins COPY ./.yarn/releases .yarn/releases +COPY ./.yarn/patches .yarn/patches COPY ./ee/apps/${SERVICE}/package.json ee/apps/${SERVICE}/package.json ENV NODE_ENV=production \ diff --git a/ee/apps/ddp-streamer/package.json b/ee/apps/ddp-streamer/package.json index 9b6e9120ac64..893bc8f09509 100644 --- a/ee/apps/ddp-streamer/package.json +++ b/ee/apps/ddp-streamer/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/ddp-streamer", "private": true, - "version": "0.1.7-rc.1", + "version": "0.1.8-rc.4", "description": "Rocket.Chat DDP-Streamer service", "scripts": { "build": "tsc -p tsconfig.json", @@ -35,7 +35,7 @@ "jaeger-client": "^3.19.0", "mem": "^8.1.1", "moleculer": "^0.14.29", - "mongodb": "^4.12.1", + "mongodb": "^4.17.1", "nats": "^2.4.0", "pino": "^8.15.0", "polka": "^0.5.2", diff --git a/ee/apps/omnichannel-transcript/CHANGELOG.md b/ee/apps/omnichannel-transcript/CHANGELOG.md index 3792b27f8777..eea1e8489b1b 100644 --- a/ee/apps/omnichannel-transcript/CHANGELOG.md +++ b/ee/apps/omnichannel-transcript/CHANGELOG.md @@ -1,5 +1,51 @@ # @rocket.chat/omnichannel-transcript +## 0.2.8-rc.4 + +### Patch Changes + +- @rocket.chat/core-typings@6.4.0-rc.4 +- @rocket.chat/omnichannel-services@0.0.14-rc.4 +- @rocket.chat/pdf-worker@0.0.14-rc.4 +- @rocket.chat/core-services@0.2.0-rc.4 +- @rocket.chat/model-typings@0.1.0-rc.4 +- @rocket.chat/models@0.0.14-rc.4 + +## 0.2.8-rc.3 + +## 0.2.7 + +### Patch Changes + +- @rocket.chat/core-typings@6.3.7 +- @rocket.chat/omnichannel-services@0.0.13 +- @rocket.chat/pdf-worker@0.0.13 +- @rocket.chat/core-services@0.1.7 +- @rocket.chat/model-typings@0.0.13 +- @rocket.chat/models@0.0.13 + +## 0.2.6 + +### Patch Changes + +- @rocket.chat/core-typings@6.4.0-rc.3 +- @rocket.chat/omnichannel-services@0.0.13-rc.3 +- @rocket.chat/pdf-worker@0.0.13-rc.3 +- @rocket.chat/core-services@0.2.0-rc.3 +- @rocket.chat/model-typings@0.1.0-rc.3 +- @rocket.chat/models@0.0.13-rc.3 + +## 0.2.7-rc.2 + +### Patch Changes + +- @rocket.chat/core-typings@6.4.0-rc.2 +- @rocket.chat/omnichannel-services@0.0.13-rc.2 +- @rocket.chat/pdf-worker@0.0.13-rc.2 +- @rocket.chat/core-services@0.2.0-rc.2 +- @rocket.chat/model-typings@0.1.0-rc.2 +- @rocket.chat/models@0.0.13-rc.2 + ## 0.2.7-rc.1 ### Patch Changes diff --git a/ee/apps/omnichannel-transcript/Dockerfile b/ee/apps/omnichannel-transcript/Dockerfile index cc27cd7de9b5..95fb836e9f27 100644 --- a/ee/apps/omnichannel-transcript/Dockerfile +++ b/ee/apps/omnichannel-transcript/Dockerfile @@ -41,6 +41,7 @@ COPY ./yarn.lock . COPY ./.yarnrc.yml . COPY ./.yarn/plugins .yarn/plugins COPY ./.yarn/releases .yarn/releases +COPY ./.yarn/patches .yarn/patches COPY ./ee/apps/${SERVICE}/package.json ee/apps/${SERVICE}/package.json ENV NODE_ENV=production \ diff --git a/ee/apps/omnichannel-transcript/package.json b/ee/apps/omnichannel-transcript/package.json index d49a70a5ba97..851626cbe980 100644 --- a/ee/apps/omnichannel-transcript/package.json +++ b/ee/apps/omnichannel-transcript/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/omnichannel-transcript", "private": true, - "version": "0.2.7-rc.1", + "version": "0.2.8-rc.4", "description": "Rocket.Chat service", "scripts": { "build": "tsc -p tsconfig.json", @@ -36,7 +36,7 @@ "moleculer": "^0.14.29", "moment-timezone": "^0.5.43", "mongo-message-queue": "^1.0.0", - "mongodb": "^4.12.1", + "mongodb": "^4.17.1", "nats": "^2.4.0", "pino": "^8.15.0", "polka": "^0.5.2" diff --git a/ee/apps/presence-service/CHANGELOG.md b/ee/apps/presence-service/CHANGELOG.md index 41ae24166a9d..7c2478a73718 100644 --- a/ee/apps/presence-service/CHANGELOG.md +++ b/ee/apps/presence-service/CHANGELOG.md @@ -1,6 +1,37 @@ # @rocket.chat/presence-service -## 0.2.7-rc.1 +## 0.2.8-rc.4 + +### Patch Changes + +- @rocket.chat/core-typings@6.4.0-rc.4 +- @rocket.chat/presence@0.0.14-rc.4 +- @rocket.chat/core-services@0.2.0-rc.4 +- @rocket.chat/model-typings@0.1.0-rc.4 +- @rocket.chat/models@0.0.14-rc.4 + +## 0.2.8-rc.3 + +### Patch Changes + +- Updated dependencies [d9a150000d] + - @rocket.chat/presence@0.0.13-rc.3 + - @rocket.chat/core-typings@6.4.0-rc.3 + - @rocket.chat/core-services@0.2.0-rc.3 + - @rocket.chat/model-typings@0.1.0-rc.3 + - @rocket.chat/models@0.0.13-rc.3 + +## 0.2.8-rc.2 + +### Patch Changes + +- @rocket.chat/core-typings@6.4.0-rc.2 +- @rocket.chat/presence@0.0.13-rc.2 +- @rocket.chat/core-services@0.2.0-rc.2 +- @rocket.chat/model-typings@0.1.0-rc.2 +- @rocket.chat/models@0.0.13-rc.2 + +## 0.2.8-rc.1 ### Patch Changes @@ -10,7 +41,7 @@ - @rocket.chat/model-typings@0.1.0-rc.1 - @rocket.chat/models@0.0.11-rc.1 -## 0.2.7-rc.0 +## 0.2.8-rc.0 ### Patch Changes @@ -33,6 +64,18 @@ - @rocket.chat/core-services@0.2.0-rc.0 - @rocket.chat/presence@0.0.11-rc.0 - @rocket.chat/models@0.0.11-rc.0 + +## 0.2.7 + +### Patch Changes + +- Updated dependencies [c655be17ca] + - @rocket.chat/presence@0.0.13 + - @rocket.chat/core-typings@6.3.7 + - @rocket.chat/core-services@0.1.7 + - @rocket.chat/model-typings@0.0.13 + - @rocket.chat/models@0.0.13 + ## 0.2.6 ### Patch Changes diff --git a/ee/apps/presence-service/Dockerfile b/ee/apps/presence-service/Dockerfile index 5db19b7c0900..f85c45246f29 100644 --- a/ee/apps/presence-service/Dockerfile +++ b/ee/apps/presence-service/Dockerfile @@ -35,6 +35,7 @@ COPY ./yarn.lock . COPY ./.yarnrc.yml . COPY ./.yarn/plugins .yarn/plugins COPY ./.yarn/releases .yarn/releases +COPY ./.yarn/patches .yarn/patches COPY ./ee/apps/${SERVICE}/package.json ee/apps/${SERVICE}/package.json ENV NODE_ENV=production \ diff --git a/ee/apps/presence-service/package.json b/ee/apps/presence-service/package.json index 7c7e148ba935..9dd31e8c0ffd 100644 --- a/ee/apps/presence-service/package.json +++ b/ee/apps/presence-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/presence-service", "private": true, - "version": "0.2.7-rc.1", + "version": "0.2.8-rc.4", "description": "Rocket.Chat Presence service", "scripts": { "build": "tsc -p tsconfig.json", @@ -30,7 +30,7 @@ "gc-stats": "^1.4.0", "mem": "^8.1.1", "moleculer": "^0.14.29", - "mongodb": "^4.12.1", + "mongodb": "^4.17.1", "nats": "^2.4.0", "pino": "^8.15.0", "polka": "^0.5.2" diff --git a/ee/apps/queue-worker/CHANGELOG.md b/ee/apps/queue-worker/CHANGELOG.md index 9e91d31dfa00..adb2e6c38e2e 100644 --- a/ee/apps/queue-worker/CHANGELOG.md +++ b/ee/apps/queue-worker/CHANGELOG.md @@ -1,6 +1,36 @@ # @rocket.chat/queue-worker -## 0.2.7-rc.1 +## 0.2.8-rc.4 + +### Patch Changes + +- @rocket.chat/core-typings@6.4.0-rc.4 +- @rocket.chat/omnichannel-services@0.0.14-rc.4 +- @rocket.chat/core-services@0.2.0-rc.4 +- @rocket.chat/model-typings@0.1.0-rc.4 +- @rocket.chat/models@0.0.14-rc.4 + +## 0.2.8-rc.3 + +### Patch Changes + +- @rocket.chat/core-typings@6.4.0-rc.3 +- @rocket.chat/omnichannel-services@0.0.13-rc.3 +- @rocket.chat/core-services@0.2.0-rc.3 +- @rocket.chat/model-typings@0.1.0-rc.3 +- @rocket.chat/models@0.0.13-rc.3 + +## 0.2.8-rc.2 + +### Patch Changes + +- @rocket.chat/core-typings@6.4.0-rc.2 +- @rocket.chat/omnichannel-services@0.0.13-rc.2 +- @rocket.chat/core-services@0.2.0-rc.2 +- @rocket.chat/model-typings@0.1.0-rc.2 +- @rocket.chat/models@0.0.13-rc.2 + +## 0.2.8-rc.1 ### Patch Changes @@ -10,7 +40,7 @@ - @rocket.chat/model-typings@0.1.0-rc.1 - @rocket.chat/models@0.0.11-rc.1 -## 0.2.7-rc.0 +## 0.2.8-rc.0 ### Patch Changes @@ -33,6 +63,17 @@ - @rocket.chat/core-services@0.2.0-rc.0 - @rocket.chat/omnichannel-services@0.0.11-rc.0 - @rocket.chat/models@0.0.11-rc.0 + +## 0.2.7 + +### Patch Changes + +- @rocket.chat/core-typings@6.3.7 +- @rocket.chat/omnichannel-services@0.0.13 +- @rocket.chat/core-services@0.1.7 +- @rocket.chat/model-typings@0.0.13 +- @rocket.chat/models@0.0.13 + ## 0.2.6 ### Patch Changes diff --git a/ee/apps/queue-worker/Dockerfile b/ee/apps/queue-worker/Dockerfile index cc27cd7de9b5..95fb836e9f27 100644 --- a/ee/apps/queue-worker/Dockerfile +++ b/ee/apps/queue-worker/Dockerfile @@ -41,6 +41,7 @@ COPY ./yarn.lock . COPY ./.yarnrc.yml . COPY ./.yarn/plugins .yarn/plugins COPY ./.yarn/releases .yarn/releases +COPY ./.yarn/patches .yarn/patches COPY ./ee/apps/${SERVICE}/package.json ee/apps/${SERVICE}/package.json ENV NODE_ENV=production \ diff --git a/ee/apps/queue-worker/package.json b/ee/apps/queue-worker/package.json index f94aef6bc2cb..31aacc6c7c1b 100644 --- a/ee/apps/queue-worker/package.json +++ b/ee/apps/queue-worker/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/queue-worker", "private": true, - "version": "0.2.7-rc.1", + "version": "0.2.8-rc.4", "description": "Rocket.Chat service", "scripts": { "build": "tsc -p tsconfig.json", @@ -34,7 +34,7 @@ "moleculer": "^0.14.29", "moment-timezone": "^0.5.43", "mongo-message-queue": "^1.0.0", - "mongodb": "^4.12.1", + "mongodb": "^4.17.1", "nats": "^2.4.0", "pino": "^8.15.0", "polka": "^0.5.2" diff --git a/ee/apps/stream-hub-service/CHANGELOG.md b/ee/apps/stream-hub-service/CHANGELOG.md index fcb6517da230..eb569a157edc 100644 --- a/ee/apps/stream-hub-service/CHANGELOG.md +++ b/ee/apps/stream-hub-service/CHANGELOG.md @@ -1,6 +1,33 @@ # @rocket.chat/stream-hub-service -## 0.2.7-rc.1 +## 0.2.8-rc.4 + +### Patch Changes + +- @rocket.chat/core-typings@6.4.0-rc.4 +- @rocket.chat/core-services@0.2.0-rc.4 +- @rocket.chat/model-typings@0.1.0-rc.4 +- @rocket.chat/models@0.0.14-rc.4 + +## 0.2.8-rc.3 + +### Patch Changes + +- @rocket.chat/core-typings@6.4.0-rc.3 +- @rocket.chat/core-services@0.2.0-rc.3 +- @rocket.chat/model-typings@0.1.0-rc.3 +- @rocket.chat/models@0.0.13-rc.3 + +## 0.2.8-rc.2 + +### Patch Changes + +- @rocket.chat/core-typings@6.4.0-rc.2 +- @rocket.chat/core-services@0.2.0-rc.2 +- @rocket.chat/model-typings@0.1.0-rc.2 +- @rocket.chat/models@0.0.13-rc.2 + +## 0.2.8-rc.1 ### Patch Changes @@ -9,7 +36,7 @@ - @rocket.chat/model-typings@0.1.0-rc.1 - @rocket.chat/models@0.0.11-rc.1 -## 0.2.7-rc.0 +## 0.2.8-rc.0 ### Patch Changes @@ -31,6 +58,16 @@ - @rocket.chat/model-typings@0.1.0-rc.0 - @rocket.chat/core-services@0.2.0-rc.0 - @rocket.chat/models@0.0.11-rc.0 + +## 0.2.7 + +### Patch Changes + +- @rocket.chat/core-typings@6.3.7 +- @rocket.chat/core-services@0.1.7 +- @rocket.chat/model-typings@0.0.13 +- @rocket.chat/models@0.0.13 + ## 0.2.6 ### Patch Changes diff --git a/ee/apps/stream-hub-service/Dockerfile b/ee/apps/stream-hub-service/Dockerfile index 2bc54c250389..c06115c887f5 100644 --- a/ee/apps/stream-hub-service/Dockerfile +++ b/ee/apps/stream-hub-service/Dockerfile @@ -32,6 +32,7 @@ COPY ./yarn.lock . COPY ./.yarnrc.yml . COPY ./.yarn/plugins .yarn/plugins COPY ./.yarn/releases .yarn/releases +COPY ./.yarn/patches .yarn/patches COPY ./ee/apps/${SERVICE}/package.json ee/apps/${SERVICE}/package.json ENV NODE_ENV=production \ diff --git a/ee/apps/stream-hub-service/package.json b/ee/apps/stream-hub-service/package.json index a204e8e472cc..43753c77c78d 100644 --- a/ee/apps/stream-hub-service/package.json +++ b/ee/apps/stream-hub-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/stream-hub-service", "private": true, - "version": "0.2.7-rc.1", + "version": "0.2.8-rc.4", "description": "Rocket.Chat Stream Hub service", "scripts": { "build": "tsc -p tsconfig.json", @@ -30,7 +30,7 @@ "gc-stats": "^1.4.0", "mem": "^8.1.1", "moleculer": "^0.14.29", - "mongodb": "^4.12.1", + "mongodb": "^4.17.1", "nats": "^2.4.0", "pino": "^8.15.0", "polka": "^0.5.2" diff --git a/ee/packages/api-client/CHANGELOG.md b/ee/packages/api-client/CHANGELOG.md index 223cbcb9626e..8369eeee332f 100644 --- a/ee/packages/api-client/CHANGELOG.md +++ b/ee/packages/api-client/CHANGELOG.md @@ -1,13 +1,34 @@ # @rocket.chat/api-client -## 0.1.7-rc.1 +## 0.1.8-rc.4 + +### Patch Changes + +- @rocket.chat/core-typings@6.4.0-rc.4 +- @rocket.chat/rest-typings@6.4.0-rc.4 + +## 0.1.8-rc.3 + +### Patch Changes + +- @rocket.chat/core-typings@6.4.0-rc.3 +- @rocket.chat/rest-typings@6.4.0-rc.3 + +## 0.1.8-rc.2 + +### Patch Changes + +- @rocket.chat/core-typings@6.4.0-rc.2 +- @rocket.chat/rest-typings@6.4.0-rc.2 + +## 0.1.8-rc.1 ### Patch Changes - @rocket.chat/core-typings@6.4.0-rc.1 - @rocket.chat/rest-typings@6.4.0-rc.1 -## 0.1.7-rc.0 +## 0.1.8-rc.0 ### Patch Changes @@ -25,6 +46,14 @@ - Updated dependencies [93d4912e17] - @rocket.chat/core-typings@6.4.0-rc.0 - @rocket.chat/rest-typings@6.4.0-rc.0 + +## 0.1.7 + +### Patch Changes + +- @rocket.chat/core-typings@6.3.7 +- @rocket.chat/rest-typings@6.3.7 + ## 0.1.6 ### Patch Changes diff --git a/ee/packages/api-client/package.json b/ee/packages/api-client/package.json index 963df9c96db5..1fe0aaf539d0 100644 --- a/ee/packages/api-client/package.json +++ b/ee/packages/api-client/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/api-client", - "version": "0.1.7-rc.1", + "version": "0.1.8-rc.4", "devDependencies": { "@swc/core": "^1.3.66", "@swc/jest": "^0.2.26", diff --git a/ee/packages/ddp-client/CHANGELOG.md b/ee/packages/ddp-client/CHANGELOG.md index 8b2691b5445f..dd1327fb6042 100644 --- a/ee/packages/ddp-client/CHANGELOG.md +++ b/ee/packages/ddp-client/CHANGELOG.md @@ -1,11 +1,32 @@ # @rocket.chat/ddp-client +## 0.2.0-rc.4 + +### Patch Changes + +- @rocket.chat/rest-typings@6.4.0-rc.4 +- @rocket.chat/api-client@0.1.8-rc.4 + +## 0.2.0-rc.3 + +### Patch Changes + +- @rocket.chat/rest-typings@6.4.0-rc.3 +- @rocket.chat/api-client@0.1.8-rc.3 + +## 0.2.0-rc.2 + +### Patch Changes + +- @rocket.chat/rest-typings@6.4.0-rc.2 +- @rocket.chat/api-client@0.1.8-rc.2 + ## 0.2.0-rc.1 ### Patch Changes - @rocket.chat/rest-typings@6.4.0-rc.1 -- @rocket.chat/api-client@0.1.5-rc.1 +- @rocket.chat/api-client@0.1.8-rc.1 ## 0.2.0-rc.0 @@ -26,6 +47,14 @@ - Updated dependencies [93d4912e17] - @rocket.chat/rest-typings@6.4.0-rc.0 - @rocket.chat/api-client@0.1.5-rc.0 + +## 0.1.7 + +### Patch Changes + +- @rocket.chat/rest-typings@6.3.7 +- @rocket.chat/api-client@0.1.7 + ## 0.1.6 ### Patch Changes diff --git a/ee/packages/ddp-client/package.json b/ee/packages/ddp-client/package.json index fe74871830c1..0c64d9117894 100644 --- a/ee/packages/ddp-client/package.json +++ b/ee/packages/ddp-client/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ddp-client", - "version": "0.2.0-rc.1", + "version": "0.2.0-rc.4", "devDependencies": { "@swc/core": "^1.3.66", "@swc/jest": "^0.2.26", diff --git a/ee/packages/omnichannel-services/CHANGELOG.md b/ee/packages/omnichannel-services/CHANGELOG.md index 1465f2f6b96d..5d4f0468c000 100644 --- a/ee/packages/omnichannel-services/CHANGELOG.md +++ b/ee/packages/omnichannel-services/CHANGELOG.md @@ -1,17 +1,50 @@ # @rocket.chat/omnichannel-services -## 0.0.13-rc.1 +## 0.0.14-rc.4 + +### Patch Changes + +- @rocket.chat/core-typings@6.4.0-rc.4 +- @rocket.chat/rest-typings@6.4.0-rc.4 +- @rocket.chat/pdf-worker@0.0.14-rc.4 +- @rocket.chat/core-services@0.2.0-rc.4 +- @rocket.chat/model-typings@0.1.0-rc.4 +- @rocket.chat/models@0.0.14-rc.4 + +## 0.0.14-rc.3 + +### Patch Changes + +- @rocket.chat/core-typings@6.4.0-rc.3 +- @rocket.chat/rest-typings@6.4.0-rc.3 +- @rocket.chat/pdf-worker@0.0.14-rc.3 +- @rocket.chat/core-services@0.2.0-rc.3 +- @rocket.chat/model-typings@0.1.0-rc.3 +- @rocket.chat/models@0.0.14-rc.3 + +## 0.0.14-rc.2 + +### Patch Changes + +- @rocket.chat/core-typings@6.4.0-rc.2 +- @rocket.chat/rest-typings@6.4.0-rc.2 +- @rocket.chat/pdf-worker@0.0.14-rc.2 +- @rocket.chat/core-services@0.2.0-rc.2 +- @rocket.chat/model-typings@0.1.0-rc.2 +- @rocket.chat/models@0.0.14-rc.2 + +## 0.0.14-rc.1 ### Patch Changes - @rocket.chat/core-typings@6.4.0-rc.1 - @rocket.chat/rest-typings@6.4.0-rc.1 -- @rocket.chat/pdf-worker@0.0.13-rc.1 +- @rocket.chat/pdf-worker@0.0.14-rc.1 - @rocket.chat/core-services@0.2.0-rc.1 - @rocket.chat/model-typings@0.1.0-rc.1 -- @rocket.chat/models@0.0.13-rc.1 +- @rocket.chat/models@0.0.14-rc.1 -## 0.0.13-rc.0 +## 0.0.14-rc.0 ### Patch Changes @@ -39,6 +72,18 @@ - @rocket.chat/core-services@0.2.0-rc.0 - @rocket.chat/pdf-worker@0.0.11-rc.0 - @rocket.chat/models@0.0.11-rc.0 + +## 0.0.13 + +### Patch Changes + +- @rocket.chat/core-typings@6.3.7 +- @rocket.chat/rest-typings@6.3.7 +- @rocket.chat/pdf-worker@0.0.13 +- @rocket.chat/core-services@0.1.7 +- @rocket.chat/model-typings@0.0.13 +- @rocket.chat/models@0.0.13 + ## 0.0.12 ### Patch Changes diff --git a/ee/packages/omnichannel-services/package.json b/ee/packages/omnichannel-services/package.json index 969ac8d4517e..17a71abc3da5 100644 --- a/ee/packages/omnichannel-services/package.json +++ b/ee/packages/omnichannel-services/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/omnichannel-services", - "version": "0.0.13-rc.1", + "version": "0.0.14-rc.4", "private": true, "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", @@ -29,7 +29,7 @@ "mem": "^8.1.1", "moment-timezone": "^0.5.43", "mongo-message-queue": "^1.0.0", - "mongodb": "^4.12.1", + "mongodb": "^4.17.1", "pino": "^8.15.0" }, "scripts": { diff --git a/ee/packages/pdf-worker/CHANGELOG.md b/ee/packages/pdf-worker/CHANGELOG.md index 624f93717870..13dc1a43e0f5 100644 --- a/ee/packages/pdf-worker/CHANGELOG.md +++ b/ee/packages/pdf-worker/CHANGELOG.md @@ -1,12 +1,30 @@ # @rocket.chat/pdf-worker -## 0.0.13-rc.1 +## 0.0.14-rc.4 + +### Patch Changes + +- @rocket.chat/core-typings@6.4.0-rc.4 + +## 0.0.14-rc.3 + +### Patch Changes + +- @rocket.chat/core-typings@6.4.0-rc.3 + +## 0.0.14-rc.2 + +### Patch Changes + +- @rocket.chat/core-typings@6.4.0-rc.2 + +## 0.0.14-rc.1 ### Patch Changes - @rocket.chat/core-typings@6.4.0-rc.1 -## 0.0.13-rc.0 +## 0.0.14-rc.0 ### Patch Changes @@ -18,6 +36,13 @@ - Updated dependencies [61128364d6] - Updated dependencies [d45365436e] - @rocket.chat/core-typings@6.4.0-rc.0 + +## 0.0.13 + +### Patch Changes + +- @rocket.chat/core-typings@6.3.7 + ## 0.0.12 ### Patch Changes diff --git a/ee/packages/pdf-worker/package.json b/ee/packages/pdf-worker/package.json index aeeb4c16303e..daa5105e3fdc 100644 --- a/ee/packages/pdf-worker/package.json +++ b/ee/packages/pdf-worker/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/pdf-worker", - "version": "0.0.13-rc.1", + "version": "0.0.14-rc.4", "private": true, "devDependencies": { "@storybook/addon-essentials": "~6.5.16", diff --git a/ee/packages/presence/CHANGELOG.md b/ee/packages/presence/CHANGELOG.md index df81eb37e1e0..befd96b837ee 100644 --- a/ee/packages/presence/CHANGELOG.md +++ b/ee/packages/presence/CHANGELOG.md @@ -1,6 +1,31 @@ # @rocket.chat/presence -## 0.0.13-rc.1 +## 0.0.14-rc.4 + +### Patch Changes + +- @rocket.chat/core-typings@6.4.0-rc.4 +- @rocket.chat/core-services@0.2.0-rc.4 +- @rocket.chat/models@0.0.14-rc.4 + +## 0.0.14-rc.3 + +### Patch Changes + +- d9a150000d: Fixed presence broadcast being disabled on server restart + - @rocket.chat/core-typings@6.4.0-rc.3 + - @rocket.chat/core-services@0.2.0-rc.3 + - @rocket.chat/models@0.0.14-rc.3 + +## 0.0.14-rc.2 + +### Patch Changes + +- @rocket.chat/core-typings@6.4.0-rc.2 +- @rocket.chat/core-services@0.2.0-rc.2 +- @rocket.chat/models@0.0.14-rc.2 + +## 0.0.14-rc.1 ### Patch Changes @@ -8,7 +33,7 @@ - @rocket.chat/core-services@0.2.0-rc.1 - @rocket.chat/models@0.0.11-rc.1 -## 0.0.13-rc.0 +## 0.0.14-rc.0 ### Patch Changes @@ -24,6 +49,16 @@ - @rocket.chat/core-typings@6.4.0-rc.0 - @rocket.chat/core-services@0.2.0-rc.0 - @rocket.chat/models@0.0.11-rc.0 + +## 0.0.13 + +### Patch Changes + +- c655be17ca: Fixed presence broadcast being disabled on server restart + - @rocket.chat/core-typings@6.3.7 + - @rocket.chat/core-services@0.1.7 + - @rocket.chat/models@0.0.13 + ## 0.0.12 ### Patch Changes diff --git a/ee/packages/presence/package.json b/ee/packages/presence/package.json index 63b1c585ec6a..9011dab086b6 100644 --- a/ee/packages/presence/package.json +++ b/ee/packages/presence/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/presence", - "version": "0.0.13-rc.1", + "version": "0.0.14-rc.4", "private": true, "devDependencies": { "@babel/core": "~7.22.9", @@ -32,6 +32,6 @@ "@rocket.chat/core-services": "workspace:^", "@rocket.chat/core-typings": "workspace:^", "@rocket.chat/models": "workspace:^", - "mongodb": "^4.12.1" + "mongodb": "^4.17.1" } } diff --git a/package.json b/package.json index 7d3e08d4f5a6..f9029efb8b66 100644 --- a/package.json +++ b/package.json @@ -63,6 +63,7 @@ "minimist": "1.2.6", "adm-zip": "0.5.9", "preact@10.15.1": "patch:preact@npm:10.15.1#.yarn/patches/preact-npm-10.15.1-bd458de913.patch", - "@storybook/react-docgen-typescript-plugin@1.0.2-canary.6.9d540b91e815f8fc2f8829189deb00553559ff63.0": "patch:@storybook/react-docgen-typescript-plugin@npm%3A1.0.2-canary.6.9d540b91e815f8fc2f8829189deb00553559ff63.0#./.yarn/patches/@storybook-react-docgen-typescript-plugin-npm-1.0.2-canary.6.9d540b91e815f8fc2f8829189deb00553559ff63.0-b31cc57c40.patch" + "@storybook/react-docgen-typescript-plugin@1.0.2-canary.6.9d540b91e815f8fc2f8829189deb00553559ff63.0": "patch:@storybook/react-docgen-typescript-plugin@npm%3A1.0.2-canary.6.9d540b91e815f8fc2f8829189deb00553559ff63.0#./.yarn/patches/@storybook-react-docgen-typescript-plugin-npm-1.0.2-canary.6.9d540b91e815f8fc2f8829189deb00553559ff63.0-b31cc57c40.patch", + "mongodb@^4.17.1": "patch:mongodb@npm:4.17.1#.yarn/patches/mongodb-npm-4.17.1-a2fe811ff1.patch" } } diff --git a/packages/agenda/package.json b/packages/agenda/package.json index dfdeb009c090..f533e05dba28 100644 --- a/packages/agenda/package.json +++ b/packages/agenda/package.json @@ -9,7 +9,7 @@ "debug": "~4.1.1", "human-interval": "^2.0.1", "moment-timezone": "~0.5.43", - "mongodb": "^4.12.1" + "mongodb": "^4.17.1" }, "devDependencies": { "@types/debug": "^4.1.8", diff --git a/packages/core-services/CHANGELOG.md b/packages/core-services/CHANGELOG.md index b2df91a73bd7..0f067001c3be 100644 --- a/packages/core-services/CHANGELOG.md +++ b/packages/core-services/CHANGELOG.md @@ -1,12 +1,36 @@ # @rocket.chat/core-services +## 0.2.0-rc.4 + +### Patch Changes + +- @rocket.chat/core-typings@6.4.0-rc.4 +- @rocket.chat/rest-typings@6.4.0-rc.4 +- @rocket.chat/models@0.0.14-rc.4 + +## 0.2.0-rc.3 + +### Patch Changes + +- @rocket.chat/core-typings@6.4.0-rc.3 +- @rocket.chat/rest-typings@6.4.0-rc.3 +- @rocket.chat/models@0.0.14-rc.3 + +## 0.2.0-rc.2 + +### Patch Changes + +- @rocket.chat/core-typings@6.4.0-rc.2 +- @rocket.chat/rest-typings@6.4.0-rc.2 +- @rocket.chat/models@0.0.14-rc.2 + ## 0.2.0-rc.1 ### Patch Changes - @rocket.chat/core-typings@6.4.0-rc.1 - @rocket.chat/rest-typings@6.4.0-rc.1 -- @rocket.chat/models@0.0.11-rc.1 +- @rocket.chat/models@0.0.14-rc.1 ## 0.2.0-rc.0 @@ -32,6 +56,15 @@ - @rocket.chat/core-typings@6.4.0-rc.0 - @rocket.chat/rest-typings@6.4.0-rc.0 - @rocket.chat/models@0.0.11-rc.0 + +## 0.1.7 + +### Patch Changes + +- @rocket.chat/core-typings@6.3.7 +- @rocket.chat/rest-typings@6.3.7 +- @rocket.chat/models@0.0.13 + ## 0.1.6 ### Patch Changes diff --git a/packages/core-services/package.json b/packages/core-services/package.json index f4e05cf08e5b..4cce8aebe07b 100644 --- a/packages/core-services/package.json +++ b/packages/core-services/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/core-services", - "version": "0.2.0-rc.1", + "version": "0.2.0-rc.4", "private": true, "devDependencies": { "@babel/core": "~7.22.9", @@ -13,7 +13,7 @@ "babel-jest": "^29.5.0", "eslint": "~8.45.0", "jest": "~29.6.1", - "mongodb": "^4.12.1", + "mongodb": "^4.17.1", "prettier": "~2.8.8", "typescript": "~5.2.2" }, diff --git a/packages/core-services/src/types/IMessageService.ts b/packages/core-services/src/types/IMessageService.ts index ea8f207df67d..b38d6a9559d6 100644 --- a/packages/core-services/src/types/IMessageService.ts +++ b/packages/core-services/src/types/IMessageService.ts @@ -9,6 +9,7 @@ export interface IMessageService { user: Pick, extraData?: Partial, ): Promise; + beforeSave(param: { message: IMessage; room: IRoom; user: IUser }): Promise; sendMessageWithValidation(user: IUser, message: Partial, room: Partial, upsert?: boolean): Promise; deleteMessage(user: IUser, message: IMessage): Promise; updateMessage(message: IMessage, user: IUser, originalMsg?: IMessage): Promise; diff --git a/packages/core-services/src/types/IRoomService.ts b/packages/core-services/src/types/IRoomService.ts index e69707e18a36..d9eee82029af 100644 --- a/packages/core-services/src/types/IRoomService.ts +++ b/packages/core-services/src/types/IRoomService.ts @@ -52,4 +52,5 @@ export interface IRoomService { sendMessage?: boolean, ): Promise; getRouteLink(room: AtLeast): Promise; + join(param: { room: IRoom; user: Pick; joinCode?: string }): Promise; } diff --git a/packages/core-typings/CHANGELOG.md b/packages/core-typings/CHANGELOG.md index c6075ce782ba..be66b7a23ccb 100644 --- a/packages/core-typings/CHANGELOG.md +++ b/packages/core-typings/CHANGELOG.md @@ -1,5 +1,11 @@ # @rocket.chat/core-typings +## 6.4.0-rc.4 + +## 6.4.0-rc.3 + +## 6.4.0-rc.2 + ## 6.4.0-rc.1 ## 6.4.0-rc.0 @@ -16,6 +22,9 @@ - ba24f3c21f: Fixed `default` field not being returned from the `setDefault` endpoints when setting to false - 61128364d6: Fixes a problem where the calculated time for considering the visitor abandonment was the first message from the visitor and not the visitor's reply to the agent. - d45365436e: Use group filter when set to LDAP sync process + +## 6.3.7 + ## 6.3.6 ## 6.3.5 diff --git a/packages/core-typings/package.json b/packages/core-typings/package.json index b582e15f3118..2d0b0d734897 100644 --- a/packages/core-typings/package.json +++ b/packages/core-typings/package.json @@ -1,10 +1,10 @@ { "name": "@rocket.chat/core-typings", - "version": "6.4.0-rc.1", + "version": "6.4.0-rc.4", "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", "eslint": "~8.45.0", - "mongodb": "^4.12.1", + "mongodb": "^4.17.1", "prettier": "~2.8.8", "typescript": "~5.2.2" }, diff --git a/packages/core-typings/src/ICloud.ts b/packages/core-typings/src/ICloud.ts index ce6b97ce7d77..6710e7ced9d2 100644 --- a/packages/core-typings/src/ICloud.ts +++ b/packages/core-typings/src/ICloud.ts @@ -1,5 +1,4 @@ export type CloudRegistrationStatus = { - connectToCloud: boolean; email: string; token: string; uniqueId: string; diff --git a/packages/core-typings/src/IIntegration.ts b/packages/core-typings/src/IIntegration.ts index 6b99424264b2..cffff75767f4 100644 --- a/packages/core-typings/src/IIntegration.ts +++ b/packages/core-typings/src/IIntegration.ts @@ -1,6 +1,8 @@ import type { IRocketChatRecord } from './IRocketChatRecord'; import type { IUser } from './IUser'; +export type IntegrationScriptEngine = 'vm2' | 'isolated-vm'; + export interface IIncomingIntegration extends IRocketChatRecord { type: 'webhook-incoming'; _createdBy: Pick | null; @@ -22,6 +24,8 @@ export interface IIncomingIntegration extends IRocketChatRecord { alias?: string; avatar?: string; emoji?: string; + + scriptEngine?: IntegrationScriptEngine; } export type OutgoingIntegrationEvent = @@ -65,6 +69,8 @@ export interface IOutgoingIntegration extends IRocketChatRecord { alias?: string; avatar?: string; emoji?: string; + + scriptEngine?: IntegrationScriptEngine; } export type IIntegration = IIncomingIntegration | IOutgoingIntegration; diff --git a/packages/core-typings/src/IIntegrationHistory.ts b/packages/core-typings/src/IIntegrationHistory.ts index 6297cd7d74a0..6594d611fb49 100644 --- a/packages/core-typings/src/IIntegrationHistory.ts +++ b/packages/core-typings/src/IIntegrationHistory.ts @@ -1,3 +1,4 @@ +import type { IMessage } from './IMessage'; import type { IRocketChatRecord } from './IRocketChatRecord'; export interface IIntegrationHistory extends IRocketChatRecord { @@ -17,10 +18,10 @@ export interface IIntegrationHistory extends IRocketChatRecord { finished: boolean; triggerWord?: string; - prepareSentMessage?: string; - processSentMessage?: string; + prepareSentMessage?: { channel: string; message: Partial }[]; + processSentMessage?: { channel: string; message: Partial }[]; url?: string; - httpCallData?: string; + httpCallData?: Record; httpError?: any; httpResult?: string; error?: any; diff --git a/packages/cron/CHANGELOG.md b/packages/cron/CHANGELOG.md index d763a70fc093..32872b06ffbe 100644 --- a/packages/cron/CHANGELOG.md +++ b/packages/cron/CHANGELOG.md @@ -1,13 +1,38 @@ # @rocket.chat/cron -## 0.0.9-rc.1 +## 0.0.10-rc.4 + +### Patch Changes + +- @rocket.chat/core-typings@6.4.0-rc.4 +- @rocket.chat/models@0.0.14-rc.4 + +## 0.0.11-rc.3 + +### Patch Changes + +- 61a106fbf2: Increase cron job check delay to 1 min from 5s. + + This reduces MongoDB requests introduced on 6.3. + + - @rocket.chat/core-typings@6.4.0-rc.3 + - @rocket.chat/models@0.0.14-rc.3 + +## 0.0.11-rc.2 + +### Patch Changes + +- @rocket.chat/core-typings@6.4.0-rc.2 +- @rocket.chat/models@0.0.14-rc.2 + +## 0.0.11-rc.1 ### Patch Changes - @rocket.chat/core-typings@6.4.0-rc.1 -- @rocket.chat/models@0.0.11-rc.1 +- @rocket.chat/models@0.0.14-rc.1 -## 0.0.9-rc.0 +## 0.0.11-rc.0 ### Patch Changes @@ -21,6 +46,18 @@ - @rocket.chat/core-typings@6.4.0-rc.0 - @rocket.chat/models@0.0.11-rc.0 - @rocket.chat/random@1.2.1 + +## 0.0.10 + +### Patch Changes + +- deffcb187c: Increase cron job check delay to 1 min from 5s. + + This reduces MongoDB requests introduced on 6.3. + + - @rocket.chat/core-typings@6.3.7 + - @rocket.chat/models@0.0.13 + ## 0.0.8 ### Patch Changes @@ -47,7 +84,7 @@ ### Patch Changes - @rocket.chat/core-typings@6.3.3 -- @rocket.chat/models@0.0.9 +- @rocket.chat/models@0.0.10 ## 0.0.4 diff --git a/packages/cron/package.json b/packages/cron/package.json index ed418ed4dc5b..c7db1e371cc1 100644 --- a/packages/cron/package.json +++ b/packages/cron/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/cron", - "version": "0.0.9-rc.1", + "version": "0.0.10-rc.4", "private": true, "devDependencies": { "@types/jest": "~29.5.3", @@ -26,6 +26,6 @@ "@rocket.chat/core-typings": "workspace:^", "@rocket.chat/models": "workspace:^", "@rocket.chat/random": "workspace:^", - "mongodb": "^4.12.1" + "mongodb": "^4.17.1" } } diff --git a/packages/fuselage-ui-kit/CHANGELOG.md b/packages/fuselage-ui-kit/CHANGELOG.md index a59fee43ac19..bffaa90dcb07 100644 --- a/packages/fuselage-ui-kit/CHANGELOG.md +++ b/packages/fuselage-ui-kit/CHANGELOG.md @@ -1,5 +1,29 @@ # Change Log +## 2.0.0-rc.4 + +### Patch Changes + +- @rocket.chat/gazzodown@2.0.0-rc.4 +- @rocket.chat/ui-contexts@2.0.0-rc.4 +- @rocket.chat/ui-video-conf@2.0.0-rc.4 + +## 2.0.0-rc.3 + +### Patch Changes + +- @rocket.chat/gazzodown@2.0.0-rc.3 +- @rocket.chat/ui-contexts@2.0.0-rc.3 +- @rocket.chat/ui-video-conf@2.0.0-rc.3 + +## 2.0.0-rc.2 + +### Patch Changes + +- @rocket.chat/gazzodown@2.0.0-rc.2 +- @rocket.chat/ui-contexts@2.0.0-rc.2 +- @rocket.chat/ui-video-conf@2.0.0-rc.2 + ## 2.0.0-rc.1 ### Patch Changes @@ -26,6 +50,15 @@ - @rocket.chat/eslint-config@0.6.0-rc.0 - @rocket.chat/gazzodown@2.0.0-rc.0 - @rocket.chat/ui-video-conf@2.0.0-rc.0 + +## 1.0.7 + +### Patch Changes + +- @rocket.chat/gazzodown@1.0.7 +- @rocket.chat/ui-contexts@1.0.7 +- @rocket.chat/ui-video-conf@1.0.7 + ## 1.0.6 ### Patch Changes diff --git a/packages/fuselage-ui-kit/package.json b/packages/fuselage-ui-kit/package.json index fe0d4f02a5cf..a376275d3b90 100644 --- a/packages/fuselage-ui-kit/package.json +++ b/packages/fuselage-ui-kit/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/fuselage-ui-kit", "private": true, - "version": "2.0.0-rc.1", + "version": "2.0.0-rc.4", "description": "UiKit elements for Rocket.Chat Apps built under Fuselage design system", "homepage": "https://rocketchat.github.io/Rocket.Chat.Fuselage/", "author": { @@ -46,9 +46,9 @@ "@rocket.chat/icons": "*", "@rocket.chat/prettier-config": "*", "@rocket.chat/styled": "*", - "@rocket.chat/ui-contexts": "2.0.0-rc.1", + "@rocket.chat/ui-contexts": "2.0.0-rc.4", "@rocket.chat/ui-kit": "*", - "@rocket.chat/ui-video-conf": "2.0.0-rc.1", + "@rocket.chat/ui-video-conf": "2.0.0-rc.4", "@tanstack/react-query": "*", "react": "*", "react-dom": "*" diff --git a/packages/gazzodown/CHANGELOG.md b/packages/gazzodown/CHANGELOG.md index 8eb779c96326..d0178b78e124 100644 --- a/packages/gazzodown/CHANGELOG.md +++ b/packages/gazzodown/CHANGELOG.md @@ -1,5 +1,29 @@ # @rocket.chat/gazzodown +## 2.0.0-rc.4 + +### Patch Changes + +- @rocket.chat/core-typings@6.4.0-rc.4 +- @rocket.chat/ui-contexts@2.0.0-rc.4 +- @rocket.chat/ui-client@2.0.0-rc.4 + +## 2.0.0-rc.3 + +### Patch Changes + +- @rocket.chat/core-typings@6.4.0-rc.3 +- @rocket.chat/ui-contexts@2.0.0-rc.3 +- @rocket.chat/ui-client@2.0.0-rc.3 + +## 2.0.0-rc.2 + +### Patch Changes + +- @rocket.chat/core-typings@6.4.0-rc.2 +- @rocket.chat/ui-contexts@2.0.0-rc.2 +- @rocket.chat/ui-client@2.0.0-rc.2 + ## 2.0.0-rc.1 ### Patch Changes @@ -25,6 +49,15 @@ - @rocket.chat/core-typings@6.4.0-rc.0 - @rocket.chat/ui-client@2.0.0-rc.0 - @rocket.chat/ui-contexts@2.0.0-rc.0 + +## 1.0.7 + +### Patch Changes + +- @rocket.chat/core-typings@6.3.7 +- @rocket.chat/ui-contexts@1.0.7 +- @rocket.chat/ui-client@1.0.7 + ## 1.0.6 ### Patch Changes diff --git a/packages/gazzodown/package.json b/packages/gazzodown/package.json index db80f6e36266..1b57545091f0 100644 --- a/packages/gazzodown/package.json +++ b/packages/gazzodown/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/gazzodown", - "version": "2.0.0-rc.1", + "version": "2.0.0-rc.4", "private": true, "devDependencies": { "@babel/core": "~7.22.9", @@ -65,14 +65,14 @@ "/dist" ], "peerDependencies": { - "@rocket.chat/core-typings": "6.4.0-rc.1", + "@rocket.chat/core-typings": "6.4.0-rc.4", "@rocket.chat/css-in-js": "*", "@rocket.chat/fuselage": "*", "@rocket.chat/fuselage-tokens": "*", "@rocket.chat/message-parser": "*", "@rocket.chat/styled": "*", - "@rocket.chat/ui-client": "2.0.0-rc.1", - "@rocket.chat/ui-contexts": "2.0.0-rc.1", + "@rocket.chat/ui-client": "2.0.0-rc.4", + "@rocket.chat/ui-contexts": "2.0.0-rc.4", "katex": "*", "react": "*" }, diff --git a/packages/gazzodown/src/elements/PlainSpan.tsx b/packages/gazzodown/src/elements/PlainSpan.tsx index 988ab94ca038..582490207717 100644 --- a/packages/gazzodown/src/elements/PlainSpan.tsx +++ b/packages/gazzodown/src/elements/PlainSpan.tsx @@ -1,3 +1,4 @@ +import { useTranslation } from '@rocket.chat/ui-contexts'; import { Fragment, memo, ReactElement, useContext, useMemo } from 'react'; import { MarkupInteractionContext } from '../MarkupInteractionContext'; @@ -7,6 +8,7 @@ type PlainSpanProps = { }; const PlainSpan = ({ text }: PlainSpanProps): ReactElement => { + const t = useTranslation(); const { highlightRegex, markRegex } = useContext(MarkupInteractionContext); const content = useMemo(() => { @@ -20,7 +22,7 @@ const PlainSpan = ({ text }: PlainSpanProps): ReactElement => { {chunks.map((chunk, i) => { if (i % 2 === 0) { return ( - + {chunk} ); @@ -51,7 +53,7 @@ const PlainSpan = ({ text }: PlainSpanProps): ReactElement => { } return text; - }, [text, highlightRegex, markRegex]); + }, [highlightRegex, markRegex, text, t]); return <>{content}; }; diff --git a/packages/gazzodown/src/mentions/ChannelMentionElement.tsx b/packages/gazzodown/src/mentions/ChannelMentionElement.tsx index 2c3129bbc639..c1a6c7a17fe4 100644 --- a/packages/gazzodown/src/mentions/ChannelMentionElement.tsx +++ b/packages/gazzodown/src/mentions/ChannelMentionElement.tsx @@ -1,4 +1,5 @@ import { Message } from '@rocket.chat/fuselage'; +import { useTranslation } from '@rocket.chat/ui-contexts'; import { memo, ReactElement, useContext, useMemo } from 'react'; import { MarkupInteractionContext } from '../MarkupInteractionContext'; @@ -10,6 +11,7 @@ type ChannelMentionElementProps = { const handleChannelMention = (mention: string, withSymbol: boolean | undefined): string => (withSymbol ? `#${mention}` : mention); const ChannelMentionElement = ({ mention }: ChannelMentionElementProps): ReactElement => { + const t = useTranslation(); const { resolveChannelMention, onChannelMentionClick, showMentionSymbol } = useContext(MarkupInteractionContext); const resolved = useMemo(() => resolveChannelMention?.(mention), [mention, resolveChannelMention]); @@ -20,7 +22,7 @@ const ChannelMentionElement = ({ mention }: ChannelMentionElementProps): ReactEl } return ( - + {handleChannelMention(resolved.name ?? mention, showMentionSymbol)} ); diff --git a/packages/gazzodown/src/mentions/UserMentionElement.tsx b/packages/gazzodown/src/mentions/UserMentionElement.tsx index 8ad646ea8fd8..308363309aa2 100644 --- a/packages/gazzodown/src/mentions/UserMentionElement.tsx +++ b/packages/gazzodown/src/mentions/UserMentionElement.tsx @@ -1,4 +1,5 @@ import { Message } from '@rocket.chat/fuselage'; +import { useTranslation } from '@rocket.chat/ui-contexts'; import { memo, ReactElement, useContext, useMemo } from 'react'; import { MarkupInteractionContext } from '../MarkupInteractionContext'; @@ -11,6 +12,7 @@ const handleUserMention = (mention: string | undefined, withSymbol: boolean | un withSymbol ? `@${mention}` : mention; const UserMentionElement = ({ mention }: UserMentionElementProps): ReactElement => { + const t = useTranslation(); const { resolveUserMention, onUserMentionClick, isMobile, ownUserId, useRealName, showMentionSymbol } = useContext(MarkupInteractionContext); @@ -20,11 +22,19 @@ const UserMentionElement = ({ mention }: UserMentionElementProps): ReactElement const showRealName = useRealName && !isMobile; if (mention === 'all') { - return {handleUserMention('all', showMentionSymbol)}; + return ( + + {handleUserMention('all', showMentionSymbol)} + + ); } if (mention === 'here') { - return {handleUserMention('here', showMentionSymbol)}; + return ( + + {handleUserMention('here', showMentionSymbol)} + + ); } if (!resolved) { @@ -34,7 +44,7 @@ const UserMentionElement = ({ mention }: UserMentionElementProps): ReactElement return ( { if (!queueInfo) { return; } - const formatDistance = await import('date-fns/formatDistance'); + const { default: formatDistance } = await import('date-fns/formatDistance'); const { spot, estimatedWaitTimeSeconds } = queueInfo; - const locale = getDateFnsLocale(); + const locale = await getDateFnsLocale(); const estimatedWaitTime = estimatedWaitTimeSeconds && formatDistance(new Date().setSeconds(estimatedWaitTimeSeconds), new Date(), { locale }); return ( diff --git a/packages/model-typings/CHANGELOG.md b/packages/model-typings/CHANGELOG.md index bf8c21bf1eeb..f80a0d805977 100644 --- a/packages/model-typings/CHANGELOG.md +++ b/packages/model-typings/CHANGELOG.md @@ -1,5 +1,23 @@ # @rocket.chat/model-typings +## 0.1.0-rc.4 + +### Patch Changes + +- @rocket.chat/core-typings@6.4.0-rc.4 + +## 0.1.0-rc.3 + +### Patch Changes + +- @rocket.chat/core-typings@6.4.0-rc.3 + +## 0.1.0-rc.2 + +### Patch Changes + +- @rocket.chat/core-typings@6.4.0-rc.2 + ## 0.1.0-rc.1 ### Patch Changes @@ -31,6 +49,13 @@ - Updated dependencies [61128364d6] - Updated dependencies [d45365436e] - @rocket.chat/core-typings@6.4.0-rc.0 + +## 0.0.13 + +### Patch Changes + +- @rocket.chat/core-typings@6.3.7 + ## 0.0.12 ### Patch Changes diff --git a/packages/model-typings/package.json b/packages/model-typings/package.json index f9cbc45b910c..b187c15b99c7 100644 --- a/packages/model-typings/package.json +++ b/packages/model-typings/package.json @@ -1,13 +1,13 @@ { "name": "@rocket.chat/model-typings", - "version": "0.1.0-rc.1", + "version": "0.1.0-rc.4", "private": true, "devDependencies": { "@types/jest": "~29.5.3", "@types/node-rsa": "^1.1.1", "eslint": "~8.45.0", "jest": "~29.6.1", - "mongodb": "^4.12.1", + "mongodb": "^4.17.1", "ts-jest": "~29.0.5", "typescript": "~5.2.2" }, diff --git a/packages/models/CHANGELOG.md b/packages/models/CHANGELOG.md index f116a2b9f4fa..31d2440aaa7f 100644 --- a/packages/models/CHANGELOG.md +++ b/packages/models/CHANGELOG.md @@ -1,12 +1,30 @@ # @rocket.chat/models -## 0.0.13-rc.1 +## 0.0.14-rc.4 + +### Patch Changes + +- @rocket.chat/model-typings@0.1.0-rc.4 + +## 0.0.14-rc.3 + +### Patch Changes + +- @rocket.chat/model-typings@0.1.0-rc.3 + +## 0.0.14-rc.2 + +### Patch Changes + +- @rocket.chat/model-typings@0.1.0-rc.2 + +## 0.0.14-rc.1 ### Patch Changes - @rocket.chat/model-typings@0.1.0-rc.1 -## 0.0.13-rc.0 +## 0.0.14-rc.0 ### Patch Changes @@ -18,6 +36,13 @@ - Updated dependencies [ead7c7bef2] - Updated dependencies [61128364d6] - @rocket.chat/model-typings@0.1.0-rc.0 + +## 0.0.13 + +### Patch Changes + +- @rocket.chat/model-typings@0.0.13 + ## 0.0.12 ### Patch Changes diff --git a/packages/models/package.json b/packages/models/package.json index 8ac94514b627..4dbaa73f037b 100644 --- a/packages/models/package.json +++ b/packages/models/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/models", - "version": "0.0.13-rc.1", + "version": "0.0.14-rc.4", "private": true, "devDependencies": { "@types/jest": "~29.5.3", diff --git a/packages/password-policies/tsconfig.json b/packages/password-policies/tsconfig.json index e2be47cf5499..f0a66c843c50 100644 --- a/packages/password-policies/tsconfig.json +++ b/packages/password-policies/tsconfig.json @@ -2,7 +2,8 @@ "extends": "../../tsconfig.base.client.json", "compilerOptions": { "rootDir": "./src", - "outDir": "./dist" + "outDir": "./dist", + "module": "commonjs" }, "include": ["./src/**/*"] } diff --git a/packages/rest-typings/CHANGELOG.md b/packages/rest-typings/CHANGELOG.md index 479c5baac925..506ed5c3580f 100644 --- a/packages/rest-typings/CHANGELOG.md +++ b/packages/rest-typings/CHANGELOG.md @@ -1,5 +1,23 @@ # @rocket.chat/rest-typings +## 6.4.0-rc.4 + +### Patch Changes + +- @rocket.chat/core-typings@6.4.0-rc.4 + +## 6.4.0-rc.3 + +### Patch Changes + +- @rocket.chat/core-typings@6.4.0-rc.3 + +## 6.4.0-rc.2 + +### Patch Changes + +- @rocket.chat/core-typings@6.4.0-rc.2 + ## 6.4.0-rc.1 ### Patch Changes @@ -30,6 +48,13 @@ - Updated dependencies [61128364d6] - Updated dependencies [d45365436e] - @rocket.chat/core-typings@6.4.0-rc.0 + +## 6.3.7 + +### Patch Changes + +- @rocket.chat/core-typings@6.3.7 + ## 6.3.6 ### Patch Changes diff --git a/packages/rest-typings/package.json b/packages/rest-typings/package.json index cc12bd6d901d..8b6f60f294b3 100644 --- a/packages/rest-typings/package.json +++ b/packages/rest-typings/package.json @@ -1,13 +1,13 @@ { "name": "@rocket.chat/rest-typings", - "version": "6.4.0-rc.1", + "version": "6.4.0-rc.4", "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", "@types/jest": "~29.5.3", "eslint": "~8.45.0", "jest": "~29.6.1", "jest-environment-jsdom": "~29.6.1", - "mongodb": "^4.12.1", + "mongodb": "^4.17.1", "ts-jest": "~29.0.5", "typescript": "~5.2.2" }, diff --git a/packages/rest-typings/src/v1/integrations/IntegrationsCreateProps.ts b/packages/rest-typings/src/v1/integrations/IntegrationsCreateProps.ts index e9ef650656cd..249a12096729 100644 --- a/packages/rest-typings/src/v1/integrations/IntegrationsCreateProps.ts +++ b/packages/rest-typings/src/v1/integrations/IntegrationsCreateProps.ts @@ -1,4 +1,4 @@ -import type { OutgoingIntegrationEvent } from '@rocket.chat/core-typings'; +import type { OutgoingIntegrationEvent, IntegrationScriptEngine } from '@rocket.chat/core-typings'; import Ajv from 'ajv'; const ajv = new Ajv(); @@ -16,6 +16,7 @@ export type IntegrationsCreateProps = alias?: string; avatar?: string; emoji?: string; + scriptEngine?: IntegrationScriptEngine; } | { type: 'webhook-outgoing'; @@ -44,6 +45,7 @@ export type IntegrationsCreateProps = alias?: string; avatar?: string; emoji?: string; + scriptEngine?: IntegrationScriptEngine; }; const integrationsCreateSchema = { @@ -96,6 +98,10 @@ const integrationsCreateSchema = { type: 'string', nullable: true, }, + scriptEngine: { + type: 'string', + nullable: true, + }, }, required: ['type', 'username', 'channel', 'scriptEnabled', 'name', 'enabled'], additionalProperties: false, @@ -196,6 +202,10 @@ const integrationsCreateSchema = { type: 'string', nullable: true, }, + scriptEngine: { + type: 'string', + nullable: true, + }, }, required: ['type', 'username', 'channel', 'event', 'scriptEnabled', 'name', 'enabled'], additionalProperties: false, diff --git a/packages/tools/src/index.ts b/packages/tools/src/index.ts index 261823100d0a..b8bc90d9cb54 100644 --- a/packages/tools/src/index.ts +++ b/packages/tools/src/index.ts @@ -1,3 +1,4 @@ export * from './pick'; export * from './timezone'; export * from './stream'; +export * from './wrapExceptions'; diff --git a/packages/tools/src/wrapExceptions.ts b/packages/tools/src/wrapExceptions.ts new file mode 100644 index 000000000000..bd830a92bfeb --- /dev/null +++ b/packages/tools/src/wrapExceptions.ts @@ -0,0 +1,46 @@ +const isPromise = (value: unknown): value is Promise => !!value && value instanceof Promise; + +export function wrapExceptions( + getter: () => T, +): { + catch: (errorWrapper: (error: any) => T) => T; + suppress: (errorWrapper?: (error: any) => void) => T | undefined; +}; +export function wrapExceptions( + getter: () => Promise, +): { + catch: (errorWrapper: (error: any) => T | Awaited) => Promise; + suppress: (errorWrapper?: (error: any) => void) => Promise; +}; +export function wrapExceptions(getter: () => T) { + const doCatch = (errorWrapper: (error: any) => T | Awaited): T => { + try { + const value = getter(); + if (isPromise(value)) { + return value.catch(errorWrapper) as T; + } + + return value; + } catch (error) { + return errorWrapper(error); + } + }; + + const doSuppress = (errorWrapper?: (error: any) => void) => { + try { + const value = getter(); + if (isPromise(value)) { + return value.catch((error) => errorWrapper?.(error)); + } + + return value; + } catch (error) { + errorWrapper?.(error); + } + }; + + return { + catch: doCatch, + suppress: doSuppress, + }; +} diff --git a/packages/ui-client/CHANGELOG.md b/packages/ui-client/CHANGELOG.md index 4141b97d6ff1..5a987f493cf1 100644 --- a/packages/ui-client/CHANGELOG.md +++ b/packages/ui-client/CHANGELOG.md @@ -1,5 +1,23 @@ # @rocket.chat/ui-client +## 2.0.0-rc.4 + +### Patch Changes + +- @rocket.chat/ui-contexts@2.0.0-rc.4 + +## 2.0.0-rc.3 + +### Patch Changes + +- @rocket.chat/ui-contexts@2.0.0-rc.3 + +## 2.0.0-rc.2 + +### Patch Changes + +- @rocket.chat/ui-contexts@2.0.0-rc.2 + ## 2.0.0-rc.1 ### Patch Changes @@ -19,6 +37,13 @@ - Updated dependencies [074db3b419] - Updated dependencies [b8f3d5014f] - @rocket.chat/ui-contexts@2.0.0-rc.0 + +## 1.0.7 + +### Patch Changes + +- @rocket.chat/ui-contexts@1.0.7 + ## 1.0.6 ### Patch Changes diff --git a/packages/ui-client/package.json b/packages/ui-client/package.json index 9fc0b7f3617c..ce183b859e06 100644 --- a/packages/ui-client/package.json +++ b/packages/ui-client/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-client", - "version": "2.0.0-rc.1", + "version": "2.0.0-rc.4", "private": true, "devDependencies": { "@babel/core": "~7.22.9", @@ -61,7 +61,7 @@ "@rocket.chat/fuselage": "*", "@rocket.chat/fuselage-hooks": "*", "@rocket.chat/icons": "*", - "@rocket.chat/ui-contexts": "2.0.0-rc.1", + "@rocket.chat/ui-contexts": "2.0.0-rc.4", "react": "~17.0.2" }, "volta": { diff --git a/packages/ui-contexts/CHANGELOG.md b/packages/ui-contexts/CHANGELOG.md index fa432dfd6c66..7e8fc0d165c3 100644 --- a/packages/ui-contexts/CHANGELOG.md +++ b/packages/ui-contexts/CHANGELOG.md @@ -1,5 +1,29 @@ # @rocket.chat/ui-contexts +## 2.0.0-rc.4 + +### Patch Changes + +- @rocket.chat/core-typings@6.4.0-rc.4 +- @rocket.chat/rest-typings@6.4.0-rc.4 +- @rocket.chat/ddp-client@0.2.0-rc.4 + +## 2.0.0-rc.3 + +### Patch Changes + +- @rocket.chat/core-typings@6.4.0-rc.3 +- @rocket.chat/rest-typings@6.4.0-rc.3 +- @rocket.chat/ddp-client@0.2.0-rc.3 + +## 2.0.0-rc.2 + +### Patch Changes + +- @rocket.chat/core-typings@6.4.0-rc.2 +- @rocket.chat/rest-typings@6.4.0-rc.2 +- @rocket.chat/ddp-client@0.2.0-rc.2 + ## 2.0.0-rc.1 ### Patch Changes @@ -34,6 +58,15 @@ - @rocket.chat/core-typings@6.4.0-rc.0 - @rocket.chat/rest-typings@6.4.0-rc.0 - @rocket.chat/ddp-client@0.2.0-rc.0 + +## 1.0.7 + +### Patch Changes + +- @rocket.chat/core-typings@6.3.7 +- @rocket.chat/rest-typings@6.3.7 +- @rocket.chat/ddp-client@0.1.7 + ## 1.0.6 ### Patch Changes diff --git a/packages/ui-contexts/package.json b/packages/ui-contexts/package.json index ce84a75089b3..82dc4519f85e 100644 --- a/packages/ui-contexts/package.json +++ b/packages/ui-contexts/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-contexts", - "version": "2.0.0-rc.1", + "version": "2.0.0-rc.4", "private": true, "devDependencies": { "@rocket.chat/core-typings": "workspace:^", @@ -14,7 +14,7 @@ "eslint": "~8.45.0", "eslint-plugin-react-hooks": "^4.6.0", "jest": "~29.6.1", - "mongodb": "^4.12.1", + "mongodb": "^4.17.1", "react": "~17.0.2", "ts-jest": "~29.0.5", "typescript": "~5.2.2", diff --git a/packages/ui-video-conf/CHANGELOG.md b/packages/ui-video-conf/CHANGELOG.md index 3d39f00d7673..bb332f206fc4 100644 --- a/packages/ui-video-conf/CHANGELOG.md +++ b/packages/ui-video-conf/CHANGELOG.md @@ -1,5 +1,23 @@ # @rocket.chat/ui-video-conf +## 2.0.0-rc.4 + +### Patch Changes + +- @rocket.chat/ui-contexts@2.0.0-rc.4 + +## 2.0.0-rc.3 + +### Patch Changes + +- @rocket.chat/ui-contexts@2.0.0-rc.3 + +## 2.0.0-rc.2 + +### Patch Changes + +- @rocket.chat/ui-contexts@2.0.0-rc.2 + ## 2.0.0-rc.1 ### Patch Changes @@ -13,6 +31,13 @@ - Updated dependencies [074db3b419] - Updated dependencies [b8f3d5014f] - @rocket.chat/ui-contexts@2.0.0-rc.0 + +## 1.0.7 + +### Patch Changes + +- @rocket.chat/ui-contexts@1.0.7 + ## 1.0.6 ### Patch Changes diff --git a/packages/ui-video-conf/package.json b/packages/ui-video-conf/package.json index 91ffd97b27d7..ded2331aa09e 100644 --- a/packages/ui-video-conf/package.json +++ b/packages/ui-video-conf/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-video-conf", - "version": "2.0.0-rc.1", + "version": "2.0.0-rc.4", "private": true, "devDependencies": { "@babel/core": "~7.22.9", @@ -35,7 +35,7 @@ "@rocket.chat/fuselage-hooks": "*", "@rocket.chat/icons": "*", "@rocket.chat/styled": "*", - "@rocket.chat/ui-contexts": "2.0.0-rc.1", + "@rocket.chat/ui-contexts": "2.0.0-rc.4", "react": "^17.0.2", "react-dom": "^17.0.2" }, diff --git a/packages/uikit-playground/CHANGELOG.md b/packages/uikit-playground/CHANGELOG.md index e1a0394597ff..ae860561c5dd 100644 --- a/packages/uikit-playground/CHANGELOG.md +++ b/packages/uikit-playground/CHANGELOG.md @@ -1,5 +1,26 @@ # @rocket.chat/uikit-playground +## 0.2.0-rc.4 + +### Patch Changes + +- @rocket.chat/ui-contexts@2.0.0-rc.4 +- @rocket.chat/fuselage-ui-kit@2.0.0-rc.4 + +## 0.2.0-rc.3 + +### Patch Changes + +- @rocket.chat/ui-contexts@2.0.0-rc.3 +- @rocket.chat/fuselage-ui-kit@2.0.0-rc.3 + +## 0.2.0-rc.2 + +### Patch Changes + +- @rocket.chat/ui-contexts@2.0.0-rc.2 +- @rocket.chat/fuselage-ui-kit@2.0.0-rc.2 + ## 0.2.0-rc.1 ### Patch Changes @@ -25,6 +46,14 @@ - Updated dependencies [b8f3d5014f] - @rocket.chat/fuselage-ui-kit@2.0.0-rc.0 - @rocket.chat/ui-contexts@2.0.0-rc.0 + +## 0.1.7 + +### Patch Changes + +- @rocket.chat/ui-contexts@1.0.7 +- @rocket.chat/fuselage-ui-kit@1.0.7 + ## 0.1.6 ### Patch Changes diff --git a/packages/uikit-playground/package.json b/packages/uikit-playground/package.json index d9b9587f5cf3..eb69dc5e017c 100644 --- a/packages/uikit-playground/package.json +++ b/packages/uikit-playground/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/uikit-playground", "private": true, - "version": "0.2.0-rc.1", + "version": "0.2.0-rc.4", "type": "module", "scripts": { "dev": "vite", diff --git a/packages/web-ui-registration/CHANGELOG.md b/packages/web-ui-registration/CHANGELOG.md index 2a76811d031a..63b5246eedcd 100644 --- a/packages/web-ui-registration/CHANGELOG.md +++ b/packages/web-ui-registration/CHANGELOG.md @@ -1,5 +1,23 @@ # @rocket.chat/web-ui-registration +## 2.0.0-rc.4 + +### Patch Changes + +- @rocket.chat/ui-contexts@2.0.0-rc.4 + +## 2.0.0-rc.3 + +### Patch Changes + +- @rocket.chat/ui-contexts@2.0.0-rc.3 + +## 2.0.0-rc.2 + +### Patch Changes + +- @rocket.chat/ui-contexts@2.0.0-rc.2 + ## 2.0.0-rc.1 ### Patch Changes @@ -14,6 +32,13 @@ - Updated dependencies [074db3b419] - Updated dependencies [b8f3d5014f] - @rocket.chat/ui-contexts@2.0.0-rc.0 + +## 1.0.7 + +### Patch Changes + +- @rocket.chat/ui-contexts@1.0.7 + ## 1.0.6 ### Patch Changes diff --git a/packages/web-ui-registration/package.json b/packages/web-ui-registration/package.json index 2f31e571ca8c..60669e1c9e19 100644 --- a/packages/web-ui-registration/package.json +++ b/packages/web-ui-registration/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/web-ui-registration", - "version": "2.0.0-rc.1", + "version": "2.0.0-rc.4", "private": true, "homepage": "https://rocket.chat", "main": "./dist/index.js", @@ -49,7 +49,7 @@ }, "peerDependencies": { "@rocket.chat/layout": "*", - "@rocket.chat/ui-contexts": "2.0.0-rc.1", + "@rocket.chat/ui-contexts": "2.0.0-rc.4", "@tanstack/react-query": "*", "react": "*", "react-hook-form": "*", diff --git a/packages/web-ui-registration/src/RegisterForm.tsx b/packages/web-ui-registration/src/RegisterForm.tsx index eb0aa7229f6d..6202916c87f2 100644 --- a/packages/web-ui-registration/src/RegisterForm.tsx +++ b/packages/web-ui-registration/src/RegisterForm.tsx @@ -129,9 +129,10 @@ export const RegisterForm = ({ setLoginRoute }: { setLoginRoute: DispatchLoginRo {errors.name && ( - {t('registration.component.form.requiredField')} + {errors.name.message} )}
@@ -159,6 +160,7 @@ export const RegisterForm = ({ setLoginRoute }: { setLoginRoute: DispatchLoginRo })} placeholder={usernameOrEmailPlaceholder || t('registration.component.form.emailPlaceholder')} error={errors?.email?.message} + aria-required='true' aria-invalid={errors.email ? 'true' : 'false'} aria-describedby={`${emailId}-error`} id={emailId} @@ -180,6 +182,7 @@ export const RegisterForm = ({ setLoginRoute }: { setLoginRoute: DispatchLoginRo required: t('registration.component.form.requiredField'), })} error={errors?.username?.message} + aria-required='true' aria-invalid={errors.username ? 'true' : 'false'} aria-describedby={`${usernameId}-error`} id={usernameId} @@ -202,7 +205,8 @@ export const RegisterForm = ({ setLoginRoute }: { setLoginRoute: DispatchLoginRo required: t('registration.component.form.requiredField'), validate: () => (!passwordIsValid ? t('Password_must_meet_the_complexity_requirements') : true), })} - error={errors.password && (errors.password?.message || t('registration.component.form.requiredField'))} + error={errors.password?.message} + aria-required='true' aria-invalid={errors.password ? 'true' : undefined} id={passwordId} placeholder={passwordPlaceholder || t('Create_a_password')} @@ -218,7 +222,9 @@ export const RegisterForm = ({ setLoginRoute }: { setLoginRoute: DispatchLoginRo {requiresPasswordConfirmation && ( - {t('registration.component.form.confirmPassword')} + + {t('registration.component.form.confirmPassword')} + (watch('password') === val ? true : t('registration.component.form.invalidConfirmPass')), })} error={errors.passwordConfirmation?.message} + aria-required='true' aria-invalid={errors.passwordConfirmation ? 'true' : 'false'} id={passwordConfirmationId} aria-describedby={`${passwordConfirmationId}-error`} @@ -252,6 +259,7 @@ export const RegisterForm = ({ setLoginRoute }: { setLoginRoute: DispatchLoginRo required: t('registration.component.form.requiredField'), })} error={errors?.reason?.message} + aria-required='true' aria-invalid={errors.reason ? 'true' : 'false'} aria-describedby={`${reasonId}-error`} id={reasonId} @@ -259,7 +267,7 @@ export const RegisterForm = ({ setLoginRoute }: { setLoginRoute: DispatchLoginRo {errors.reason && ( - {t('registration.component.form.requiredField')} + {errors.reason.message} )} diff --git a/packages/web-ui-registration/src/ResetPassword/ResetPasswordPage.tsx b/packages/web-ui-registration/src/ResetPassword/ResetPasswordPage.tsx index d3a3e6fa7413..19b0a13983bb 100644 --- a/packages/web-ui-registration/src/ResetPassword/ResetPasswordPage.tsx +++ b/packages/web-ui-registration/src/ResetPassword/ResetPasswordPage.tsx @@ -1,10 +1,11 @@ -import { Button, Field, Modal, PasswordInput } from '@rocket.chat/fuselage'; +import { Button, FieldGroup, Field, FieldLabel, ButtonGroup, PasswordInput, FieldRow, FieldError } from '@rocket.chat/fuselage'; import { useUniqueId } from '@rocket.chat/fuselage-hooks'; import { Form } from '@rocket.chat/layout'; import { PasswordVerifier, useValidatePassword } from '@rocket.chat/ui-client'; import type { TranslationKey } from '@rocket.chat/ui-contexts'; import { useSetting, useRouter, useRouteParameter, useUser, useMethod, useTranslation, useLoginWithToken } from '@rocket.chat/ui-contexts'; import type { ReactElement } from 'react'; +import { useEffect, useRef } from 'react'; import { useForm } from 'react-hook-form'; import HorizontalTemplate from '../template/HorizontalTemplate'; @@ -21,10 +22,15 @@ const ResetPasswordPage = (): ReactElement => { const resetPassword = useMethod('resetPassword'); const token = useRouteParameter('token'); + const resetPasswordFormRef = useRef(null); const passwordId = useUniqueId(); + const passwordConfirmationId = useUniqueId(); const passwordVerifierId = useUniqueId(); + const formLabelId = useUniqueId(); const requiresPasswordConfirmation = useSetting('Accounts_RequirePasswordConfirmation'); + const passwordPlaceholder = String(useSetting('Accounts_PasswordPlaceholder')); + const passwordConfirmationPlaceholder = String(useSetting('Accounts_ConfirmPasswordPlaceholder')); const router = useRouter(); @@ -36,7 +42,7 @@ const ResetPasswordPage = (): ReactElement => { register, handleSubmit, setError, - formState: { errors, isValid }, + formState: { errors, isSubmitting }, watch, } = useForm<{ password: string; @@ -48,76 +54,103 @@ const ResetPasswordPage = (): ReactElement => { const password = watch('password'); const passwordIsValid = useValidatePassword(password); - const submit = handleSubmit(async (data) => { + useEffect(() => { + if (resetPasswordFormRef.current) { + resetPasswordFormRef.current.focus(); + } + }, []); + + const handleResetPassword = async ({ password }: { password: string }) => { try { if (token) { - const result = await resetPassword(token, data.password); + const result = await resetPassword(token, password); await loginWithToken(result.token); router.navigate('/home'); } else { - await setUserPassword(data.password); + await setUserPassword(password); } } catch ({ error, reason }: any) { const _error = reason ?? error; setError('password', { message: String(_error) }); } - }); + }; return ( -
+ - {t('Reset_password')} + {t('Reset_password')} + {t(changePasswordReason)} - - {t(changePasswordReason)} - - (!passwordIsValid ? t('Password_must_meet_the_complexity_requirements') : true), - })} - error={errors.password?.message} - aria-invalid={errors.password ? 'true' : 'false'} - id={passwordId} - placeholder={t('Create_a_password')} - name='password' - autoComplete='off' - aria-describedby={passwordVerifierId} - /> - - {errors?.password && ( - - {errors.password.message} - - )} - - {requiresPasswordConfirmation && ( - + + + + {t('registration.component.form.password')} + + password === val, + {...register('password', { + required: t('registration.component.form.requiredField'), + validate: () => (!passwordIsValid ? t('Password_must_meet_the_complexity_requirements') : true), })} - error={errors.passwordConfirmation?.type === 'validate' ? t('registration.component.form.invalidConfirmPass') : undefined} - aria-invalid={errors.passwordConfirmation ? 'true' : false} - id='passwordConfirmation' - placeholder={t('Confirm_password')} - disabled={!passwordIsValid} + error={errors?.password?.message} + aria-invalid={errors.password ? 'true' : 'false'} + aria-required='true' + id={passwordId} + placeholder={passwordPlaceholder || t('Create_a_password')} + aria-describedby={`${passwordVerifierId} ${passwordId}-error`} /> - + + {errors?.password && ( + + {errors.password.message} + + )} + + + {requiresPasswordConfirmation && ( + + + {t('registration.component.form.confirmPassword')} + + + (password === val ? true : t('registration.component.form.invalidConfirmPass')), + })} + error={errors?.passwordConfirmation?.message} + aria-required='true' + aria-invalid={errors.passwordConfirmation ? 'true' : 'false'} + aria-describedby={`${passwordConfirmationId}-error`} + id={passwordConfirmationId} + placeholder={passwordConfirmationPlaceholder || t('Confirm_password')} + disabled={!passwordIsValid} + /> + + {errors.passwordConfirmation && ( + + {errors.passwordConfirmation?.message} + + )} + )} - {errors && {errors.password?.message}} - + - - - +
diff --git a/packages/web-ui-registration/src/ResetPasswordForm.tsx b/packages/web-ui-registration/src/ResetPasswordForm.tsx index 33f6c76c588e..d53b5d1fd793 100644 --- a/packages/web-ui-registration/src/ResetPasswordForm.tsx +++ b/packages/web-ui-registration/src/ResetPasswordForm.tsx @@ -1,7 +1,8 @@ -import { FieldGroup, TextInput, Field, ButtonGroup, Button, Callout } from '@rocket.chat/fuselage'; +import { FieldGroup, TextInput, Field, FieldLabel, FieldRow, FieldError, ButtonGroup, Button, Callout } from '@rocket.chat/fuselage'; +import { useUniqueId } from '@rocket.chat/fuselage-hooks'; import { Form, ActionLink } from '@rocket.chat/layout'; import type { ReactElement } from 'react'; -import { useState } from 'react'; +import { useEffect, useRef } from 'react'; import { useForm } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; @@ -10,54 +11,72 @@ import { useSendForgotPassword } from './hooks/useSendForgotPassword'; export const ResetPasswordForm = ({ setLoginRoute }: { setLoginRoute: DispatchLoginRouter }): ReactElement => { const { t } = useTranslation(); + const emailId = useUniqueId(); + const formLabelId = useUniqueId(); + const forgotPasswordFormRef = useRef(null); - const [sent, setSent] = useState(false); const { register, handleSubmit, formState: { errors, isSubmitting }, } = useForm<{ email: string; - }>(); + }>({ mode: 'onBlur' }); - const resetPassword = useSendForgotPassword(); + useEffect(() => { + if (forgotPasswordFormRef.current) { + forgotPasswordFormRef.current.focus(); + } + }, []); + + const { mutateAsync, isSuccess } = useSendForgotPassword(); return (
{ - resetPassword({ email: data.email }); - setSent(true); + mutateAsync({ email: data.email }); })} > - {t('registration.component.resetPassword')} + {t('registration.component.resetPassword')} - {t('registration.component.form.email')} - + + {t('registration.component.form.email')} + + - - {errors.email && {errors.email.message || t('registration.component.form.requiredField')}} + + {errors.email && ( + + {errors.email.message} + + )} - {sent && ( + {isSuccess && ( - + {t('registration.page.resetPassword.sent')} @@ -69,7 +88,6 @@ export const ResetPasswordForm = ({ setLoginRoute }: { setLoginRoute: DispatchLo {t('registration.page.resetPassword.sendInstructions')} - { setLoginRoute('login'); diff --git a/packages/web-ui-registration/src/hooks/useSendForgotPassword.ts b/packages/web-ui-registration/src/hooks/useSendForgotPassword.ts index 5e14c164b6cf..0dcef2d04bf4 100644 --- a/packages/web-ui-registration/src/hooks/useSendForgotPassword.ts +++ b/packages/web-ui-registration/src/hooks/useSendForgotPassword.ts @@ -1,7 +1,10 @@ import { useEndpoint } from '@rocket.chat/ui-contexts'; +import { useMutation } from '@tanstack/react-query'; export const useSendForgotPassword = () => { - const forgot = useEndpoint('POST', '/v1/users.forgotPassword'); + const sendForgotPassword = useEndpoint('POST', '/v1/users.forgotPassword'); - return forgot; + return useMutation({ + mutationFn: sendForgotPassword, + }); }; diff --git a/yarn.lock b/yarn.lock index 80c6598eb02c..145079c6eb7a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4349,6 +4349,15 @@ __metadata: languageName: node linkType: hard +"@mongodb-js/saslprep@npm:^1.1.0": + version: 1.1.0 + resolution: "@mongodb-js/saslprep@npm:1.1.0" + dependencies: + sparse-bitfield: ^3.0.3 + checksum: 1479a43e216734672f8eb1a2a55165b6896841bd00fb5bd645390a24374ef6c29f0f6d19a43618a19b8f1912fcbd2b2cc2210a62361103d1f28dce6852cf31d4 + languageName: node + linkType: hard + "@mrmlnc/readdir-enhanced@npm:^2.2.1": version: 2.2.1 resolution: "@mrmlnc/readdir-enhanced@npm:2.2.1" @@ -7693,7 +7702,7 @@ __metadata: gc-stats: ^1.4.0 mem: ^8.1.1 moleculer: ^0.14.29 - mongodb: ^4.12.1 + mongodb: ^4.17.1 nats: ^2.4.0 pino: ^8.15.0 polka: ^0.5.2 @@ -7728,7 +7737,7 @@ __metadata: human-interval: ^2.0.1 jest: ~29.6.1 moment-timezone: ~0.5.43 - mongodb: ^4.12.1 + mongodb: ^4.17.1 ts-jest: ~29.0.5 typescript: ~5.2.2 languageName: unknown @@ -7815,7 +7824,7 @@ __metadata: gc-stats: ^1.4.0 mem: ^8.1.1 moleculer: ^0.14.29 - mongodb: ^4.12.1 + mongodb: ^4.17.1 nats: ^2.4.0 pino: ^8.15.0 polka: ^0.5.2 @@ -7876,7 +7885,7 @@ __metadata: eslint: ~8.45.0 fibers: ^5.0.3 jest: ~29.6.1 - mongodb: ^4.12.1 + mongodb: ^4.17.1 prettier: ~2.8.8 typescript: ~5.2.2 languageName: unknown @@ -7892,7 +7901,7 @@ __metadata: "@rocket.chat/message-parser": next "@rocket.chat/ui-kit": ^0.32.1 eslint: ~8.45.0 - mongodb: ^4.12.1 + mongodb: ^4.17.1 prettier: ~2.8.8 typescript: ~5.2.2 languageName: unknown @@ -7909,7 +7918,7 @@ __metadata: "@types/jest": ~29.5.3 eslint: ~8.45.0 jest: ~29.6.1 - mongodb: ^4.12.1 + mongodb: ^4.17.1 ts-jest: ~29.0.5 typescript: ~5.2.2 languageName: unknown @@ -8014,7 +8023,7 @@ __metadata: jaeger-client: ^3.19.0 mem: ^8.1.1 moleculer: ^0.14.29 - mongodb: ^4.12.1 + mongodb: ^4.17.1 nats: ^2.4.0 pino: ^8.15.0 pino-pretty: ^7.6.1 @@ -8224,9 +8233,9 @@ __metadata: "@rocket.chat/icons": "*" "@rocket.chat/prettier-config": "*" "@rocket.chat/styled": "*" - "@rocket.chat/ui-contexts": 2.0.0-rc.1 + "@rocket.chat/ui-contexts": 2.0.0-rc.4 "@rocket.chat/ui-kit": "*" - "@rocket.chat/ui-video-conf": 2.0.0-rc.1 + "@rocket.chat/ui-video-conf": 2.0.0-rc.4 "@tanstack/react-query": "*" react: "*" react-dom: "*" @@ -8308,14 +8317,14 @@ __metadata: ts-jest: ~29.0.5 typescript: ~5.2.2 peerDependencies: - "@rocket.chat/core-typings": 6.4.0-rc.1 + "@rocket.chat/core-typings": 6.4.0-rc.4 "@rocket.chat/css-in-js": "*" "@rocket.chat/fuselage": "*" "@rocket.chat/fuselage-tokens": "*" "@rocket.chat/message-parser": "*" "@rocket.chat/styled": "*" - "@rocket.chat/ui-client": 2.0.0-rc.1 - "@rocket.chat/ui-contexts": 2.0.0-rc.1 + "@rocket.chat/ui-client": 2.0.0-rc.4 + "@rocket.chat/ui-contexts": 2.0.0-rc.4 katex: "*" react: "*" languageName: unknown @@ -8350,7 +8359,7 @@ __metadata: "@rocket.chat/eslint-config": "workspace:^" "@rocket.chat/models": "workspace:^" eslint: ~8.45.0 - mongodb: ^4.12.1 + mongodb: ^4.17.1 prettier: ~2.8.8 typescript: ~5.2.2 languageName: unknown @@ -8787,6 +8796,7 @@ __metadata: imap: ^0.8.19 ip-range-check: ^0.2.0 is-svg: ^4.3.2 + isolated-vm: 4.4.2 jest: ~29.6.1 jquery: ^3.6.0 jschardet: ^3.0.0 @@ -8814,8 +8824,7 @@ __metadata: moment: ^2.29.4 moment-timezone: ^0.5.43 mongo-message-queue: ^1.0.0 - mongodb: ^4.12.1 - mongodb-memory-server: ^7.6.3 + mongodb: ^4.17.1 nats: ^2.6.1 node-abort-controller: ^3.1.1 node-dogstatsd: ^0.0.7 @@ -8933,7 +8942,7 @@ __metadata: "@types/node-rsa": ^1.1.1 eslint: ~8.45.0 jest: ~29.6.1 - mongodb: ^4.12.1 + mongodb: ^4.17.1 ts-jest: ~29.0.5 typescript: ~5.2.2 languageName: unknown @@ -8987,7 +8996,7 @@ __metadata: mem: ^8.1.1 moment-timezone: ^0.5.43 mongo-message-queue: ^1.0.0 - mongodb: ^4.12.1 + mongodb: ^4.17.1 pino: ^8.15.0 ts-jest: ~29.0.5 typescript: ~5.2.2 @@ -9024,7 +9033,7 @@ __metadata: moleculer: ^0.14.29 moment-timezone: ^0.5.43 mongo-message-queue: ^1.0.0 - mongodb: ^4.12.1 + mongodb: ^4.17.1 nats: ^2.4.0 pino: ^8.15.0 polka: ^0.5.2 @@ -9133,7 +9142,7 @@ __metadata: gc-stats: ^1.4.0 mem: ^8.1.1 moleculer: ^0.14.29 - mongodb: ^4.12.1 + mongodb: ^4.17.1 nats: ^2.4.0 pino: ^8.15.0 polka: ^0.5.2 @@ -9159,7 +9168,7 @@ __metadata: babel-jest: ^29.0.3 eslint: ~8.45.0 jest: ~29.6.1 - mongodb: ^4.12.1 + mongodb: ^4.17.1 typescript: ~5.2.2 languageName: unknown linkType: soft @@ -9200,7 +9209,7 @@ __metadata: moleculer: ^0.14.29 moment-timezone: ^0.5.43 mongo-message-queue: ^1.0.0 - mongodb: ^4.12.1 + mongodb: ^4.17.1 nats: ^2.4.0 pino: ^8.15.0 polka: ^0.5.2 @@ -9261,7 +9270,7 @@ __metadata: eslint: ~8.45.0 jest: ~29.6.1 jest-environment-jsdom: ~29.6.1 - mongodb: ^4.12.1 + mongodb: ^4.17.1 ts-jest: ~29.0.5 typescript: ~5.2.2 languageName: unknown @@ -9338,7 +9347,7 @@ __metadata: gc-stats: ^1.4.0 mem: ^8.1.1 moleculer: ^0.14.29 - mongodb: ^4.12.1 + mongodb: ^4.17.1 nats: ^2.4.0 pino: ^8.15.0 polka: ^0.5.2 @@ -9453,7 +9462,7 @@ __metadata: "@rocket.chat/fuselage": "*" "@rocket.chat/fuselage-hooks": "*" "@rocket.chat/icons": "*" - "@rocket.chat/ui-contexts": 2.0.0-rc.1 + "@rocket.chat/ui-contexts": 2.0.0-rc.4 react: ~17.0.2 languageName: unknown linkType: soft @@ -9507,7 +9516,7 @@ __metadata: eslint: ~8.45.0 eslint-plugin-react-hooks: ^4.6.0 jest: ~29.6.1 - mongodb: ^4.12.1 + mongodb: ^4.17.1 react: ~17.0.2 ts-jest: ~29.0.5 typescript: ~5.2.2 @@ -9606,7 +9615,7 @@ __metadata: "@rocket.chat/fuselage-hooks": "*" "@rocket.chat/icons": "*" "@rocket.chat/styled": "*" - "@rocket.chat/ui-contexts": 2.0.0-rc.1 + "@rocket.chat/ui-contexts": 2.0.0-rc.4 react: ^17.0.2 react-dom: ^17.0.2 languageName: unknown @@ -9690,7 +9699,7 @@ __metadata: typescript: ~5.2.2 peerDependencies: "@rocket.chat/layout": "*" - "@rocket.chat/ui-contexts": 2.0.0-rc.1 + "@rocket.chat/ui-contexts": 2.0.0-rc.4 "@tanstack/react-query": "*" react: "*" react-hook-form: "*" @@ -11908,15 +11917,6 @@ __metadata: languageName: node linkType: hard -"@types/bson@npm:*": - version: 4.2.0 - resolution: "@types/bson@npm:4.2.0" - dependencies: - bson: "*" - checksum: 55abf60c57b7f05655c210b386392636a299a7df18b89cec2cde0aa87374d97dd4ac9632226b0f6fe135d16ad4296ae5ddc782f6e9132d38c53dd26a6df8e704 - languageName: node - linkType: hard - "@types/busboy@npm:^1.5.0": version: 1.5.0 resolution: "@types/busboy@npm:1.5.0" @@ -12595,16 +12595,6 @@ __metadata: languageName: node linkType: hard -"@types/mongodb@npm:^3.6.20": - version: 3.6.20 - resolution: "@types/mongodb@npm:3.6.20" - dependencies: - "@types/bson": "*" - "@types/node": "*" - checksum: e5397ada2ed728997f7c3f5424e8c28f682a635488be967c9c18a5de27b1641cf28bb42bc12026ac6d475c457a880e27097e13c8120350ba13219f4ccc030656 - languageName: node - linkType: hard - "@types/ms@npm:*": version: 0.7.31 resolution: "@types/ms@npm:0.7.31" @@ -13124,13 +13114,6 @@ __metadata: languageName: node linkType: hard -"@types/tmp@npm:^0.2.2": - version: 0.2.3 - resolution: "@types/tmp@npm:0.2.3" - checksum: 0ca45e99b3b3c6959d5c4f4555f73c8007db540cfb0fbbb9373217f9ab85e67eef75193f51a1d6564b0ee6c6f5ffa259d1034d7f7530a5b7ce80acb94cfc4daa - languageName: node - linkType: hard - "@types/tough-cookie@npm:*": version: 4.0.1 resolution: "@types/tough-cookie@npm:4.0.1" @@ -14910,15 +14893,6 @@ __metadata: languageName: node linkType: hard -"async-mutex@npm:^0.3.2": - version: 0.3.2 - resolution: "async-mutex@npm:0.3.2" - dependencies: - tslib: ^2.3.1 - checksum: 620b771dfdea1cad0a6b712915c31a1e3ca880a8cf1eae92b4590f435995e0260929c6ebaae0b9126b1456790ea498064b5bb9a506948cda760f48d3d0dcc4c8 - languageName: node - linkType: hard - "async-retry@npm:^1.3.3": version: 1.3.3 resolution: "async-retry@npm:1.3.3" @@ -15645,16 +15619,6 @@ __metadata: languageName: node linkType: hard -"bl@npm:^2.2.1": - version: 2.2.1 - resolution: "bl@npm:2.2.1" - dependencies: - readable-stream: ^2.3.5 - safe-buffer: ^5.1.1 - checksum: 4f5d9b258919646a8d02f1731379e53b6f6309e34596ae02afbc3aeb183910bd2d0b70681f889b7c620ca48f65dc1cd0992ee1266c90d6d7c3be60688d141233 - languageName: node - linkType: hard - "bl@npm:^4.0.3": version: 4.1.0 resolution: "bl@npm:4.1.0" @@ -16059,19 +16023,12 @@ __metadata: languageName: node linkType: hard -"bson@npm:*, bson@npm:^4.6.4, bson@npm:^4.7.0": - version: 4.7.0 - resolution: "bson@npm:4.7.0" +"bson@npm:^4.6.4, bson@npm:^4.7.2": + version: 4.7.2 + resolution: "bson@npm:4.7.2" dependencies: buffer: ^5.6.0 - checksum: 83e7b64afdad5a505073a7e6206e7b345f59e7888fbcb1948fba72b6101a1baf58b7499314f8e24b650567665f7973eda048aabbb1ddcfbadfba7d6c6b0f5e83 - languageName: node - linkType: hard - -"bson@npm:^1.1.4": - version: 1.1.6 - resolution: "bson@npm:1.1.6" - checksum: 75762c9b7e0b3156cb0f38c7eb9ffcade53f0b04ac87dece9cba38f6dc570d9af91251de6a8988b294063cfaa21894c60ac9e85c34176accb3674acb092d66a7 + checksum: f357d12c5679c8eb029a62e410ad40fb862b7b91f0fc12a3399fb3668e14aecaa63205ffeeee48735a01d393171743607dcd527eb8c058b6f2bd294079ee4125 languageName: node linkType: hard @@ -16506,7 +16463,7 @@ __metadata: languageName: node linkType: hard -"camelcase@npm:^6.0.0, camelcase@npm:^6.1.0, camelcase@npm:^6.2.0, camelcase@npm:^6.3.0": +"camelcase@npm:^6.0.0, camelcase@npm:^6.2.0, camelcase@npm:^6.3.0": version: 6.3.0 resolution: "camelcase@npm:6.3.0" checksum: 8c96818a9076434998511251dcb2761a94817ea17dbdc37f47ac080bd088fc62c7369429a19e2178b993497132c8cbcf5cc1f44ba963e76782ba469c0474938d @@ -18654,7 +18611,7 @@ __metadata: languageName: node linkType: hard -"debug@npm:4, debug@npm:^4.0.0, debug@npm:^4.0.1, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.2.0, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4, debug@npm:~4.3.1": +"debug@npm:4, debug@npm:^4.0.0, debug@npm:^4.0.1, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4, debug@npm:~4.3.1": version: 4.3.4 resolution: "debug@npm:4.3.4" dependencies: @@ -19019,13 +18976,6 @@ __metadata: languageName: node linkType: hard -"denque@npm:^1.4.1": - version: 1.5.1 - resolution: "denque@npm:1.5.1" - checksum: 4375ad19d5cea99f90effa82a8cecdaa10f4eb261fbcd7e47cd753ff2737f037aac8f7f4e031cc77f3966314c491c86a0d3b20c128aeee57f791b4662c45108e - languageName: node - linkType: hard - "depd@npm:2.0.0, depd@npm:~2.0.0": version: 2.0.0 resolution: "depd@npm:2.0.0" @@ -21544,7 +21494,7 @@ __metadata: languageName: node linkType: hard -"find-cache-dir@npm:^3.2.0, find-cache-dir@npm:^3.3.1, find-cache-dir@npm:^3.3.2": +"find-cache-dir@npm:^3.2.0, find-cache-dir@npm:^3.3.1": version: 3.3.2 resolution: "find-cache-dir@npm:3.3.2" dependencies: @@ -22276,13 +22226,6 @@ __metadata: languageName: node linkType: hard -"get-port@npm:^5.1.1": - version: 5.1.1 - resolution: "get-port@npm:5.1.1" - checksum: 0162663ffe5c09e748cd79d97b74cd70e5a5c84b760a475ce5767b357fb2a57cb821cee412d646aa8a156ed39b78aab88974eddaa9e5ee926173c036c0713787 - languageName: node - linkType: hard - "get-proxy@npm:^2.0.0": version: 2.1.0 resolution: "get-proxy@npm:2.1.0" @@ -25330,6 +25273,15 @@ __metadata: languageName: node linkType: hard +"isolated-vm@npm:4.4.2": + version: 4.4.2 + resolution: "isolated-vm@npm:4.4.2" + dependencies: + node-gyp: latest + checksum: 86d12d96f90ceef74a3fc096439c71b0c115235ae3053d600eb8f7c678443d9ca3c8a2805dcd7f97463d11eb7d2e667868946b90e377a3e6d50fdd4085506fbc + languageName: node + linkType: hard + "isomorphic-unfetch@npm:^3.1.0": version: 3.1.0 resolution: "isomorphic-unfetch@npm:3.1.0" @@ -27581,15 +27533,6 @@ __metadata: languageName: node linkType: hard -"md5-file@npm:^5.0.0": - version: 5.0.0 - resolution: "md5-file@npm:5.0.0" - bin: - md5-file: cli.js - checksum: c606a00ff58adf5428e8e2f36d86e5d3c7029f9688126faca302cd83b5e92cac183a62e1d1f05fae7c2614e80f993326fd0a8d6a3a913c41ec7ea0eefc25aa76 - languageName: node - linkType: hard - "md5.js@npm:^1.3.4": version: 1.3.5 resolution: "md5.js@npm:1.3.5" @@ -28619,7 +28562,7 @@ __metadata: languageName: node linkType: hard -"mongodb-connection-string-url@npm:^2.5.4": +"mongodb-connection-string-url@npm:^2.6.0": version: 2.6.0 resolution: "mongodb-connection-string-url@npm:2.6.0" dependencies: @@ -28629,87 +28572,39 @@ __metadata: languageName: node linkType: hard -"mongodb-memory-server-core@npm:7.6.3": - version: 7.6.3 - resolution: "mongodb-memory-server-core@npm:7.6.3" - dependencies: - "@types/mongodb": ^3.6.20 - "@types/tmp": ^0.2.2 - async-mutex: ^0.3.2 - camelcase: ^6.1.0 - debug: ^4.2.0 - find-cache-dir: ^3.3.2 - get-port: ^5.1.1 - https-proxy-agent: ^5.0.0 - md5-file: ^5.0.0 - mkdirp: ^1.0.4 - mongodb: ^3.7.3 - new-find-package-json: ^1.1.0 - semver: ^7.3.5 - tar-stream: ^2.1.4 - tmp: ^0.2.1 - tslib: ^2.3.0 - uuid: ^8.3.1 - yauzl: ^2.10.0 - checksum: 2c111f7a90f72b6810e9083da40b8bbf905d1388eb8453f71225ff805a865985efef2c40a88d082baf9ece737b4d9bd3c9fd517d1fcc656aae53e9f62e44ee14 - languageName: node - linkType: hard - -"mongodb-memory-server@npm:^7.6.3": - version: 7.6.3 - resolution: "mongodb-memory-server@npm:7.6.3" - dependencies: - mongodb-memory-server-core: 7.6.3 - tslib: ^2.3.0 - checksum: 8161ad3be8e31012f64ac4a1ac555b10071416ee6de6a50ee1a05d76018eaadacadb34364c29bba73e0877236f2f01163cd0e2dc0432427fbbe69a1fb4eaecbc - languageName: node - linkType: hard - -"mongodb@npm:^3.7.3": - version: 3.7.3 - resolution: "mongodb@npm:3.7.3" +"mongodb@npm:4.17.1, mongodb@npm:^4.3.1": + version: 4.17.1 + resolution: "mongodb@npm:4.17.1" dependencies: - bl: ^2.2.1 - bson: ^1.1.4 - denque: ^1.4.1 - optional-require: ^1.1.8 - safe-buffer: ^5.1.2 - saslprep: ^1.0.0 + "@aws-sdk/credential-providers": ^3.186.0 + "@mongodb-js/saslprep": ^1.1.0 + bson: ^4.7.2 + mongodb-connection-string-url: ^2.6.0 + socks: ^2.7.1 dependenciesMeta: - saslprep: - optional: true - peerDependenciesMeta: - aws4: - optional: true - bson-ext: - optional: true - kerberos: - optional: true - mongodb-client-encryption: - optional: true - mongodb-extjson: + "@aws-sdk/credential-providers": optional: true - snappy: + "@mongodb-js/saslprep": optional: true - checksum: ef7690fe6ee7d1752f121b14e59b3fabfddc60ff0536babce6c945703ad0010de9e6fa7de4c91b99275c256876a72a06899ce27893aba0838c2b542088bd1044 + checksum: e7f280570d0f23d60c308b2a484ed55762ec8e523946c0de1a0b3b398f24efcf1916a745e5407f32cd1c105b2f19d8ac75474c92f73cdf651affe3430a963f54 languageName: node linkType: hard -"mongodb@npm:^4.12.1, mongodb@npm:^4.3.1": - version: 4.12.1 - resolution: "mongodb@npm:4.12.1" +"mongodb@patch:mongodb@npm:4.17.1#.yarn/patches/mongodb-npm-4.17.1-a2fe811ff1.patch::locator=rocket.chat%40workspace%3A.": + version: 4.17.1 + resolution: "mongodb@patch:mongodb@npm%3A4.17.1#.yarn/patches/mongodb-npm-4.17.1-a2fe811ff1.patch::version=4.17.1&hash=f5fa42&locator=rocket.chat%40workspace%3A." dependencies: "@aws-sdk/credential-providers": ^3.186.0 - bson: ^4.7.0 - mongodb-connection-string-url: ^2.5.4 - saslprep: ^1.0.3 + "@mongodb-js/saslprep": ^1.1.0 + bson: ^4.7.2 + mongodb-connection-string-url: ^2.6.0 socks: ^2.7.1 dependenciesMeta: "@aws-sdk/credential-providers": optional: true - saslprep: + "@mongodb-js/saslprep": optional: true - checksum: 84590484b2c93bce849ec1e334b064e983444ed73942061c91e09556348c80db9d4a40544b927cd795bdfbfc51d1b713a7df5ced4ecf13cd00fab5e3c3e32ada + checksum: 7aa00b4000e8f01b18386b6d11033a3216de97ea892a7f10a9c0d0da40a51d91b1c9cbb0e51ff5691487e0fc926d06b5aebb944747153e6fbdaca08cf71d601c languageName: node linkType: hard @@ -29012,16 +28907,6 @@ __metadata: languageName: node linkType: hard -"new-find-package-json@npm:^1.1.0": - version: 1.1.0 - resolution: "new-find-package-json@npm:1.1.0" - dependencies: - debug: ^4.3.2 - tslib: ^2.3.0 - checksum: 818e5a837f87c62fb9bc4893247fd9b7b2ff1bbf25b174af9e9ec22d60d44ce355e60f80ed0657652370cca06e59539c7df292354250820403fa33cd210e76ed - languageName: node - linkType: hard - "nice-try@npm:^1.0.4": version: 1.0.5 resolution: "nice-try@npm:1.0.5" @@ -29920,15 +29805,6 @@ __metadata: languageName: node linkType: hard -"optional-require@npm:^1.1.8": - version: 1.1.8 - resolution: "optional-require@npm:1.1.8" - dependencies: - require-at: ^1.0.6 - checksum: 437db76f713052925185ae80837b593877f75101154e8937f50d33b0b07bd500c214efc9016748642109b6e3e1197eb0513a2963eb06bcf3890f88a2724b1c87 - languageName: node - linkType: hard - "optional@npm:^0.1.3": version: 0.1.4 resolution: "optional@npm:0.1.4" @@ -33943,13 +33819,6 @@ __metadata: languageName: node linkType: hard -"require-at@npm:^1.0.6": - version: 1.0.6 - resolution: "require-at@npm:1.0.6" - checksum: 7753a6ebad99855ef015d5533a787c65e883c94c23371368eebf6f1c7e2a078811013b204823152cbab206a00e825e8e5ca09416fd835a489fa30bf064fbe6d9 - languageName: node - linkType: hard - "require-directory@npm:^2.1.1": version: 2.1.1 resolution: "require-directory@npm:2.1.1" @@ -34272,7 +34141,7 @@ __metadata: jaeger-client: ^3.19.0 mem: ^8.1.1 moleculer: ^0.14.29 - mongodb: ^4.12.1 + mongodb: ^4.17.1 nats: ^2.6.1 npm-run-all: ^4.1.5 pino: ^8.15.0 @@ -34444,15 +34313,6 @@ __metadata: languageName: node linkType: hard -"saslprep@npm:^1.0.0, saslprep@npm:^1.0.3": - version: 1.0.3 - resolution: "saslprep@npm:1.0.3" - dependencies: - sparse-bitfield: ^3.0.3 - checksum: 4fdc0b70fb5e523f977de405e12cca111f1f10dd68a0cfae0ca52c1a7919a94d1556598ba2d35f447655c3b32879846c77f9274c90806f6673248ae3cea6ee43 - languageName: node - linkType: hard - "sass-loader@npm:~10.4.1": version: 10.4.1 resolution: "sass-loader@npm:10.4.1" @@ -37118,15 +36978,6 @@ __metadata: languageName: node linkType: hard -"tmp@npm:^0.2.1": - version: 0.2.1 - resolution: "tmp@npm:0.2.1" - dependencies: - rimraf: ^3.0.0 - checksum: 8b1214654182575124498c87ca986ac53dc76ff36e8f0e0b67139a8d221eaecfdec108c0e6ec54d76f49f1f72ab9325500b246f562b926f85bcdfca8bf35df9e - languageName: node - linkType: hard - "tmpl@npm:1.0.5": version: 1.0.5 resolution: "tmpl@npm:1.0.5" @@ -38684,7 +38535,7 @@ __metadata: languageName: node linkType: hard -"uuid@npm:^8.0.0, uuid@npm:^8.3.1, uuid@npm:^8.3.2": +"uuid@npm:^8.0.0, uuid@npm:^8.3.2": version: 8.3.2 resolution: "uuid@npm:8.3.2" bin: @@ -40179,7 +40030,7 @@ __metadata: languageName: node linkType: hard -"yauzl@npm:^2.10.0, yauzl@npm:^2.4.2": +"yauzl@npm:^2.4.2": version: 2.10.0 resolution: "yauzl@npm:2.10.0" dependencies: