Skip to content

Commit

Permalink
Improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
flaviendelangle committed Jun 25, 2024
1 parent b5bf2dc commit f8c3dca
Show file tree
Hide file tree
Showing 8 changed files with 62 additions and 76 deletions.
3 changes: 2 additions & 1 deletion packages/x-license/src/Watermark/Watermark.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as React from 'react';
import { MuiCommercialPackageName, useLicenseVerifier } from '../useLicenseVerifier';
import { useLicenseVerifier } from '../useLicenseVerifier';
import { LICENSE_STATUS, LicenseStatus } from '../utils/licenseStatus';
import { MuiCommercialPackageName } from '../utils/commercialPackages';

function getLicenseErrorMessage(licenseStatus: LicenseStatus) {
switch (licenseStatus) {
Expand Down
1 change: 0 additions & 1 deletion packages/x-license/src/useLicenseVerifier/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
export { useLicenseVerifier } from './useLicenseVerifier';
export type { MuiCommercialPackageName } from './useLicenseVerifier';
15 changes: 2 additions & 13 deletions packages/x-license/src/useLicenseVerifier/useLicenseVerifier.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,8 @@ import {
showNotAvailableInInitialProPlanError,
} from '../utils/licenseErrorMessageUtils';
import { LICENSE_STATUS, LicenseStatus } from '../utils/licenseStatus';
import { extractAcceptedScopes, extractProductLine } from '../utils/licenseScope';
import MuiLicenseInfoContext from '../Unstable_LicenseInfoProvider/MuiLicenseInfoContext';

export type MuiCommercialPackageName =
| 'x-data-grid-pro'
| 'x-data-grid-premium'
| 'x-date-pickers-pro'
| 'x-tree-view-pro'
| 'x-charts-pro';
import { MuiCommercialPackageName } from '../utils/commercialPackages';

export const sharedLicenseStatuses: {
[packageName in MuiCommercialPackageName]?: {
Expand Down Expand Up @@ -48,15 +41,11 @@ export function useLicenseVerifier(
return sharedLicenseStatuses[packageName]!.licenseVerifier;
}

const acceptedScopes = extractAcceptedScopes(packageName);
const productLine = extractProductLine(packageName);

const plan = packageName.includes('premium') ? 'Premium' : 'Pro';
const licenseStatus = verifyLicense({
releaseInfo,
licenseKey,
acceptedScopes,
productLine,
packageName,
});

const fullPackageName = `@mui/${packageName}`;
Expand Down
6 changes: 6 additions & 0 deletions packages/x-license/src/utils/commercialPackages.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export type MuiCommercialPackageName =
| 'x-data-grid-pro'
| 'x-data-grid-premium'
| 'x-date-pickers-pro'
| 'x-tree-view-pro'
| 'x-charts-pro';
1 change: 1 addition & 0 deletions packages/x-license/src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export * from './licenseInfo';
export * from './licenseStatus';
export type { LicenseScope } from './licenseScope';
export type { LicensingModel } from './licensingModel';
export type { MuiCommercialPackageName } from './commercialPackages';
14 changes: 0 additions & 14 deletions packages/x-license/src/utils/licenseScope.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,3 @@ export const PLAN_VERSIONS = ['initial', 'Q3-2024'] as const;

export type LicenseScope = (typeof LICENSE_SCOPES)[number];
export type PlanVersion = (typeof PLAN_VERSIONS)[number];
export type ProductLine = 'data-grid' | 'date-pickers' | 'charts' | 'tree-view'

export const extractProductLine = (packageName: string): ProductLine => {
// extract the part between "x-" and "-pro"/"-premium"
const regex = /x-(.*?)(-pro|-premium)?$/;
const match = packageName.match(regex);
return match![1] as ProductLine;
};

export const extractAcceptedScopes = (packageName: string): readonly LicenseScope[] => {
return packageName.includes('premium')
? LICENSE_SCOPES.filter((scope) => scope.includes('premium'))
: LICENSE_SCOPES;
};
54 changes: 18 additions & 36 deletions packages/x-license/src/verifyLicense/verifyLicense.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,7 @@ describe('License: verifyLicense', () => {
verifyLicense({
releaseInfo: '__RELEASE_INFO__',
licenseKey,
acceptedScopes: ['pro', 'premium'],
productLine: 'data-grid',
packageName: 'x-data-grid-pro',
}).status,
).to.throw('MUI X: The release information is invalid. Not able to validate license.');
});
Expand All @@ -42,8 +41,7 @@ describe('License: verifyLicense', () => {
verifyLicense({
releaseInfo: RELEASE_INFO,
licenseKey,
acceptedScopes: ['pro', 'premium'],
productLine: 'data-grid',
packageName: 'x-data-grid-pro',
}).status,
).to.equal(LICENSE_STATUS.Valid);
});
Expand All @@ -62,8 +60,7 @@ describe('License: verifyLicense', () => {
verifyLicense({
releaseInfo: RELEASE_INFO,
licenseKey: expiredLicenseKey,
acceptedScopes: ['pro', 'premium'],
productLine: 'data-grid',
packageName: 'x-data-grid-pro',
}).status,
).to.equal(LICENSE_STATUS.ExpiredVersion);
});
Expand All @@ -75,8 +72,7 @@ describe('License: verifyLicense', () => {
releaseInfo: RELEASE_INFO,
licenseKey:
'b43ff5f9ac93f021855ff59ff0ba5220TkFNRTpNYC1VSSBTQVMsREVWRUxPUEVSX0NPVU5UPTEwLEVYUElSWT0xNTkxNzIzMDY3MDQyLFZFUlNJT049MS4yLjM',
acceptedScopes: ['pro', 'premium'],
productLine: 'data-grid',
packageName: 'x-data-grid-pro',
}).status,
).to.equal(LICENSE_STATUS.Invalid);
});
Expand Down Expand Up @@ -106,8 +102,7 @@ describe('License: verifyLicense', () => {
verifyLicense({
releaseInfo: '__RELEASE_INFO__',
licenseKey: licenseKeyPro,
acceptedScopes: ['pro', 'premium'],
productLine: 'data-grid',
packageName: 'x-data-grid-pro',
}).status,
).to.throw('MUI X: The release information is invalid. Not able to validate license.');
});
Expand All @@ -119,8 +114,7 @@ describe('License: verifyLicense', () => {
verifyLicense({
releaseInfo: RELEASE_INFO,
licenseKey: licenseKeyPro,
acceptedScopes: ['pro', 'premium'],
productLine: 'data-grid',
packageName: 'x-data-grid-pro',
}).status,
).to.equal(LICENSE_STATUS.Valid);
});
Expand All @@ -131,8 +125,7 @@ describe('License: verifyLicense', () => {
verifyLicense({
releaseInfo: RELEASE_INFO,
licenseKey: licenseKeyPremium,
acceptedScopes: ['premium'],
productLine: 'data-grid',
packageName: 'x-data-grid-premium',
}).status,
).to.equal(LICENSE_STATUS.Valid);
});
Expand All @@ -143,8 +136,7 @@ describe('License: verifyLicense', () => {
verifyLicense({
releaseInfo: RELEASE_INFO,
licenseKey: licenseKeyPro,
acceptedScopes: ['premium'],
productLine: 'data-grid',
packageName: 'x-data-grid-premium',
}).status,
).to.equal(LICENSE_STATUS.OutOfScope);
});
Expand All @@ -165,8 +157,7 @@ describe('License: verifyLicense', () => {
verifyLicense({
releaseInfo: RELEASE_INFO,
licenseKey: expiredLicenseKey,
acceptedScopes: ['pro', 'premium'],
productLine: 'data-grid',
packageName: 'x-data-grid-pro',
}).status,
).to.equal(LICENSE_STATUS.Valid);
});
Expand All @@ -184,8 +175,7 @@ describe('License: verifyLicense', () => {
verifyLicense({
releaseInfo: RELEASE_INFO,
licenseKey: expiredLicenseKey,
acceptedScopes: ['pro', 'premium'],
productLine: 'data-grid',
packageName: 'x-data-grid-pro',
}).status,
).to.equal(LICENSE_STATUS.ExpiredAnnualGrace);
});
Expand All @@ -204,8 +194,7 @@ describe('License: verifyLicense', () => {
verifyLicense({
releaseInfo: RELEASE_INFO,
licenseKey: expiredLicenseKey,
acceptedScopes: ['pro', 'premium'],
productLine: 'data-grid',
packageName: 'x-data-grid-pro',
}).status,
).to.equal(LICENSE_STATUS.ExpiredAnnual);
});
Expand All @@ -223,8 +212,7 @@ describe('License: verifyLicense', () => {
verifyLicense({
releaseInfo: RELEASE_INFO,
licenseKey: expiredLicenseKey,
acceptedScopes: ['pro', 'premium'],
productLine: 'data-grid',
packageName: 'x-data-grid-pro',
}).status,
).to.equal(LICENSE_STATUS.Valid);
});
Expand All @@ -237,8 +225,7 @@ describe('License: verifyLicense', () => {
releaseInfo: RELEASE_INFO,
licenseKey:
'b43ff5f9ac93f021855ff59ff0ba5220TkFNRTpNYC1VSSBTQVMsREVWRUxPUEVSX0NPVU5UPTEwLEVYUElSWT0xNTkxNzIzMDY3MDQyLFZFUlNJT049MS4yLjM',
acceptedScopes: ['pro', 'premium'],
productLine: 'data-grid',
packageName: 'x-data-grid-pro',
}).status,
).to.equal(LICENSE_STATUS.Invalid);
});
Expand All @@ -259,8 +246,7 @@ describe('License: verifyLicense', () => {
verifyLicense({
releaseInfo: RELEASE_INFO,
licenseKey: licenseKeyPro,
acceptedScopes: ['pro', 'premium'],
productLine: 'data-grid',
packageName: 'x-data-grid-pro',
}).status,
).to.equal(LICENSE_STATUS.Valid);
});
Expand Down Expand Up @@ -289,8 +275,7 @@ describe('License: verifyLicense', () => {
verifyLicense({
releaseInfo: RELEASE_INFO,
licenseKey: licenseKeyInitial,
acceptedScopes: ['pro', 'premium'],
productLine: 'charts',
packageName: 'x-charts-pro',
}).status,
).to.equal(LICENSE_STATUS.NotAvailableInInitialProPlan);
});
Expand All @@ -301,8 +286,7 @@ describe('License: verifyLicense', () => {
verifyLicense({
releaseInfo: RELEASE_INFO,
licenseKey: licenseKeyInitial,
acceptedScopes: ['pro', 'premium'],
productLine: 'tree-view',
packageName: 'x-tree-view-pro',
}).status,
).to.equal(LICENSE_STATUS.NotAvailableInInitialProPlan);
});
Expand All @@ -313,8 +297,7 @@ describe('License: verifyLicense', () => {
verifyLicense({
releaseInfo: RELEASE_INFO,
licenseKey: licenseKey2,
acceptedScopes: ['pro', 'premium'],
productLine: 'charts',
packageName: 'x-charts-pro',
}).status,
).to.equal(LICENSE_STATUS.Valid);
});
Expand All @@ -325,8 +308,7 @@ describe('License: verifyLicense', () => {
verifyLicense({
releaseInfo: RELEASE_INFO,
licenseKey: licenseKey2,
acceptedScopes: ['pro', 'premium'],
productLine: 'tree-view',
packageName: 'x-tree-view-pro',
}).status,
).to.equal(LICENSE_STATUS.Valid);
});
Expand Down
44 changes: 33 additions & 11 deletions packages/x-license/src/verifyLicense/verifyLicense.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { base64Decode, base64Encode } from '../encoding/base64';
import { md5 } from '../encoding/md5';
import { LICENSE_STATUS, LicenseStatus } from '../utils/licenseStatus';
import { LicenseScope, LICENSE_SCOPES, ProductLine, PlanVersion } from '../utils/licenseScope';
import { LicenseScope, LICENSE_SCOPES, PlanVersion } from '../utils/licenseScope';
import { LicensingModel, LICENSING_MODELS } from '../utils/licensingModel';
import { MuiCommercialPackageName } from '../utils/commercialPackages';

