Move crl functionality under ee

This commit is contained in:
Tuan Dang
2024-06-13 15:38:32 -07:00
parent 561992e5cf
commit 8fca6b60b3
18 changed files with 332 additions and 240 deletions

View File

@@ -6,6 +6,7 @@ import { TAccessApprovalRequestServiceFactory } from "@app/ee/services/access-ap
import { TAuditLogServiceFactory } from "@app/ee/services/audit-log/audit-log-service";
import { TCreateAuditLogDTO } from "@app/ee/services/audit-log/audit-log-types";
import { TAuditLogStreamServiceFactory } from "@app/ee/services/audit-log-stream/audit-log-stream-service";
import { TCertificateAuthorityCrlServiceFactory } from "@app/ee/services/certificate-authority-crl/certificate-authority-crl-service";
import { TDynamicSecretServiceFactory } from "@app/ee/services/dynamic-secret/dynamic-secret-service";
import { TDynamicSecretLeaseServiceFactory } from "@app/ee/services/dynamic-secret-lease/dynamic-secret-lease-service";
import { TGroupServiceFactory } from "@app/ee/services/group/group-service";
@@ -141,6 +142,7 @@ declare module "fastify" {
auditLogStream: TAuditLogStreamServiceFactory;
certificate: TCertificateServiceFactory;
certificateAuthority: TCertificateAuthorityServiceFactory;
certificateAuthorityCrl: TCertificateAuthorityCrlServiceFactory;
secretScanning: TSecretScanningServiceFactory;
license: TLicenseServiceFactory;
trustedIp: TTrustedIpServiceFactory;

View File

@@ -0,0 +1,86 @@
import { z } from "zod";
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
import { CERTIFICATE_AUTHORITIES } from "@app/lib/api-docs";
import { readLimit } from "@app/server/config/rateLimiter";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type";
export const registerCaCrlRouter = async (server: FastifyZodProvider) => {
server.route({
method: "GET",
url: "/:caId/crl",
config: {
rateLimit: readLimit
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
description: "Get CRL of the CA",
params: z.object({
caId: z.string().trim().describe(CERTIFICATE_AUTHORITIES.GET_CRL.caId)
}),
response: {
200: z.object({
crl: z.string().describe(CERTIFICATE_AUTHORITIES.GET_CRL.crl)
})
}
},
handler: async (req) => {
const { crl, ca } = await server.services.certificateAuthorityCrl.getCaCrl({
caId: req.params.caId,
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId
});
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
projectId: ca.projectId,
event: {
type: EventType.GET_CA_CRL,
metadata: {
caId: ca.id,
dn: ca.dn
}
}
});
return {
crl
};
}
});
// server.route({
// method: "GET",
// url: "/:caId/crl/rotate",
// config: {
// rateLimit: writeLimit
// },
// onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
// schema: {
// description: "Rotate CRL of the CA",
// params: z.object({
// caId: z.string().trim()
// }),
// response: {
// 200: z.object({
// message: z.string()
// })
// }
// },
// handler: async (req) => {
// await server.services.certificateAuthority.rotateCaCrl({
// caId: req.params.caId,
// actor: req.permission.type,
// actorId: req.permission.id,
// actorAuthMethod: req.permission.authMethod,
// actorOrgId: req.permission.orgId
// });
// return {
// message: "Successfully rotated CA CRL"
// };
// }
// });
};

View File

