mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-07 14:27:30 +00:00
feat: added collection selection for cert template
This commit is contained in:
@@ -10,6 +10,8 @@ export async function up(knex: Knex): Promise<void> {
|
|||||||
tb.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
tb.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
tb.uuid("caId").notNullable();
|
tb.uuid("caId").notNullable();
|
||||||
tb.foreign("caId").references("id").inTable(TableName.CertificateAuthority).onDelete("CASCADE");
|
tb.foreign("caId").references("id").inTable(TableName.CertificateAuthority).onDelete("CASCADE");
|
||||||
|
tb.uuid("pkiCollectionId");
|
||||||
|
tb.foreign("pkiCollectionId").references("id").inTable(TableName.PkiCollection).onDelete("SET NULL");
|
||||||
tb.string("name").notNullable();
|
tb.string("name").notNullable();
|
||||||
tb.string("commonName").notNullable();
|
tb.string("commonName").notNullable();
|
||||||
tb.string("subjectAlternativeName").notNullable();
|
tb.string("subjectAlternativeName").notNullable();
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import { TImmutableDBKeys } from "./models";
|
|||||||
export const CertificateTemplatesSchema = z.object({
|
export const CertificateTemplatesSchema = z.object({
|
||||||
id: z.string().uuid(),
|
id: z.string().uuid(),
|
||||||
caId: z.string().uuid(),
|
caId: z.string().uuid(),
|
||||||
|
pkiCollectionId: z.string().uuid().nullable().optional(),
|
||||||
name: z.string(),
|
name: z.string(),
|
||||||
commonName: z.string(),
|
commonName: z.string(),
|
||||||
subjectAlternativeName: z.string(),
|
subjectAlternativeName: z.string(),
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ export const registerCertRouter = async (server: FastifyZodProvider) => {
|
|||||||
.trim()
|
.trim()
|
||||||
.optional()
|
.optional()
|
||||||
.describe(CERTIFICATE_AUTHORITIES.ISSUE_CERT.certificateTemplateId),
|
.describe(CERTIFICATE_AUTHORITIES.ISSUE_CERT.certificateTemplateId),
|
||||||
|
pkiCollectionId: z.string().trim().optional().describe(CERTIFICATE_AUTHORITIES.SIGN_CERT.pkiCollectionId),
|
||||||
friendlyName: z.string().trim().optional().describe(CERTIFICATE_AUTHORITIES.ISSUE_CERT.friendlyName),
|
friendlyName: z.string().trim().optional().describe(CERTIFICATE_AUTHORITIES.ISSUE_CERT.friendlyName),
|
||||||
commonName: z.string().trim().min(1).describe(CERTIFICATE_AUTHORITIES.ISSUE_CERT.commonName),
|
commonName: z.string().trim().min(1).describe(CERTIFICATE_AUTHORITIES.ISSUE_CERT.commonName),
|
||||||
altNames: validateAltNamesField.describe(CERTIFICATE_AUTHORITIES.ISSUE_CERT.altNames),
|
altNames: validateAltNamesField.describe(CERTIFICATE_AUTHORITIES.ISSUE_CERT.altNames),
|
||||||
@@ -166,6 +167,7 @@ export const registerCertRouter = async (server: FastifyZodProvider) => {
|
|||||||
.trim()
|
.trim()
|
||||||
.optional()
|
.optional()
|
||||||
.describe(CERTIFICATE_AUTHORITIES.ISSUE_CERT.certificateTemplateId),
|
.describe(CERTIFICATE_AUTHORITIES.ISSUE_CERT.certificateTemplateId),
|
||||||
|
pkiCollectionId: z.string().trim().optional().describe(CERTIFICATE_AUTHORITIES.SIGN_CERT.pkiCollectionId),
|
||||||
csr: z.string().trim().min(1).describe(CERTIFICATE_AUTHORITIES.SIGN_CERT.csr),
|
csr: z.string().trim().min(1).describe(CERTIFICATE_AUTHORITIES.SIGN_CERT.csr),
|
||||||
friendlyName: z.string().trim().optional().describe(CERTIFICATE_AUTHORITIES.SIGN_CERT.friendlyName),
|
friendlyName: z.string().trim().optional().describe(CERTIFICATE_AUTHORITIES.SIGN_CERT.friendlyName),
|
||||||
commonName: z.string().trim().min(1).optional().describe(CERTIFICATE_AUTHORITIES.SIGN_CERT.commonName),
|
commonName: z.string().trim().min(1).optional().describe(CERTIFICATE_AUTHORITIES.SIGN_CERT.commonName),
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ const sanitizedCertificateTemplate = CertificateTemplatesSchema.pick({
|
|||||||
name: true,
|
name: true,
|
||||||
commonName: true,
|
commonName: true,
|
||||||
subjectAlternativeName: true,
|
subjectAlternativeName: true,
|
||||||
|
pkiCollectionId: true,
|
||||||
ttl: true
|
ttl: true
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -61,6 +62,7 @@ export const registerCertificateTemplateRouter = async (server: FastifyZodProvid
|
|||||||
schema: {
|
schema: {
|
||||||
body: z.object({
|
body: z.object({
|
||||||
caId: z.string(),
|
caId: z.string(),
|
||||||
|
pkiCollectionId: z.string().optional(),
|
||||||
name: z.string().min(1),
|
name: z.string().min(1),
|
||||||
commonName: validateTemplateRegexField,
|
commonName: validateTemplateRegexField,
|
||||||
subjectAlternativeName: validateTemplateRegexField,
|
subjectAlternativeName: validateTemplateRegexField,
|
||||||
@@ -95,6 +97,7 @@ export const registerCertificateTemplateRouter = async (server: FastifyZodProvid
|
|||||||
schema: {
|
schema: {
|
||||||
body: z.object({
|
body: z.object({
|
||||||
caId: z.string().optional(),
|
caId: z.string().optional(),
|
||||||
|
pkiCollectionId: z.string().optional(),
|
||||||
name: z.string().min(1).optional(),
|
name: z.string().min(1).optional(),
|
||||||
commonName: validateTemplateRegexField.optional(),
|
commonName: validateTemplateRegexField.optional(),
|
||||||
subjectAlternativeName: validateTemplateRegexField.optional(),
|
subjectAlternativeName: validateTemplateRegexField.optional(),
|
||||||
|
|||||||
@@ -1033,6 +1033,7 @@ export const certificateAuthorityServiceFactory = ({
|
|||||||
}: TIssueCertFromCaDTO) => {
|
}: TIssueCertFromCaDTO) => {
|
||||||
let ca: TCertificateAuthorities | undefined;
|
let ca: TCertificateAuthorities | undefined;
|
||||||
let certificateTemplate: TCertificateTemplates | undefined;
|
let certificateTemplate: TCertificateTemplates | undefined;
|
||||||
|
let collectionId = pkiCollectionId;
|
||||||
|
|
||||||
if (caId) {
|
if (caId) {
|
||||||
ca = await certificateAuthorityDAL.findById(caId);
|
ca = await certificateAuthorityDAL.findById(caId);
|
||||||
@@ -1044,6 +1045,7 @@ export const certificateAuthorityServiceFactory = ({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
collectionId = certificateTemplate.pkiCollectionId as string;
|
||||||
ca = await certificateAuthorityDAL.findById(certificateTemplate.caId);
|
ca = await certificateAuthorityDAL.findById(certificateTemplate.caId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1070,8 +1072,8 @@ export const certificateAuthorityServiceFactory = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check PKI collection
|
// check PKI collection
|
||||||
if (pkiCollectionId) {
|
if (collectionId) {
|
||||||
const pkiCollection = await pkiCollectionDAL.findById(pkiCollectionId);
|
const pkiCollection = await pkiCollectionDAL.findById(collectionId);
|
||||||
if (!pkiCollection) throw new NotFoundError({ message: "PKI collection not found" });
|
if (!pkiCollection) throw new NotFoundError({ message: "PKI collection not found" });
|
||||||
if (pkiCollection.projectId !== ca.projectId) throw new BadRequestError({ message: "Invalid PKI collection" });
|
if (pkiCollection.projectId !== ca.projectId) throw new BadRequestError({ message: "Invalid PKI collection" });
|
||||||
}
|
}
|
||||||
@@ -1237,10 +1239,10 @@ export const certificateAuthorityServiceFactory = ({
|
|||||||
tx
|
tx
|
||||||
);
|
);
|
||||||
|
|
||||||
if (pkiCollectionId) {
|
if (collectionId) {
|
||||||
await pkiCollectionItemDAL.create(
|
await pkiCollectionItemDAL.create(
|
||||||
{
|
{
|
||||||
pkiCollectionId,
|
pkiCollectionId: collectionId,
|
||||||
certId: cert.id
|
certId: cert.id
|
||||||
},
|
},
|
||||||
tx
|
tx
|
||||||
@@ -1290,6 +1292,7 @@ export const certificateAuthorityServiceFactory = ({
|
|||||||
}: TSignCertFromCaDTO) => {
|
}: TSignCertFromCaDTO) => {
|
||||||
let ca: TCertificateAuthorities | undefined;
|
let ca: TCertificateAuthorities | undefined;
|
||||||
let certificateTemplate: TCertificateTemplates | undefined;
|
let certificateTemplate: TCertificateTemplates | undefined;
|
||||||
|
let collectionId = pkiCollectionId;
|
||||||
|
|
||||||
if (caId) {
|
if (caId) {
|
||||||
ca = await certificateAuthorityDAL.findById(caId);
|
ca = await certificateAuthorityDAL.findById(caId);
|
||||||
@@ -1301,6 +1304,7 @@ export const certificateAuthorityServiceFactory = ({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
collectionId = certificateTemplate.pkiCollectionId as string;
|
||||||
ca = await certificateAuthorityDAL.findById(certificateTemplate.caId);
|
ca = await certificateAuthorityDAL.findById(certificateTemplate.caId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1490,10 +1494,10 @@ export const certificateAuthorityServiceFactory = ({
|
|||||||
tx
|
tx
|
||||||
);
|
);
|
||||||
|
|
||||||
if (pkiCollectionId) {
|
if (collectionId) {
|
||||||
await pkiCollectionItemDAL.create(
|
await pkiCollectionItemDAL.create(
|
||||||
{
|
{
|
||||||
pkiCollectionId,
|
pkiCollectionId: collectionId,
|
||||||
certId: cert.id
|
certId: cert.id
|
||||||
},
|
},
|
||||||
tx
|
tx
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ export const certificateTemplateServiceFactory = ({
|
|||||||
}: TCertificateTemplateServiceFactoryDep) => {
|
}: TCertificateTemplateServiceFactoryDep) => {
|
||||||
const createCertTemplate = async ({
|
const createCertTemplate = async ({
|
||||||
caId,
|
caId,
|
||||||
|
pkiCollectionId,
|
||||||
name,
|
name,
|
||||||
commonName,
|
commonName,
|
||||||
subjectAlternativeName,
|
subjectAlternativeName,
|
||||||
@@ -58,6 +59,7 @@ export const certificateTemplateServiceFactory = ({
|
|||||||
|
|
||||||
const certificateTemplate = await certificateTemplateDAL.create({
|
const certificateTemplate = await certificateTemplateDAL.create({
|
||||||
caId,
|
caId,
|
||||||
|
pkiCollectionId,
|
||||||
name,
|
name,
|
||||||
commonName,
|
commonName,
|
||||||
subjectAlternativeName,
|
subjectAlternativeName,
|
||||||
@@ -70,6 +72,7 @@ export const certificateTemplateServiceFactory = ({
|
|||||||
const updateCertTemplate = async ({
|
const updateCertTemplate = async ({
|
||||||
id,
|
id,
|
||||||
caId,
|
caId,
|
||||||
|
pkiCollectionId,
|
||||||
name,
|
name,
|
||||||
commonName,
|
commonName,
|
||||||
subjectAlternativeName,
|
subjectAlternativeName,
|
||||||
@@ -110,6 +113,7 @@ export const certificateTemplateServiceFactory = ({
|
|||||||
|
|
||||||
const updatedCertTemplate = await certificateTemplateDAL.updateById(certTemplate.id, {
|
const updatedCertTemplate = await certificateTemplateDAL.updateById(certTemplate.id, {
|
||||||
caId,
|
caId,
|
||||||
|
pkiCollectionId,
|
||||||
commonName,
|
commonName,
|
||||||
subjectAlternativeName,
|
subjectAlternativeName,
|
||||||
name,
|
name,
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { TProjectPermission } from "@app/lib/types";
|
|||||||
|
|
||||||
export type TCreateCertTemplateDTO = {
|
export type TCreateCertTemplateDTO = {
|
||||||
caId: string;
|
caId: string;
|
||||||
|
pkiCollectionId?: string;
|
||||||
name: string;
|
name: string;
|
||||||
commonName: string;
|
commonName: string;
|
||||||
subjectAlternativeName: string;
|
subjectAlternativeName: string;
|
||||||
@@ -11,6 +12,7 @@ export type TCreateCertTemplateDTO = {
|
|||||||
export type TUpdateCertTemplateDTO = {
|
export type TUpdateCertTemplateDTO = {
|
||||||
id: string;
|
id: string;
|
||||||
caId?: string;
|
caId?: string;
|
||||||
|
pkiCollectionId?: string;
|
||||||
name?: string;
|
name?: string;
|
||||||
commonName?: string;
|
commonName?: string;
|
||||||
subjectAlternativeName?: string;
|
subjectAlternativeName?: string;
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ export type TCertificateTemplateListEntry = {
|
|||||||
export type TCertificateTemplate = {
|
export type TCertificateTemplate = {
|
||||||
id: string;
|
id: string;
|
||||||
caId: string;
|
caId: string;
|
||||||
|
pkiCollectionId?: string;
|
||||||
name: string;
|
name: string;
|
||||||
commonName: string;
|
commonName: string;
|
||||||
subjectAlternativeName: string;
|
subjectAlternativeName: string;
|
||||||
@@ -16,6 +17,7 @@ export type TCertificateTemplate = {
|
|||||||
|
|
||||||
export type TCreateCertificateTemplateDTO = {
|
export type TCreateCertificateTemplateDTO = {
|
||||||
caId: string;
|
caId: string;
|
||||||
|
pkiCollectionId?: string;
|
||||||
name: string;
|
name: string;
|
||||||
commonName: string;
|
commonName: string;
|
||||||
subjectAlternativeName: string;
|
subjectAlternativeName: string;
|
||||||
@@ -26,6 +28,7 @@ export type TCreateCertificateTemplateDTO = {
|
|||||||
export type TUpdateCertificateTemplateDTO = {
|
export type TUpdateCertificateTemplateDTO = {
|
||||||
id: string;
|
id: string;
|
||||||
caId?: string;
|
caId?: string;
|
||||||
|
pkiCollectionId?: string;
|
||||||
name?: string;
|
name?: string;
|
||||||
commonName?: string;
|
commonName?: string;
|
||||||
subjectAlternativeName?: string;
|
subjectAlternativeName?: string;
|
||||||
|
|||||||
+2
-1
@@ -243,7 +243,7 @@ export const CertificateModal = ({ popUp, handlePopUpToggle }: Props) => {
|
|||||||
</FormControl>
|
</FormControl>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
)}
|
) && (
|
||||||
<Controller
|
<Controller
|
||||||
control={control}
|
control={control}
|
||||||
name="collectionId"
|
name="collectionId"
|
||||||
@@ -270,6 +270,7 @@ export const CertificateModal = ({ popUp, handlePopUpToggle }: Props) => {
|
|||||||
</FormControl>
|
</FormControl>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
<Controller
|
<Controller
|
||||||
control={control}
|
control={control}
|
||||||
defaultValue=""
|
defaultValue=""
|
||||||
|
|||||||
+35
@@ -19,6 +19,7 @@ import {
|
|||||||
useCreateCertTemplate,
|
useCreateCertTemplate,
|
||||||
useGetCertTemplate,
|
useGetCertTemplate,
|
||||||
useListWorkspaceCas,
|
useListWorkspaceCas,
|
||||||
|
useListWorkspacePkiCollections,
|
||||||
useUpdateCertTemplate
|
useUpdateCertTemplate
|
||||||
} from "@app/hooks/api";
|
} from "@app/hooks/api";
|
||||||
import { caTypeToNameMap } from "@app/hooks/api/ca/constants";
|
import { caTypeToNameMap } from "@app/hooks/api/ca/constants";
|
||||||
@@ -36,6 +37,7 @@ const validateTemplateRegexField = z
|
|||||||
|
|
||||||
const schema = z.object({
|
const schema = z.object({
|
||||||
caId: z.string(),
|
caId: z.string(),
|
||||||
|
collectionId: z.string().optional(),
|
||||||
name: z.string().min(1),
|
name: z.string().min(1),
|
||||||
commonName: validateTemplateRegexField,
|
commonName: validateTemplateRegexField,
|
||||||
subjectAlternativeName: validateTemplateRegexField,
|
subjectAlternativeName: validateTemplateRegexField,
|
||||||
@@ -63,6 +65,10 @@ export const CertificateTemplateModal = ({ popUp, handlePopUpToggle }: Props) =>
|
|||||||
status: CaStatus.ACTIVE
|
status: CaStatus.ACTIVE
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { data: collectionsData } = useListWorkspacePkiCollections({
|
||||||
|
workspaceId: currentWorkspace?.id || ""
|
||||||
|
});
|
||||||
|
|
||||||
const { mutateAsync: createCertTemplate } = useCreateCertTemplate();
|
const { mutateAsync: createCertTemplate } = useCreateCertTemplate();
|
||||||
const { mutateAsync: updateCertTemplate } = useUpdateCertTemplate();
|
const { mutateAsync: updateCertTemplate } = useUpdateCertTemplate();
|
||||||
|
|
||||||
@@ -82,6 +88,7 @@ export const CertificateTemplateModal = ({ popUp, handlePopUpToggle }: Props) =>
|
|||||||
name: certTemplate.name,
|
name: certTemplate.name,
|
||||||
commonName: certTemplate.commonName,
|
commonName: certTemplate.commonName,
|
||||||
subjectAlternativeName: certTemplate.subjectAlternativeName,
|
subjectAlternativeName: certTemplate.subjectAlternativeName,
|
||||||
|
collectionId: certTemplate.pkiCollectionId ?? undefined,
|
||||||
ttl: certTemplate.ttl
|
ttl: certTemplate.ttl
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@@ -96,6 +103,7 @@ export const CertificateTemplateModal = ({ popUp, handlePopUpToggle }: Props) =>
|
|||||||
|
|
||||||
const onFormSubmit = async ({
|
const onFormSubmit = async ({
|
||||||
caId,
|
caId,
|
||||||
|
collectionId,
|
||||||
name,
|
name,
|
||||||
commonName,
|
commonName,
|
||||||
subjectAlternativeName,
|
subjectAlternativeName,
|
||||||
@@ -110,6 +118,7 @@ export const CertificateTemplateModal = ({ popUp, handlePopUpToggle }: Props) =>
|
|||||||
await updateCertTemplate({
|
await updateCertTemplate({
|
||||||
id: certTemplate.id,
|
id: certTemplate.id,
|
||||||
projectId: currentWorkspace.id,
|
projectId: currentWorkspace.id,
|
||||||
|
pkiCollectionId: collectionId,
|
||||||
caId,
|
caId,
|
||||||
name,
|
name,
|
||||||
commonName,
|
commonName,
|
||||||
@@ -124,6 +133,7 @@ export const CertificateTemplateModal = ({ popUp, handlePopUpToggle }: Props) =>
|
|||||||
} else {
|
} else {
|
||||||
await createCertTemplate({
|
await createCertTemplate({
|
||||||
projectId: currentWorkspace.id,
|
projectId: currentWorkspace.id,
|
||||||
|
pkiCollectionId: collectionId,
|
||||||
caId,
|
caId,
|
||||||
name,
|
name,
|
||||||
commonName,
|
commonName,
|
||||||
@@ -200,6 +210,31 @@ export const CertificateTemplateModal = ({ popUp, handlePopUpToggle }: Props) =>
|
|||||||
</FormControl>
|
</FormControl>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name="collectionId"
|
||||||
|
render={({ field: { onChange, ...field }, fieldState: { error } }) => (
|
||||||
|
<FormControl
|
||||||
|
label="Certificate Collection (Optional)"
|
||||||
|
errorText={error?.message}
|
||||||
|
isError={Boolean(error)}
|
||||||
|
className="mt-4"
|
||||||
|
>
|
||||||
|
<Select
|
||||||
|
defaultValue={field.value}
|
||||||
|
{...field}
|
||||||
|
onValueChange={(e) => onChange(e)}
|
||||||
|
className="w-full"
|
||||||
|
>
|
||||||
|
{(collectionsData?.collections || []).map(({ id, name }) => (
|
||||||
|
<SelectItem value={id} key={`pki-collection-${id}`}>
|
||||||
|
{name}
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
<Controller
|
<Controller
|
||||||
control={control}
|
control={control}
|
||||||
defaultValue=""
|
defaultValue=""
|
||||||
|
|||||||
+1
-1
@@ -76,7 +76,7 @@ export const CertificateTemplatesTable = ({ handlePopUpOpen }: Props) => {
|
|||||||
}
|
}
|
||||||
icon={<FontAwesomeIcon icon={faGear} />}
|
icon={<FontAwesomeIcon icon={faGear} />}
|
||||||
>
|
>
|
||||||
Manage
|
Manage Policies
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
<ProjectPermissionCan
|
<ProjectPermissionCan
|
||||||
I={ProjectPermissionActions.Delete}
|
I={ProjectPermissionActions.Delete}
|
||||||
|
|||||||
Reference in New Issue
Block a user