From 18beafe3b38d4efbf480d1ab6ad339a80d937d61 Mon Sep 17 00:00:00 2001 From: Marcos Defendi Date: Thu, 24 Aug 2023 18:53:56 -0300 Subject: [PATCH 01/20] feat: add new properties to the info endpoint --- .../app/api/server/lib/getServerInfo.ts | 26 ++++++++- apps/meteor/client/definitions/info.d.ts | 1 + apps/meteor/package.json | 6 ++ .../plugin/compile-version.js | 3 + .../app/api/server/lib/getServerInfo.spec.ts | 57 +++++++++++++++++++ 5 files changed, 91 insertions(+), 2 deletions(-) create mode 100644 apps/meteor/tests/unit/app/api/server/lib/getServerInfo.spec.ts diff --git a/apps/meteor/app/api/server/lib/getServerInfo.ts b/apps/meteor/app/api/server/lib/getServerInfo.ts index 39f4b82b350b..87eb6a9fc25a 100644 --- a/apps/meteor/app/api/server/lib/getServerInfo.ts +++ b/apps/meteor/app/api/server/lib/getServerInfo.ts @@ -1,4 +1,7 @@ +import { serverFetch as fetch } from '@rocket.chat/server-fetch'; + import { hasPermissionAsync } from '../../../authorization/server/functions/hasPermission'; +import { getWorkspaceAccessToken } from '../../../cloud/server'; import { Info } from '../../../utils/rocketchat.info'; type ServerInfo = @@ -13,9 +16,28 @@ const removePatchInfo = (version: string): string => version.replace(/(\d+\.\d+) export async function getServerInfo(userId?: string): Promise { if (userId && (await hasPermissionAsync(userId, 'get-server-info'))) { - return { - info: Info, + const token = await getWorkspaceAccessToken(); + const headers = { + ...(token && { Authorization: `Bearer ${token}` }), }; + try { + const response = await fetch('https://releases.rocket.chat/supported/server', { + headers, + }); + const data = await response.json(); + const { signed: supportedVersions } = data; + + return { + info: { + ...Info, + supportedVersions, + }, + }; + } catch (e) { + return { + info: Info, + }; + } } return { version: removePatchInfo(Info.version), diff --git a/apps/meteor/client/definitions/info.d.ts b/apps/meteor/client/definitions/info.d.ts index 2b66032f484a..b49bfc967d84 100644 --- a/apps/meteor/client/definitions/info.d.ts +++ b/apps/meteor/client/definitions/info.d.ts @@ -22,5 +22,6 @@ declare module '*.info' { version: string; tag?: string; branch?: string; + supportedVersions: string; }; } diff --git a/apps/meteor/package.json b/apps/meteor/package.json index 69bd345bc8fb..31fed2d7f013 100644 --- a/apps/meteor/package.json +++ b/apps/meteor/package.json @@ -471,5 +471,11 @@ }, "installConfig": { "hoistingLimits": "workspaces" + }, + "rocketchat": { + "minimumClientVersions": { + "desktop": "3.9.6", + "mobile": "4.39.0" + } } } diff --git a/apps/meteor/packages/rocketchat-version/plugin/compile-version.js b/apps/meteor/packages/rocketchat-version/plugin/compile-version.js index c283af960e67..d18bbafafdbc 100644 --- a/apps/meteor/packages/rocketchat-version/plugin/compile-version.js +++ b/apps/meteor/packages/rocketchat-version/plugin/compile-version.js @@ -1,6 +1,8 @@ import { exec } from 'child_process'; import os from 'os'; import util from 'util'; +import path from 'path'; +import fs from 'fs'; const execAsync = util.promisify(exec); @@ -24,6 +26,7 @@ class VersionCompiler { }; output.marketplaceApiVersion = require('@rocket.chat/apps-engine/package.json').version.replace(/^[^0-9]/g, ''); + output.minimumClientVersions = JSON.parse(fs.readFileSync(path.resolve(process.cwd(), './package.json'), { encoding: 'utf8' }))?.rocketchat?.minimumClientVersions || {}; try { const result = await execAsync("git log --pretty=format:'%H%n%ad%n%an%n%s' -n 1"); const data = result.stdout.split('\n'); diff --git a/apps/meteor/tests/unit/app/api/server/lib/getServerInfo.spec.ts b/apps/meteor/tests/unit/app/api/server/lib/getServerInfo.spec.ts new file mode 100644 index 000000000000..c346df1a810f --- /dev/null +++ b/apps/meteor/tests/unit/app/api/server/lib/getServerInfo.spec.ts @@ -0,0 +1,57 @@ +import { expect } from 'chai'; +import { describe, it } from 'mocha'; +import proxyquire from 'proxyquire'; +import sinon from 'sinon'; + +const hasAllPermissionAsyncMock = sinon.stub(); +const serverFetchMock = sinon.stub(); + +const { getServerInfo } = proxyquire.noCallThru().load('../../../../../../app/api/server/lib/getServerInfo', { + '../../../utils/rocketchat.info': { + Info: { + version: '3.0.1', + }, + }, + '../../../authorization/server/functions/hasPermission': { + hasPermissionAsync: hasAllPermissionAsyncMock, + }, + '../../../cloud/server': { + getWorkspaceAccessToken: async () => 'token', + }, + '@rocket.chat/server-fetch': { + serverFetch: serverFetchMock, + }, +}); + +describe('#getServerInfo()', () => { + beforeEach(() => { + hasAllPermissionAsyncMock.reset(); + serverFetchMock.reset(); + }); + + it('should return only the version (without the patch info) when the user is not present', async () => { + expect(await getServerInfo(undefined)).to.be.eql({ version: '3.0' }); + }); + + it('should return only the version (without the patch info) when the user present but they dont have permission', async () => { + hasAllPermissionAsyncMock.resolves(false); + expect(await getServerInfo('userId')).to.be.eql({ version: '3.0' }); + }); + + it('should return the info object + the supportedVersions from the cloud when the request to the cloud was a success', async () => { + const signedJwt = 'signedJwt'; + hasAllPermissionAsyncMock.resolves(true); + serverFetchMock.resolves({ + json: async () => ({ + signed: signedJwt, + }), + }); + expect(await getServerInfo('userId')).to.be.eql({ info: { version: '3.0.1', supportedVersions: signedJwt } }); + }); + + it('should return the info object ONLY from the cloud when the request to the cloud was NOT a success', async () => { + hasAllPermissionAsyncMock.resolves(true); + serverFetchMock.rejects(); + expect(await getServerInfo('userId')).to.be.eql({ info: { version: '3.0.1' } }); + }); +}); From 3eec7d60e83c2a85c115d45bfdfb0cf9d0ccaa12 Mon Sep 17 00:00:00 2001 From: Marcos Defendi Date: Wed, 30 Aug 2023 17:41:31 -0300 Subject: [PATCH 02/20] fix: cache the token on a setting and renew it on sync process --- .../app/api/server/lib/getServerInfo.ts | 16 ++------ .../functions/getWorkspaceAccessToken.ts | 8 ++++ .../functions/supportedVersionsToken.ts | 41 +++++++++++++++++++ .../cloud/server/functions/syncWorkspace.ts | 2 + .../app/api/server/lib/getServerInfo.spec.ts | 19 +++------ 5 files changed, 60 insertions(+), 26 deletions(-) create mode 100644 apps/meteor/app/cloud/server/functions/supportedVersionsToken.ts diff --git a/apps/meteor/app/api/server/lib/getServerInfo.ts b/apps/meteor/app/api/server/lib/getServerInfo.ts index 87eb6a9fc25a..9203aa23e5d5 100644 --- a/apps/meteor/app/api/server/lib/getServerInfo.ts +++ b/apps/meteor/app/api/server/lib/getServerInfo.ts @@ -1,7 +1,5 @@ -import { serverFetch as fetch } from '@rocket.chat/server-fetch'; - import { hasPermissionAsync } from '../../../authorization/server/functions/hasPermission'; -import { getWorkspaceAccessToken } from '../../../cloud/server'; +import { getCachedSupportedVersionsToken } from '../../../cloud/server/functions/supportedVersionsToken'; import { Info } from '../../../utils/rocketchat.info'; type ServerInfo = @@ -16,21 +14,13 @@ const removePatchInfo = (version: string): string => version.replace(/(\d+\.\d+) export async function getServerInfo(userId?: string): Promise { if (userId && (await hasPermissionAsync(userId, 'get-server-info'))) { - const token = await getWorkspaceAccessToken(); - const headers = { - ...(token && { Authorization: `Bearer ${token}` }), - }; try { - const response = await fetch('https://releases.rocket.chat/supported/server', { - headers, - }); - const data = await response.json(); - const { signed: supportedVersions } = data; + const supportedVersionsToken = await getCachedSupportedVersionsToken(); return { info: { ...Info, - supportedVersions, + supportedVersions: supportedVersionsToken, }, }; } catch (e) { diff --git a/apps/meteor/app/cloud/server/functions/getWorkspaceAccessToken.ts b/apps/meteor/app/cloud/server/functions/getWorkspaceAccessToken.ts index 2b731ef82757..49bf7bc8d748 100644 --- a/apps/meteor/app/cloud/server/functions/getWorkspaceAccessToken.ts +++ b/apps/meteor/app/cloud/server/functions/getWorkspaceAccessToken.ts @@ -39,3 +39,11 @@ export async function getWorkspaceAccessToken(forceNew = false, scope = '', save return accessToken.token; } + +export const generateWorkspaceBearerHttpHeader = async (): Promise<{ Authorization: string }> => { + const token = await getWorkspaceAccessToken(); + + return { + Authorization: `Bearer ${token}`, + }; +}; diff --git a/apps/meteor/app/cloud/server/functions/supportedVersionsToken.ts b/apps/meteor/app/cloud/server/functions/supportedVersionsToken.ts new file mode 100644 index 000000000000..59060555cefa --- /dev/null +++ b/apps/meteor/app/cloud/server/functions/supportedVersionsToken.ts @@ -0,0 +1,41 @@ +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 { generateWorkspaceBearerHttpHeader } from './getWorkspaceAccessToken'; + +export const getSupportedVersionsToken = async (): Promise => { + const headers = await generateWorkspaceBearerHttpHeader(); + + const response = await fetch('https://releases.rocket.chat/supported/server', { + headers, + }); + const data = await response.json(); + const { signed } = data; + + return signed; +}; + +export const cacheNewSupportedVersionsToken = async (): Promise => { + try { + const signed = await getSupportedVersionsToken(); + + await Settings.updateValueById('Cloud_Workspace_Supported_Versions_Token', signed); + } catch (error) { + SystemLogger.error({ + msg: 'Failed to fetch supported versions token', + url: 'https://releases.rocket.chat/supported/server', + }); + } +}; + +export const getCachedSupportedVersionsToken = async (): Promise => { + const token = settings.get('Cloud_Workspace_Supported_Versions_Token'); + + if (token) { + return token; + } + + return getSupportedVersionsToken(); +}; diff --git a/apps/meteor/app/cloud/server/functions/syncWorkspace.ts b/apps/meteor/app/cloud/server/functions/syncWorkspace.ts index c8a323e40f95..e5adddb803f7 100644 --- a/apps/meteor/app/cloud/server/functions/syncWorkspace.ts +++ b/apps/meteor/app/cloud/server/functions/syncWorkspace.ts @@ -9,6 +9,7 @@ import { buildWorkspaceRegistrationData } from './buildRegistrationData'; import { getWorkspaceAccessToken } from './getWorkspaceAccessToken'; import { getWorkspaceLicense } from './getWorkspaceLicense'; import { retrieveRegistrationStatus } from './retrieveRegistrationStatus'; +import { cacheNewSupportedVersionsToken } from './supportedVersionsToken'; export async function syncWorkspace(_reconnectCheck = false) { const { workspaceRegistered } = await retrieveRegistrationStatus(); @@ -103,6 +104,7 @@ export async function syncWorkspace(_reconnectCheck = false) { }); } } + await cacheNewSupportedVersionsToken(); return true; } diff --git a/apps/meteor/tests/unit/app/api/server/lib/getServerInfo.spec.ts b/apps/meteor/tests/unit/app/api/server/lib/getServerInfo.spec.ts index c346df1a810f..bc7f48a7396b 100644 --- a/apps/meteor/tests/unit/app/api/server/lib/getServerInfo.spec.ts +++ b/apps/meteor/tests/unit/app/api/server/lib/getServerInfo.spec.ts @@ -4,7 +4,7 @@ import proxyquire from 'proxyquire'; import sinon from 'sinon'; const hasAllPermissionAsyncMock = sinon.stub(); -const serverFetchMock = sinon.stub(); +const getCachedSupportedVersionsTokenMock = sinon.stub(); const { getServerInfo } = proxyquire.noCallThru().load('../../../../../../app/api/server/lib/getServerInfo', { '../../../utils/rocketchat.info': { @@ -15,18 +15,15 @@ const { getServerInfo } = proxyquire.noCallThru().load('../../../../../../app/ap '../../../authorization/server/functions/hasPermission': { hasPermissionAsync: hasAllPermissionAsyncMock, }, - '../../../cloud/server': { - getWorkspaceAccessToken: async () => 'token', - }, - '@rocket.chat/server-fetch': { - serverFetch: serverFetchMock, + '../../../cloud/server/functions/supportedVersionsToken': { + getCachedSupportedVersionsToken: getCachedSupportedVersionsTokenMock, }, }); describe('#getServerInfo()', () => { beforeEach(() => { hasAllPermissionAsyncMock.reset(); - serverFetchMock.reset(); + getCachedSupportedVersionsTokenMock.reset(); }); it('should return only the version (without the patch info) when the user is not present', async () => { @@ -41,17 +38,13 @@ describe('#getServerInfo()', () => { it('should return the info object + the supportedVersions from the cloud when the request to the cloud was a success', async () => { const signedJwt = 'signedJwt'; hasAllPermissionAsyncMock.resolves(true); - serverFetchMock.resolves({ - json: async () => ({ - signed: signedJwt, - }), - }); + getCachedSupportedVersionsTokenMock.resolves(signedJwt); expect(await getServerInfo('userId')).to.be.eql({ info: { version: '3.0.1', supportedVersions: signedJwt } }); }); it('should return the info object ONLY from the cloud when the request to the cloud was NOT a success', async () => { hasAllPermissionAsyncMock.resolves(true); - serverFetchMock.rejects(); + getCachedSupportedVersionsTokenMock.rejects(); expect(await getServerInfo('userId')).to.be.eql({ info: { version: '3.0.1' } }); }); }); From cdda7a9e81e6836034e76132054169518d0be903 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Wed, 13 Sep 2023 11:45:12 -0300 Subject: [PATCH 03/20] wip --- .../functions/getWorkspaceAccessToken.ts | 17 ++- .../cloud/server/functions/syncWorkspace.ts | 128 ++++++++++-------- 2 files changed, 82 insertions(+), 63 deletions(-) diff --git a/apps/meteor/app/cloud/server/functions/getWorkspaceAccessToken.ts b/apps/meteor/app/cloud/server/functions/getWorkspaceAccessToken.ts index 49bf7bc8d748..e323a6f7b917 100644 --- a/apps/meteor/app/cloud/server/functions/getWorkspaceAccessToken.ts +++ b/apps/meteor/app/cloud/server/functions/getWorkspaceAccessToken.ts @@ -10,7 +10,7 @@ import { retrieveRegistrationStatus } from './retrieveRegistrationStatus'; * @param {boolean} save * @returns string */ -export async function getWorkspaceAccessToken(forceNew = false, scope = '', save = true) { +export async function getWorkspaceAccessToken(forceNew = false, scope = '', save = true): Promise { const { workspaceRegistered } = await retrieveRegistrationStatus(); if (!workspaceRegistered) { @@ -22,10 +22,11 @@ export async function getWorkspaceAccessToken(forceNew = false, scope = '', save if (expires === null) { throw new Error('Cloud_Workspace_Access_Token_Expires_At is not set'); } + const now = new Date(); if (expires.value && now < expires.value && !forceNew) { - return settings.get('Cloud_Workspace_Access_Token'); + return settings.get('Cloud_Workspace_Access_Token'); } const accessToken = await getWorkspaceAccessTokenWithScope(scope); @@ -40,8 +41,16 @@ export async function getWorkspaceAccessToken(forceNew = false, scope = '', save return accessToken.token; } -export const generateWorkspaceBearerHttpHeader = async (): Promise<{ Authorization: string }> => { - const token = await getWorkspaceAccessToken(); +export const generateWorkspaceBearerHttpHeader = async ( + forceNew = false, + scope = '', + save = true, +): Promise<{ Authorization: string } | Record> => { + const token = await getWorkspaceAccessToken(forceNew, scope, save); + + if (!token) { + return {}; + } return { Authorization: `Bearer ${token}`, diff --git a/apps/meteor/app/cloud/server/functions/syncWorkspace.ts b/apps/meteor/app/cloud/server/functions/syncWorkspace.ts index e5adddb803f7..c6be8c7aea6b 100644 --- a/apps/meteor/app/cloud/server/functions/syncWorkspace.ts +++ b/apps/meteor/app/cloud/server/functions/syncWorkspace.ts @@ -6,34 +6,43 @@ import { SystemLogger } from '../../../../server/lib/logger/system'; import { getAndCreateNpsSurvey } from '../../../../server/services/nps/getAndCreateNpsSurvey'; import { settings } from '../../../settings/server'; import { buildWorkspaceRegistrationData } from './buildRegistrationData'; -import { getWorkspaceAccessToken } from './getWorkspaceAccessToken'; +import { generateWorkspaceBearerHttpHeader } from './getWorkspaceAccessToken'; import { getWorkspaceLicense } from './getWorkspaceLicense'; import { retrieveRegistrationStatus } from './retrieveRegistrationStatus'; import { cacheNewSupportedVersionsToken } from './supportedVersionsToken'; +/** + * Rocket.Chat Cloud Sync Procedure + * It does not matter if you are registered with Rocket.Chat Cloud: + * - Sends Statistics to Rocket.Chat Cloud + * If you are registered with Rocket.Chat Cloud + * - Communicates with Rocket.Chat Cloud to update valuable information + * - Receives NPS Survey from Rocket.Chat Cloud if applicable + * - Receives Banners from Rocket.Chat Cloud if applicable + * - Receives License from Rocket.Chat Cloud if applicable + * - Receives a new List of Supported Versions from Rocket.Chat Cloud + */ + export async function syncWorkspace(_reconnectCheck = false) { const { workspaceRegistered } = await retrieveRegistrationStatus(); if (!workspaceRegistered) { - return false; - } const info = await buildWorkspaceRegistrationData(undefined); const workspaceUrl = settings.get('Cloud_Workspace_Registration_Client_Uri'); + const token = await generateWorkspaceBearerHttpHeader(true); + let result; try { - const headers: Record = {}; - const token = await getWorkspaceAccessToken(true); - - if (token) { - headers.Authorization = `Bearer ${token}`; - } else { + if (!token) { return false; } const request = await fetch(`${workspaceUrl}/client`, { - headers, + headers: { + ...token, + }, body: info, method: 'POST', }); @@ -43,67 +52,68 @@ export async function syncWorkspace(_reconnectCheck = false) { } result = await request.json(); - } catch (err: any) { - SystemLogger.error({ - msg: 'Failed to sync with Rocket.Chat Cloud', - url: '/client', - err, - }); - - return false; - } finally { - // aways fetch the license - await getWorkspaceLicense(); - } - const data = result; - if (!data) { - return true; - } + const data = result; + if (!data) { + return true; + } - if (data.publicKey) { - await Settings.updateValueById('Cloud_Workspace_PublicKey', data.publicKey); - } + if (data.publicKey) { + await Settings.updateValueById('Cloud_Workspace_PublicKey', data.publicKey); + } - if (data.trial?.trialId) { - await Settings.updateValueById('Cloud_Workspace_Had_Trial', true); - } + if (data.trial?.trialId) { + await Settings.updateValueById('Cloud_Workspace_Had_Trial', true); + } - if (data.nps) { - const { id: npsId, expireAt } = data.nps; + if (data.nps) { + const { id: npsId, expireAt } = data.nps; - const startAt = new Date(data.nps.startAt); + const startAt = new Date(data.nps.startAt); - await NPS.create({ - npsId, - startAt, - expireAt: new Date(expireAt), - createdBy: { - _id: 'rocket.cat', - username: 'rocket.cat', - }, - }); + await NPS.create({ + npsId, + startAt, + expireAt: new Date(expireAt), + createdBy: { + _id: 'rocket.cat', + username: 'rocket.cat', + }, + }); - const now = new Date(); + const now = new Date(); - if (startAt.getFullYear() === now.getFullYear() && startAt.getMonth() === now.getMonth() && startAt.getDate() === now.getDate()) { - await getAndCreateNpsSurvey(npsId); + if (startAt.getFullYear() === now.getFullYear() && startAt.getMonth() === now.getMonth() && startAt.getDate() === now.getDate()) { + await getAndCreateNpsSurvey(npsId); + } } - } - - // add banners - if (data.banners) { - for await (const banner of data.banners) { - const { createdAt, expireAt, startAt } = banner; - await Banner.create({ - ...banner, - createdAt: new Date(createdAt), - expireAt: new Date(expireAt), - startAt: new Date(startAt), - }); + // add banners + if (data.banners) { + for await (const banner of data.banners) { + const { createdAt, expireAt, startAt } = banner; + + await Banner.create({ + ...banner, + createdAt: new Date(createdAt), + expireAt: new Date(expireAt), + startAt: new Date(startAt), + }); + } } + } catch (err: any) { + SystemLogger.error({ + msg: 'Failed to sync with Rocket.Chat Cloud', + url: '/client', + err, + }); + + return false; + } finally { + // always fetch the license + await getWorkspaceLicense(); } + await cacheNewSupportedVersionsToken(); return true; From cb305d11c752d376e7ea290402eb565fb1b698a7 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Wed, 13 Sep 2023 15:55:47 -0300 Subject: [PATCH 04/20] move setting creation --- apps/meteor/server/settings/setup-wizard.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/meteor/server/settings/setup-wizard.ts b/apps/meteor/server/settings/setup-wizard.ts index b5cdb4f6a4b1..62da3f1471cf 100644 --- a/apps/meteor/server/settings/setup-wizard.ts +++ b/apps/meteor/server/settings/setup-wizard.ts @@ -1204,6 +1204,13 @@ export const createSetupWSettings = () => secret: true, }); + await this.add('Cloud_Workspace_Supported_Versions_Token', '', { + type: 'string', + hidden: true, + readonly: true, + secret: true, + }); + await this.add('Cloud_Url', 'https://cloud.rocket.chat', { type: 'string', hidden: true, From 0afd6713d142ba8a28aea461cb3441c077e815a1 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Wed, 13 Sep 2023 18:49:10 -0300 Subject: [PATCH 05/20] Review --- .../app/api/server/lib/getServerInfo.ts | 25 ++-- .../functions/getWorkspaceAccessToken.ts | 4 +- .../functions/supportedVersionsToken.ts | 123 +++++++++++++++--- .../cloud/server/functions/syncWorkspace.ts | 4 +- apps/meteor/client/definitions/info.d.ts | 5 +- apps/meteor/package.json | 1 + .../server-cloud-communication/.eslintrc.json | 4 + .../server-cloud-communication/package.json | 24 ++++ .../src/definitions/index.ts | 49 +++++++ .../server-cloud-communication/src/index.ts | 2 + .../server-cloud-communication/tsconfig.json | 8 ++ yarn.lock | 33 +++++ 12 files changed, 244 insertions(+), 38 deletions(-) create mode 100644 packages/server-cloud-communication/.eslintrc.json create mode 100644 packages/server-cloud-communication/package.json create mode 100644 packages/server-cloud-communication/src/definitions/index.ts create mode 100644 packages/server-cloud-communication/src/index.ts create mode 100644 packages/server-cloud-communication/tsconfig.json diff --git a/apps/meteor/app/api/server/lib/getServerInfo.ts b/apps/meteor/app/api/server/lib/getServerInfo.ts index 9203aa23e5d5..1abe31301f97 100644 --- a/apps/meteor/app/api/server/lib/getServerInfo.ts +++ b/apps/meteor/app/api/server/lib/getServerInfo.ts @@ -1,5 +1,5 @@ import { hasPermissionAsync } from '../../../authorization/server/functions/hasPermission'; -import { getCachedSupportedVersionsToken } from '../../../cloud/server/functions/supportedVersionsToken'; +import { getCachedSupportedVersionsToken, wrapPromise } from '../../../cloud/server/functions/supportedVersionsToken'; import { Info } from '../../../utils/rocketchat.info'; type ServerInfo = @@ -14,21 +14,18 @@ const removePatchInfo = (version: string): string => version.replace(/(\d+\.\d+) export async function getServerInfo(userId?: string): Promise { if (userId && (await hasPermissionAsync(userId, 'get-server-info'))) { - try { - const supportedVersionsToken = await getCachedSupportedVersionsToken(); + const supportedVersionsToken = await wrapPromise(getCachedSupportedVersionsToken()); - return { - info: { - ...Info, - supportedVersions: supportedVersionsToken, - }, - }; - } catch (e) { - return { - info: Info, - }; - } + return { + info: { + ...Info, + ...(supportedVersionsToken.success && { + supportedVersions: supportedVersionsToken.result, + }), + }, + }; } + return { version: removePatchInfo(Info.version), }; diff --git a/apps/meteor/app/cloud/server/functions/getWorkspaceAccessToken.ts b/apps/meteor/app/cloud/server/functions/getWorkspaceAccessToken.ts index e323a6f7b917..49f04433c7c2 100644 --- a/apps/meteor/app/cloud/server/functions/getWorkspaceAccessToken.ts +++ b/apps/meteor/app/cloud/server/functions/getWorkspaceAccessToken.ts @@ -45,11 +45,11 @@ export const generateWorkspaceBearerHttpHeader = async ( forceNew = false, scope = '', save = true, -): Promise<{ Authorization: string } | Record> => { +): Promise<{ Authorization: string } | undefined> => { const token = await getWorkspaceAccessToken(forceNew, scope, save); if (!token) { - return {}; + return undefined; } return { diff --git a/apps/meteor/app/cloud/server/functions/supportedVersionsToken.ts b/apps/meteor/app/cloud/server/functions/supportedVersionsToken.ts index 59060555cefa..251ededfb890 100644 --- a/apps/meteor/app/cloud/server/functions/supportedVersionsToken.ts +++ b/apps/meteor/app/cloud/server/functions/supportedVersionsToken.ts @@ -1,41 +1,126 @@ +import type { SettingValue } from '@rocket.chat/core-typings'; import { Settings } from '@rocket.chat/models'; +import type { CloudVersionsResponse } from '@rocket.chat/server-cloud-communication'; +import type { Response } from '@rocket.chat/server-fetch'; import { serverFetch as fetch } from '@rocket.chat/server-fetch'; +import { supportedVersions } from '../../../../ee/app/license/server/license'; import { SystemLogger } from '../../../../server/lib/logger/system'; import { settings } from '../../../settings/server'; import { generateWorkspaceBearerHttpHeader } from './getWorkspaceAccessToken'; -export const getSupportedVersionsToken = async (): Promise => { - const headers = await generateWorkspaceBearerHttpHeader(); +/** HELPERS */ - const response = await fetch('https://releases.rocket.chat/supported/server', { - headers, - }); - const data = await response.json(); - const { signed } = data; +export const wrapPromise = ( + promise: Promise, +): Promise< + | { + success: true; + result: T; + } + | { + success: false; + error: any; + } +> => + promise + .then((result) => ({ success: true, result } as const)) + .catch((error) => ({ + success: false, + error, + })); + +export const handleResponse = async (promise: Promise) => { + return wrapPromise( + (async () => { + const request = await promise; + if (!request.ok) { + throw new Error((await request.json()).error); + } + + return request.json(); + })(), + ); +}; + +const cacheValueInSettings = ( + key: string, + fn: () => Promise, +): (() => Promise) & { + reset: () => Promise; +} => { + const reset = async () => { + const value = await fn(); + + await Settings.updateValueById(key, value); + + return value; + }; + + return Object.assign( + async () => { + const storedValue = settings.get(key); + + if (storedValue) { + return storedValue; + } - return signed; + return reset(); + }, + { + reset, + }, + ); }; -export const cacheNewSupportedVersionsToken = async (): Promise => { - try { - const signed = await getSupportedVersionsToken(); +/** CODE */ - await Settings.updateValueById('Cloud_Workspace_Supported_Versions_Token', signed); - } catch (error) { +const getSupportedVersionsFromCloud = async () => { + const headers = await generateWorkspaceBearerHttpHeader(); + + const response = await handleResponse( + fetch('https://releases.rocket.chat/supported/server', { + headers, + }), + ); + + if (!response.success) { SystemLogger.error({ - msg: 'Failed to fetch supported versions token', + msg: 'Failed to communicate with Rocket.Chat Cloud', url: 'https://releases.rocket.chat/supported/server', + err: response.error, }); } + + return response; }; -export const getCachedSupportedVersionsToken = async (): Promise => { - const token = settings.get('Cloud_Workspace_Supported_Versions_Token'); +const electSupportedVersion = async (...tokens: (CloudVersionsResponse | undefined)[]) => { + const [token] = (tokens.filter(Boolean) as CloudVersionsResponse[]).sort((a, b) => { + return new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime(); + }); + + return token?.signed ?? ''; +}; - if (token) { - return token; +const getSupportedVersionsToken = async () => { + if (process.env.NODE_ENV === 'development') { + if (process.env.MOCK_CLOUD_SUPPORTED_VERSIONS_TOKEN) { + return JSON.parse(process.env.MOCK_CLOUD_SUPPORTED_VERSIONS_TOKEN); + } } + /** + * Gets the supported versions from the license + * Gets the supported versions from the cloud + * Gets the latest version + * return the token + */ + + const [versionsFromLicense, response] = await Promise.all([supportedVersions(), getSupportedVersionsFromCloud()]); - return getSupportedVersionsToken(); + // TODO: get values from jtw token + + return electSupportedVersion(versionsFromLicense, (response.success && response.result) || undefined); }; + +export const getCachedSupportedVersionsToken = cacheValueInSettings('Cloud_Workspace_Supported_Versions_Token', getSupportedVersionsToken); diff --git a/apps/meteor/app/cloud/server/functions/syncWorkspace.ts b/apps/meteor/app/cloud/server/functions/syncWorkspace.ts index c6be8c7aea6b..f224cbce9b99 100644 --- a/apps/meteor/app/cloud/server/functions/syncWorkspace.ts +++ b/apps/meteor/app/cloud/server/functions/syncWorkspace.ts @@ -9,7 +9,7 @@ import { buildWorkspaceRegistrationData } from './buildRegistrationData'; import { generateWorkspaceBearerHttpHeader } from './getWorkspaceAccessToken'; import { getWorkspaceLicense } from './getWorkspaceLicense'; import { retrieveRegistrationStatus } from './retrieveRegistrationStatus'; -import { cacheNewSupportedVersionsToken } from './supportedVersionsToken'; +import { getCachedSupportedVersionsToken } from './supportedVersionsToken'; /** * Rocket.Chat Cloud Sync Procedure @@ -114,7 +114,7 @@ export async function syncWorkspace(_reconnectCheck = false) { await getWorkspaceLicense(); } - await cacheNewSupportedVersionsToken(); + await getCachedSupportedVersionsToken.reset(); return true; } diff --git a/apps/meteor/client/definitions/info.d.ts b/apps/meteor/client/definitions/info.d.ts index b49bfc967d84..18d499213dcb 100644 --- a/apps/meteor/client/definitions/info.d.ts +++ b/apps/meteor/client/definitions/info.d.ts @@ -22,6 +22,9 @@ declare module '*.info' { version: string; tag?: string; branch?: string; - supportedVersions: string; + minimumClientVersions: { + desktop: string; + mobile: string; + }; }; } diff --git a/apps/meteor/package.json b/apps/meteor/package.json index 31fed2d7f013..b59552d1fcc5 100644 --- a/apps/meteor/package.json +++ b/apps/meteor/package.json @@ -265,6 +265,7 @@ "@rocket.chat/presence": "workspace:^", "@rocket.chat/random": "workspace:^", "@rocket.chat/rest-typings": "workspace:^", + "@rocket.chat/server-cloud-communication": "workspace:^", "@rocket.chat/server-fetch": "workspace:^", "@rocket.chat/sha256": "workspace:^", "@rocket.chat/string-helpers": "next", diff --git a/packages/server-cloud-communication/.eslintrc.json b/packages/server-cloud-communication/.eslintrc.json new file mode 100644 index 000000000000..a83aeda48e66 --- /dev/null +++ b/packages/server-cloud-communication/.eslintrc.json @@ -0,0 +1,4 @@ +{ + "extends": ["@rocket.chat/eslint-config"], + "ignorePatterns": ["**/dist"] +} diff --git a/packages/server-cloud-communication/package.json b/packages/server-cloud-communication/package.json new file mode 100644 index 000000000000..0cae9a9e730e --- /dev/null +++ b/packages/server-cloud-communication/package.json @@ -0,0 +1,24 @@ +{ + "name": "@rocket.chat/server-cloud-communication", + "version": "0.0.1", + "private": true, + "devDependencies": { + "@types/jest": "~29.5.3", + "eslint": "~8.45.0", + "jest": "~29.6.1", + "ts-jest": "~29.0.5", + "typescript": "~5.1.6" + }, + "scripts": { + "lint": "eslint --ext .js,.jsx,.ts,.tsx .", + "lint:fix": "eslint --ext .js,.jsx,.ts,.tsx . --fix", + "test": "jest", + "build": "rm -rf dist && tsc -p tsconfig.json", + "dev": "tsc -p tsconfig.json --watch --preserveWatchOutput" + }, + "main": "./src/index.ts", + "typings": "./dist/index.d.ts", + "files": [ + "/dist" + ] +} diff --git a/packages/server-cloud-communication/src/definitions/index.ts b/packages/server-cloud-communication/src/definitions/index.ts new file mode 100644 index 000000000000..99ddcdbaa714 --- /dev/null +++ b/packages/server-cloud-communication/src/definitions/index.ts @@ -0,0 +1,49 @@ +type Dictionary = { [lng: string]: Record }; + +type Message = { + remainingDays: number; + title: 'message_token'; + subtitle: 'message_token'; + description: 'message_token'; + type: 'info' | 'alert' | 'error'; + params: Record & { + instance_ws_name: string; + instance_domain: string; + remaining_days: number; + }; + link: string; +}; + +type Version = { + version: string; + expiration: Date; + messages?: Message[]; +}; + +// eslint-disable-next-line @typescript-eslint/naming-convention +export interface SupportedVersions { + timestamp: string; + messages?: Message[]; + versions: Version[]; + exceptions?: { + domain: string; + uniqueId: string; + messages?: Message[]; + versions: Version[]; + }; + i18n?: Dictionary; +} + +// eslint-disable-next-line @typescript-eslint/naming-convention +export interface CloudVersionsResponse { + signed: string; // SerializedJWT; + timestamp: string; + messages?: Message[]; + versions: Version[]; + exceptions?: { + domain: string; + uniqueId: string; + messages?: Message[]; + versions: Version[]; + }; +} diff --git a/packages/server-cloud-communication/src/index.ts b/packages/server-cloud-communication/src/index.ts new file mode 100644 index 000000000000..d7a394815e25 --- /dev/null +++ b/packages/server-cloud-communication/src/index.ts @@ -0,0 +1,2 @@ +import type { CloudVersionsResponse } from './definitions'; +export { CloudVersionsResponse }; diff --git a/packages/server-cloud-communication/tsconfig.json b/packages/server-cloud-communication/tsconfig.json new file mode 100644 index 000000000000..e2be47cf5499 --- /dev/null +++ b/packages/server-cloud-communication/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.base.client.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./dist" + }, + "include": ["./src/**/*"] +} diff --git a/yarn.lock b/yarn.lock index a3d8d34c8906..5bf3d65d6d9b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8719,6 +8719,7 @@ __metadata: "@rocket.chat/presence": "workspace:^" "@rocket.chat/random": "workspace:^" "@rocket.chat/rest-typings": "workspace:^" + "@rocket.chat/server-cloud-communication": "workspace:^" "@rocket.chat/server-fetch": "workspace:^" "@rocket.chat/sha256": "workspace:^" "@rocket.chat/string-helpers": next @@ -9403,6 +9404,18 @@ __metadata: languageName: node linkType: hard +"@rocket.chat/server-cloud-communication@workspace:^, @rocket.chat/server-cloud-communication@workspace:packages/server-cloud-communication": + version: 0.0.0-use.local + resolution: "@rocket.chat/server-cloud-communication@workspace:packages/server-cloud-communication" + dependencies: + "@types/jest": ~29.5.3 + eslint: ~8.45.0 + jest: ~29.6.1 + ts-jest: ~29.0.5 + typescript: ~5.1.6 + languageName: unknown + linkType: soft + "@rocket.chat/server-fetch@workspace:^, @rocket.chat/server-fetch@workspace:packages/server-fetch": version: 0.0.0-use.local resolution: "@rocket.chat/server-fetch@workspace:packages/server-fetch" @@ -37888,6 +37901,16 @@ __metadata: languageName: node linkType: hard +"typescript@npm:~5.1.6": + version: 5.1.6 + resolution: "typescript@npm:5.1.6" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: b2f2c35096035fe1f5facd1e38922ccb8558996331405eb00a5111cc948b2e733163cc22fab5db46992aba7dd520fff637f2c1df4996ff0e134e77d3249a7350 + languageName: node + linkType: hard + "typescript@patch:typescript@^5.2.2#~builtin, typescript@patch:typescript@~5.2.2#~builtin": version: 5.2.2 resolution: "typescript@patch:typescript@npm%3A5.2.2#~builtin::version=5.2.2&hash=f456af" @@ -37898,6 +37921,16 @@ __metadata: languageName: node linkType: hard +"typescript@patch:typescript@~5.1.6#~builtin": + version: 5.1.6 + resolution: "typescript@patch:typescript@npm%3A5.1.6#~builtin::version=5.1.6&hash=f456af" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 21e88b0a0c0226f9cb9fd25b9626fb05b4c0f3fddac521844a13e1f30beb8f14e90bd409a9ac43c812c5946d714d6e0dee12d5d02dfc1c562c5aacfa1f49b606 + languageName: node + linkType: hard + "ua-parser-js@npm:^1.0.35": version: 1.0.35 resolution: "ua-parser-js@npm:1.0.35" From b1a53056af71f380bfaeac2f0e5db88a543ce837 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Wed, 13 Sep 2023 18:59:20 -0300 Subject: [PATCH 06/20] supportedVersionsToken.spec --- .../app/api/server/lib/getServerInfo.ts | 5 +++- .../supportedVersionsChooseLatest.spec.ts | 23 +++++++++++++++++++ .../supportedVersionsChooseLatest.ts | 9 ++++++++ .../supportedVersionsToken.ts | 19 +++++---------- .../cloud/server/functions/syncWorkspace.ts | 4 +++- 5 files changed, 45 insertions(+), 15 deletions(-) create mode 100644 apps/meteor/app/cloud/server/functions/supportedVersionsToken/supportedVersionsChooseLatest.spec.ts create mode 100644 apps/meteor/app/cloud/server/functions/supportedVersionsToken/supportedVersionsChooseLatest.ts rename apps/meteor/app/cloud/server/functions/{ => supportedVersionsToken}/supportedVersionsToken.ts (78%) diff --git a/apps/meteor/app/api/server/lib/getServerInfo.ts b/apps/meteor/app/api/server/lib/getServerInfo.ts index 1abe31301f97..8b0f15ef2470 100644 --- a/apps/meteor/app/api/server/lib/getServerInfo.ts +++ b/apps/meteor/app/api/server/lib/getServerInfo.ts @@ -1,5 +1,8 @@ import { hasPermissionAsync } from '../../../authorization/server/functions/hasPermission'; -import { getCachedSupportedVersionsToken, wrapPromise } from '../../../cloud/server/functions/supportedVersionsToken'; +import { + getCachedSupportedVersionsToken, + wrapPromise, +} from '../../../cloud/server/functions/supportedVersionsToken/supportedVersionsToken'; import { Info } from '../../../utils/rocketchat.info'; type ServerInfo = diff --git a/apps/meteor/app/cloud/server/functions/supportedVersionsToken/supportedVersionsChooseLatest.spec.ts b/apps/meteor/app/cloud/server/functions/supportedVersionsToken/supportedVersionsChooseLatest.spec.ts new file mode 100644 index 000000000000..888ec4ea7bb0 --- /dev/null +++ b/apps/meteor/app/cloud/server/functions/supportedVersionsToken/supportedVersionsChooseLatest.spec.ts @@ -0,0 +1,23 @@ +import type { CloudVersionsResponse } from '@rocket.chat/server-cloud-communication'; + +import { supportedVersionsChooseLatest } from './supportedVersionsChooseLatest'; + +describe('supportedVersionsChooseLatest', () => { + test('should return the latest version', async () => { + const versionFromLicense: CloudVersionsResponse = { + timestamp: '2021-08-31T18:00:00.000Z', + signed: 'license', + versions: [], + }; + + const versionFromCloud: CloudVersionsResponse = { + timestamp: '2021-08-31T19:00:00.000Z', + signed: 'cloud', + versions: [], + }; + + const result = await supportedVersionsChooseLatest(versionFromLicense, versionFromCloud); + + expect(result).toBe(versionFromCloud.signed); + }); +}); diff --git a/apps/meteor/app/cloud/server/functions/supportedVersionsToken/supportedVersionsChooseLatest.ts b/apps/meteor/app/cloud/server/functions/supportedVersionsToken/supportedVersionsChooseLatest.ts new file mode 100644 index 000000000000..3ee89266c275 --- /dev/null +++ b/apps/meteor/app/cloud/server/functions/supportedVersionsToken/supportedVersionsChooseLatest.ts @@ -0,0 +1,9 @@ +import type { CloudVersionsResponse } from '@rocket.chat/server-cloud-communication'; + +export const supportedVersionsChooseLatest = async (...tokens: (CloudVersionsResponse | undefined)[]) => { + const [token] = (tokens.filter(Boolean) as CloudVersionsResponse[]).sort((a, b) => { + return new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime(); + }); + + return token?.signed ?? ''; +}; diff --git a/apps/meteor/app/cloud/server/functions/supportedVersionsToken.ts b/apps/meteor/app/cloud/server/functions/supportedVersionsToken/supportedVersionsToken.ts similarity index 78% rename from apps/meteor/app/cloud/server/functions/supportedVersionsToken.ts rename to apps/meteor/app/cloud/server/functions/supportedVersionsToken/supportedVersionsToken.ts index 251ededfb890..1f0ef718e33d 100644 --- a/apps/meteor/app/cloud/server/functions/supportedVersionsToken.ts +++ b/apps/meteor/app/cloud/server/functions/supportedVersionsToken/supportedVersionsToken.ts @@ -4,10 +4,11 @@ import type { CloudVersionsResponse } from '@rocket.chat/server-cloud-communicat import type { Response } from '@rocket.chat/server-fetch'; import { serverFetch as fetch } from '@rocket.chat/server-fetch'; -import { supportedVersions } from '../../../../ee/app/license/server/license'; -import { SystemLogger } from '../../../../server/lib/logger/system'; -import { settings } from '../../../settings/server'; -import { generateWorkspaceBearerHttpHeader } from './getWorkspaceAccessToken'; +import { supportedVersions } from '../../../../../ee/app/license/server/license'; +import { SystemLogger } from '../../../../../server/lib/logger/system'; +import { settings } from '../../../../settings/server'; +import { generateWorkspaceBearerHttpHeader } from '../getWorkspaceAccessToken'; +import { supportedVersionsChooseLatest } from './supportedVersionsChooseLatest'; /** HELPERS */ @@ -95,14 +96,6 @@ const getSupportedVersionsFromCloud = async () => { return response; }; -const electSupportedVersion = async (...tokens: (CloudVersionsResponse | undefined)[]) => { - const [token] = (tokens.filter(Boolean) as CloudVersionsResponse[]).sort((a, b) => { - return new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime(); - }); - - return token?.signed ?? ''; -}; - const getSupportedVersionsToken = async () => { if (process.env.NODE_ENV === 'development') { if (process.env.MOCK_CLOUD_SUPPORTED_VERSIONS_TOKEN) { @@ -120,7 +113,7 @@ const getSupportedVersionsToken = async () => { // TODO: get values from jtw token - return electSupportedVersion(versionsFromLicense, (response.success && response.result) || undefined); + return supportedVersionsChooseLatest(versionsFromLicense, (response.success && response.result) || undefined); }; export const getCachedSupportedVersionsToken = cacheValueInSettings('Cloud_Workspace_Supported_Versions_Token', getSupportedVersionsToken); diff --git a/apps/meteor/app/cloud/server/functions/syncWorkspace.ts b/apps/meteor/app/cloud/server/functions/syncWorkspace.ts index f224cbce9b99..1707999a5d5c 100644 --- a/apps/meteor/app/cloud/server/functions/syncWorkspace.ts +++ b/apps/meteor/app/cloud/server/functions/syncWorkspace.ts @@ -9,7 +9,7 @@ import { buildWorkspaceRegistrationData } from './buildRegistrationData'; import { generateWorkspaceBearerHttpHeader } from './getWorkspaceAccessToken'; import { getWorkspaceLicense } from './getWorkspaceLicense'; import { retrieveRegistrationStatus } from './retrieveRegistrationStatus'; -import { getCachedSupportedVersionsToken } from './supportedVersionsToken'; +import { getCachedSupportedVersionsToken } from './supportedVersionsToken/supportedVersionsToken'; /** * Rocket.Chat Cloud Sync Procedure @@ -26,6 +26,8 @@ import { getCachedSupportedVersionsToken } from './supportedVersionsToken'; export async function syncWorkspace(_reconnectCheck = false) { const { workspaceRegistered } = await retrieveRegistrationStatus(); if (!workspaceRegistered) { + return false; + } const info = await buildWorkspaceRegistrationData(undefined); From 859be63ea329afd0668e64db9a80d36f11ecba24 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Wed, 13 Sep 2023 19:05:20 -0300 Subject: [PATCH 07/20] syncWorkspace/syncWorkspace.back --- apps/meteor/app/cloud/server/functions/syncWorkspace.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/meteor/app/cloud/server/functions/syncWorkspace.ts b/apps/meteor/app/cloud/server/functions/syncWorkspace.ts index 1707999a5d5c..8fc1d7b797a5 100644 --- a/apps/meteor/app/cloud/server/functions/syncWorkspace.ts +++ b/apps/meteor/app/cloud/server/functions/syncWorkspace.ts @@ -112,11 +112,10 @@ export async function syncWorkspace(_reconnectCheck = false) { return false; } finally { - // always fetch the license + // aways fetch the license await getWorkspaceLicense(); } await getCachedSupportedVersionsToken.reset(); - return true; } From 7196d88c701b80a4676c558550d13d52526160b4 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Wed, 13 Sep 2023 19:07:42 -0300 Subject: [PATCH 08/20] remove reconnectCheck from syncWorkspace --- apps/meteor/app/cloud/server/functions/reconnectWorkspace.ts | 2 +- .../meteor/app/cloud/server/functions/startRegisterWorkspace.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/meteor/app/cloud/server/functions/reconnectWorkspace.ts b/apps/meteor/app/cloud/server/functions/reconnectWorkspace.ts index db425d2e8a30..7ee02a5e5de4 100644 --- a/apps/meteor/app/cloud/server/functions/reconnectWorkspace.ts +++ b/apps/meteor/app/cloud/server/functions/reconnectWorkspace.ts @@ -11,7 +11,7 @@ export async function reconnectWorkspace() { await Settings.updateValueById('Register_Server', true); - await syncWorkspace(true); + await syncWorkspace(); return true; } diff --git a/apps/meteor/app/cloud/server/functions/startRegisterWorkspace.ts b/apps/meteor/app/cloud/server/functions/startRegisterWorkspace.ts index af74fcd7d211..7f7c78a137e0 100644 --- a/apps/meteor/app/cloud/server/functions/startRegisterWorkspace.ts +++ b/apps/meteor/app/cloud/server/functions/startRegisterWorkspace.ts @@ -10,7 +10,7 @@ import { syncWorkspace } from './syncWorkspace'; export async function startRegisterWorkspace(resend = false) { const { workspaceRegistered } = await retrieveRegistrationStatus(); if (workspaceRegistered || process.env.TEST_MODE) { - await syncWorkspace(true); + await syncWorkspace(); return true; } From 7f61579255c3c2ddcc465be69fd740ae29c00450 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Wed, 13 Sep 2023 19:57:41 -0300 Subject: [PATCH 09/20] refactor syncWorkspace --- .../functions/getWorkspaceAccessToken.ts | 27 ++++ .../server/functions/getWorkspaceLicense.ts | 60 ++++----- .../supportedVersionsToken.ts | 5 +- .../cloud/server/functions/syncWorkspace.ts | 121 ------------------ .../server/functions/syncWorkspace/index.ts | 17 +++ .../functions/syncWorkspace/syncCloudData.ts | 85 ++++++++++++ 6 files changed, 157 insertions(+), 158 deletions(-) delete mode 100644 apps/meteor/app/cloud/server/functions/syncWorkspace.ts create mode 100644 apps/meteor/app/cloud/server/functions/syncWorkspace/index.ts create mode 100644 apps/meteor/app/cloud/server/functions/syncWorkspace/syncCloudData.ts diff --git a/apps/meteor/app/cloud/server/functions/getWorkspaceAccessToken.ts b/apps/meteor/app/cloud/server/functions/getWorkspaceAccessToken.ts index 49f04433c7c2..b495e3342d4b 100644 --- a/apps/meteor/app/cloud/server/functions/getWorkspaceAccessToken.ts +++ b/apps/meteor/app/cloud/server/functions/getWorkspaceAccessToken.ts @@ -41,6 +41,33 @@ export async function getWorkspaceAccessToken(forceNew = false, scope = '', save return accessToken.token; } +export class CloudWorkspaceAccessTokenError extends Error { + constructor() { + super('Could not get workspace access token'); + } +} + +export async function getWorkspaceAccessTokenOrThrow(forceNew = false, scope = '', save = true): Promise { + const token = await getWorkspaceAccessToken(forceNew, scope, save); + + if (!token) { + throw new CloudWorkspaceAccessTokenError(); + } + + return token; +} + +export const generateWorkspaceBearerHttpHeaderOrThrow = async ( + forceNew = false, + scope = '', + save = true, +): Promise<{ Authorization: string }> => { + const token = await getWorkspaceAccessTokenOrThrow(forceNew, scope, save); + return { + Authorization: `Bearer ${token}`, + }; +}; + export const generateWorkspaceBearerHttpHeader = async ( forceNew = false, scope = '', diff --git a/apps/meteor/app/cloud/server/functions/getWorkspaceLicense.ts b/apps/meteor/app/cloud/server/functions/getWorkspaceLicense.ts index 275e646e5343..6be18f86d466 100644 --- a/apps/meteor/app/cloud/server/functions/getWorkspaceLicense.ts +++ b/apps/meteor/app/cloud/server/functions/getWorkspaceLicense.ts @@ -5,64 +5,52 @@ import { callbacks } from '../../../../lib/callbacks'; import { SystemLogger } from '../../../../server/lib/logger/system'; import { settings } from '../../../settings/server'; import { LICENSE_VERSION } from '../license'; -import { getWorkspaceAccessToken } from './getWorkspaceAccessToken'; +import { generateWorkspaceBearerHttpHeaderOrThrow } from './getWorkspaceAccessToken'; +import { handleResponse } from './supportedVersionsToken/supportedVersionsToken'; -export async function getWorkspaceLicense(): Promise<{ updated: boolean; license: string }> { - const currentLicense = await Settings.findOne('Cloud_Workspace_License'); - - const cachedLicenseReturn = async () => { - const license = currentLicense?.value as string; - if (license) { - await callbacks.run('workspaceLicenseChanged', license); - } +export async function getWorkspaceLicense() { + const token = await generateWorkspaceBearerHttpHeaderOrThrow(); - return { updated: false, license }; - }; + const currentLicense = await Settings.findOne('Cloud_Workspace_License'); - const token = await getWorkspaceAccessToken(); - if (!token) { - return cachedLicenseReturn(); + // TODO: check if this is the correct way to handle this + // If there is no license, in theory, it should be a new workspace non registered + // in this case the `generateWorkspaceBearerHttpHeaderOrThrow` show throw an error before + // so in theory, this should never happen + if (!currentLicense?._updatedAt) { + throw new Error('Failed to retrieve current license'); } - let licenseResult; - try { - const request = await fetch(`${settings.get('Cloud_Workspace_Registration_Client_Uri')}/license`, { + const request = await handleResponse( + fetch(`${settings.get('Cloud_Workspace_Registration_Client_Uri')}/license`, { headers: { - Authorization: `Bearer ${token}`, + ...token, }, params: { version: LICENSE_VERSION, }, - }); - - if (!request.ok) { - throw new Error((await request.json()).error); - } + }), + ); - licenseResult = await request.json(); - } catch (err: any) { + if (!request.success) { SystemLogger.error({ msg: 'Failed to update license from Rocket.Chat Cloud', url: '/license', - err, + err: request.error, }); - - return cachedLicenseReturn(); + if (currentLicense.value) { + return callbacks.run('workspaceLicenseChanged', currentLicense.value); + } + return; } - const remoteLicense = licenseResult; - - if (!currentLicense || !currentLicense._updatedAt) { - throw new Error('Failed to retrieve current license'); - } + const remoteLicense = request.result as any; if (remoteLicense.updatedAt <= currentLicense._updatedAt) { - return cachedLicenseReturn(); + return callbacks.run('workspaceLicenseChanged', currentLicense.value); } await Settings.updateValueById('Cloud_Workspace_License', remoteLicense.license); await callbacks.run('workspaceLicenseChanged', remoteLicense.license); - - return { updated: true, license: remoteLicense.license }; } diff --git a/apps/meteor/app/cloud/server/functions/supportedVersionsToken/supportedVersionsToken.ts b/apps/meteor/app/cloud/server/functions/supportedVersionsToken/supportedVersionsToken.ts index 1f0ef718e33d..e868e5ec83b7 100644 --- a/apps/meteor/app/cloud/server/functions/supportedVersionsToken/supportedVersionsToken.ts +++ b/apps/meteor/app/cloud/server/functions/supportedVersionsToken/supportedVersionsToken.ts @@ -36,7 +36,10 @@ export const handleResponse = async (promise: Promise) => { (async () => { const request = await promise; if (!request.ok) { - throw new Error((await request.json()).error); + if (request.size > 0) { + throw new Error((await request.json()).error); + } + throw new Error(request.statusText); } return request.json(); diff --git a/apps/meteor/app/cloud/server/functions/syncWorkspace.ts b/apps/meteor/app/cloud/server/functions/syncWorkspace.ts deleted file mode 100644 index 8fc1d7b797a5..000000000000 --- a/apps/meteor/app/cloud/server/functions/syncWorkspace.ts +++ /dev/null @@ -1,121 +0,0 @@ -import { NPS, Banner } from '@rocket.chat/core-services'; -import { Settings } from '@rocket.chat/models'; -import { serverFetch as fetch } from '@rocket.chat/server-fetch'; - -import { SystemLogger } from '../../../../server/lib/logger/system'; -import { getAndCreateNpsSurvey } from '../../../../server/services/nps/getAndCreateNpsSurvey'; -import { settings } from '../../../settings/server'; -import { buildWorkspaceRegistrationData } from './buildRegistrationData'; -import { generateWorkspaceBearerHttpHeader } from './getWorkspaceAccessToken'; -import { getWorkspaceLicense } from './getWorkspaceLicense'; -import { retrieveRegistrationStatus } from './retrieveRegistrationStatus'; -import { getCachedSupportedVersionsToken } from './supportedVersionsToken/supportedVersionsToken'; - -/** - * Rocket.Chat Cloud Sync Procedure - * It does not matter if you are registered with Rocket.Chat Cloud: - * - Sends Statistics to Rocket.Chat Cloud - * If you are registered with Rocket.Chat Cloud - * - Communicates with Rocket.Chat Cloud to update valuable information - * - Receives NPS Survey from Rocket.Chat Cloud if applicable - * - Receives Banners from Rocket.Chat Cloud if applicable - * - Receives License from Rocket.Chat Cloud if applicable - * - Receives a new List of Supported Versions from Rocket.Chat Cloud - */ - -export async function syncWorkspace(_reconnectCheck = false) { - const { workspaceRegistered } = await retrieveRegistrationStatus(); - if (!workspaceRegistered) { - return false; - } - - const info = await buildWorkspaceRegistrationData(undefined); - - const workspaceUrl = settings.get('Cloud_Workspace_Registration_Client_Uri'); - - const token = await generateWorkspaceBearerHttpHeader(true); - - let result; - try { - if (!token) { - return false; - } - - const request = await fetch(`${workspaceUrl}/client`, { - headers: { - ...token, - }, - body: info, - method: 'POST', - }); - - if (!request.ok) { - throw new Error((await request.json()).error); - } - - result = await request.json(); - - const data = result; - if (!data) { - return true; - } - - if (data.publicKey) { - await Settings.updateValueById('Cloud_Workspace_PublicKey', data.publicKey); - } - - if (data.trial?.trialId) { - await Settings.updateValueById('Cloud_Workspace_Had_Trial', true); - } - - if (data.nps) { - const { id: npsId, expireAt } = data.nps; - - const startAt = new Date(data.nps.startAt); - - await NPS.create({ - npsId, - startAt, - expireAt: new Date(expireAt), - createdBy: { - _id: 'rocket.cat', - username: 'rocket.cat', - }, - }); - - const now = new Date(); - - if (startAt.getFullYear() === now.getFullYear() && startAt.getMonth() === now.getMonth() && startAt.getDate() === now.getDate()) { - await getAndCreateNpsSurvey(npsId); - } - } - - // add banners - if (data.banners) { - for await (const banner of data.banners) { - const { createdAt, expireAt, startAt } = banner; - - await Banner.create({ - ...banner, - createdAt: new Date(createdAt), - expireAt: new Date(expireAt), - startAt: new Date(startAt), - }); - } - } - } catch (err: any) { - SystemLogger.error({ - msg: 'Failed to sync with Rocket.Chat Cloud', - url: '/client', - err, - }); - - return false; - } finally { - // aways fetch the license - await getWorkspaceLicense(); - } - - await getCachedSupportedVersionsToken.reset(); - return true; -} diff --git a/apps/meteor/app/cloud/server/functions/syncWorkspace/index.ts b/apps/meteor/app/cloud/server/functions/syncWorkspace/index.ts new file mode 100644 index 000000000000..48d5afa9dbc5 --- /dev/null +++ b/apps/meteor/app/cloud/server/functions/syncWorkspace/index.ts @@ -0,0 +1,17 @@ +import { CloudWorkspaceAccessTokenError } from '../getWorkspaceAccessToken'; +import { getWorkspaceLicense } from '../getWorkspaceLicense'; +import { getCachedSupportedVersionsToken } from '../supportedVersionsToken/supportedVersionsToken'; +import { syncCloudData } from './syncCloudData'; + +export async function syncWorkspace() { + try { + await syncCloudData(); + await getWorkspaceLicense(); + } catch (error) { + if (error instanceof CloudWorkspaceAccessTokenError) { + // TODO: Remove License if there is no access token + } + } + + await getCachedSupportedVersionsToken.reset(); +} diff --git a/apps/meteor/app/cloud/server/functions/syncWorkspace/syncCloudData.ts b/apps/meteor/app/cloud/server/functions/syncWorkspace/syncCloudData.ts new file mode 100644 index 000000000000..0dc56f31c5da --- /dev/null +++ b/apps/meteor/app/cloud/server/functions/syncWorkspace/syncCloudData.ts @@ -0,0 +1,85 @@ +import { NPS, Banner } from '@rocket.chat/core-services'; +import { Settings } from '@rocket.chat/models'; +import { serverFetch as fetch } from '@rocket.chat/server-fetch'; + +import { SystemLogger } from '../../../../../server/lib/logger/system'; +import { getAndCreateNpsSurvey } from '../../../../../server/services/nps/getAndCreateNpsSurvey'; +import { settings } from '../../../../settings/server'; +import { buildWorkspaceRegistrationData } from '../buildRegistrationData'; +import { generateWorkspaceBearerHttpHeaderOrThrow } from '../getWorkspaceAccessToken'; +import { handleResponse } from '../supportedVersionsToken/supportedVersionsToken'; + +export async function syncCloudData() { + const info = await buildWorkspaceRegistrationData(undefined); + + const token = await generateWorkspaceBearerHttpHeaderOrThrow(true); + + const request = await handleResponse( + fetch(`${settings.get('Cloud_Workspace_Registration_Client_Uri')}/client`, { + headers: { + ...token, + }, + body: info, + method: 'POST', + }), + ); + + if (!request.success) { + return SystemLogger.error({ + msg: 'Failed to sync with Rocket.Chat Cloud', + url: '/client', + err: request.error, + }); + } + + const data = request.result as any; + if (!data) { + return true; + } + + if (data.publicKey) { + await Settings.updateValueById('Cloud_Workspace_PublicKey', data.publicKey); + } + + if (data.trial?.trialId) { + await Settings.updateValueById('Cloud_Workspace_Had_Trial', true); + } + + if (data.nps) { + const { id: npsId, expireAt } = data.nps; + + const startAt = new Date(data.nps.startAt); + + await NPS.create({ + npsId, + startAt, + expireAt: new Date(expireAt), + createdBy: { + _id: 'rocket.cat', + username: 'rocket.cat', + }, + }); + + const now = new Date(); + + if (startAt.getFullYear() === now.getFullYear() && startAt.getMonth() === now.getMonth() && startAt.getDate() === now.getDate()) { + await getAndCreateNpsSurvey(npsId); + } + } + + // add banners + if (data.banners) { + for await (const banner of data.banners) { + const { createdAt, expireAt, startAt } = banner; + + await Banner.create({ + ...banner, + createdAt: new Date(createdAt), + expireAt: new Date(expireAt), + startAt: new Date(startAt), + }); + } + } + + return true; +} From 2e505bc5999c7e1f8372c41392c0909b93496b62 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Wed, 13 Sep 2023 20:48:53 -0300 Subject: [PATCH 10/20] remove connectToCloud --- .../functions/getUserCloudAccessToken.ts | 113 ------------------ 1 file changed, 113 deletions(-) delete mode 100644 apps/meteor/app/cloud/server/functions/getUserCloudAccessToken.ts diff --git a/apps/meteor/app/cloud/server/functions/getUserCloudAccessToken.ts b/apps/meteor/app/cloud/server/functions/getUserCloudAccessToken.ts deleted file mode 100644 index bf39a50b6234..000000000000 --- a/apps/meteor/app/cloud/server/functions/getUserCloudAccessToken.ts +++ /dev/null @@ -1,113 +0,0 @@ -import type { IUser } from '@rocket.chat/core-typings'; -import { Users } 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 { userScopes } from '../oauthScopes'; -import { getRedirectUri } from './getRedirectUri'; -import { removeWorkspaceRegistrationInfo } from './removeWorkspaceRegistrationInfo'; -import { retrieveRegistrationStatus } from './retrieveRegistrationStatus'; -import { userLoggedOut } from './userLoggedOut'; - -export async function getUserCloudAccessToken(userId: string, forceNew = false, scope = '', save = true) { - const { workspaceRegistered } = await retrieveRegistrationStatus(); - - if (!workspaceRegistered) { - return ''; - } - - if (!userId) { - return ''; - } - - const user = await Users.findOneById>(userId, { projection: { 'services.cloud': 1 } }); - if (!user?.services?.cloud?.accessToken || !user?.services?.cloud?.refreshToken) { - return ''; - } - - const { accessToken, refreshToken, expiresAt } = user.services.cloud; - - const clientId = settings.get('Cloud_Workspace_Client_Id'); - if (!clientId) { - return ''; - } - - const clientSecret = settings.get('Cloud_Workspace_Client_Secret'); - if (!clientSecret) { - return ''; - } - - const now = new Date(); - - if (now < expiresAt && !forceNew) { - return accessToken; - } - - const cloudUrl = settings.get('Cloud_Url'); - const redirectUri = getRedirectUri(); - - if (scope === '') { - scope = userScopes.join(' '); - } - - let authTokenResult; - try { - const request = await fetch(`${cloudUrl}/api/oauth/token`, { - headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, - method: 'POST', - params: new URLSearchParams({ - client_id: clientId, - client_secret: clientSecret, - refresh_token: refreshToken, - scope, - grant_type: 'refresh_token', - redirect_uri: redirectUri, - }), - }); - - if (!request.ok) { - throw new Error((await request.json()).error); - } - - authTokenResult = await request.json(); - } catch (err: any) { - SystemLogger.error({ - msg: 'Failed to get User AccessToken from Rocket.Chat Cloud', - url: '/api/oauth/token', - err, - }); - - if (err) { - if (err.message.includes('oauth_invalid_client_credentials')) { - SystemLogger.error('Server has been unregistered from cloud'); - await removeWorkspaceRegistrationInfo(); - } - - if (err.message.includes('unauthorized')) { - await userLoggedOut(userId); - } - } - - return ''; - } - - if (save) { - const willExpireAt = new Date(); - willExpireAt.setSeconds(willExpireAt.getSeconds() + authTokenResult.expires_in); - - await Users.updateOne( - { _id: user._id }, - { - $set: { - 'services.cloud': { - accessToken: authTokenResult.access_token, - expiresAt: willExpireAt, - }, - }, - }, - ); - } - - return authTokenResult.access_token; -} From b24a3d19fe6e30b149bbd7e0cc001cd52a1a03c0 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Wed, 13 Sep 2023 21:31:57 -0300 Subject: [PATCH 11/20] unit --- .../unit => }/app/api/server/lib/getServerInfo.spec.ts | 8 +++++--- apps/meteor/app/cloud/server/methods.ts | 4 +++- packages/server-cloud-communication/package.json | 1 - packages/server-cloud-communication/src/index.ts | 1 + 4 files changed, 9 insertions(+), 5 deletions(-) rename apps/meteor/{tests/unit => }/app/api/server/lib/getServerInfo.spec.ts (89%) diff --git a/apps/meteor/tests/unit/app/api/server/lib/getServerInfo.spec.ts b/apps/meteor/app/api/server/lib/getServerInfo.spec.ts similarity index 89% rename from apps/meteor/tests/unit/app/api/server/lib/getServerInfo.spec.ts rename to apps/meteor/app/api/server/lib/getServerInfo.spec.ts index bc7f48a7396b..ca55cfa33e3e 100644 --- a/apps/meteor/tests/unit/app/api/server/lib/getServerInfo.spec.ts +++ b/apps/meteor/app/api/server/lib/getServerInfo.spec.ts @@ -6,7 +6,7 @@ import sinon from 'sinon'; const hasAllPermissionAsyncMock = sinon.stub(); const getCachedSupportedVersionsTokenMock = sinon.stub(); -const { getServerInfo } = proxyquire.noCallThru().load('../../../../../../app/api/server/lib/getServerInfo', { +const { getServerInfo } = proxyquire.noCallThru().load('./getServerInfo', { '../../../utils/rocketchat.info': { Info: { version: '3.0.1', @@ -15,11 +15,13 @@ const { getServerInfo } = proxyquire.noCallThru().load('../../../../../../app/ap '../../../authorization/server/functions/hasPermission': { hasPermissionAsync: hasAllPermissionAsyncMock, }, - '../../../cloud/server/functions/supportedVersionsToken': { + '../../../cloud/server/functions/supportedVersionsToken/supportedVersionsToken': { getCachedSupportedVersionsToken: getCachedSupportedVersionsTokenMock, }, + '../../../settings/server': { + settings: new Map(), + }, }); - describe('#getServerInfo()', () => { beforeEach(() => { hasAllPermissionAsyncMock.reset(); diff --git a/apps/meteor/app/cloud/server/methods.ts b/apps/meteor/app/cloud/server/methods.ts index 89e7b99e7146..1d328d0c213e 100644 --- a/apps/meteor/app/cloud/server/methods.ts +++ b/apps/meteor/app/cloud/server/methods.ts @@ -108,7 +108,9 @@ Meteor.methods({ }); } - return syncWorkspace(); + await syncWorkspace(); + + return true; }, async 'cloud:connectWorkspace'(token) { check(token, String); diff --git a/packages/server-cloud-communication/package.json b/packages/server-cloud-communication/package.json index 0cae9a9e730e..c9e212263a8f 100644 --- a/packages/server-cloud-communication/package.json +++ b/packages/server-cloud-communication/package.json @@ -13,7 +13,6 @@ "lint": "eslint --ext .js,.jsx,.ts,.tsx .", "lint:fix": "eslint --ext .js,.jsx,.ts,.tsx . --fix", "test": "jest", - "build": "rm -rf dist && tsc -p tsconfig.json", "dev": "tsc -p tsconfig.json --watch --preserveWatchOutput" }, "main": "./src/index.ts", diff --git a/packages/server-cloud-communication/src/index.ts b/packages/server-cloud-communication/src/index.ts index d7a394815e25..def13791e8a1 100644 --- a/packages/server-cloud-communication/src/index.ts +++ b/packages/server-cloud-communication/src/index.ts @@ -1,2 +1,3 @@ import type { CloudVersionsResponse } from './definitions'; + export { CloudVersionsResponse }; From 711b40d121117228b006206c0e78e2330b5b892c Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Thu, 14 Sep 2023 01:54:31 -0300 Subject: [PATCH 12/20] fix typings --- packages/server-cloud-communication/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/server-cloud-communication/package.json b/packages/server-cloud-communication/package.json index c9e212263a8f..9b091bbc464f 100644 --- a/packages/server-cloud-communication/package.json +++ b/packages/server-cloud-communication/package.json @@ -16,7 +16,7 @@ "dev": "tsc -p tsconfig.json --watch --preserveWatchOutput" }, "main": "./src/index.ts", - "typings": "./dist/index.d.ts", + "types": "./src/index.ts", "files": [ "/dist" ] From 97f8925e15f83afedab1a29edcf08cf466c65ed7 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Thu, 14 Sep 2023 20:20:34 -0300 Subject: [PATCH 13/20] test --- apps/meteor/app/api/server/lib/getServerInfo.ts | 10 +++++++--- .../supportedVersionsToken/supportedVersionsToken.ts | 5 ----- apps/meteor/client/definitions/info.d.ts | 9 +++++---- .../rocketchat-version/plugin/compile-version.js | 7 +++++-- 4 files changed, 17 insertions(+), 14 deletions(-) diff --git a/apps/meteor/app/api/server/lib/getServerInfo.ts b/apps/meteor/app/api/server/lib/getServerInfo.ts index 8b0f15ef2470..987519742f14 100644 --- a/apps/meteor/app/api/server/lib/getServerInfo.ts +++ b/apps/meteor/app/api/server/lib/getServerInfo.ts @@ -3,11 +3,13 @@ import { getCachedSupportedVersionsToken, wrapPromise, } from '../../../cloud/server/functions/supportedVersionsToken/supportedVersionsToken'; -import { Info } from '../../../utils/rocketchat.info'; +import { Info, minimumClientVersions } from '../../../utils/rocketchat.info'; type ServerInfo = | { info: typeof Info; + supportedVersions?: string; + minimumClientVersions: typeof minimumClientVersions; } | { version: string | undefined; @@ -22,10 +24,12 @@ export async function getServerInfo(userId?: string): Promise { return { info: { ...Info, - ...(supportedVersionsToken.success && { + }, + minimumClientVersions, + ...(supportedVersionsToken.success && + supportedVersionsToken.result && { supportedVersions: supportedVersionsToken.result, }), - }, }; } diff --git a/apps/meteor/app/cloud/server/functions/supportedVersionsToken/supportedVersionsToken.ts b/apps/meteor/app/cloud/server/functions/supportedVersionsToken/supportedVersionsToken.ts index e868e5ec83b7..6aae9adc9600 100644 --- a/apps/meteor/app/cloud/server/functions/supportedVersionsToken/supportedVersionsToken.ts +++ b/apps/meteor/app/cloud/server/functions/supportedVersionsToken/supportedVersionsToken.ts @@ -100,11 +100,6 @@ const getSupportedVersionsFromCloud = async () => { }; const getSupportedVersionsToken = async () => { - if (process.env.NODE_ENV === 'development') { - if (process.env.MOCK_CLOUD_SUPPORTED_VERSIONS_TOKEN) { - return JSON.parse(process.env.MOCK_CLOUD_SUPPORTED_VERSIONS_TOKEN); - } - } /** * Gets the supported versions from the license * Gets the supported versions from the cloud diff --git a/apps/meteor/client/definitions/info.d.ts b/apps/meteor/client/definitions/info.d.ts index 18d499213dcb..43fa1fc53414 100644 --- a/apps/meteor/client/definitions/info.d.ts +++ b/apps/meteor/client/definitions/info.d.ts @@ -22,9 +22,10 @@ declare module '*.info' { version: string; tag?: string; branch?: string; - minimumClientVersions: { - desktop: string; - mobile: string; - }; + }; + + export const minimumClientVersions: { + desktop: string; + mobile: string; }; } diff --git a/apps/meteor/packages/rocketchat-version/plugin/compile-version.js b/apps/meteor/packages/rocketchat-version/plugin/compile-version.js index d18bbafafdbc..20b26b9cdcf0 100644 --- a/apps/meteor/packages/rocketchat-version/plugin/compile-version.js +++ b/apps/meteor/packages/rocketchat-version/plugin/compile-version.js @@ -26,7 +26,9 @@ class VersionCompiler { }; output.marketplaceApiVersion = require('@rocket.chat/apps-engine/package.json').version.replace(/^[^0-9]/g, ''); - output.minimumClientVersions = JSON.parse(fs.readFileSync(path.resolve(process.cwd(), './package.json'), { encoding: 'utf8' }))?.rocketchat?.minimumClientVersions || {}; + const minimumClientVersions = + JSON.parse(fs.readFileSync(path.resolve(process.cwd(), './package.json'), { encoding: 'utf8' }))?.rocketchat + ?.minimumClientVersions || {}; try { const result = await execAsync("git log --pretty=format:'%H%n%ad%n%an%n%s' -n 1"); const data = result.stdout.split('\n'); @@ -58,7 +60,8 @@ class VersionCompiler { // no branch } - output = `exports.Info = ${JSON.stringify(output, null, 4)};`; + output = `exports.Info = ${JSON.stringify(output, null, 4)}; + exports.minimumClientVersions = ${JSON.stringify(minimumClientVersions, null, 4)};`; file.addJavaScript({ data: output, From d116bd7bc453a598f3cc4ce36ec911f2e4d6994f Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Fri, 15 Sep 2023 13:44:57 -0300 Subject: [PATCH 14/20] remove disconnected variation --- apps/meteor/client/views/admin/cloud/RegisterWorkspace.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/meteor/client/views/admin/cloud/RegisterWorkspace.tsx b/apps/meteor/client/views/admin/cloud/RegisterWorkspace.tsx index e3e1f474cb91..a75e66ec1e4b 100644 --- a/apps/meteor/client/views/admin/cloud/RegisterWorkspace.tsx +++ b/apps/meteor/client/views/admin/cloud/RegisterWorkspace.tsx @@ -57,9 +57,9 @@ const RegisterWorkspace = () => { - - {isWorkspaceRegistered && t('RegisterWorkspace_NotRegistered_Subtitle')} - {!isWorkspaceRegistered && t('RegisterWorkspace_Registered_Description')} + + {!isWorkspaceRegistered && t('RegisterWorkspace_NotRegistered_Subtitle')} + {isWorkspaceRegistered && t('RegisterWorkspace_Registered_Description')} From 04e159238b796d6ac66df754022a7fe7f5c081f3 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Mon, 18 Sep 2023 14:42:47 -0300 Subject: [PATCH 15/20] expose exceptions to non logged users --- apps/meteor/app/api/server/default/info.ts | 5 +- .../app/api/server/lib/getServerInfo.ts | 40 ++++++------ packages/rest-typings/src/default/index.ts | 62 ++++++++++--------- 3 files changed, 52 insertions(+), 55 deletions(-) diff --git a/apps/meteor/app/api/server/default/info.ts b/apps/meteor/app/api/server/default/info.ts index b7806ab08f32..0deda662275d 100644 --- a/apps/meteor/app/api/server/default/info.ts +++ b/apps/meteor/app/api/server/default/info.ts @@ -1,5 +1,4 @@ import { API } from '../api'; -import { getLoggedInUser } from '../helpers/getLoggedInUser'; import { getServerInfo } from '../lib/getServerInfo'; API.default.addRoute( @@ -7,9 +6,7 @@ API.default.addRoute( { authRequired: false }, { async get() { - const user = await getLoggedInUser(this.request); - - return API.v1.success(await getServerInfo(user?._id)); + return API.v1.success(await getServerInfo(this.userId)); }, }, ); diff --git a/apps/meteor/app/api/server/lib/getServerInfo.ts b/apps/meteor/app/api/server/lib/getServerInfo.ts index 987519742f14..bea3ccc6da11 100644 --- a/apps/meteor/app/api/server/lib/getServerInfo.ts +++ b/apps/meteor/app/api/server/lib/getServerInfo.ts @@ -5,35 +5,33 @@ import { } from '../../../cloud/server/functions/supportedVersionsToken/supportedVersionsToken'; import { Info, minimumClientVersions } from '../../../utils/rocketchat.info'; -type ServerInfo = - | { - info: typeof Info; - supportedVersions?: string; - minimumClientVersions: typeof minimumClientVersions; - } - | { - version: string | undefined; - }; +type ServerInfo = { + info?: typeof Info; + supportedVersions?: string; + minimumClientVersions: typeof minimumClientVersions; + version: string | undefined; +}; const removePatchInfo = (version: string): string => version.replace(/(\d+\.\d+).*/, '$1'); export async function getServerInfo(userId?: string): Promise { - if (userId && (await hasPermissionAsync(userId, 'get-server-info'))) { - const supportedVersionsToken = await wrapPromise(getCachedSupportedVersionsToken()); + const hasPermissionToViewStatistics = userId && (await hasPermissionAsync(userId, 'view-statistics')); + const supportedVersionsToken = await wrapPromise(getCachedSupportedVersionsToken()); - return { + return { + version: removePatchInfo(Info.version), + + ...(hasPermissionToViewStatistics && { info: { ...Info, }, - minimumClientVersions, - ...(supportedVersionsToken.success && - supportedVersionsToken.result && { - supportedVersions: supportedVersionsToken.result, - }), - }; - } + version: Info.version, + }), - return { - version: removePatchInfo(Info.version), + minimumClientVersions, + ...(supportedVersionsToken.success && + supportedVersionsToken.result && { + supportedVersions: supportedVersionsToken.result, + }), }; } diff --git a/packages/rest-typings/src/default/index.ts b/packages/rest-typings/src/default/index.ts index b3aa5d3aa535..d990fbdc6a29 100644 --- a/packages/rest-typings/src/default/index.ts +++ b/packages/rest-typings/src/default/index.ts @@ -1,36 +1,38 @@ // eslint-disable-next-line @typescript-eslint/naming-convention export interface DefaultEndpoints { '/info': { - GET: () => - | { - info: { - build: { - arch: string; - cpus: number; - date: string; - freeMemory: number; - nodeVersion: string; - osRelease: string; - platform: string; - totalMemory: number; - }; - commit: { - author?: string; - branch?: string; - date?: string; - hash?: string; - subject?: string; - tag?: string; - }; - marketplaceApiVersion: string; - version: string; - tag?: string; - branch?: string; - }; - } - | { - version: string | undefined; - }; + GET: () => { + info: { + build: { + arch: string; + cpus: number; + date: string; + freeMemory: number; + nodeVersion: string; + osRelease: string; + platform: string; + totalMemory: number; + }; + commit: { + author?: string; + branch?: string; + date?: string; + hash?: string; + subject?: string; + tag?: string; + }; + marketplaceApiVersion: string; + version: string; + tag?: string; + branch?: string; + }; + supportedVersions?: string; + minimumClientVersions: { + desktop: string; + mobile: string; + }; + version: string | undefined; + }; }; '/ecdh_proxy/initEncryptedSession': { POST: () => void; From 15c9ca94e3c5c20c93234c617104e45da057eca0 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Mon, 18 Sep 2023 19:01:38 -0300 Subject: [PATCH 16/20] export token as signed prop --- apps/meteor/app/api/server/lib/getServerInfo.ts | 6 +++--- packages/rest-typings/src/default/index.ts | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/meteor/app/api/server/lib/getServerInfo.ts b/apps/meteor/app/api/server/lib/getServerInfo.ts index bea3ccc6da11..53ba3656babe 100644 --- a/apps/meteor/app/api/server/lib/getServerInfo.ts +++ b/apps/meteor/app/api/server/lib/getServerInfo.ts @@ -7,9 +7,9 @@ import { Info, minimumClientVersions } from '../../../utils/rocketchat.info'; type ServerInfo = { info?: typeof Info; - supportedVersions?: string; + supportedVersions?: { signed: string }; minimumClientVersions: typeof minimumClientVersions; - version: string | undefined; + version: string; }; const removePatchInfo = (version: string): string => version.replace(/(\d+\.\d+).*/, '$1'); @@ -31,7 +31,7 @@ export async function getServerInfo(userId?: string): Promise { minimumClientVersions, ...(supportedVersionsToken.success && supportedVersionsToken.result && { - supportedVersions: supportedVersionsToken.result, + supportedVersions: { signed: supportedVersionsToken.result }, }), }; } diff --git a/packages/rest-typings/src/default/index.ts b/packages/rest-typings/src/default/index.ts index d990fbdc6a29..0be60fc4413b 100644 --- a/packages/rest-typings/src/default/index.ts +++ b/packages/rest-typings/src/default/index.ts @@ -26,7 +26,7 @@ export interface DefaultEndpoints { tag?: string; branch?: string; }; - supportedVersions?: string; + supportedVersions?: { signed: string }; minimumClientVersions: { desktop: string; mobile: string; From c555df18b57f50bbd2c63a38edb06172b2d27d64 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Tue, 19 Sep 2023 14:05:55 -0300 Subject: [PATCH 17/20] e2e api --- apps/meteor/app/api/server/default/info.ts | 4 +++- apps/meteor/tests/end-to-end/api/00-miscellaneous.js | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/meteor/app/api/server/default/info.ts b/apps/meteor/app/api/server/default/info.ts index 0deda662275d..8297f90fffd9 100644 --- a/apps/meteor/app/api/server/default/info.ts +++ b/apps/meteor/app/api/server/default/info.ts @@ -1,4 +1,5 @@ import { API } from '../api'; +import { getLoggedInUser } from '../helpers/getLoggedInUser'; import { getServerInfo } from '../lib/getServerInfo'; API.default.addRoute( @@ -6,7 +7,8 @@ API.default.addRoute( { authRequired: false }, { async get() { - return API.v1.success(await getServerInfo(this.userId)); + const user = await getLoggedInUser(this.request); + return API.v1.success(await getServerInfo(user?._id)); }, }, ); diff --git a/apps/meteor/tests/end-to-end/api/00-miscellaneous.js b/apps/meteor/tests/end-to-end/api/00-miscellaneous.js index 7525fd6ab443..e9fec42e4b66 100644 --- a/apps/meteor/tests/end-to-end/api/00-miscellaneous.js +++ b/apps/meteor/tests/end-to-end/api/00-miscellaneous.js @@ -24,6 +24,7 @@ describe('miscellaneous', function () { .expect('Content-Type', 'application/json') .expect(200) .expect((res) => { + expect(res.body).to.have.property('version').and.to.be.a('string'); expect(res.body.info).to.have.property('version').and.to.be.a('string'); expect(res.body.info).to.have.property('build').and.to.be.an('object'); expect(res.body.info).to.have.property('commit').and.to.be.an('object'); From a786651089779cb58b98ff136d4e0dc02990258e Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Thu, 28 Sep 2023 21:30:04 -0300 Subject: [PATCH 18/20] rename types --- .../supportedVersionsChooseLatest.spec.ts | 12 +++++------ .../supportedVersionsChooseLatest.ts | 8 ++++---- .../supportedVersionsToken.ts | 20 ++++++++++++------- ee/packages/license/package.json | 3 ++- .../license/src/definition/ILicenseV3.ts | 4 ++++ ee/packages/license/src/index.ts | 8 +++++++- .../src/definitions/index.ts | 11 +--------- .../server-cloud-communication/src/index.ts | 4 ++-- yarn.lock | 1 + 9 files changed, 40 insertions(+), 31 deletions(-) diff --git a/apps/meteor/app/cloud/server/functions/supportedVersionsToken/supportedVersionsChooseLatest.spec.ts b/apps/meteor/app/cloud/server/functions/supportedVersionsToken/supportedVersionsChooseLatest.spec.ts index 888ec4ea7bb0..183065fd92a6 100644 --- a/apps/meteor/app/cloud/server/functions/supportedVersionsToken/supportedVersionsChooseLatest.spec.ts +++ b/apps/meteor/app/cloud/server/functions/supportedVersionsToken/supportedVersionsChooseLatest.spec.ts @@ -1,23 +1,23 @@ -import type { CloudVersionsResponse } from '@rocket.chat/server-cloud-communication'; +import type { SignedSupportedVersions } from '@rocket.chat/server-cloud-communication'; import { supportedVersionsChooseLatest } from './supportedVersionsChooseLatest'; describe('supportedVersionsChooseLatest', () => { test('should return the latest version', async () => { - const versionFromLicense: CloudVersionsResponse = { + const versionFromLicense: SignedSupportedVersions = { + signed: 'signed____', timestamp: '2021-08-31T18:00:00.000Z', - signed: 'license', versions: [], }; - const versionFromCloud: CloudVersionsResponse = { + const versionFromCloud: SignedSupportedVersions = { + signed: 'signed_------', timestamp: '2021-08-31T19:00:00.000Z', - signed: 'cloud', versions: [], }; const result = await supportedVersionsChooseLatest(versionFromLicense, versionFromCloud); - expect(result).toBe(versionFromCloud.signed); + expect(result.timestamp).toBe(versionFromCloud.timestamp); }); }); diff --git a/apps/meteor/app/cloud/server/functions/supportedVersionsToken/supportedVersionsChooseLatest.ts b/apps/meteor/app/cloud/server/functions/supportedVersionsToken/supportedVersionsChooseLatest.ts index 3ee89266c275..f0683535de6b 100644 --- a/apps/meteor/app/cloud/server/functions/supportedVersionsToken/supportedVersionsChooseLatest.ts +++ b/apps/meteor/app/cloud/server/functions/supportedVersionsToken/supportedVersionsChooseLatest.ts @@ -1,9 +1,9 @@ -import type { CloudVersionsResponse } from '@rocket.chat/server-cloud-communication'; +import type { SignedSupportedVersions } from '@rocket.chat/server-cloud-communication'; -export const supportedVersionsChooseLatest = async (...tokens: (CloudVersionsResponse | undefined)[]) => { - const [token] = (tokens.filter(Boolean) as CloudVersionsResponse[]).sort((a, b) => { +export const supportedVersionsChooseLatest = async (...tokens: (SignedSupportedVersions | undefined)[]) => { + const [token] = (tokens.filter(Boolean) as SignedSupportedVersions[]).sort((a, b) => { return new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime(); }); - return token?.signed ?? ''; + return token; }; diff --git a/apps/meteor/app/cloud/server/functions/supportedVersionsToken/supportedVersionsToken.ts b/apps/meteor/app/cloud/server/functions/supportedVersionsToken/supportedVersionsToken.ts index 6aae9adc9600..f03f8b5aca16 100644 --- a/apps/meteor/app/cloud/server/functions/supportedVersionsToken/supportedVersionsToken.ts +++ b/apps/meteor/app/cloud/server/functions/supportedVersionsToken/supportedVersionsToken.ts @@ -1,10 +1,10 @@ import type { SettingValue } from '@rocket.chat/core-typings'; +import { License } from '@rocket.chat/license'; import { Settings } from '@rocket.chat/models'; -import type { CloudVersionsResponse } from '@rocket.chat/server-cloud-communication'; +import type { SupportedVersions } from '@rocket.chat/server-cloud-communication'; import type { Response } from '@rocket.chat/server-fetch'; import { serverFetch as fetch } from '@rocket.chat/server-fetch'; -import { supportedVersions } from '../../../../../ee/app/license/server/license'; import { SystemLogger } from '../../../../../server/lib/logger/system'; import { settings } from '../../../../settings/server'; import { generateWorkspaceBearerHttpHeader } from '../getWorkspaceAccessToken'; @@ -80,9 +80,17 @@ const cacheValueInSettings = ( /** CODE */ const getSupportedVersionsFromCloud = async () => { + if (process.env.CLOUD_SUPPORTED_VERSIONS_TOKEN) { + return { + success: true, + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + result: JSON.parse(process.env.CLOUD_SUPPORTED_VERSIONS!), + }; + } + const headers = await generateWorkspaceBearerHttpHeader(); - const response = await handleResponse( + const response = await handleResponse( fetch('https://releases.rocket.chat/supported/server', { headers, }), @@ -107,11 +115,9 @@ const getSupportedVersionsToken = async () => { * return the token */ - const [versionsFromLicense, response] = await Promise.all([supportedVersions(), getSupportedVersionsFromCloud()]); - - // TODO: get values from jtw token + const [versionsFromLicense, response] = await Promise.all([License.supportedVersions(), getSupportedVersionsFromCloud()]); - return supportedVersionsChooseLatest(versionsFromLicense, (response.success && response.result) || undefined); + return (await supportedVersionsChooseLatest(versionsFromLicense, (response.success && response.result) || undefined))?.signed; }; export const getCachedSupportedVersionsToken = cacheValueInSettings('Cloud_Workspace_Supported_Versions_Token', getSupportedVersionsToken); diff --git a/ee/packages/license/package.json b/ee/packages/license/package.json index f6a1e7a2b7d5..24ecdc30bc49 100644 --- a/ee/packages/license/package.json +++ b/ee/packages/license/package.json @@ -42,6 +42,7 @@ "dependencies": { "@rocket.chat/core-typings": "workspace:^", "@rocket.chat/jwt": "workspace:^", - "@rocket.chat/logger": "workspace:^" + "@rocket.chat/logger": "workspace:^", + "@rocket.chat/server-cloud-communication": "workspace:^" } } diff --git a/ee/packages/license/src/definition/ILicenseV3.ts b/ee/packages/license/src/definition/ILicenseV3.ts index d3a2d7f572a3..e2a8bd424bb2 100644 --- a/ee/packages/license/src/definition/ILicenseV3.ts +++ b/ee/packages/license/src/definition/ILicenseV3.ts @@ -1,3 +1,5 @@ +import type { SignedSupportedVersions } from '@rocket.chat/server-cloud-communication'; + import type { ILicenseTag } from './ILicenseTag'; import type { LicenseLimit } from './LicenseLimit'; import type { LicenseModule } from './LicenseModule'; @@ -59,6 +61,8 @@ export interface ILicenseV3 { monthlyActiveContacts?: LicenseLimit[]; }; cloudMeta?: Record; + + supportedVersions?: SignedSupportedVersions; } export type LicenseLimitKind = keyof ILicenseV3['limits']; diff --git a/ee/packages/license/src/index.ts b/ee/packages/license/src/index.ts index 9dbd94db53ed..11cf3bbbe4c5 100644 --- a/ee/packages/license/src/index.ts +++ b/ee/packages/license/src/index.ts @@ -1,4 +1,4 @@ -import type { LicenseLimitKind } from './definition/ILicenseV3'; +import type { ILicenseV3, LicenseLimitKind } from './definition/ILicenseV3'; import type { LimitContext } from './definition/LimitContext'; import { getAppsConfig, getMaxActiveUsers, getUnmodifiedLicenseAndModules } from './deprecated'; import { onLicense } from './events/deprecated'; @@ -45,6 +45,8 @@ interface License { onInvalidateLicense: typeof onInvalidateLicense; onLimitReached: typeof onLimitReached; + supportedVersions(): ILicenseV3['supportedVersions']; + // Deprecated: onLicense: typeof onLicense; // Deprecated: @@ -56,6 +58,10 @@ interface License { } export class LicenseImp extends LicenseManager implements License { + supportedVersions() { + return this.getLicense()?.supportedVersions; + } + validateFormat = validateFormat; hasModule = hasModule; diff --git a/packages/server-cloud-communication/src/definitions/index.ts b/packages/server-cloud-communication/src/definitions/index.ts index 99ddcdbaa714..d554aa538059 100644 --- a/packages/server-cloud-communication/src/definitions/index.ts +++ b/packages/server-cloud-communication/src/definitions/index.ts @@ -35,15 +35,6 @@ export interface SupportedVersions { } // eslint-disable-next-line @typescript-eslint/naming-convention -export interface CloudVersionsResponse { +export interface SignedSupportedVersions extends SupportedVersions { signed: string; // SerializedJWT; - timestamp: string; - messages?: Message[]; - versions: Version[]; - exceptions?: { - domain: string; - uniqueId: string; - messages?: Message[]; - versions: Version[]; - }; } diff --git a/packages/server-cloud-communication/src/index.ts b/packages/server-cloud-communication/src/index.ts index def13791e8a1..a18306b926eb 100644 --- a/packages/server-cloud-communication/src/index.ts +++ b/packages/server-cloud-communication/src/index.ts @@ -1,3 +1,3 @@ -import type { CloudVersionsResponse } from './definitions'; +import type { SupportedVersions, SignedSupportedVersions } from './definitions'; -export { CloudVersionsResponse }; +export { SupportedVersions, SignedSupportedVersions }; diff --git a/yarn.lock b/yarn.lock index 5bf3d65d6d9b..368d87e88f05 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8472,6 +8472,7 @@ __metadata: "@rocket.chat/core-typings": "workspace:^" "@rocket.chat/jwt": "workspace:^" "@rocket.chat/logger": "workspace:^" + "@rocket.chat/server-cloud-communication": "workspace:^" "@swc/core": ^1.3.66 "@swc/jest": ^0.2.26 "@types/babel__core": ^7 From 71b654011fd83d4fc23b8dc3c9fa9dda076f34a8 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Thu, 28 Sep 2023 22:30:37 -0300 Subject: [PATCH 19/20] Apply suggestions from code review Co-authored-by: Aaron Ogle --- .../supportedVersionsToken/supportedVersionsToken.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/meteor/app/cloud/server/functions/supportedVersionsToken/supportedVersionsToken.ts b/apps/meteor/app/cloud/server/functions/supportedVersionsToken/supportedVersionsToken.ts index f03f8b5aca16..3d79ed436e51 100644 --- a/apps/meteor/app/cloud/server/functions/supportedVersionsToken/supportedVersionsToken.ts +++ b/apps/meteor/app/cloud/server/functions/supportedVersionsToken/supportedVersionsToken.ts @@ -91,7 +91,7 @@ const getSupportedVersionsFromCloud = async () => { const headers = await generateWorkspaceBearerHttpHeader(); const response = await handleResponse( - fetch('https://releases.rocket.chat/supported/server', { + fetch('https://releases.rocket.chat/v2/server/supportedVersions', { headers, }), ); @@ -99,7 +99,7 @@ const getSupportedVersionsFromCloud = async () => { if (!response.success) { SystemLogger.error({ msg: 'Failed to communicate with Rocket.Chat Cloud', - url: 'https://releases.rocket.chat/supported/server', + url: 'https://releases.rocket.chat/v2/server/supportedVersions', err: response.error, }); } From a1baa70ad253cc9858a525902b980119a4554668 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Thu, 28 Sep 2023 22:56:02 -0300 Subject: [PATCH 20/20] add package to docker file --- ee/apps/account-service/Dockerfile | 2 ++ ee/apps/authorization-service/Dockerfile | 2 ++ ee/apps/ddp-streamer/Dockerfile | 2 ++ ee/apps/omnichannel-transcript/Dockerfile | 2 ++ ee/apps/presence-service/Dockerfile | 2 ++ ee/apps/queue-worker/Dockerfile | 2 ++ ee/apps/stream-hub-service/Dockerfile | 2 ++ 7 files changed, 14 insertions(+) diff --git a/ee/apps/account-service/Dockerfile b/ee/apps/account-service/Dockerfile index dbd8717e8716..d3dff1f3d805 100644 --- a/ee/apps/account-service/Dockerfile +++ b/ee/apps/account-service/Dockerfile @@ -28,6 +28,8 @@ COPY ./packages/models/dist packages/models/dist COPY ./packages/logger/package.json packages/logger/package.json COPY ./packages/logger/dist packages/logger/dist +COPY ./packages/server-cloud-communication/ packages/server-cloud-communication/ + COPY ./ee/packages/license/package.json packages/license/package.json COPY ./ee/packages/license/dist packages/license/dist diff --git a/ee/apps/authorization-service/Dockerfile b/ee/apps/authorization-service/Dockerfile index dbd8717e8716..d3dff1f3d805 100644 --- a/ee/apps/authorization-service/Dockerfile +++ b/ee/apps/authorization-service/Dockerfile @@ -28,6 +28,8 @@ COPY ./packages/models/dist packages/models/dist COPY ./packages/logger/package.json packages/logger/package.json COPY ./packages/logger/dist packages/logger/dist +COPY ./packages/server-cloud-communication/ packages/server-cloud-communication/ + COPY ./ee/packages/license/package.json packages/license/package.json COPY ./ee/packages/license/dist packages/license/dist diff --git a/ee/apps/ddp-streamer/Dockerfile b/ee/apps/ddp-streamer/Dockerfile index 9386aac4f21e..19fef1639db5 100644 --- a/ee/apps/ddp-streamer/Dockerfile +++ b/ee/apps/ddp-streamer/Dockerfile @@ -34,6 +34,8 @@ COPY ./packages/models/dist packages/models/dist COPY ./packages/logger/package.json packages/logger/package.json COPY ./packages/logger/dist packages/logger/dist +COPY ./packages/server-cloud-communication/ packages/server-cloud-communication/ + COPY ./ee/packages/license/package.json packages/license/package.json COPY ./ee/packages/license/dist packages/license/dist diff --git a/ee/apps/omnichannel-transcript/Dockerfile b/ee/apps/omnichannel-transcript/Dockerfile index e6a1aa00fc88..2c3c22a998c3 100644 --- a/ee/apps/omnichannel-transcript/Dockerfile +++ b/ee/apps/omnichannel-transcript/Dockerfile @@ -28,6 +28,8 @@ COPY ./packages/models/dist packages/models/dist COPY ./packages/logger/package.json packages/logger/package.json COPY ./packages/logger/dist packages/logger/dist +COPY ./packages/server-cloud-communication/ packages/server-cloud-communication/ + COPY ./ee/packages/license/package.json packages/license/package.json COPY ./ee/packages/license/dist packages/license/dist diff --git a/ee/apps/presence-service/Dockerfile b/ee/apps/presence-service/Dockerfile index aabf78295b8f..9a056c4fde3d 100644 --- a/ee/apps/presence-service/Dockerfile +++ b/ee/apps/presence-service/Dockerfile @@ -31,6 +31,8 @@ COPY ./packages/models/dist packages/models/dist COPY ./packages/logger/package.json packages/logger/package.json COPY ./packages/logger/dist packages/logger/dist +COPY ./packages/server-cloud-communication/ packages/server-cloud-communication/ + COPY ./ee/packages/license/package.json packages/license/package.json COPY ./ee/packages/license/dist packages/license/dist diff --git a/ee/apps/queue-worker/Dockerfile b/ee/apps/queue-worker/Dockerfile index e6a1aa00fc88..2c3c22a998c3 100644 --- a/ee/apps/queue-worker/Dockerfile +++ b/ee/apps/queue-worker/Dockerfile @@ -28,6 +28,8 @@ COPY ./packages/models/dist packages/models/dist COPY ./packages/logger/package.json packages/logger/package.json COPY ./packages/logger/dist packages/logger/dist +COPY ./packages/server-cloud-communication/ packages/server-cloud-communication/ + COPY ./ee/packages/license/package.json packages/license/package.json COPY ./ee/packages/license/dist packages/license/dist diff --git a/ee/apps/stream-hub-service/Dockerfile b/ee/apps/stream-hub-service/Dockerfile index dbd8717e8716..d3dff1f3d805 100644 --- a/ee/apps/stream-hub-service/Dockerfile +++ b/ee/apps/stream-hub-service/Dockerfile @@ -28,6 +28,8 @@ COPY ./packages/models/dist packages/models/dist COPY ./packages/logger/package.json packages/logger/package.json COPY ./packages/logger/dist packages/logger/dist +COPY ./packages/server-cloud-communication/ packages/server-cloud-communication/ + COPY ./ee/packages/license/package.json packages/license/package.json COPY ./ee/packages/license/dist packages/license/dist