@@ -1,6 +1,7 @@
import { registerAccessApprovalPolicyRouter } from "./access-approval-policy-router";
import { registerAccessApprovalRequestRouter } from "./access-approval-request-router";
import { registerAuditLogStreamRouter } from "./audit-log-stream-router";
import { registerCaCrlRouter } from "./certificate-authority-crl-router";
import { registerDynamicSecretLeaseRouter } from "./dynamic-secret-lease-router";
import { registerDynamicSecretRouter } from "./dynamic-secret-router";
import { registerGroupRouter } from "./group-router";
@@ -54,6 +55,13 @@ export const registerV1EERoutes = async (server: FastifyZodProvider) => {
{ prefix: "/dynamic-secrets" }
);
await server.register(
async (pkiRouter) => {
await pkiRouter.register(registerCaCrlRouter, { prefix: "/ca" });
},
{ prefix: "/pki" }
);
await server.register(registerSamlRouter, { prefix: "/sso" });
await server.register(registerScimRouter, { prefix: "/scim" });
await server.register(registerLdapRouter, { prefix: "/ldap" });

View File

@@ -0,0 +1,172 @@
import { ForbiddenError } from "@casl/ability";
import * as x509 from "@peculiar/x509";
import { TCertificateAuthorityCrlDALFactory } from "@app/ee/services/certificate-authority-crl/certificate-authority-crl-dal";
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 { BadRequestError } from "@app/lib/errors";
import { TCertificateAuthorityDALFactory } from "@app/services/certificate-authority/certificate-authority-dal";
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
import { TProjectDALFactory } from "@app/services/project/project-dal";
import { getProjectKmsCertificateKeyId } from "@app/services/project/project-fns";
import { TGetCrl } from "./certificate-authority-crl-types";
type TCertificateAuthorityCrlServiceFactoryDep = {
certificateAuthorityDAL: Pick<TCertificateAuthorityDALFactory, "findById">;
certificateAuthorityCrlDAL: Pick<TCertificateAuthorityCrlDALFactory, "findOne">;
projectDAL: Pick<TProjectDALFactory, "findOne" | "updateById" | "transaction">;
kmsService: Pick<TKmsServiceFactory, "decrypt" | "generateKmsKey">;
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
};
export type TCertificateAuthorityCrlServiceFactory = ReturnType<typeof certificateAuthorityCrlServiceFactory>;
export const certificateAuthorityCrlServiceFactory = ({
certificateAuthorityDAL,
certificateAuthorityCrlDAL,
projectDAL,
kmsService,
permissionService,
licenseService
}: TCertificateAuthorityCrlServiceFactoryDep) => {
/**
* Return the Certificate Revocation List (CRL) for CA with id [caId]
*/
const getCaCrl = async ({ caId, actorId, actorAuthMethod, actor, actorOrgId }: TGetCrl) => {
const ca = await certificateAuthorityDAL.findById(caId);
if (!ca) throw new BadRequestError({ message: "CA not found" });
const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
ca.projectId,
actorAuthMethod,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Read,
ProjectPermissionSub.CertificateAuthorities
);
const plan = await licenseService.getPlan(actorOrgId);
if (!plan.caCrl)
throw new BadRequestError({
message:
"Failed to get CA certificate revocation list (CRL) due to plan restriction. Upgrade plan to get the CA CRL."
});
const caCrl = await certificateAuthorityCrlDAL.findOne({ caId: ca.id });
if (!caCrl) throw new BadRequestError({ message: "CRL not found" });
const keyId = await getProjectKmsCertificateKeyId({
projectId: ca.projectId,
projectDAL,
kmsService
});
const decryptedCrl = await kmsService.decrypt({
kmsId: keyId,
cipherTextBlob: caCrl.encryptedCrl
});
const crl = new x509.X509Crl(decryptedCrl);
const base64crl = crl.toString("base64");
const crlPem = `-----BEGIN X509 CRL-----\n${base64crl.match(/.{1,64}/g)?.join("\n")}\n-----END X509 CRL-----`;
return {
crl: crlPem,
ca
};
};
// const rotateCaCrl = async ({ caId, actorId, actorAuthMethod, actor, actorOrgId }: TRotateCrlDTO) => {
// const ca = await certificateAuthorityDAL.findById(caId);
// if (!ca) throw new BadRequestError({ message: "CA not found" });
// const { permission } = await permissionService.getProjectPermission(
// actor,
// actorId,
// ca.projectId,
// actorAuthMethod,
// actorOrgId
// );
// ForbiddenError.from(permission).throwUnlessCan(
// ProjectPermissionActions.Read,
// ProjectPermissionSub.CertificateAuthorities
// );
// const caSecret = await certificateAuthoritySecretDAL.findOne({ caId: ca.id });
// const alg = keyAlgorithmToAlgCfg(ca.keyAlgorithm as CertKeyAlgorithm);
// const keyId = await getProjectKmsCertificateKeyId({
// projectId: ca.projectId,
// projectDAL,
// kmsService
// });
// const privateKey = await kmsService.decrypt({
// kmsId: keyId,
// cipherTextBlob: caSecret.encryptedPrivateKey
// });
// const skObj = crypto.createPrivateKey({ key: privateKey, format: "der", type: "pkcs8" });
// const sk = await crypto.subtle.importKey("pkcs8", skObj.export({ format: "der", type: "pkcs8" }), alg, true, [
// "sign"
// ]);
// const revokedCerts = await certificateDAL.find({
// caId: ca.id,
// status: CertStatus.REVOKED
// });
// const crl = await x509.X509CrlGenerator.create({
// issuer: ca.dn,
// thisUpdate: new Date(),
// nextUpdate: new Date("2025/12/12"),
// entries: revokedCerts.map((revokedCert) => {
// return {
// serialNumber: revokedCert.serialNumber,
// revocationDate: new Date(revokedCert.revokedAt as Date),
// reason: revokedCert.revocationReason as number,
// invalidity: new Date("2022/01/01"),
// issuer: ca.dn
// };
// }),
// signingAlgorithm: alg,
// signingKey: sk
// });
// const { cipherTextBlob: encryptedCrl } = await kmsService.encrypt({
// kmsId: keyId,
// plainText: Buffer.from(new Uint8Array(crl.rawData))
// });
// await certificateAuthorityCrlDAL.update(
// {
// caId: ca.id
// },
// {
// encryptedCrl
// }
// );
// const base64crl = crl.toString("base64");
// const crlPem = `-----BEGIN X509 CRL-----\n${base64crl.match(/.{1,64}/g)?.join("\n")}\n-----END X509 CRL-----`;
// return {
// crl: crlPem
// };
// };
return {
getCaCrl
// rotateCaCrl
};
};

