From c882da2e1a37fd78779347e56cf385a9eba04ae3 Mon Sep 17 00:00:00 2001 From: Akhil Mohan Date: Tue, 26 Mar 2024 14:35:19 +0530 Subject: [PATCH] feat: added license check for dynamic secret --- .../src/ee/services/license/licence-fns.ts | 1 + .../src/ee/services/license/license-types.ts | 1 + .../dynamic-secret-lease-service.ts | 19 ++++++++++++++++++- .../dynamic-secret/dynamic-secret-service.ts | 17 +++++++++++++++++ .../components/ActionBar/ActionBar.tsx | 12 ++++++++---- 5 files changed, 45 insertions(+), 5 deletions(-) diff --git a/backend/src/ee/services/license/licence-fns.ts b/backend/src/ee/services/license/licence-fns.ts index 8dca96737..104d1465b 100644 --- a/backend/src/ee/services/license/licence-fns.ts +++ b/backend/src/ee/services/license/licence-fns.ts @@ -15,6 +15,7 @@ export const getDefaultOnPremFeatures = (): TFeatureSet => ({ membersUsed: 0, environmentLimit: null, environmentsUsed: 0, + dynamicSecret: false, secretVersioning: true, pitRecovery: false, ipAllowlisting: false, diff --git a/backend/src/ee/services/license/license-types.ts b/backend/src/ee/services/license/license-types.ts index f8ed8aff3..735d8458e 100644 --- a/backend/src/ee/services/license/license-types.ts +++ b/backend/src/ee/services/license/license-types.ts @@ -27,6 +27,7 @@ export type TFeatureSet = { tier: -1; workspaceLimit: null; workspacesUsed: 0; + dynamicSecret: false; memberLimit: null; membersUsed: 0; environmentLimit: null; diff --git a/backend/src/services/dynamic-secret-lease/dynamic-secret-lease-service.ts b/backend/src/services/dynamic-secret-lease/dynamic-secret-lease-service.ts index 0d7e3c0f8..ecddcd04a 100644 --- a/backend/src/services/dynamic-secret-lease/dynamic-secret-lease-service.ts +++ b/backend/src/services/dynamic-secret-lease/dynamic-secret-lease-service.ts @@ -2,6 +2,7 @@ import { ForbiddenError, subject } from "@casl/ability"; import ms from "ms"; import { SecretKeyEncoding } from "@app/db/schemas"; +import { TLicenseServiceFactory } from "@app/ee/services/license/license-service"; import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service"; import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission"; import { getConfig } from "@app/lib/config/env"; @@ -28,6 +29,7 @@ type TDynamicSecretLeaseServiceFactoryDep = { dynamicSecretDAL: Pick; dynamicSecretProviders: Record; dynamicSecretQueueService: TDynamicSecretLeaseQueueServiceFactory; + licenseService: Pick; folderDAL: Pick; permissionService: Pick; projectDAL: Pick; @@ -42,7 +44,8 @@ export const dynamicSecretLeaseServiceFactory = ({ folderDAL, permissionService, dynamicSecretQueueService, - projectDAL + projectDAL, + licenseService }: TDynamicSecretLeaseServiceFactoryDep) => { const create = async ({ environmentSlug, @@ -72,6 +75,13 @@ export const dynamicSecretLeaseServiceFactory = ({ subject(ProjectPermissionSub.Secrets, { environment: environmentSlug, secretPath: path }) ); + const plan = await licenseService.getPlan(actorOrgId); + if (!plan?.dynamicSecret) { + throw new BadRequestError({ + message: "Failed to create lease due to plan restriction. Upgrade plan to create dynamic secret." + }); + } + const folder = await folderDAL.findBySecretPath(projectId, environmentSlug, path); if (!folder) throw new BadRequestError({ message: "Folder not found" }); @@ -138,6 +148,13 @@ export const dynamicSecretLeaseServiceFactory = ({ subject(ProjectPermissionSub.Secrets, { environment: environmentSlug, secretPath: path }) ); + const plan = await licenseService.getPlan(actorOrgId); + if (!plan?.dynamicSecret) { + throw new BadRequestError({ + message: "Failed to renew lease due to plan restriction. Upgrade plan to create dynamic secret." + }); + } + const folder = await folderDAL.findBySecretPath(projectId, environmentSlug, path); if (!folder) throw new BadRequestError({ message: "Folder not found" }); diff --git a/backend/src/services/dynamic-secret/dynamic-secret-service.ts b/backend/src/services/dynamic-secret/dynamic-secret-service.ts index 459512754..48d203ff2 100644 --- a/backend/src/services/dynamic-secret/dynamic-secret-service.ts +++ b/backend/src/services/dynamic-secret/dynamic-secret-service.ts @@ -1,6 +1,7 @@ import { ForbiddenError, subject } from "@casl/ability"; import { SecretKeyEncoding } from "@app/db/schemas"; +import { TLicenseServiceFactory } from "@app/ee/services/license/license-service"; import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service"; import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission"; import { infisicalSymmetricDecrypt, infisicalSymmetricEncypt } from "@app/lib/crypto/encryption"; @@ -29,6 +30,7 @@ type TDynamicSecretServiceFactoryDep = { TDynamicSecretLeaseQueueServiceFactory, "pruneDynamicSecret" | "unsetLeaseRevocation" >; + licenseService: Pick; folderDAL: Pick; projectDAL: Pick; permissionService: Pick; @@ -39,6 +41,7 @@ export type TDynamicSecretServiceFactory = ReturnType} onClick={() => { - handlePopUpOpen("addDynamicSecret"); - handlePopUpClose("misc"); + if (subscription && subscription.dynamicSecret) { + handlePopUpOpen("addDynamicSecret"); + handlePopUpClose("misc"); + return; + } + handlePopUpOpen("upgradePlan"); }} isDisabled={!isAllowed} variant="outline_bg" @@ -471,8 +475,8 @@ export const ActionBar = ({ onOpenChange={(isOpen) => handlePopUpToggle("upgradePlan", isOpen)} text={ subscription.slug === null - ? "You can perform point-in-time recovery under an Enterprise license" - : "You can perform point-in-time recovery if you switch to Infisical's Team plan" + ? "You can perform this action under an Enterprise license" + : "You can perform this action if you switch to Infisical's Team plan" } /> )}