mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-03 02:25:48 +00:00
feat: added license check for dynamic secret
This commit is contained in:
@@ -15,6 +15,7 @@ export const getDefaultOnPremFeatures = (): TFeatureSet => ({
|
|||||||
membersUsed: 0,
|
membersUsed: 0,
|
||||||
environmentLimit: null,
|
environmentLimit: null,
|
||||||
environmentsUsed: 0,
|
environmentsUsed: 0,
|
||||||
|
dynamicSecret: false,
|
||||||
secretVersioning: true,
|
secretVersioning: true,
|
||||||
pitRecovery: false,
|
pitRecovery: false,
|
||||||
ipAllowlisting: false,
|
ipAllowlisting: false,
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ export type TFeatureSet = {
|
|||||||
tier: -1;
|
tier: -1;
|
||||||
workspaceLimit: null;
|
workspaceLimit: null;
|
||||||
workspacesUsed: 0;
|
workspacesUsed: 0;
|
||||||
|
dynamicSecret: false;
|
||||||
memberLimit: null;
|
memberLimit: null;
|
||||||
membersUsed: 0;
|
membersUsed: 0;
|
||||||
environmentLimit: null;
|
environmentLimit: null;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { ForbiddenError, subject } from "@casl/ability";
|
|||||||
import ms from "ms";
|
import ms from "ms";
|
||||||
|
|
||||||
import { SecretKeyEncoding } from "@app/db/schemas";
|
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 { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
||||||
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
|
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
|
||||||
import { getConfig } from "@app/lib/config/env";
|
import { getConfig } from "@app/lib/config/env";
|
||||||
@@ -28,6 +29,7 @@ type TDynamicSecretLeaseServiceFactoryDep = {
|
|||||||
dynamicSecretDAL: Pick<TDynamicSecretDALFactory, "findOne">;
|
dynamicSecretDAL: Pick<TDynamicSecretDALFactory, "findOne">;
|
||||||
dynamicSecretProviders: Record<DynamicSecretProviders, TDynamicProviderFns>;
|
dynamicSecretProviders: Record<DynamicSecretProviders, TDynamicProviderFns>;
|
||||||
dynamicSecretQueueService: TDynamicSecretLeaseQueueServiceFactory;
|
dynamicSecretQueueService: TDynamicSecretLeaseQueueServiceFactory;
|
||||||
|
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
||||||
folderDAL: Pick<TSecretFolderDALFactory, "findBySecretPath">;
|
folderDAL: Pick<TSecretFolderDALFactory, "findBySecretPath">;
|
||||||
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
|
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
|
||||||
projectDAL: Pick<TProjectDALFactory, "findProjectBySlug">;
|
projectDAL: Pick<TProjectDALFactory, "findProjectBySlug">;
|
||||||
@@ -42,7 +44,8 @@ export const dynamicSecretLeaseServiceFactory = ({
|
|||||||
folderDAL,
|
folderDAL,
|
||||||
permissionService,
|
permissionService,
|
||||||
dynamicSecretQueueService,
|
dynamicSecretQueueService,
|
||||||
projectDAL
|
projectDAL,
|
||||||
|
licenseService
|
||||||
}: TDynamicSecretLeaseServiceFactoryDep) => {
|
}: TDynamicSecretLeaseServiceFactoryDep) => {
|
||||||
const create = async ({
|
const create = async ({
|
||||||
environmentSlug,
|
environmentSlug,
|
||||||
@@ -72,6 +75,13 @@ export const dynamicSecretLeaseServiceFactory = ({
|
|||||||
subject(ProjectPermissionSub.Secrets, { environment: environmentSlug, secretPath: path })
|
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);
|
const folder = await folderDAL.findBySecretPath(projectId, environmentSlug, path);
|
||||||
if (!folder) throw new BadRequestError({ message: "Folder not found" });
|
if (!folder) throw new BadRequestError({ message: "Folder not found" });
|
||||||
|
|
||||||
@@ -138,6 +148,13 @@ export const dynamicSecretLeaseServiceFactory = ({
|
|||||||
subject(ProjectPermissionSub.Secrets, { environment: environmentSlug, secretPath: path })
|
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);
|
const folder = await folderDAL.findBySecretPath(projectId, environmentSlug, path);
|
||||||
if (!folder) throw new BadRequestError({ message: "Folder not found" });
|
if (!folder) throw new BadRequestError({ message: "Folder not found" });
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { ForbiddenError, subject } from "@casl/ability";
|
import { ForbiddenError, subject } from "@casl/ability";
|
||||||
|
|
||||||
import { SecretKeyEncoding } from "@app/db/schemas";
|
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 { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
||||||
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
|
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
|
||||||
import { infisicalSymmetricDecrypt, infisicalSymmetricEncypt } from "@app/lib/crypto/encryption";
|
import { infisicalSymmetricDecrypt, infisicalSymmetricEncypt } from "@app/lib/crypto/encryption";
|
||||||
@@ -29,6 +30,7 @@ type TDynamicSecretServiceFactoryDep = {
|
|||||||
TDynamicSecretLeaseQueueServiceFactory,
|
TDynamicSecretLeaseQueueServiceFactory,
|
||||||
"pruneDynamicSecret" | "unsetLeaseRevocation"
|
"pruneDynamicSecret" | "unsetLeaseRevocation"
|
||||||
>;
|
>;
|
||||||
|
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
||||||
folderDAL: Pick<TSecretFolderDALFactory, "findBySecretPath">;
|
folderDAL: Pick<TSecretFolderDALFactory, "findBySecretPath">;
|
||||||
projectDAL: Pick<TProjectDALFactory, "findProjectBySlug">;
|
projectDAL: Pick<TProjectDALFactory, "findProjectBySlug">;
|
||||||
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
|
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
|
||||||
@@ -39,6 +41,7 @@ export type TDynamicSecretServiceFactory = ReturnType<typeof dynamicSecretServic
|
|||||||
export const dynamicSecretServiceFactory = ({
|
export const dynamicSecretServiceFactory = ({
|
||||||
dynamicSecretDAL,
|
dynamicSecretDAL,
|
||||||
dynamicSecretLeaseDAL,
|
dynamicSecretLeaseDAL,
|
||||||
|
licenseService,
|
||||||
folderDAL,
|
folderDAL,
|
||||||
dynamicSecretProviders,
|
dynamicSecretProviders,
|
||||||
permissionService,
|
permissionService,
|
||||||
@@ -74,6 +77,13 @@ export const dynamicSecretServiceFactory = ({
|
|||||||
subject(ProjectPermissionSub.Secrets, { environment: environmentSlug, secretPath: path })
|
subject(ProjectPermissionSub.Secrets, { environment: environmentSlug, secretPath: path })
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const plan = await licenseService.getPlan(actorOrgId);
|
||||||
|
if (!plan?.dynamicSecret) {
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: "Failed to create dynamic secret due to plan restriction. Upgrade plan to create dynamic secret."
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const folder = await folderDAL.findBySecretPath(projectId, environmentSlug, path);
|
const folder = await folderDAL.findBySecretPath(projectId, environmentSlug, path);
|
||||||
if (!folder) throw new BadRequestError({ message: "Folder not found" });
|
if (!folder) throw new BadRequestError({ message: "Folder not found" });
|
||||||
|
|
||||||
@@ -135,6 +145,13 @@ export const dynamicSecretServiceFactory = ({
|
|||||||
subject(ProjectPermissionSub.Secrets, { environment: environmentSlug, secretPath: path })
|
subject(ProjectPermissionSub.Secrets, { environment: environmentSlug, secretPath: path })
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const plan = await licenseService.getPlan(actorOrgId);
|
||||||
|
if (!plan?.dynamicSecret) {
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: "Failed to update dynamic secret due to plan restriction. Upgrade plan to create dynamic secret."
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const folder = await folderDAL.findBySecretPath(projectId, environmentSlug, path);
|
const folder = await folderDAL.findBySecretPath(projectId, environmentSlug, path);
|
||||||
if (!folder) throw new BadRequestError({ message: "Folder not found" });
|
if (!folder) throw new BadRequestError({ message: "Folder not found" });
|
||||||
|
|
||||||
|
|||||||
@@ -360,8 +360,12 @@ export const ActionBar = ({
|
|||||||
<Button
|
<Button
|
||||||
leftIcon={<FontAwesomeIcon icon={faFingerprint} className="pr-2" />}
|
leftIcon={<FontAwesomeIcon icon={faFingerprint} className="pr-2" />}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
handlePopUpOpen("addDynamicSecret");
|
if (subscription && subscription.dynamicSecret) {
|
||||||
handlePopUpClose("misc");
|
handlePopUpOpen("addDynamicSecret");
|
||||||
|
handlePopUpClose("misc");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
handlePopUpOpen("upgradePlan");
|
||||||
}}
|
}}
|
||||||
isDisabled={!isAllowed}
|
isDisabled={!isAllowed}
|
||||||
variant="outline_bg"
|
variant="outline_bg"
|
||||||
@@ -471,8 +475,8 @@ export const ActionBar = ({
|
|||||||
onOpenChange={(isOpen) => handlePopUpToggle("upgradePlan", isOpen)}
|
onOpenChange={(isOpen) => handlePopUpToggle("upgradePlan", isOpen)}
|
||||||
text={
|
text={
|
||||||
subscription.slug === null
|
subscription.slug === null
|
||||||
? "You can perform point-in-time recovery under an Enterprise license"
|
? "You can perform this action under an Enterprise license"
|
||||||
: "You can perform point-in-time recovery if you switch to Infisical's Team plan"
|
: "You can perform this action if you switch to Infisical's Team plan"
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
Reference in New Issue
Block a user