View File

@@ -0,0 +1,5 @@
import { TProjectPermission } from "@app/lib/types";
export type TGetCrl = {
caId: string;
} & Omit<TProjectPermission, "projectId">;

View File

@@ -25,6 +25,7 @@ export const getDefaultOnPremFeatures = () => {
trial_end: null,
has_used_trial: true,
secretApproval: false,
secretRotation: true
secretRotation: true,
caCrl: false
};
};

View File

@@ -34,7 +34,8 @@ export const getDefaultOnPremFeatures = (): TFeatureSet => ({
trial_end: null,
has_used_trial: true,
secretApproval: false,
secretRotation: true
secretRotation: true,
caCrl: false
});
export const setupLicenceRequestWithStore = (baseURL: string, refreshUrl: string, licenseKey: string) => {

View File

@@ -52,6 +52,7 @@ export type TFeatureSet = {
has_used_trial: true;
secretApproval: false;
secretRotation: true;
caCrl: false;
};
export type TOrgPlansTableDTO = {

View File

@@ -13,6 +13,8 @@ import { auditLogQueueServiceFactory } from "@app/ee/services/audit-log/audit-lo
import { auditLogServiceFactory } from "@app/ee/services/audit-log/audit-log-service";
import { auditLogStreamDALFactory } from "@app/ee/services/audit-log-stream/audit-log-stream-dal";
import { auditLogStreamServiceFactory } from "@app/ee/services/audit-log-stream/audit-log-stream-service";
import { certificateAuthorityCrlDALFactory } from "@app/ee/services/certificate-authority-crl/certificate-authority-crl-dal";
import { certificateAuthorityCrlServiceFactory } from "@app/ee/services/certificate-authority-crl/certificate-authority-crl-service";
import { dynamicSecretDALFactory } from "@app/ee/services/dynamic-secret/dynamic-secret-dal";
import { dynamicSecretServiceFactory } from "@app/ee/services/dynamic-secret/dynamic-secret-service";
import { buildDynamicSecretProviders } from "@app/ee/services/dynamic-secret/providers";
@@ -75,7 +77,6 @@ import { certificateBodyDALFactory } from "@app/services/certificate/certificate
import { certificateDALFactory } from "@app/services/certificate/certificate-dal";
import { certificateServiceFactory } from "@app/services/certificate/certificate-service";
import { certificateAuthorityCertDALFactory } from "@app/services/certificate-authority/certificate-authority-cert-dal";
import { certificateAuthorityCrlDALFactory } from "@app/services/certificate-authority/certificate-authority-crl-dal";
import { certificateAuthorityDALFactory } from "@app/services/certificate-authority/certificate-authority-dal";
import { certificateAuthorityQueueFactory } from "@app/services/certificate-authority/certificate-authority-queue";
import { certificateAuthoritySecretDALFactory } from "@app/services/certificate-authority/certificate-authority-secret-dal";
@@ -558,6 +559,15 @@ export const registerRoutes = async (
permissionService
});
const certificateAuthorityCrlService = certificateAuthorityCrlServiceFactory({
certificateAuthorityDAL,
certificateAuthorityCrlDAL,
projectDAL,
kmsService,
permissionService,
licenseService
});
const projectService = projectServiceFactory({
permissionService,
projectDAL,
@@ -945,6 +955,7 @@ export const registerRoutes = async (
auditLogStream: auditLogStreamService,
certificate: certificateService,
certificateAuthority: certificateAuthorityService,
certificateAuthorityCrl: certificateAuthorityCrlService,
secretScanning: secretScanningService,
license: licenseService,
trustedIp: trustedIpService,

View File

@@ -512,81 +512,4 @@ export const registerCaRouter = async (server: FastifyZodProvider) => {
};
}
});
server.route({
method: "GET",
url: "/:caId/crl",
config: {
rateLimit: readLimit
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
description: "Get CRL of the CA",
params: z.object({
caId: z.string().trim().describe(CERTIFICATE_AUTHORITIES.GET_CRL.caId)
}),
response: {
200: z.object({
crl: z.string().describe(CERTIFICATE_AUTHORITIES.GET_CRL.crl)
})
}
},
handler: async (req) => {
const { crl, ca } = await server.services.certificateAuthority.getCaCrl({
caId: req.params.caId,
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId
});
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
projectId: ca.projectId,
event: {
type: EventType.GET_CA_CRL,
metadata: {
caId: ca.id,
dn: ca.dn
}
}
});
return {
crl
};
}
});
// server.route({
// method: "GET",
// url: "/:caId/crl/rotate",
// config: {
// rateLimit: writeLimit
// },
// onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
// schema: {
// description: "Rotate CRL of the CA",
// params: z.object({
// caId: z.string().trim()
// }),
// response: {
// 200: z.object({
// message: z.string()
// })
// }
// },
// handler: async (req) => {
// await server.services.certificateAuthority.rotateCaCrl({
// caId: req.params.caId,
// actor: req.permission.type,
// actorId: req.permission.id,
// actorAuthMethod: req.permission.authMethod,
// actorOrgId: req.permission.orgId
// });
// return {
// message: "Successfully rotated CA CRL"
// };
// }
// });
};

