RocketChat/Rocket.Chat

View on GitHub
apps/meteor/app/cloud/server/functions/getWorkspaceLicense.ts

Summary

Maintainability
A
2 hrs
Test Coverage
import type { Cloud, Serialized } from '@rocket.chat/core-typings';
import { Settings } from '@rocket.chat/models';
import { serverFetch as fetch } from '@rocket.chat/server-fetch';
import { v, compile } from 'suretype';

import { callbacks } from '../../../../lib/callbacks';
import { CloudWorkspaceConnectionError } from '../../../../lib/errors/CloudWorkspaceConnectionError';
import { CloudWorkspaceLicenseError } from '../../../../lib/errors/CloudWorkspaceLicenseError';
import { SystemLogger } from '../../../../server/lib/logger/system';
import { settings } from '../../../settings/server';
import { LICENSE_VERSION } from '../license';
import { getWorkspaceAccessToken } from './getWorkspaceAccessToken';

const workspaceLicensePayloadSchema = v.object({
    version: v.number().required(),
    address: v.string().required(),
    license: v.string().required(),
    updatedAt: v.string().format('date-time').required(),
    modules: v.string().required(),
    expireAt: v.string().format('date-time').required(),
});

const assertWorkspaceLicensePayload = compile(workspaceLicensePayloadSchema);

const fetchCloudWorkspaceLicensePayload = async ({ token }: { token: string }): Promise<Serialized<Cloud.WorkspaceLicensePayload>> => {
    const workspaceRegistrationClientUri = settings.get<string>('Cloud_Workspace_Registration_Client_Uri');
    const response = await fetch(`${workspaceRegistrationClientUri}/license`, {
        headers: {
            Authorization: `Bearer ${token}`,
        },
        params: {
            version: LICENSE_VERSION,
        },
    });

    if (!response.ok) {
        try {
            const { error } = await response.json();
            throw new CloudWorkspaceConnectionError(`Failed to connect to Rocket.Chat Cloud: ${error}`);
        } catch (error) {
            throw new CloudWorkspaceConnectionError(`Failed to connect to Rocket.Chat Cloud: ${response.statusText}`);
        }
    }

    const payload = await response.json();

    assertWorkspaceLicensePayload(payload);

    return payload;
};

export async function getWorkspaceLicense() {
    const currentLicense = await Settings.findOne('Cloud_Workspace_License');
    // it should never happen, since even if the license is not found, it will return an empty settings
    if (!currentLicense?._updatedAt) {
        throw new CloudWorkspaceLicenseError('Failed to retrieve current license');
    }

    try {
        const token = await getWorkspaceAccessToken();
        if (!token) {
            return;
        }

        const payload = await fetchCloudWorkspaceLicensePayload({ token });

        if (currentLicense.value && Date.parse(payload.updatedAt) <= currentLicense._updatedAt.getTime()) {
            return;
        }
        await callbacks.run('workspaceLicenseChanged', payload.license);

        return { updated: true, license: payload.license };
    } catch (err) {
        SystemLogger.error({
            msg: 'Failed to update license from Rocket.Chat Cloud',
            url: '/license',
            err,
        });
    }
}