Skip to content

Commit

Permalink
fix: licenses.info endpoint only available for admins (#30644)
Browse files Browse the repository at this point in the history
  • Loading branch information
pierre-lehnen-rc committed Oct 16, 2023
1 parent a0dcc38 commit 85ddfb2
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 21 deletions.
7 changes: 5 additions & 2 deletions apps/meteor/ee/server/api/licenses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,13 @@ API.v1.addRoute(

API.v1.addRoute(
'licenses.info',
{ authRequired: true, validateParams: isLicensesInfoProps, permissionsRequired: ['view-privileged-setting'] },
{ authRequired: true, validateParams: isLicensesInfoProps },
{
async get() {
const data = await License.getInfo(Boolean(this.queryParams.loadValues));
const unrestrictedAccess = await hasPermissionAsync(this.userId, 'view-privileged-setting');
const loadCurrentValues = unrestrictedAccess && Boolean(this.queryParams.loadValues);

const data = await License.getInfo({ limits: unrestrictedAccess, license: unrestrictedAccess, currentValues: loadCurrentValues });

return API.v1.success({ data });
},
Expand Down
46 changes: 46 additions & 0 deletions apps/meteor/tests/end-to-end/api/20-licenses.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,52 @@ describe('licenses', function () {
});
});

describe('[/licenses.info]', () => {
it('should fail if not logged in', (done) => {
request
.get(api('licenses.info'))
.expect('Content-Type', 'application/json')
.expect(401)
.expect((res) => {
expect(res.body).to.have.property('status', 'error');
expect(res.body).to.have.property('message');
})
.end(done);
});

it('should return limited information if user is unauthorized', (done) => {
request
.get(api('licenses.info'))
.set(unauthorizedUserCredentials)
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
expect(res.body).to.have.property('data').and.to.be.an('object');
expect(res.body.data).to.not.have.property('license');
expect(res.body.data).to.have.property('tags').and.to.be.an('array');
})
.end(done);
});

it('should return unrestricted info if user is logged in and is authorized', (done) => {
request
.get(api('licenses.info'))
.set(credentials)
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
expect(res.body).to.have.property('data').and.to.be.an('object');
if (process.env.IS_EE) {
expect(res.body.data).to.have.property('license').and.to.be.an('object');
}
expect(res.body.data).to.have.property('tags').and.to.be.an('array');
})

.end(done);
});
});

describe('[/licenses.isEnterprise]', () => {
it('should fail if not logged in', (done) => {
request
Expand Down
10 changes: 10 additions & 0 deletions ee/packages/license/src/definition/LicenseInfo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import type { ILicenseTag } from './ILicenseTag';
import type { ILicenseV3, LicenseLimitKind } from './ILicenseV3';
import type { LicenseModule } from './LicenseModule';

export type LicenseInfo = {
license?: ILicenseV3;
activeModules: LicenseModule[];
limits: Record<LicenseLimitKind, { value?: number; max: number }>;
tags: ILicenseTag[];
};
11 changes: 4 additions & 7 deletions ee/packages/license/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { ILicenseV3, LicenseLimitKind } from './definition/ILicenseV3';
import type { LicenseModule } from './definition/LicenseModule';
import type { LicenseLimitKind } from './definition/ILicenseV3';
import type { LicenseInfo } from './definition/LicenseInfo';
import type { LimitContext } from './definition/LimitContext';
import { getAppsConfig, getMaxActiveUsers, getUnmodifiedLicenseAndModules } from './deprecated';
import { onLicense } from './events/deprecated';
Expand All @@ -24,6 +24,7 @@ export * from './definition/ILicenseTag';
export * from './definition/ILicenseV2';
export * from './definition/ILicenseV3';
export * from './definition/LicenseBehavior';
export * from './definition/LicenseInfo';
export * from './definition/LicenseLimit';
export * from './definition/LicenseModule';
export * from './definition/LicensePeriod';
Expand All @@ -49,11 +50,7 @@ interface License {
onBehaviorTriggered: typeof onBehaviorTriggered;
revalidateLicense: () => Promise<void>;

getInfo: (loadCurrentValues: boolean) => Promise<{
license: ILicenseV3 | undefined;
activeModules: LicenseModule[];
limits: Record<LicenseLimitKind, { value?: number; max: number }>;
}>;
getInfo: (info: { limits: boolean; currentValues: boolean; license: boolean }) => Promise<LicenseInfo>;

// Deprecated:
onLicense: typeof onLicense;
Expand Down
19 changes: 13 additions & 6 deletions ee/packages/license/src/license.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { type ILicenseTag } from './definition/ILicenseTag';
import type { ILicenseV2 } from './definition/ILicenseV2';
import type { ILicenseV3, LicenseLimitKind } from './definition/ILicenseV3';
import type { BehaviorWithContext } from './definition/LicenseBehavior';
import type { LicenseInfo } from './definition/LicenseInfo';
import type { LicenseModule } from './definition/LicenseModule';
import type { LicenseValidationOptions } from './definition/LicenseValidationOptions';
import type { LimitContext } from './definition/LimitContext';
Expand Down Expand Up @@ -291,17 +292,22 @@ export class LicenseManager extends Emitter<LicenseEvents> {
return isBehaviorsInResult(validationResult, ['prevent_action']);
}

public async getInfo(loadCurrentValues = false): Promise<{
license: ILicenseV3 | undefined;
activeModules: LicenseModule[];
limits: Record<LicenseLimitKind, { value?: number; max: number }>;
}> {
public async getInfo({
limits: includeLimits,
currentValues: loadCurrentValues,
license: includeLicense,
}: {
limits: boolean;
currentValues: boolean;
license: boolean;
}): Promise<LicenseInfo> {
const activeModules = getModules.call(this);
const license = this.getLicense();

// Get all limits present in the license and their current value
const limits = (
(license &&
includeLimits &&
(await Promise.all(
globalLimitKinds
.map((limitKey) => ({
Expand All @@ -322,9 +328,10 @@ export class LicenseManager extends Emitter<LicenseEvents> {
).reduce((prev, curr) => ({ ...prev, ...curr }), {});

return {
license,
license: (includeLicense && license) || undefined,
activeModules,
limits: limits as Record<LicenseLimitKind, { max: number; value: number }>,
tags: license?.information.tags || [],
};
}
}
8 changes: 2 additions & 6 deletions packages/rest-typings/src/v1/licenses.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { ILicenseV2, ILicenseV3, LicenseLimitKind } from '@rocket.chat/license';
import type { ILicenseV2, ILicenseV3, LicenseInfo } from '@rocket.chat/license';
import Ajv from 'ajv';

const ajv = new Ajv({
Expand Down Expand Up @@ -45,11 +45,7 @@ export type LicensesEndpoints = {
};
'/v1/licenses.info': {
GET: (params: licensesInfoProps) => {
data: {
license: ILicenseV3 | undefined;
activeModules: string[];
limits: Record<LicenseLimitKind, { max: number; value?: number }>;
};
data: LicenseInfo;
};
};
'/v1/licenses.add': {
Expand Down

0 comments on commit 85ddfb2

Please sign in to comment.