View File

@@ -12,7 +12,7 @@ import { TKmsServiceFactory } from "@app/services/kms/kms-service";
import { TProjectDALFactory } from "@app/services/project/project-dal";
import { getProjectKmsCertificateKeyId } from "@app/services/project/project-fns";
import { TCertificateAuthorityCrlDALFactory } from "./certificate-authority-crl-dal";
import { TCertificateAuthorityCrlDALFactory } from "../../ee/services/certificate-authority-crl/certificate-authority-crl-dal";
import { TCertificateAuthorityDALFactory } from "./certificate-authority-dal";
import { keyAlgorithmToAlgCfg } from "./certificate-authority-fns";
import { TCertificateAuthoritySecretDALFactory } from "./certificate-authority-secret-dal";

View File

@@ -13,9 +13,9 @@ import { TKmsServiceFactory } from "@app/services/kms/kms-service";
import { TProjectDALFactory } from "@app/services/project/project-dal";
import { getProjectKmsCertificateKeyId } from "@app/services/project/project-fns";
import { TCertificateAuthorityCrlDALFactory } from "../../ee/services/certificate-authority-crl/certificate-authority-crl-dal";
import { CertKeyAlgorithm, CertStatus } from "../certificate/certificate-types";
import { TCertificateAuthorityCertDALFactory } from "./certificate-authority-cert-dal";
import { TCertificateAuthorityCrlDALFactory } from "./certificate-authority-crl-dal";
import { TCertificateAuthorityDALFactory } from "./certificate-authority-dal";
import {
createDistinguishedName,
@@ -33,10 +33,8 @@ import {
TGetCaCertDTO,
TGetCaCsrDTO,
TGetCaDTO,
TGetCrl,
TImportCertToCaDTO,
TIssueCertFromCaDTO,
// TRotateCrlDTO,
TSignIntermediateDTO,
TUpdateCaDTO
} from "./certificate-authority-types";
@@ -809,132 +807,6 @@ export const certificateAuthorityServiceFactory = ({
};
};
/**
* Return the Certificate Revocation List (CRL) for CA with id [caId]
*/
const getCaCrl = async ({ caId, actorId, actorAuthMethod, actor, actorOrgId }: TGetCrl) => {
const ca = await certificateAuthorityDAL.findById(caId);
if (!ca) throw new BadRequestError({ message: "CA not found" });
const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
ca.projectId,
actorAuthMethod,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Read,
ProjectPermissionSub.CertificateAuthorities
);
const caCrl = await certificateAuthorityCrlDAL.findOne({ caId: ca.id });
if (!caCrl) throw new BadRequestError({ message: "CRL not found" });
const keyId = await getProjectKmsCertificateKeyId({
projectId: ca.projectId,
projectDAL,
kmsService
});
const decryptedCrl = await kmsService.decrypt({
kmsId: keyId,
cipherTextBlob: caCrl.encryptedCrl
});
const crl = new x509.X509Crl(decryptedCrl);
const base64crl = crl.toString("base64");
const crlPem = `-----BEGIN X509 CRL-----\n${base64crl.match(/.{1,64}/g)?.join("\n")}\n-----END X509 CRL-----`;
return {
crl: crlPem,
ca
};
};
// const rotateCaCrl = async ({ caId, actorId, actorAuthMethod, actor, actorOrgId }: TRotateCrlDTO) => {
// const ca = await certificateAuthorityDAL.findById(caId);
// if (!ca) throw new BadRequestError({ message: "CA not found" });
// const { permission } = await permissionService.getProjectPermission(
// actor,
// actorId,
// ca.projectId,
// actorAuthMethod,
// actorOrgId
// );
// ForbiddenError.from(permission).throwUnlessCan(
// ProjectPermissionActions.Read,
// ProjectPermissionSub.CertificateAuthorities
// );
// const caSecret = await certificateAuthoritySecretDAL.findOne({ caId: ca.id });
// const alg = keyAlgorithmToAlgCfg(ca.keyAlgorithm as CertKeyAlgorithm);
// const keyId = await getProjectKmsCertificateKeyId({
// projectId: ca.projectId,
// projectDAL,
// kmsService
// });
// const privateKey = await kmsService.decrypt({
// kmsId: keyId,
// cipherTextBlob: caSecret.encryptedPrivateKey
// });
// const skObj = crypto.createPrivateKey({ key: privateKey, format: "der", type: "pkcs8" });
// const sk = await crypto.subtle.importKey("pkcs8", skObj.export({ format: "der", type: "pkcs8" }), alg, true, [
// "sign"
// ]);
// const revokedCerts = await certificateDAL.find({
// caId: ca.id,
// status: CertStatus.REVOKED
// });
// const crl = await x509.X509CrlGenerator.create({
// issuer: ca.dn,
// thisUpdate: new Date(),
// nextUpdate: new Date("2025/12/12"),
// entries: revokedCerts.map((revokedCert) => {
// return {
// serialNumber: revokedCert.serialNumber,
// revocationDate: new Date(revokedCert.revokedAt as Date),
// reason: revokedCert.revocationReason as number,
// invalidity: new Date("2022/01/01"),
// issuer: ca.dn
// };
// }),
// signingAlgorithm: alg,
// signingKey: sk
// });
// const { cipherTextBlob: encryptedCrl } = await kmsService.encrypt({
// kmsId: keyId,
// plainText: Buffer.from(new Uint8Array(crl.rawData))
// });
// await certificateAuthorityCrlDAL.update(
// {
// caId: ca.id
// },
// {
// encryptedCrl
// }
// );
// const base64crl = crl.toString("base64");
// const crlPem = `-----BEGIN X509 CRL-----\n${base64crl.match(/.{1,64}/g)?.join("\n")}\n-----END X509 CRL-----`;
// return {
// crl: crlPem
// };
// };
return {
createCa,
getCaById,
@@ -944,8 +816,6 @@ export const certificateAuthorityServiceFactory = ({
getCaCert,
signIntermediate,
importCertToCa,
issueCertFromCa,
getCaCrl
// rotateCaCrl
issueCertFromCa
};
};

View File

@@ -3,9 +3,9 @@ import { TCertificateDALFactory } from "@app/services/certificate/certificate-da
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
import { TProjectDALFactory } from "@app/services/project/project-dal";
import { TCertificateAuthorityCrlDALFactory } from "../../ee/services/certificate-authority-crl/certificate-authority-crl-dal";
import { CertKeyAlgorithm } from "../certificate/certificate-types";
import { TCertificateAuthorityCertDALFactory } from "./certificate-authority-cert-dal";
import { TCertificateAuthorityCrlDALFactory } from "./certificate-authority-crl-dal";
import { TCertificateAuthorityDALFactory } from "./certificate-authority-dal";
import { TCertificateAuthoritySecretDALFactory } from "./certificate-authority-secret-dal";
@@ -80,14 +80,6 @@ export type TIssueCertFromCaDTO = {
notAfter?: string;
} & Omit<TProjectPermission, "projectId">;
export type TGetCrl = {
caId: string;
} & Omit<TProjectPermission, "projectId">;
export type TRotateCrlDTO = {
caId: string;
} & Omit<TProjectPermission, "projectId">;
export type TDNParts = {
commonName?: string;
organization?: string;

View File

@@ -1,12 +1,12 @@
import { ForbiddenError } from "@casl/ability";
import * as x509 from "@peculiar/x509";
import { TCertificateAuthorityCrlDALFactory } from "@app/ee/services/certificate-authority-crl/certificate-authority-crl-dal";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
import { TCertificateBodyDALFactory } from "@app/services/certificate/certificate-body-dal";
import { TCertificateDALFactory } from "@app/services/certificate/certificate-dal";
import { TCertificateAuthorityCertDALFactory } from "@app/services/certificate-authority/certificate-authority-cert-dal";
import { TCertificateAuthorityCrlDALFactory } from "@app/services/certificate-authority/certificate-authority-crl-dal";
import { TCertificateAuthorityDALFactory } from "@app/services/certificate-authority/certificate-authority-dal";
import { TCertificateAuthoritySecretDALFactory } from "@app/services/certificate-authority/certificate-authority-secret-dal";
import { TKmsServiceFactory } from "@app/services/kms/kms-service";

View File

@@ -25,14 +25,15 @@ export type SubscriptionPlan = {
ldap: boolean;
groups: boolean;
status:
| "incomplete"
| "incomplete_expired"
| "trialing"
| "active"
| "past_due"
| "canceled"
| "unpaid"
| null;
| "incomplete"
| "incomplete_expired"
| "trialing"
| "active"
| "past_due"
| "canceled"
| "unpaid"
| null;
trial_end: number | null;
has_used_trial: boolean;
caCrl: boolean;
};

View File

@@ -3,7 +3,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { createNotification } from "@app/components/notifications";
import { ProjectPermissionCan } from "@app/components/permissions";
import { Button, DeleteActionModal } from "@app/components/v2";
import { Button, DeleteActionModal, UpgradePlanModal } from "@app/components/v2";
import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context";
import { CaStatus, useDeleteCa, useUpdateCa } from "@app/hooks/api";
import { usePopUp } from "@app/hooks/usePopUp";
@@ -25,7 +25,8 @@ export const CaSection = () => {
"installCaCert",
"deleteCa",
"caStatus", // enable / disable
"caCrl" // enable / disable
"caCrl", // enable / disable
"upgradePlan"
] as const);
const onRemoveCaSubmit = async (caId: string) => {
@@ -124,6 +125,11 @@ export const CaSection = () => {
onUpdateCaStatus(popUp?.caStatus?.data as { caId: string; status: CaStatus })
}
/>
<UpgradePlanModal
isOpen={popUp.upgradePlan.isOpen}
onOpenChange={(isOpen) => handlePopUpToggle("upgradePlan", isOpen)}
text={(popUp.upgradePlan?.data as { description: string })?.description}
/>
</div>
);
};

