From 77de085ffc5cc9c06af7f08b0e9bad1d2848fe1b Mon Sep 17 00:00:00 2001 From: Sheen Capadngan Date: Thu, 22 May 2025 00:22:49 +0800 Subject: [PATCH] misc: addressed first set of review comments --- .../20250521110635_add-external-ca-pki.ts | 19 +-- .../src/db/schemas/certificate-authorities.ts | 4 +- .../external-certificate-authorities.ts | 7 +- .../internal-certificate-authorities.ts | 3 +- backend/src/lib/api-docs/constants.ts | 7 +- backend/src/server/routes/sanitizedSchemas.ts | 1 + .../certificate-authority-endpoints.ts | 66 +++++---- .../server/routes/v1/pki-subscriber-router.ts | 16 +-- .../acme/acme-certificate-authority-fns.ts | 47 +++---- .../certificate-authority-dal.ts | 130 +++++++++++++----- .../certificate-authority-fns.ts | 2 +- .../certificate-authority-schemas.ts | 9 +- .../certificate-authority-service.ts | 86 +++++++----- .../certificate-authority-types.ts | 3 +- .../internal-certificate-authority-service.ts | 48 +++---- .../internal-certificate-authority-types.ts | 2 + .../certificate-template-dal.ts | 4 +- .../src/services/pki-alert/pki-alert-dal.ts | 2 +- .../pki-collection/pki-collection-item-dal.ts | 2 +- .../certificate-authorities/acme/delete.mdx | 2 +- .../certificate-authorities/acme/read.mdx | 2 +- .../certificate-authorities/acme/update.mdx | 2 +- .../subscribers/get-active-cert-bundle.mdx | 4 - .../subscribers/get-latest-cert-bundle.mdx | 4 + docs/mint.json | 2 +- frontend/src/hooks/api/ca/index.tsx | 2 +- frontend/src/hooks/api/ca/mutations.tsx | 19 +-- frontend/src/hooks/api/ca/queries.tsx | 32 +++-- frontend/src/hooks/api/ca/types.ts | 9 +- .../components/ExternalCaModal.tsx | 31 +++-- .../components/ExternalCaSection.tsx | 14 +- .../components/ExternalCaTable.tsx | 10 +- 32 files changed, 339 insertions(+), 252 deletions(-) delete mode 100644 docs/api-reference/endpoints/pki/subscribers/get-active-cert-bundle.mdx create mode 100644 docs/api-reference/endpoints/pki/subscribers/get-latest-cert-bundle.mdx diff --git a/backend/src/db/migrations/20250521110635_add-external-ca-pki.ts b/backend/src/db/migrations/20250521110635_add-external-ca-pki.ts index 34d8d2052..b4e076331 100644 --- a/backend/src/db/migrations/20250521110635_add-external-ca-pki.ts +++ b/backend/src/db/migrations/20250521110635_add-external-ca-pki.ts @@ -24,6 +24,7 @@ export async function up(knex: Knex): Promise { t.dropColumn("requireTemplateForIssuance"); t.dropColumn("createdAt"); t.dropColumn("updatedAt"); + t.dropColumn("status"); t.uuid("parentCaId") .nullable() .references("id") @@ -44,22 +45,18 @@ export async function up(knex: Knex): Promise { await Promise.all( cas.map((ca) => { const slugifiedName = ca.friendlyName - ? slugify(`${ca.friendlyName}-${alphaNumericNanoId(8)}`) + ? slugify(`${ca.friendlyName.slice(0, 16)}-${alphaNumericNanoId(8)}`) : slugify(alphaNumericNanoId(12)); - return ( - knex(TableName.CertificateAuthority) - .where({ id: ca.id }) - // @ts-expect-error intentional: migration - .update({ name: slugifiedName, enableDirectIssuance: !ca.enableDirectIssuance }) - ); + return knex(TableName.CertificateAuthority) + .where({ id: ca.id }) + .update({ name: slugifiedName, enableDirectIssuance: !ca.enableDirectIssuance }); }) ); await knex.schema.alterTable(TableName.CertificateAuthority, (t) => { t.dropColumn("parentCaId"); t.dropColumn("type"); - t.dropColumn("status"); t.dropColumn("friendlyName"); t.dropColumn("organization"); t.dropColumn("ou"); @@ -74,6 +71,7 @@ export async function up(knex: Knex): Promise { t.dropColumn("notBefore"); t.dropColumn("notAfter"); t.dropColumn("activeCaCertId"); + t.boolean("enableDirectIssuance").notNullable().defaultTo(true).alter(); t.string("name").notNullable().alter(); t.unique(["name", "projectId"]); }); @@ -90,7 +88,6 @@ export async function up(knex: Knex): Promise { t.uuid("caId").notNullable().references("id").inTable(TableName.CertificateAuthority).onDelete("CASCADE"); t.binary("credentials"); t.json("configuration"); - t.string("status").notNullable(); }); } @@ -114,7 +111,6 @@ export async function down(knex: Knex): Promise { await knex.schema.alterTable(TableName.CertificateAuthority, (t) => { t.uuid("parentCaId").nullable().references("id").inTable(TableName.CertificateAuthority).onDelete("CASCADE"); t.string("type").nullable(); - t.string("status").nullable(); t.string("friendlyName").nullable(); t.string("organization").nullable(); t.string("ou").nullable(); @@ -150,7 +146,6 @@ export async function down(knex: Knex): Promise { UPDATE ${TableName.CertificateAuthority} ca SET type = ica.type, - status = ica.status, "friendlyName" = ica."friendlyName", organization = ica.organization, ou = ica.ou, @@ -172,7 +167,6 @@ export async function down(knex: Knex): Promise { await knex.schema.alterTable(TableName.CertificateAuthority, (t) => { t.string("type").notNullable().alter(); - t.string("status").notNullable().alter(); t.string("friendlyName").notNullable().alter(); t.string("organization").notNullable().alter(); t.string("ou").notNullable().alter(); @@ -182,6 +176,7 @@ export async function down(knex: Knex): Promise { t.string("commonName").notNullable().alter(); t.string("dn").notNullable().alter(); t.string("keyAlgorithm").notNullable().alter(); + t.boolean("requireTemplateForIssuance").notNullable().defaultTo(false).alter(); }); await knex.schema.dropTable(TableName.InternalCertificateAuthority); diff --git a/backend/src/db/schemas/certificate-authorities.ts b/backend/src/db/schemas/certificate-authorities.ts index 8752f25d0..62a2d6ceb 100644 --- a/backend/src/db/schemas/certificate-authorities.ts +++ b/backend/src/db/schemas/certificate-authorities.ts @@ -12,7 +12,9 @@ export const CertificateAuthoritiesSchema = z.object({ createdAt: z.date(), updatedAt: z.date(), projectId: z.string(), - disableDirectIssuance: z.boolean().default(false) + enableDirectIssuance: z.boolean().default(true), + status: z.string(), + name: z.string() }); export type TCertificateAuthorities = z.infer; diff --git a/backend/src/db/schemas/external-certificate-authorities.ts b/backend/src/db/schemas/external-certificate-authorities.ts index f36c54770..4f20ce0da 100644 --- a/backend/src/db/schemas/external-certificate-authorities.ts +++ b/backend/src/db/schemas/external-certificate-authorities.ts @@ -12,14 +12,11 @@ import { TImmutableDBKeys } from "./models"; export const ExternalCertificateAuthoritiesSchema = z.object({ id: z.string().uuid(), type: z.string(), - name: z.string(), - projectId: z.string(), appConnectionId: z.string().uuid().nullable().optional(), dnsAppConnectionId: z.string().uuid().nullable().optional(), - certificateAuthorityId: z.string().uuid(), + caId: z.string().uuid(), credentials: zodBuffer.nullable().optional(), - configuration: z.unknown().nullable().optional(), - status: z.string() + configuration: z.unknown().nullable().optional() }); export type TExternalCertificateAuthorities = z.infer; diff --git a/backend/src/db/schemas/internal-certificate-authorities.ts b/backend/src/db/schemas/internal-certificate-authorities.ts index 3a27bfcdb..70f31c155 100644 --- a/backend/src/db/schemas/internal-certificate-authorities.ts +++ b/backend/src/db/schemas/internal-certificate-authorities.ts @@ -11,7 +11,6 @@ export const InternalCertificateAuthoritiesSchema = z.object({ id: z.string().uuid(), parentCaId: z.string().uuid().nullable().optional(), type: z.string(), - status: z.string(), friendlyName: z.string(), organization: z.string(), ou: z.string(), @@ -26,7 +25,7 @@ export const InternalCertificateAuthoritiesSchema = z.object({ notBefore: z.date().nullable().optional(), notAfter: z.date().nullable().optional(), activeCaCertId: z.string().uuid().nullable().optional(), - certificateAuthorityId: z.string().uuid() + caId: z.string().uuid() }); export type TInternalCertificateAuthorities = z.infer; diff --git a/backend/src/lib/api-docs/constants.ts b/backend/src/lib/api-docs/constants.ts index 537264028..1fe774508 100644 --- a/backend/src/lib/api-docs/constants.ts +++ b/backend/src/lib/api-docs/constants.ts @@ -1793,7 +1793,7 @@ export const PKI_SUBSCRIBERS = { subscriberName: "The name of the PKI subscriber to get.", projectId: "The ID of the project to get the PKI subscriber for." }, - GET_ACTIVE_CERT_BUNDLE: { + GET_LATEST_CERT_BUNDLE: { subscriberName: "The name of the PKI subscriber to get the active certificate bundle for.", projectId: "The ID of the project to get the active certificate bundle for.", certificate: "The active certificate for the subscriber.", @@ -2018,13 +2018,14 @@ export const CertificateAuthorities = { CREATE: (type: CaType) => ({ name: `The name of the ${CERTIFICATE_AUTHORITIES_TYPE_MAP[type]} Certificate Authority to create. Must be slug-friendly.`, projectId: `The ID of the project to create the Certificate Authority in.`, - disableDirectIssuance: `Whether or not to disable direct issuance of certificates for the ${CERTIFICATE_AUTHORITIES_TYPE_MAP[type]} Certificate Authority.`, + enableDirectIssuance: `Whether or not to enable direct issuance of certificates for the ${CERTIFICATE_AUTHORITIES_TYPE_MAP[type]} Certificate Authority.`, status: `The status of the ${CERTIFICATE_AUTHORITIES_TYPE_MAP[type]} Certificate Authority.` }), UPDATE: (type: CaType) => ({ caId: `The ID of the ${CERTIFICATE_AUTHORITIES_TYPE_MAP[type]} Certificate Authority to update.`, + projectId: `The ID of the project to update the Certificate Authority in.`, name: `The updated name of the ${CERTIFICATE_AUTHORITIES_TYPE_MAP[type]} Certificate Authority. Must be slug-friendly.`, - disableDirectIssuance: `Whether or not to disable direct issuance of certificates for the ${CERTIFICATE_AUTHORITIES_TYPE_MAP[type]} Certificate Authority.`, + enableDirectIssuance: `Whether or not to enable direct issuance of certificates for the ${CERTIFICATE_AUTHORITIES_TYPE_MAP[type]} Certificate Authority.`, status: `The updated status of the ${CERTIFICATE_AUTHORITIES_TYPE_MAP[type]} Certificate Authority.` }), CONFIGURATIONS: { diff --git a/backend/src/server/routes/sanitizedSchemas.ts b/backend/src/server/routes/sanitizedSchemas.ts index 50145e323..209044434 100644 --- a/backend/src/server/routes/sanitizedSchemas.ts +++ b/backend/src/server/routes/sanitizedSchemas.ts @@ -277,6 +277,7 @@ export const SanitizedTagSchema = SecretTagsSchema.pick({ export const InternalCertificateAuthorityResponseSchema = CertificateAuthoritiesSchema.merge( InternalCertificateAuthoritiesSchema.omit({ + caId: true, notAfter: true, notBefore: true }) diff --git a/backend/src/server/routes/v1/certificate-authority-routers/certificate-authority-endpoints.ts b/backend/src/server/routes/v1/certificate-authority-routers/certificate-authority-endpoints.ts index 701fb6d2e..80855c558 100644 --- a/backend/src/server/routes/v1/certificate-authority-routers/certificate-authority-endpoints.ts +++ b/backend/src/server/routes/v1/certificate-authority-routers/certificate-authority-endpoints.ts @@ -28,13 +28,14 @@ export const registerCertificateAuthorityEndpoints = < projectId: string; status: CaStatus; configuration: I["configuration"]; - disableDirectIssuance: boolean; + enableDirectIssuance: boolean; }>; updateSchema: z.ZodType<{ + projectId: string; name?: string; status?: CaStatus; configuration?: I["configuration"]; - disableDirectIssuance?: boolean; + enableDirectIssuance?: boolean; }>; responseSchema: z.ZodTypeAny; }) => { @@ -51,7 +52,7 @@ export const registerCertificateAuthorityEndpoints = < projectId: z.string().trim().min(1, "Project ID required") }), response: { - 200: z.object({ certificateAuthorities: responseSchema.array() }) + 200: responseSchema.array() } }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), @@ -76,13 +77,13 @@ export const registerCertificateAuthorityEndpoints = < } }); - return { certificateAuthorities }; + return certificateAuthorities; } }); server.route({ method: "GET", - url: "/:certificateAuthorityId", + url: "/:caName", config: { rateLimit: readLimit }, @@ -90,20 +91,25 @@ export const registerCertificateAuthorityEndpoints = < hide: false, tags: [ApiDocsTags.PkiCertificateAuthorities], params: z.object({ - certificateAuthorityId: z.string().uuid() + caName: z.string() + }), + querystring: z.object({ + projectId: z.string().uuid() }), response: { - 200: z.object({ certificateAuthority: responseSchema }) + 200: responseSchema } }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), handler: async (req) => { - const { certificateAuthorityId } = req.params; + const { caName } = req.params; + const { projectId } = req.query; - const certificateAuthority = (await server.services.certificateAuthority.findCertificateAuthorityById( - { certificateAuthorityId, type: caType }, - req.permission - )) as T; + const certificateAuthority = + (await server.services.certificateAuthority.findCertificateAuthorityByNameAndProjectId( + { caName, type: caType, projectId }, + req.permission + )) as T; await server.services.auditLog.createAuditLog({ ...req.auditLogInfo, @@ -116,7 +122,7 @@ export const registerCertificateAuthorityEndpoints = < } }); - return { certificateAuthority }; + return certificateAuthority; } }); @@ -131,7 +137,7 @@ export const registerCertificateAuthorityEndpoints = < tags: [ApiDocsTags.PkiCertificateAuthorities], body: createSchema, response: { - 200: z.object({ certificateAuthority: responseSchema }) + 200: responseSchema } }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), @@ -152,13 +158,13 @@ export const registerCertificateAuthorityEndpoints = < } }); - return { certificateAuthority }; + return certificateAuthority; } }); server.route({ method: "PATCH", - url: "/:certificateAuthorityId", + url: "/:caName", config: { rateLimit: writeLimit }, @@ -166,22 +172,22 @@ export const registerCertificateAuthorityEndpoints = < hide: false, tags: [ApiDocsTags.PkiCertificateAuthorities], params: z.object({ - certificateAuthorityId: z.string().uuid() + caName: z.string() }), body: updateSchema, response: { - 200: z.object({ certificateAuthority: responseSchema }) + 200: responseSchema } }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), handler: async (req) => { - const { certificateAuthorityId } = req.params; + const { caName } = req.params; const certificateAuthority = (await server.services.certificateAuthority.updateCertificateAuthority( { ...req.body, - id: certificateAuthorityId, - type: caType + type: caType, + caName }, req.permission )) as T; @@ -198,13 +204,13 @@ export const registerCertificateAuthorityEndpoints = < } }); - return { certificateAuthority }; + return certificateAuthority; } }); server.route({ method: "DELETE", - url: "/:certificateAuthorityId", + url: "/:caName", config: { rateLimit: writeLimit }, @@ -212,18 +218,22 @@ export const registerCertificateAuthorityEndpoints = < hide: false, tags: [ApiDocsTags.PkiCertificateAuthorities], params: z.object({ - certificateAuthorityId: z.string().uuid() + caName: z.string() + }), + body: z.object({ + projectId: z.string().uuid() }), response: { - 200: z.object({ certificateAuthority: responseSchema }) + 200: responseSchema } }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), handler: async (req) => { - const { certificateAuthorityId } = req.params; + const { caName } = req.params; + const { projectId } = req.body; const certificateAuthority = (await server.services.certificateAuthority.deleteCertificateAuthority( - { id: certificateAuthorityId, type: caType }, + { caName, type: caType, projectId }, req.permission )) as T; @@ -238,7 +248,7 @@ export const registerCertificateAuthorityEndpoints = < } }); - return { certificateAuthority }; + return certificateAuthority; } }); }; diff --git a/backend/src/server/routes/v1/pki-subscriber-router.ts b/backend/src/server/routes/v1/pki-subscriber-router.ts index 12ece4d0f..b667b5b72 100644 --- a/backend/src/server/routes/v1/pki-subscriber-router.ts +++ b/backend/src/server/routes/v1/pki-subscriber-router.ts @@ -485,30 +485,30 @@ export const registerPkiSubscriberRouter = async (server: FastifyZodProvider) => server.route({ method: "GET", - url: "/:subscriberName/active-certificate/bundle", + url: "/:subscriberName/latest-certificate-bundle", config: { rateLimit: readLimit }, schema: { hide: false, tags: [ApiDocsTags.PkiSubscribers], - description: "Get active certificate bundle of a subscriber", + description: "Get latest certificate bundle of a subscriber", params: z.object({ - subscriberName: z.string().describe(PKI_SUBSCRIBERS.GET_ACTIVE_CERT_BUNDLE.subscriberName) + subscriberName: z.string().describe(PKI_SUBSCRIBERS.GET_LATEST_CERT_BUNDLE.subscriberName) }), querystring: z.object({ - projectId: z.string().trim().describe(PKI_SUBSCRIBERS.GET_ACTIVE_CERT_BUNDLE.projectId) + projectId: z.string().trim().describe(PKI_SUBSCRIBERS.GET_LATEST_CERT_BUNDLE.projectId) }), response: { 200: z.object({ - certificate: z.string().trim().describe(PKI_SUBSCRIBERS.GET_ACTIVE_CERT_BUNDLE.certificate), + certificate: z.string().trim().describe(PKI_SUBSCRIBERS.GET_LATEST_CERT_BUNDLE.certificate), certificateChain: z .string() .trim() .nullable() - .describe(PKI_SUBSCRIBERS.GET_ACTIVE_CERT_BUNDLE.certificateChain), - privateKey: z.string().trim().describe(PKI_SUBSCRIBERS.GET_ACTIVE_CERT_BUNDLE.privateKey), - serialNumber: z.string().trim().describe(PKI_SUBSCRIBERS.GET_ACTIVE_CERT_BUNDLE.serialNumber) + .describe(PKI_SUBSCRIBERS.GET_LATEST_CERT_BUNDLE.certificateChain), + privateKey: z.string().trim().describe(PKI_SUBSCRIBERS.GET_LATEST_CERT_BUNDLE.privateKey), + serialNumber: z.string().trim().describe(PKI_SUBSCRIBERS.GET_LATEST_CERT_BUNDLE.serialNumber) }) } }, diff --git a/backend/src/services/certificate-authority/acme/acme-certificate-authority-fns.ts b/backend/src/services/certificate-authority/acme/acme-certificate-authority-fns.ts index 9fc8937a0..8e0372953 100644 --- a/backend/src/services/certificate-authority/acme/acme-certificate-authority-fns.ts +++ b/backend/src/services/certificate-authority/acme/acme-certificate-authority-fns.ts @@ -77,8 +77,8 @@ export const castDbEntryToAcmeCertificateAuthority = ( return { id: ca.id, type: CaType.ACME, - disableDirectIssuance: ca.disableDirectIssuance, - name: ca.externalCa.name, + enableDirectIssuance: ca.enableDirectIssuance, + name: ca.name, projectId: ca.projectId, credentials: ca.externalCa.credentials, configuration: { @@ -90,7 +90,7 @@ export const castDbEntryToAcmeCertificateAuthority = ( directoryUrl: dbConfigurationCol.directoryUrl, accountEmail: dbConfigurationCol.accountEmail }, - status: ca.externalCa.status as CaStatus + status: ca.status as CaStatus }; }; @@ -176,7 +176,7 @@ export const AcmeCertificateAuthorityFns = ({ name, projectId, configuration, - disableDirectIssuance, + enableDirectIssuance, actor, status }: { @@ -184,7 +184,7 @@ export const AcmeCertificateAuthorityFns = ({ name: string; projectId: string; configuration: TCreateAcmeCertificateAuthorityDTO["configuration"]; - disableDirectIssuance: boolean; + enableDirectIssuance: boolean; actor: OrgServiceActor; }) => { const { dnsAppConnectionId, directoryUrl, accountEmail, dnsProviderConfig } = configuration; @@ -208,25 +208,24 @@ export const AcmeCertificateAuthorityFns = ({ const ca = await certificateAuthorityDAL.create( { projectId, - disableDirectIssuance + enableDirectIssuance, + name, + status }, tx ); await externalCertificateAuthorityDAL.create( { - certificateAuthorityId: ca.id, + caId: ca.id, dnsAppConnectionId, type: CaType.ACME, - name, - projectId, configuration: { directoryUrl, accountEmail, dnsProvider: dnsProviderConfig.provider, hostedZoneId: dnsProviderConfig.hostedZoneId - }, - status + } }, tx ); @@ -255,14 +254,14 @@ export const AcmeCertificateAuthorityFns = ({ id, status, configuration, - disableDirectIssuance, + enableDirectIssuance, actor, name }: { id: string; status?: CaStatus; configuration: TUpdateAcmeCertificateAuthorityDTO["configuration"]; - disableDirectIssuance?: boolean; + enableDirectIssuance?: boolean; actor: OrgServiceActor; name?: string; }) => { @@ -290,7 +289,7 @@ export const AcmeCertificateAuthorityFns = ({ await externalCertificateAuthorityDAL.update( { - certificateAuthorityId: id, + caId: id, type: CaType.ACME }, { @@ -306,23 +305,13 @@ export const AcmeCertificateAuthorityFns = ({ ); } - await externalCertificateAuthorityDAL.update( - { - certificateAuthorityId: id, - type: CaType.ACME - }, - { - name, - status - }, - tx - ); - - if (disableDirectIssuance !== undefined) { + if (name || status || enableDirectIssuance) { await certificateAuthorityDAL.updateById( id, { - disableDirectIssuance + name, + status, + enableDirectIssuance }, tx ); @@ -399,7 +388,7 @@ export const AcmeCertificateAuthorityFns = ({ }); await externalCertificateAuthorityDAL.update( { - certificateAuthorityId: acmeCa.id + caId: acmeCa.id }, { credentials: encryptedNewCredentials diff --git a/backend/src/services/certificate-authority/certificate-authority-dal.ts b/backend/src/services/certificate-authority/certificate-authority-dal.ts index 32f053117..d5a45ce50 100644 --- a/backend/src/services/certificate-authority/certificate-authority-dal.ts +++ b/backend/src/services/certificate-authority/certificate-authority-dal.ts @@ -14,25 +14,25 @@ export type TCertificateAuthorityWithAssociatedCa = Awaited< export const certificateAuthorityDALFactory = (db: TDbClient) => { const caOrm = ormify(db, TableName.CertificateAuthority); - const findByIdWithAssociatedCa = async (caId: string, tx?: Knex) => { + const findByNameAndProjectIdWithAssociatedCa = async (caName: string, projectId: string, tx?: Knex) => { const result = await (tx || db.replicaNode())(TableName.CertificateAuthority) .leftJoin( TableName.InternalCertificateAuthority, `${TableName.CertificateAuthority}.id`, - `${TableName.InternalCertificateAuthority}.certificateAuthorityId` + `${TableName.InternalCertificateAuthority}.caId` ) .leftJoin( TableName.ExternalCertificateAuthority, `${TableName.CertificateAuthority}.id`, - `${TableName.ExternalCertificateAuthority}.certificateAuthorityId` + `${TableName.ExternalCertificateAuthority}.caId` ) - .where(`${TableName.CertificateAuthority}.id`, caId) + .where(`${TableName.CertificateAuthority}.name`, caName) + .where(`${TableName.CertificateAuthority}.projectId`, projectId) .select(selectAllTableCols(TableName.CertificateAuthority)) .select( db.ref("id").withSchema(TableName.InternalCertificateAuthority).as("internalCaId"), db.ref("parentCaId").withSchema(TableName.InternalCertificateAuthority).as("internalParentCaId"), db.ref("type").withSchema(TableName.InternalCertificateAuthority).as("internalType"), - db.ref("status").withSchema(TableName.InternalCertificateAuthority).as("internalStatus"), db.ref("friendlyName").withSchema(TableName.InternalCertificateAuthority).as("internalFriendlyName"), db.ref("organization").withSchema(TableName.InternalCertificateAuthority).as("internalOrganization"), db.ref("ou").withSchema(TableName.InternalCertificateAuthority).as("internalOu"), @@ -46,17 +46,11 @@ export const certificateAuthorityDALFactory = (db: TDbClient) => { db.ref("keyAlgorithm").withSchema(TableName.InternalCertificateAuthority).as("internalKeyAlgorithm"), db.ref("notBefore").withSchema(TableName.InternalCertificateAuthority).as("internalNotBefore"), db.ref("notAfter").withSchema(TableName.InternalCertificateAuthority).as("internalNotAfter"), - db.ref("activeCaCertId").withSchema(TableName.InternalCertificateAuthority).as("internalActiveCaCertId"), - db - .ref("certificateAuthorityId") - .withSchema(TableName.InternalCertificateAuthority) - .as("internalCertificateAuthorityId") + db.ref("activeCaCertId").withSchema(TableName.InternalCertificateAuthority).as("internalActiveCaCertId") ) .select( db.ref("id").withSchema(TableName.ExternalCertificateAuthority).as("externalCaId"), - db.ref("name").withSchema(TableName.ExternalCertificateAuthority).as("externalName"), db.ref("type").withSchema(TableName.ExternalCertificateAuthority).as("externalType"), - db.ref("status").withSchema(TableName.ExternalCertificateAuthority).as("externalStatus"), db.ref("configuration").withSchema(TableName.ExternalCertificateAuthority).as("externalConfiguration"), db.ref("credentials").withSchema(TableName.ExternalCertificateAuthority).as("externalCredentials"), db @@ -74,7 +68,6 @@ export const certificateAuthorityDALFactory = (db: TDbClient) => { id: result.internalCaId, parentCaId: result.internalParentCaId, type: result.internalType, - status: result.internalStatus, friendlyName: result.internalFriendlyName, organization: result.internalOrganization, ou: result.internalOu, @@ -88,16 +81,97 @@ export const certificateAuthorityDALFactory = (db: TDbClient) => { keyAlgorithm: result.internalKeyAlgorithm, notBefore: result.internalNotBefore?.toISOString(), notAfter: result.internalNotAfter?.toISOString(), - activeCaCertId: result.internalActiveCaCertId, - certificateAuthorityId: result.internalCertificateAuthorityId + activeCaCertId: result.internalActiveCaCertId + } + : undefined, + externalCa: result + ? { + id: result.externalCaId, + type: result.externalType, + configuration: result.externalConfiguration, + dnsAppConnectionId: result.externalDnsAppConnectionId, + appConnectionId: result.externalAppConnectionId, + credentials: result.externalCredentials + } + : undefined + }; + + return data; + }; + + const findByIdWithAssociatedCa = async (caId: string, tx?: Knex) => { + const result = await (tx || db.replicaNode())(TableName.CertificateAuthority) + .leftJoin( + TableName.InternalCertificateAuthority, + `${TableName.CertificateAuthority}.id`, + `${TableName.InternalCertificateAuthority}.caId` + ) + .leftJoin( + TableName.ExternalCertificateAuthority, + `${TableName.CertificateAuthority}.id`, + `${TableName.ExternalCertificateAuthority}.caId` + ) + .where(`${TableName.CertificateAuthority}.id`, caId) + .select(selectAllTableCols(TableName.CertificateAuthority)) + .select( + db.ref("id").withSchema(TableName.InternalCertificateAuthority).as("internalCaId"), + db.ref("parentCaId").withSchema(TableName.InternalCertificateAuthority).as("internalParentCaId"), + db.ref("type").withSchema(TableName.InternalCertificateAuthority).as("internalType"), + db.ref("friendlyName").withSchema(TableName.InternalCertificateAuthority).as("internalFriendlyName"), + db.ref("organization").withSchema(TableName.InternalCertificateAuthority).as("internalOrganization"), + db.ref("ou").withSchema(TableName.InternalCertificateAuthority).as("internalOu"), + db.ref("country").withSchema(TableName.InternalCertificateAuthority).as("internalCountry"), + db.ref("province").withSchema(TableName.InternalCertificateAuthority).as("internalProvince"), + db.ref("locality").withSchema(TableName.InternalCertificateAuthority).as("internalLocality"), + db.ref("commonName").withSchema(TableName.InternalCertificateAuthority).as("internalCommonName"), + db.ref("dn").withSchema(TableName.InternalCertificateAuthority).as("internalDn"), + db.ref("serialNumber").withSchema(TableName.InternalCertificateAuthority).as("internalSerialNumber"), + db.ref("maxPathLength").withSchema(TableName.InternalCertificateAuthority).as("internalMaxPathLength"), + db.ref("keyAlgorithm").withSchema(TableName.InternalCertificateAuthority).as("internalKeyAlgorithm"), + db.ref("notBefore").withSchema(TableName.InternalCertificateAuthority).as("internalNotBefore"), + db.ref("notAfter").withSchema(TableName.InternalCertificateAuthority).as("internalNotAfter"), + db.ref("activeCaCertId").withSchema(TableName.InternalCertificateAuthority).as("internalActiveCaCertId") + ) + .select( + db.ref("id").withSchema(TableName.ExternalCertificateAuthority).as("externalCaId"), + db.ref("type").withSchema(TableName.ExternalCertificateAuthority).as("externalType"), + db.ref("configuration").withSchema(TableName.ExternalCertificateAuthority).as("externalConfiguration"), + db.ref("credentials").withSchema(TableName.ExternalCertificateAuthority).as("externalCredentials"), + db + .ref("dnsAppConnectionId") + .withSchema(TableName.ExternalCertificateAuthority) + .as("externalDnsAppConnectionId"), + db.ref("appConnectionId").withSchema(TableName.ExternalCertificateAuthority).as("externalAppConnectionId") + ) + .first(); + + const data = { + ...CertificateAuthoritiesSchema.parse(result), + internalCa: result + ? { + id: result.internalCaId, + parentCaId: result.internalParentCaId, + type: result.internalType, + friendlyName: result.internalFriendlyName, + organization: result.internalOrganization, + ou: result.internalOu, + country: result.internalCountry, + province: result.internalProvince, + locality: result.internalLocality, + commonName: result.internalCommonName, + dn: result.internalDn, + serialNumber: result.internalSerialNumber, + maxPathLength: result.internalMaxPathLength, + keyAlgorithm: result.internalKeyAlgorithm, + notBefore: result.internalNotBefore?.toISOString(), + notAfter: result.internalNotAfter?.toISOString(), + activeCaCertId: result.internalActiveCaCertId } : undefined, externalCa: result ? { id: result.externalCaId, - name: result.externalName, type: result.externalType, - status: result.externalStatus, configuration: result.externalConfiguration, dnsAppConnectionId: result.externalDnsAppConnectionId, appConnectionId: result.externalAppConnectionId, @@ -153,12 +227,12 @@ export const certificateAuthorityDALFactory = (db: TDbClient) => { .leftJoin( TableName.InternalCertificateAuthority, `${TableName.CertificateAuthority}.id`, - `${TableName.InternalCertificateAuthority}.certificateAuthorityId` + `${TableName.InternalCertificateAuthority}.caId` ) .leftJoin( TableName.ExternalCertificateAuthority, `${TableName.CertificateAuthority}.id`, - `${TableName.ExternalCertificateAuthority}.certificateAuthorityId` + `${TableName.ExternalCertificateAuthority}.caId` ) // eslint-disable-next-line @typescript-eslint/no-misused-promises .where(buildFindFilter(filter)) @@ -167,7 +241,6 @@ export const certificateAuthorityDALFactory = (db: TDbClient) => { db.ref("id").withSchema(TableName.InternalCertificateAuthority).as("internalCaId"), db.ref("parentCaId").withSchema(TableName.InternalCertificateAuthority).as("internalParentCaId"), db.ref("type").withSchema(TableName.InternalCertificateAuthority).as("internalType"), - db.ref("status").withSchema(TableName.InternalCertificateAuthority).as("internalStatus"), db.ref("friendlyName").withSchema(TableName.InternalCertificateAuthority).as("internalFriendlyName"), db.ref("organization").withSchema(TableName.InternalCertificateAuthority).as("internalOrganization"), db.ref("ou").withSchema(TableName.InternalCertificateAuthority).as("internalOu"), @@ -181,17 +254,11 @@ export const certificateAuthorityDALFactory = (db: TDbClient) => { db.ref("keyAlgorithm").withSchema(TableName.InternalCertificateAuthority).as("internalKeyAlgorithm"), db.ref("notBefore").withSchema(TableName.InternalCertificateAuthority).as("internalNotBefore"), db.ref("notAfter").withSchema(TableName.InternalCertificateAuthority).as("internalNotAfter"), - db.ref("activeCaCertId").withSchema(TableName.InternalCertificateAuthority).as("internalActiveCaCertId"), - db - .ref("certificateAuthorityId") - .withSchema(TableName.InternalCertificateAuthority) - .as("internalCertificateAuthorityId") + db.ref("activeCaCertId").withSchema(TableName.InternalCertificateAuthority).as("internalActiveCaCertId") ) .select( db.ref("id").withSchema(TableName.ExternalCertificateAuthority).as("externalCaId"), - db.ref("name").withSchema(TableName.ExternalCertificateAuthority).as("externalName"), db.ref("type").withSchema(TableName.ExternalCertificateAuthority).as("externalType"), - db.ref("status").withSchema(TableName.ExternalCertificateAuthority).as("externalStatus"), db.ref("configuration").withSchema(TableName.ExternalCertificateAuthority).as("externalConfiguration"), db .ref("dnsAppConnectionId") @@ -220,7 +287,6 @@ export const certificateAuthorityDALFactory = (db: TDbClient) => { id: ca.internalCaId, parentCaId: ca.internalParentCaId, type: ca.internalType, - status: ca.internalStatus, friendlyName: ca.internalFriendlyName, organization: ca.internalOrganization, ou: ca.internalOu, @@ -234,16 +300,13 @@ export const certificateAuthorityDALFactory = (db: TDbClient) => { keyAlgorithm: ca.internalKeyAlgorithm, notBefore: ca.internalNotBefore?.toISOString(), notAfter: ca.internalNotAfter?.toISOString(), - activeCaCertId: ca.internalActiveCaCertId, - certificateAuthorityId: ca.internalCertificateAuthorityId + activeCaCertId: ca.internalActiveCaCertId } : undefined, externalCa: ca ? { id: ca.externalCaId, - name: ca.externalName, type: ca.externalType, - status: ca.externalStatus, configuration: ca.externalConfiguration, dnsAppConnectionId: ca.externalDnsAppConnectionId, appConnectionId: ca.externalAppConnectionId, @@ -260,6 +323,7 @@ export const certificateAuthorityDALFactory = (db: TDbClient) => { ...caOrm, findWithAssociatedCa, buildCertificateChain, - findByIdWithAssociatedCa + findByIdWithAssociatedCa, + findByNameAndProjectIdWithAssociatedCa }; }; diff --git a/backend/src/services/certificate-authority/certificate-authority-fns.ts b/backend/src/services/certificate-authority/certificate-authority-fns.ts index ac188bc4e..02be76565 100644 --- a/backend/src/services/certificate-authority/certificate-authority-fns.ts +++ b/backend/src/services/certificate-authority/certificate-authority-fns.ts @@ -329,6 +329,6 @@ export const expandInternalCa = ( return { ...ca.internalCa, ...ca, - requireTemplateForIssuance: ca.disableDirectIssuance + requireTemplateForIssuance: !ca.enableDirectIssuance } as const; }; diff --git a/backend/src/services/certificate-authority/certificate-authority-schemas.ts b/backend/src/services/certificate-authority/certificate-authority-schemas.ts index 1c7832b70..61d620156 100644 --- a/backend/src/services/certificate-authority/certificate-authority-schemas.ts +++ b/backend/src/services/certificate-authority/certificate-authority-schemas.ts @@ -8,10 +8,10 @@ import { CaStatus, CaType } from "./certificate-authority-enums"; export const BaseCertificateAuthoritySchema = CertificateAuthoritiesSchema.pick({ projectId: true, - disableDirectIssuance: true, + enableDirectIssuance: true, + name: true, id: true }).extend({ - name: z.string(), status: z.nativeEnum(CaStatus) }); @@ -19,13 +19,14 @@ export const GenericCreateCertificateAuthorityFieldsSchema = (type: CaType) => z.object({ name: slugSchema({ field: "name" }).describe(CertificateAuthorities.CREATE(type).name), projectId: z.string().trim().min(1, "Project ID required").describe(CertificateAuthorities.CREATE(type).projectId), - disableDirectIssuance: z.boolean().describe(CertificateAuthorities.CREATE(type).disableDirectIssuance), + enableDirectIssuance: z.boolean().describe(CertificateAuthorities.CREATE(type).enableDirectIssuance), status: z.nativeEnum(CaStatus).describe(CertificateAuthorities.CREATE(type).status) }); export const GenericUpdateCertificateAuthorityFieldsSchema = (type: CaType) => z.object({ name: slugSchema({ field: "name" }).optional().describe(CertificateAuthorities.UPDATE(type).name), - disableDirectIssuance: z.boolean().optional().describe(CertificateAuthorities.UPDATE(type).disableDirectIssuance), + projectId: z.string().trim().min(1, "Project ID required").describe(CertificateAuthorities.UPDATE(type).projectId), + enableDirectIssuance: z.boolean().optional().describe(CertificateAuthorities.UPDATE(type).enableDirectIssuance), status: z.nativeEnum(CaStatus).optional().describe(CertificateAuthorities.UPDATE(type).status) }); diff --git a/backend/src/services/certificate-authority/certificate-authority-service.ts b/backend/src/services/certificate-authority/certificate-authority-service.ts index 7979cf684..d94abf165 100644 --- a/backend/src/services/certificate-authority/certificate-authority-service.ts +++ b/backend/src/services/certificate-authority/certificate-authority-service.ts @@ -46,6 +46,7 @@ type TCertificateAuthorityServiceFactoryDep = { | "findOne" | "findByIdWithAssociatedCa" | "findWithAssociatedCa" + | "findByNameAndProjectIdWithAssociatedCa" >; externalCertificateAuthorityDAL: Pick; internalCertificateAuthorityService: TInternalCertificateAuthorityServiceFactory; @@ -94,7 +95,7 @@ export const certificateAuthorityServiceFactory = ({ }); const createCertificateAuthority = async ( - { type, projectId, name, disableDirectIssuance, configuration, status }: TCreateCertificateAuthorityDTO, + { type, projectId, name, enableDirectIssuance, configuration, status }: TCreateCertificateAuthorityDTO, actor: OrgServiceActor ) => { let finalProjectId: string = projectId; @@ -126,7 +127,7 @@ export const certificateAuthorityServiceFactory = ({ ...(configuration as TCreateInternalCertificateAuthorityDTO["configuration"]), isInternal: true, projectId: finalProjectId, - requireTemplateForIssuance: disableDirectIssuance + requireTemplateForIssuance: !enableDirectIssuance }); if (!ca.internalCa) { @@ -138,8 +139,8 @@ export const certificateAuthorityServiceFactory = ({ return { id: ca.id, type, - disableDirectIssuance: ca.disableDirectIssuance, - name: ca.internalCa?.friendlyName, + enableDirectIssuance: ca.enableDirectIssuance, + name: ca.name, projectId: finalProjectId, status, configuration: ca.internalCa @@ -151,7 +152,7 @@ export const certificateAuthorityServiceFactory = ({ name, projectId: finalProjectId, configuration: configuration as TCreateAcmeCertificateAuthorityDTO["configuration"], - disableDirectIssuance, + enableDirectIssuance, status, actor }); @@ -160,15 +161,18 @@ export const certificateAuthorityServiceFactory = ({ throw new BadRequestError({ message: "Invalid certificate authority type" }); }; - const findCertificateAuthorityById = async ( - { certificateAuthorityId, type }: { certificateAuthorityId: string; type: CaType }, + const findCertificateAuthorityByNameAndProjectId = async ( + { caName, type, projectId }: { caName: string; type: CaType; projectId: string }, actor: OrgServiceActor ) => { - const certificateAuthority = await certificateAuthorityDAL.findByIdWithAssociatedCa(certificateAuthorityId); + const certificateAuthority = await certificateAuthorityDAL.findByNameAndProjectIdWithAssociatedCa( + caName, + projectId + ); if (!certificateAuthority) throw new NotFoundError({ - message: `Could not find certificate authority with ID "${certificateAuthorityId}"` + message: `Could not find certificate authority with name "${caName}" in project "${projectId}"` }); const { permission } = await permissionService.getProjectPermission({ @@ -188,24 +192,24 @@ export const certificateAuthorityServiceFactory = ({ if (type === CaType.INTERNAL) { if (!certificateAuthority.internalCa?.id) { throw new NotFoundError({ - message: `Internal certificate authority with ID "${certificateAuthorityId}" not found` + message: `Internal certificate authority with name "${caName}" in project "${projectId}" not found` }); } return { id: certificateAuthority.id, type, - disableDirectIssuance: certificateAuthority.disableDirectIssuance, - name: certificateAuthority.internalCa.friendlyName, + enableDirectIssuance: certificateAuthority.enableDirectIssuance, + name: certificateAuthority.name, projectId: certificateAuthority.projectId, configuration: certificateAuthority.internalCa, - status: certificateAuthority.internalCa.status + status: certificateAuthority.status } as TCertificateAuthority; } if (certificateAuthority.externalCa?.type !== type) { throw new NotFoundError({ - message: `Could not find external certificate authority with ID "${certificateAuthorityId}" and type "${type}"` + message: `Could not find external certificate authority with name "${caName}" in project "${projectId}" and type "${type}"` }); } @@ -255,11 +259,11 @@ export const certificateAuthorityServiceFactory = ({ .map((ca) => ({ id: ca.id, type, - disableDirectIssuance: ca.disableDirectIssuance, - name: ca.internalCa.friendlyName, + enableDirectIssuance: ca.enableDirectIssuance, + name: ca.name, projectId: ca.projectId, configuration: ca.internalCa, - status: ca.internalCa.status + status: ca.status })) as TCertificateAuthority[]; } @@ -271,14 +275,17 @@ export const certificateAuthorityServiceFactory = ({ }; const updateCertificateAuthority = async ( - { id, type, configuration, disableDirectIssuance, status, name }: TUpdateCertificateAuthorityDTO, + { caName, type, configuration, enableDirectIssuance, status, name, projectId }: TUpdateCertificateAuthorityDTO, actor: OrgServiceActor ) => { - const certificateAuthority = await certificateAuthorityDAL.findByIdWithAssociatedCa(id); + const certificateAuthority = await certificateAuthorityDAL.findByNameAndProjectIdWithAssociatedCa( + caName, + projectId + ); if (!certificateAuthority) throw new NotFoundError({ - message: `Could not find certificate authority with ID "${id}"` + message: `Could not find certificate authority with name "${caName}" in project "${projectId}"` }); const { permission } = await permissionService.getProjectPermission({ @@ -298,15 +305,16 @@ export const certificateAuthorityServiceFactory = ({ if (type === CaType.INTERNAL) { if (!certificateAuthority.internalCa?.id) { throw new NotFoundError({ - message: `Internal certificate authority with ID "${id}" not found` + message: `Internal certificate authority with name "${caName}" in project "${projectId}" not found` }); } const updatedCa = await internalCertificateAuthorityService.updateCaById({ ...configuration, isInternal: true, - requireTemplateForIssuance: disableDirectIssuance, - caId: id + requireTemplateForIssuance: !enableDirectIssuance, + caId: certificateAuthority.id, + name }); if (!updatedCa.internalCa) { @@ -318,19 +326,19 @@ export const certificateAuthorityServiceFactory = ({ return { id: updatedCa.id, type, - disableDirectIssuance: updatedCa.disableDirectIssuance, - name: updatedCa.internalCa?.friendlyName, + enableDirectIssuance: updatedCa.enableDirectIssuance, + name: updatedCa.name, projectId: updatedCa.projectId, configuration: updatedCa.internalCa, - status: updatedCa.internalCa?.status + status: updatedCa.status } as TCertificateAuthority; } if (type === CaType.ACME) { return acmeFns.updateCertificateAuthority({ - id, + id: certificateAuthority.id, configuration: configuration as TUpdateAcmeCertificateAuthorityDTO["configuration"], - disableDirectIssuance, + enableDirectIssuance, actor, status, name @@ -340,12 +348,18 @@ export const certificateAuthorityServiceFactory = ({ throw new BadRequestError({ message: "Invalid certificate authority type" }); }; - const deleteCertificateAuthority = async ({ id, type }: { id: string; type: CaType }, actor: OrgServiceActor) => { - const certificateAuthority = await certificateAuthorityDAL.findByIdWithAssociatedCa(id); + const deleteCertificateAuthority = async ( + { caName, type, projectId }: { caName: string; type: CaType; projectId: string }, + actor: OrgServiceActor + ) => { + const certificateAuthority = await certificateAuthorityDAL.findByNameAndProjectIdWithAssociatedCa( + caName, + projectId + ); if (!certificateAuthority) throw new NotFoundError({ - message: `Could not find certificate authority with ID "${id}"` + message: `Could not find certificate authority with name "${caName}" in project "${projectId}"` }); const { permission } = await permissionService.getProjectPermission({ @@ -374,17 +388,17 @@ export const certificateAuthorityServiceFactory = ({ }); } - await certificateAuthorityDAL.deleteById(id); + await certificateAuthorityDAL.deleteById(certificateAuthority.id); if (type === CaType.INTERNAL) { return { id: certificateAuthority.id, type, - disableDirectIssuance: certificateAuthority.disableDirectIssuance, - name: certificateAuthority.internalCa?.friendlyName, + enableDirectIssuance: certificateAuthority.enableDirectIssuance, + name: certificateAuthority.name, projectId: certificateAuthority.projectId, configuration: certificateAuthority.internalCa, - status: certificateAuthority.internalCa?.status + status: certificateAuthority.status } as TCertificateAuthority; } @@ -397,7 +411,7 @@ export const certificateAuthorityServiceFactory = ({ return { createCertificateAuthority, - findCertificateAuthorityById, + findCertificateAuthorityByNameAndProjectId, listCertificateAuthoritiesByProjectId, updateCertificateAuthority, deleteCertificateAuthority diff --git a/backend/src/services/certificate-authority/certificate-authority-types.ts b/backend/src/services/certificate-authority/certificate-authority-types.ts index 5f1949887..d76330bd8 100644 --- a/backend/src/services/certificate-authority/certificate-authority-types.ts +++ b/backend/src/services/certificate-authority/certificate-authority-types.ts @@ -13,5 +13,6 @@ export type TCreateCertificateAuthorityDTO = Omit; export type TUpdateCertificateAuthorityDTO = Partial> & { type: CaType; - id: string; + caName: string; + projectId: string; }; diff --git a/backend/src/services/certificate-authority/internal/internal-certificate-authority-service.ts b/backend/src/services/certificate-authority/internal/internal-certificate-authority-service.ts index b967d48ad..7a0ccfeed 100644 --- a/backend/src/services/certificate-authority/internal/internal-certificate-authority-service.ts +++ b/backend/src/services/certificate-authority/internal/internal-certificate-authority-service.ts @@ -1,6 +1,7 @@ /* eslint-disable no-bitwise */ import { ForbiddenError } from "@casl/ability"; import * as x509 from "@peculiar/x509"; +import slugify from "@sindresorhus/slugify"; import crypto, { KeyObject } from "crypto"; import { z } from "zod"; @@ -21,6 +22,7 @@ import { extractX509CertFromChain } from "@app/lib/certificates/extract-certific import { getConfig } from "@app/lib/config/env"; import { BadRequestError, NotFoundError } from "@app/lib/errors"; import { ms } from "@app/lib/ms"; +import { alphaNumericNanoId } from "@app/lib/nanoid"; import { isFQDN } from "@app/lib/validator/validate-url"; import { TCertificateBodyDALFactory } from "@app/services/certificate/certificate-body-dal"; import { TCertificateDALFactory } from "@app/services/certificate/certificate-dal"; @@ -200,14 +202,16 @@ export const internalCertificateAuthorityServiceFactory = ({ const ca = await certificateAuthorityDAL.create( { projectId, - disableDirectIssuance: requireTemplateForIssuance + enableDirectIssuance: !requireTemplateForIssuance, + name: slugify(`${friendlyName || dn}-${alphaNumericNanoId(8)}`), + status: type === InternalCaType.ROOT ? CaStatus.ACTIVE : CaStatus.PENDING_CERTIFICATE }, tx ); const internalCa = await internalCertificateAuthorityDAL.create( { - certificateAuthorityId: ca.id, + caId: ca.id, type, organization, ou, @@ -216,7 +220,6 @@ export const internalCertificateAuthorityServiceFactory = ({ locality, friendlyName: friendlyName || dn, commonName, - status: type === InternalCaType.ROOT ? CaStatus.ACTIVE : CaStatus.PENDING_CERTIFICATE, dn, keyAlgorithm, ...(type === InternalCaType.ROOT && { @@ -357,7 +360,7 @@ export const internalCertificateAuthorityServiceFactory = ({ * Update CA with id [caId]. * Note: Used to enable/disable CA */ - const updateCaById = async ({ caId, status, requireTemplateForIssuance, ...dto }: TUpdateCaDTO) => { + const updateCaById = async ({ caId, status, requireTemplateForIssuance, name, ...dto }: TUpdateCaDTO) => { const ca = await certificateAuthorityDAL.findByIdWithAssociatedCa(caId); if (!ca.internalCa) throw new NotFoundError({ message: `CA with ID '${caId}' not found` }); @@ -378,20 +381,14 @@ export const internalCertificateAuthorityServiceFactory = ({ } const updatedCa = await certificateAuthorityDAL.transaction(async (tx) => { - if (status !== undefined) { - await internalCertificateAuthorityDAL.update( - { - certificateAuthorityId: ca.id - }, - { status }, + if (requireTemplateForIssuance !== undefined || status !== undefined || name !== undefined) { + await certificateAuthorityDAL.updateById( + ca.id, + { enableDirectIssuance: !requireTemplateForIssuance, status, name }, tx ); } - if (requireTemplateForIssuance !== undefined) { - await certificateAuthorityDAL.updateById(ca.id, { disableDirectIssuance: requireTemplateForIssuance }, tx); - } - return certificateAuthorityDAL.findByIdWithAssociatedCa(caId, tx); }); @@ -509,7 +506,7 @@ export const internalCertificateAuthorityServiceFactory = ({ ProjectPermissionSub.CertificateAuthorities ); - if (ca.internalCa.status === CaStatus.DISABLED) throw new BadRequestError({ message: "CA is disabled" }); + if (ca.status === CaStatus.DISABLED) throw new BadRequestError({ message: "CA is disabled" }); // get latest CA certificate const caCert = await certificateAuthorityCertDAL.findById(ca.internalCa.activeCaCertId); @@ -604,7 +601,7 @@ export const internalCertificateAuthorityServiceFactory = ({ await internalCertificateAuthorityDAL.update( { - certificateAuthorityId: ca.id + caId: ca.id }, { activeCaCertId: newCaCert.id, @@ -746,7 +743,7 @@ export const internalCertificateAuthorityServiceFactory = ({ await internalCertificateAuthorityDAL.update( { - certificateAuthorityId: ca.id + caId: ca.id }, { activeCaCertId: newCaCert.id, @@ -914,7 +911,7 @@ export const internalCertificateAuthorityServiceFactory = ({ ProjectPermissionSub.CertificateAuthorities ); - if (ca.internalCa.status === CaStatus.DISABLED) throw new BadRequestError({ message: "CA is disabled" }); + if (ca.status === CaStatus.DISABLED) throw new BadRequestError({ message: "CA is disabled" }); if (!ca.internalCa.activeCaCertId) throw new BadRequestError({ message: "CA does not have a certificate installed" }); @@ -1150,12 +1147,15 @@ export const internalCertificateAuthorityServiceFactory = ({ tx ); + await certificateAuthorityDAL.updateById(ca.id, { + status: CaStatus.ACTIVE + }); + await internalCertificateAuthorityDAL.update( { - certificateAuthorityId: ca.id + caId: ca.id }, { - status: CaStatus.ACTIVE, maxPathLength: maxPathLength === undefined ? -1 : maxPathLength, notBefore: new Date(certObj.notBefore), notAfter: new Date(certObj.notAfter), @@ -1231,10 +1231,10 @@ export const internalCertificateAuthorityServiceFactory = ({ ProjectPermissionSub.Certificates ); - if (ca.internalCa.status !== CaStatus.ACTIVE) throw new BadRequestError({ message: "CA is not active" }); + if (ca.status !== CaStatus.ACTIVE) throw new BadRequestError({ message: "CA is not active" }); if (!ca.internalCa.activeCaCertId) throw new BadRequestError({ message: "CA does not have a certificate installed" }); - if (ca.disableDirectIssuance && !certificateTemplate) { + if (!ca.enableDirectIssuance && !certificateTemplate) { throw new BadRequestError({ message: "Certificate template or subscriber is required for issuance" }); } @@ -1589,10 +1589,10 @@ export const internalCertificateAuthorityServiceFactory = ({ ); } - if (ca.internalCa.status !== CaStatus.ACTIVE) throw new BadRequestError({ message: "CA is not active" }); + if (ca.status !== CaStatus.ACTIVE) throw new BadRequestError({ message: "CA is not active" }); if (!ca.internalCa.activeCaCertId) throw new BadRequestError({ message: "CA does not have a certificate installed" }); - if (ca.disableDirectIssuance && !certificateTemplate) { + if (!ca.enableDirectIssuance && !certificateTemplate) { throw new BadRequestError({ message: "Certificate template or subscriber is required for issuance" }); } diff --git a/backend/src/services/certificate-authority/internal/internal-certificate-authority-types.ts b/backend/src/services/certificate-authority/internal/internal-certificate-authority-types.ts index 206db0cd6..54daa78d7 100644 --- a/backend/src/services/certificate-authority/internal/internal-certificate-authority-types.ts +++ b/backend/src/services/certificate-authority/internal/internal-certificate-authority-types.ts @@ -69,12 +69,14 @@ export type TUpdateCaDTO = | { isInternal: true; caId: string; + name?: string; status?: CaStatus; requireTemplateForIssuance?: boolean; } | ({ isInternal: false; caId: string; + name?: string; status?: CaStatus; requireTemplateForIssuance?: boolean; } & Omit); diff --git a/backend/src/services/certificate-template/certificate-template-dal.ts b/backend/src/services/certificate-template/certificate-template-dal.ts index 5429b2b4a..092215c45 100644 --- a/backend/src/services/certificate-template/certificate-template-dal.ts +++ b/backend/src/services/certificate-template/certificate-template-dal.ts @@ -21,7 +21,7 @@ export const certificateTemplateDALFactory = (db: TDbClient) => { ) .join( TableName.InternalCertificateAuthority, - `${TableName.InternalCertificateAuthority}.certificateAuthorityId`, + `${TableName.InternalCertificateAuthority}.caId`, `${TableName.CertificateAuthority}.id` ) .where(`${TableName.CertificateAuthority}.projectId`, "=", projectId) @@ -48,7 +48,7 @@ export const certificateTemplateDALFactory = (db: TDbClient) => { .join(TableName.Project, `${TableName.Project}.id`, `${TableName.CertificateAuthority}.projectId`) .join( TableName.InternalCertificateAuthority, - `${TableName.InternalCertificateAuthority}.certificateAuthorityId`, + `${TableName.InternalCertificateAuthority}.caId`, `${TableName.CertificateAuthority}.id` ) .where(`${TableName.CertificateTemplate}.id`, "=", id) diff --git a/backend/src/services/pki-alert/pki-alert-dal.ts b/backend/src/services/pki-alert/pki-alert-dal.ts index 2f560b17f..2183f6a41 100644 --- a/backend/src/services/pki-alert/pki-alert-dal.ts +++ b/backend/src/services/pki-alert/pki-alert-dal.ts @@ -37,7 +37,7 @@ export const pkiAlertDALFactory = (db: TDbClient) => { "pci.pkiCollectionId" ) .from(`${TableName.CertificateAuthority} as ${PkiItemType.CA}`) - .join(`${TableName.InternalCertificateAuthority} as ic`, `${PkiItemType.CA}.id`, "ic.certificateAuthorityId") + .join(`${TableName.InternalCertificateAuthority} as ic`, `${PkiItemType.CA}.id`, "ic.caId") .join(`${TableName.PkiCollectionItem} as pci`, `${PkiItemType.CA}.id`, "pci.caId") .unionAll((qb) => { void qb diff --git a/backend/src/services/pki-collection/pki-collection-item-dal.ts b/backend/src/services/pki-collection/pki-collection-item-dal.ts index fadd08d2f..d2b056e6d 100644 --- a/backend/src/services/pki-collection/pki-collection-item-dal.ts +++ b/backend/src/services/pki-collection/pki-collection-item-dal.ts @@ -44,7 +44,7 @@ export const pkiCollectionItemDALFactory = (db: TDbClient) => { .leftJoin( TableName.InternalCertificateAuthority, `${TableName.PkiCollectionItem}.caId`, - `${TableName.InternalCertificateAuthority}.certificateAuthorityId` + `${TableName.InternalCertificateAuthority}.caId` ) .leftJoin(TableName.Certificate, `${TableName.PkiCollectionItem}.certId`, `${TableName.Certificate}.id`) .where((builder) => { diff --git a/docs/api-reference/endpoints/certificate-authorities/acme/delete.mdx b/docs/api-reference/endpoints/certificate-authorities/acme/delete.mdx index f06cfe6c9..9decc3b6e 100644 --- a/docs/api-reference/endpoints/certificate-authorities/acme/delete.mdx +++ b/docs/api-reference/endpoints/certificate-authorities/acme/delete.mdx @@ -1,4 +1,4 @@ --- title: "Delete" -openapi: "DELETE /api/v1/pki/ca/acme/{certificateAuthorityId}" +openapi: "DELETE /api/v1/pki/ca/acme/{caName}" --- diff --git a/docs/api-reference/endpoints/certificate-authorities/acme/read.mdx b/docs/api-reference/endpoints/certificate-authorities/acme/read.mdx index c01780805..a80e31f9a 100644 --- a/docs/api-reference/endpoints/certificate-authorities/acme/read.mdx +++ b/docs/api-reference/endpoints/certificate-authorities/acme/read.mdx @@ -1,4 +1,4 @@ --- title: "Read" -openapi: "GET /api/v1/pki/ca/acme/{certificateAuthorityId}" +openapi: "GET /api/v1/pki/ca/acme/{caName}" --- diff --git a/docs/api-reference/endpoints/certificate-authorities/acme/update.mdx b/docs/api-reference/endpoints/certificate-authorities/acme/update.mdx index 45dac8067..69f758771 100644 --- a/docs/api-reference/endpoints/certificate-authorities/acme/update.mdx +++ b/docs/api-reference/endpoints/certificate-authorities/acme/update.mdx @@ -1,4 +1,4 @@ --- title: "Update" -openapi: "PATCH /api/v1/pki/ca/acme/{certificateAuthorityId}" +openapi: "PATCH /api/v1/pki/ca/acme/{caName}" --- diff --git a/docs/api-reference/endpoints/pki/subscribers/get-active-cert-bundle.mdx b/docs/api-reference/endpoints/pki/subscribers/get-active-cert-bundle.mdx deleted file mode 100644 index eae668463..000000000 --- a/docs/api-reference/endpoints/pki/subscribers/get-active-cert-bundle.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: "Retrieve active certificate bundle" -openapi: "GET /api/v1/pki/subscribers/{subscriberName}/active-certificate/bundle" ---- diff --git a/docs/api-reference/endpoints/pki/subscribers/get-latest-cert-bundle.mdx b/docs/api-reference/endpoints/pki/subscribers/get-latest-cert-bundle.mdx new file mode 100644 index 000000000..894c8ed4e --- /dev/null +++ b/docs/api-reference/endpoints/pki/subscribers/get-latest-cert-bundle.mdx @@ -0,0 +1,4 @@ +--- +title: "Retrieve latest certificate bundle" +openapi: "GET /api/v1/pki/subscribers/{subscriberName}/latest-certificate-bundle" +--- diff --git a/docs/mint.json b/docs/mint.json index c8d98f1c0..2f10b2616 100644 --- a/docs/mint.json +++ b/docs/mint.json @@ -1522,7 +1522,7 @@ "api-reference/endpoints/pki/subscribers/issue-cert", "api-reference/endpoints/pki/subscribers/sign-cert", "api-reference/endpoints/pki/subscribers/order-cert", - "api-reference/endpoints/pki/subscribers/get-active-cert-bundle" + "api-reference/endpoints/pki/subscribers/get-latest-cert-bundle" ] }, { diff --git a/frontend/src/hooks/api/ca/index.tsx b/frontend/src/hooks/api/ca/index.tsx index bf3a21265..ca96c676e 100644 --- a/frontend/src/hooks/api/ca/index.tsx +++ b/frontend/src/hooks/api/ca/index.tsx @@ -12,8 +12,8 @@ export { useUpdateUnifiedCa } from "./mutations"; export { + useGetCa, useGetCaById, - useGetCaByTypeAndId, useGetCaCert, useGetCaCerts, useGetCaCertTemplates, diff --git a/frontend/src/hooks/api/ca/mutations.tsx b/frontend/src/hooks/api/ca/mutations.tsx index 70fe1f4cd..165fbe121 100644 --- a/frontend/src/hooks/api/ca/mutations.tsx +++ b/frontend/src/hooks/api/ca/mutations.tsx @@ -26,15 +26,13 @@ import { export const useUpdateUnifiedCa = () => { const queryClient = useQueryClient(); return useMutation({ - mutationFn: async ({ id, ...body }) => { - const { - data: { certificateAuthority } - } = await apiRequest.patch<{ certificateAuthority: TUnifiedCertificateAuthority }>( - `/api/v1/pki/ca/${body.type}/${id}`, + mutationFn: async ({ caName, ...body }) => { + const { data } = await apiRequest.patch( + `/api/v1/pki/ca/${body.type}/${caName}`, body ); - return certificateAuthority; + return data; }, onSuccess: ({ projectId, type }) => { queryClient.invalidateQueries({ @@ -65,11 +63,16 @@ export const useCreateUnifiedCa = () => { export const useDeleteUnifiedCa = () => { const queryClient = useQueryClient(); return useMutation({ - mutationFn: async ({ caId, type }) => { + mutationFn: async ({ caName, type, projectId }) => { const { data: { certificateAuthority } } = await apiRequest.delete<{ certificateAuthority: TUnifiedCertificateAuthority }>( - `/api/v1/pki/ca/${type}/${caId}` + `/api/v1/pki/ca/${type}/${caName}`, + { + data: { + projectId + } + } ); return certificateAuthority; }, diff --git a/frontend/src/hooks/api/ca/queries.tsx b/frontend/src/hooks/api/ca/queries.tsx index 82c311fa4..4f10c6e84 100644 --- a/frontend/src/hooks/api/ca/queries.tsx +++ b/frontend/src/hooks/api/ca/queries.tsx @@ -8,7 +8,7 @@ import { TCertificateAuthority, TUnifiedCertificateAuthority } from "./types"; export const caKeys = { getCaById: (caId: string) => [{ caId }, "ca"], - getCaByTypeAndId: (type: CaType, caId: string) => [{ type, caId }, "ca"], + getCaByNameAndProjectId: (caName: string, projectId: string) => [{ caName, projectId }, "ca"], listCasByTypeAndProjectId: (type: CaType, projectId: string) => [{ type, projectId }, "cas"], listCasByProjectId: (projectId: string) => [{ projectId }, "cas"], getCaCerts: (caId: string) => [{ caId }, "ca-cert"], @@ -20,18 +20,24 @@ export const caKeys = { getCaEstConfig: (caId: string) => [{ caId }, "ca-est-config"] }; -export const useGetCaByTypeAndId = (type: CaType, caId: string) => { +export const useGetCa = ({ + caName, + projectId, + type +}: { + caName: string; + projectId: string; + type: CaType; +}) => { return useQuery({ - queryKey: caKeys.getCaByTypeAndId(type, caId), + queryKey: caKeys.getCaByNameAndProjectId(caName, projectId), queryFn: async () => { - const { - data: { certificateAuthority } - } = await apiRequest.get<{ certificateAuthority: TUnifiedCertificateAuthority }>( - `/api/v1/pki/ca/${type}/${caId}` + const { data } = await apiRequest.get( + `/api/v1/pki/ca/${type}/${caName}?projectId=${projectId}` ); - return certificateAuthority; + return data; }, - enabled: Boolean(caId) + enabled: Boolean(caName && projectId && type) }); }; @@ -39,11 +45,11 @@ export const useListCasByTypeAndProjectId = (type: CaType, projectId: string) => return useQuery({ queryKey: caKeys.listCasByTypeAndProjectId(type, projectId), queryFn: async () => { - const { data } = await apiRequest.get<{ - certificateAuthorities: TUnifiedCertificateAuthority[]; - }>(`/api/v1/pki/ca/${type}?projectId=${projectId}`); + const { data } = await apiRequest.get( + `/api/v1/pki/ca/${type}?projectId=${projectId}` + ); - return data.certificateAuthorities; + return data; } }); }; diff --git a/frontend/src/hooks/api/ca/types.ts b/frontend/src/hooks/api/ca/types.ts index 34eade1f4..171143c12 100644 --- a/frontend/src/hooks/api/ca/types.ts +++ b/frontend/src/hooks/api/ca/types.ts @@ -7,7 +7,7 @@ export type TAcmeCertificateAuthority = { type: CaType.ACME; status: CaStatus; name: string; - disableDirectIssuance: boolean; + enableDirectIssuance: boolean; configuration: { dnsAppConnectionId: string; dnsProviderConfig: { @@ -25,7 +25,7 @@ export type TInternalCertificateAuthority = { type: CaType.INTERNAL; status: CaStatus; name: string; - disableDirectIssuance: boolean; + enableDirectIssuance: boolean; configuration: { type: InternalCaType; friendlyName?: string; @@ -52,12 +52,13 @@ export type TUnifiedCertificateAuthority = export type TCreateUnifiedCertificateAuthorityDTO = Omit; export type TUpdateUnifiedCertificateAuthorityDTO = Partial & { - id: string; + caName: string; + projectId: string; type: CaType; }; export type TDeleteUnifiedCertificateAuthorityDTO = { - caId: string; + caName: string; type: CaType; projectId: string; }; diff --git a/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/ExternalCaModal.tsx b/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/ExternalCaModal.tsx index 8bb9a872c..d0ce4eada 100644 --- a/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/ExternalCaModal.tsx +++ b/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/ExternalCaModal.tsx @@ -23,7 +23,7 @@ import { CaStatus, CaType, useCreateUnifiedCa, - useGetCaByTypeAndId, + useGetCa, useUpdateUnifiedCa } from "@app/hooks/api/ca"; import { UsePopUpState } from "@app/hooks/usePopUp"; @@ -35,7 +35,7 @@ const schema = z name: slugSchema({ field: "Name" }), - disableDirectIssuance: z.boolean(), + enableDirectIssuance: z.boolean(), status: z.nativeEnum(CaStatus), configuration: z.object({ dnsAppConnection: z.object({ @@ -65,10 +65,11 @@ const caTypes = [{ label: "ACME", value: CaType.ACME }]; export const ExternalCaModal = ({ popUp, handlePopUpToggle }: Props) => { const { currentWorkspace } = useWorkspace(); - const { data: ca } = useGetCaByTypeAndId( - (popUp?.ca?.data as { type: CaType })?.type || "", - (popUp?.ca?.data as { caId: string })?.caId || "" - ); + const { data: ca } = useGetCa({ + caName: (popUp?.ca?.data as { name: string })?.name || "", + projectId: currentWorkspace?.id || "", + type: (popUp?.ca?.data as { type: CaType })?.type || "" + }); const { mutateAsync: createMutateAsync } = useCreateUnifiedCa(); const { mutateAsync: updateMutateAsync } = useUpdateUnifiedCa(); @@ -85,7 +86,7 @@ export const ExternalCaModal = ({ popUp, handlePopUpToggle }: Props) => { type: CaType.ACME, name: "", status: CaStatus.ACTIVE, - disableDirectIssuance: false, + enableDirectIssuance: true, configuration: { dnsAppConnection: { id: "", @@ -122,7 +123,7 @@ export const ExternalCaModal = ({ popUp, handlePopUpToggle }: Props) => { type: ca.type, name: ca.name, status: ca.status, - disableDirectIssuance: ca.disableDirectIssuance, + enableDirectIssuance: ca.enableDirectIssuance, configuration: { dnsAppConnection: { id: ca.configuration.dnsAppConnectionId, @@ -142,7 +143,7 @@ export const ExternalCaModal = ({ popUp, handlePopUpToggle }: Props) => { type: CaType.ACME, name: "", status: CaStatus.ACTIVE, - disableDirectIssuance: false, + enableDirectIssuance: true, configuration: { dnsAppConnection: { id: "", @@ -162,7 +163,7 @@ export const ExternalCaModal = ({ popUp, handlePopUpToggle }: Props) => { const onFormSubmit = async ({ type, name, - disableDirectIssuance, + enableDirectIssuance, status, configuration }: FormData) => { @@ -171,12 +172,12 @@ export const ExternalCaModal = ({ popUp, handlePopUpToggle }: Props) => { if (ca && type !== CaType.INTERNAL) { await updateMutateAsync({ - id: ca.id, + caName: ca.name, projectId: currentWorkspace.id, name, type, status, - disableDirectIssuance, + enableDirectIssuance, configuration: { ...configuration, dnsAppConnectionId: configuration.dnsAppConnection.id @@ -188,7 +189,7 @@ export const ExternalCaModal = ({ popUp, handlePopUpToggle }: Props) => { name, type, status, - disableDirectIssuance, + enableDirectIssuance, configuration: { ...configuration, dnsAppConnectionId: configuration.dnsAppConnection.id @@ -369,7 +370,7 @@ export const ExternalCaModal = ({ popUp, handlePopUpToggle }: Props) => { )} { return ( @@ -378,7 +379,7 @@ export const ExternalCaModal = ({ popUp, handlePopUpToggle }: Props) => { onCheckedChange={(value) => field.onChange(value)} isChecked={field.value} > -

Disable Direct Issuance

+

Enable Direct Issuance

); diff --git a/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/ExternalCaSection.tsx b/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/ExternalCaSection.tsx index d2f5248a6..597e860d7 100644 --- a/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/ExternalCaSection.tsx +++ b/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/ExternalCaSection.tsx @@ -24,11 +24,11 @@ export const ExternalCaSection = () => { "upgradePlan" ] as const); - const onRemoveCaSubmit = async (caId: string, type: CaType) => { + const onRemoveCaSubmit = async (caName: string, type: CaType) => { try { if (!currentWorkspace?.id) return; - await deleteCa({ caId, type, projectId: currentWorkspace.id }); + await deleteCa({ caName, type, projectId: currentWorkspace.id }); createNotification({ text: "Successfully deleted CA", @@ -45,18 +45,18 @@ export const ExternalCaSection = () => { }; const onUpdateCaStatus = async ({ - caId, + name, type, status }: { - caId: string; + name: string; type: CaType; status: CaStatus; }) => { try { if (!currentWorkspace?.slug) return; - await updateCa({ id: caId, type, status }); + await updateCa({ caName: name, type, status, projectId: currentWorkspace.id }); createNotification({ text: `Successfully ${status === CaStatus.ACTIVE ? "enabled" : "disabled"} CA`, @@ -105,7 +105,7 @@ export const ExternalCaSection = () => { deleteKey="confirm" onDeleteApproved={() => onRemoveCaSubmit( - (popUp?.deleteCa?.data as { caId: string })?.caId, + (popUp?.deleteCa?.data as { name: string })?.name, (popUp?.deleteCa?.data as { type: CaType })?.type ) } @@ -127,7 +127,7 @@ export const ExternalCaSection = () => { deleteKey="confirm" onDeleteApproved={() => onUpdateCaStatus( - popUp?.caStatus?.data as { caId: string; type: CaType; status: CaStatus } + popUp?.caStatus?.data as { name: string; type: CaType; status: CaStatus } ) } /> diff --git a/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/ExternalCaTable.tsx b/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/ExternalCaTable.tsx index f3a67f75d..d6e12e214 100644 --- a/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/ExternalCaTable.tsx +++ b/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/ExternalCaTable.tsx @@ -35,7 +35,7 @@ type Props = { handlePopUpOpen: ( popUpName: keyof UsePopUpState<["ca", "deleteCa", "caStatus", "upgradePlan"]>, data?: { - caId?: string; + name?: string; type?: CaType; status?: CaStatus; description?: string; @@ -71,7 +71,7 @@ export const ExternalCaTable = ({ handlePopUpOpen }: Props) => { key={`ca-${ca.id}`} onClick={() => { handlePopUpOpen("ca", { - caId: ca.id, + name: ca.name, type: ca.type }); }} @@ -105,7 +105,7 @@ export const ExternalCaTable = ({ handlePopUpOpen }: Props) => { onClick={(e) => { e.stopPropagation(); handlePopUpOpen("ca", { - caId: ca.id, + name: ca.name, type: ca.type }); }} @@ -130,7 +130,7 @@ export const ExternalCaTable = ({ handlePopUpOpen }: Props) => { onClick={(e) => { e.stopPropagation(); handlePopUpOpen("caStatus", { - caId: ca.id, + name: ca.name, type: ca.type, status: ca.status === CaStatus.ACTIVE @@ -158,7 +158,7 @@ export const ExternalCaTable = ({ handlePopUpOpen }: Props) => { onClick={(e) => { e.stopPropagation(); handlePopUpOpen("deleteCa", { - caId: ca.id, + name: ca.name, type: ca.type }); }}