const getDefaultReleaseDate = () => {
const today = new Date();
Expand All @@ -15,6 +16,22 @@ export function generateReleaseInfo(releaseDate = getDefaultReleaseDate()) {
return base64Encode(releaseDate.getTime().toString());
}

function isLicenseScopeSufficient(
packageName: MuiCommercialPackageName,
licenseScope: LicenseScope,
) {
let acceptedScopes: LicenseScope[];
if (packageName.includes('pro')) {
acceptedScopes = ['pro', 'premium'];
} else if (packageName.includes('premium')) {
acceptedScopes = ['premium'];
} else {
acceptedScopes = [];
}

return acceptedScopes.includes(licenseScope);
}

const expiryReg = /^.*EXPIRY=([0-9]+),.*$/;

interface MuiLicense {
Expand All @@ -24,7 +41,10 @@ interface MuiLicense {
planVersion: PlanVersion;
}

const PRODUCT_LINES_AVAILABLE_IN_INITIAL_PRO_PLAN: ProductLine[] = ['data-grid', 'date-pickers']
const PRO_PACKAGES_AVAILABLE_IN_INITIAL_PRO_PLAN: MuiCommercialPackageName[] = [
'x-data-grid-pro',
'x-date-pickers-pro',
];

/**
* Format: ORDER:${orderNumber},EXPIRY=${expiryTimestamp},KEYVERSION=1
Expand Down Expand Up @@ -107,13 +127,11 @@ const decodeLicense = (encodedLicense: string): MuiLicense | null => {
export function verifyLicense({
releaseInfo,
licenseKey,
acceptedScopes,
productLine,
packageName,
}: {
releaseInfo: string;
licenseKey?: string;
acceptedScopes: readonly LicenseScope[];
productLine: ProductLine;
packageName: MuiCommercialPackageName;
}): { status: LicenseStatus; meta?: any } {
if (!releaseInfo) {
throw new Error('MUI X: The release information is missing. Not able to validate license.');
Expand Down Expand Up @@ -180,13 +198,17 @@ export function verifyLicense({
return { status: LICENSE_STATUS.Invalid };
}

// 'charts-pro' or 'tree-view-pro' can only be used with a newer Pro license
if (license.planVersion === 'initial' && license.scope === 'pro' && !PRODUCT_LINES_AVAILABLE_IN_INITIAL_PRO_PLAN.includes(productLine)) {
return { status: LICENSE_STATUS.NotAvailableInInitialProPlan };
if (!isLicenseScopeSufficient(packageName, license.scope)) {
return { status: LICENSE_STATUS.OutOfScope };
}

if (!acceptedScopes.includes(license.scope)) {
return { status: LICENSE_STATUS.OutOfScope };
// 'charts-pro' or 'tree-view-pro' can only be used with a newer Pro license
if (
license.planVersion === 'initial' &&
license.scope === 'pro' &&
!PRO_PACKAGES_AVAILABLE_IN_INITIAL_PRO_PLAN.includes(packageName)
) {
return { status: LICENSE_STATUS.NotAvailableInInitialProPlan };
}

return { status: LICENSE_STATUS.Valid };
Expand Down

0 comments on commit f8c3dca

Please sign in to comment.