View File

@@ -27,7 +27,11 @@ import {
Tooltip,
Tr
} from "@app/components/v2";
import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context";
import {
ProjectPermissionActions,
ProjectPermissionSub,
useSubscription,
useWorkspace} from "@app/context";
import { CaStatus, useListWorkspaceCas } from "@app/hooks/api";
import { caStatusToNameMap, caTypeToNameMap } from "@app/hooks/api/ca/constants";
import { UsePopUpState } from "@app/hooks/usePopUp";
@@ -35,17 +39,19 @@ import { UsePopUpState } from "@app/hooks/usePopUp";
type Props = {
handlePopUpOpen: (
popUpName: keyof UsePopUpState<
["installCaCert", "caCert", "ca", "deleteCa", "caStatus", "caCrl"]
["installCaCert", "caCert", "ca", "deleteCa", "caStatus", "caCrl", "upgradePlan"]
>,
data?: {
caId?: string;
dn?: string;
status?: CaStatus;
description?: string;
}
) => void;
};
export const CaTable = ({ handlePopUpOpen }: Props) => {
const { subscription } = useSubscription();
const { currentWorkspace } = useWorkspace();
const { data, isLoading } = useListWorkspaceCas({
projectSlug: currentWorkspace?.slug ?? ""
@@ -144,11 +150,18 @@ export const CaTable = ({ handlePopUpOpen }: Props) => {
!isAllowed &&
"pointer-events-none cursor-not-allowed opacity-50"
)}
onClick={async () =>
handlePopUpOpen("caCrl", {
caId: ca.id
})
}
onClick={async () => {
if (!subscription?.caCrl) {
handlePopUpOpen("upgradePlan", {
description:
"You can use the certificate revocation list (CRL) feature if you upgrade your Infisical plan."
});
} else {
handlePopUpOpen("caCrl", {
caId: ca.id
});
}
}}
disabled={!isAllowed}
icon={<FontAwesomeIcon icon={faFile} />}
>