diff --git a/backend/src/@types/knex.d.ts b/backend/src/@types/knex.d.ts index 9630429b8..5c7787920 100644 --- a/backend/src/@types/knex.d.ts +++ b/backend/src/@types/knex.d.ts @@ -202,6 +202,9 @@ import { TProjectSlackConfigs, TProjectSlackConfigsInsert, TProjectSlackConfigsUpdate, + TProjectSplitBackfillIds, + TProjectSplitBackfillIdsInsert, + TProjectSplitBackfillIdsUpdate, TProjectsUpdate, TProjectTemplates, TProjectTemplatesInsert, @@ -838,5 +841,10 @@ declare module "knex/types/tables" { TProjectTemplatesUpdate >; [TableName.TotpConfig]: KnexOriginal.CompositeTableType; + [TableName.ProjectSplitBackfillIds]: KnexOriginal.CompositeTableType< + TProjectSplitBackfillIds, + TProjectSplitBackfillIdsInsert, + TProjectSplitBackfillIdsUpdate + >; } } diff --git a/backend/src/db/schemas/index.ts b/backend/src/db/schemas/index.ts index bd26610d9..02d6c404a 100644 --- a/backend/src/db/schemas/index.ts +++ b/backend/src/db/schemas/index.ts @@ -65,6 +65,7 @@ export * from "./project-keys"; export * from "./project-memberships"; export * from "./project-roles"; export * from "./project-slack-configs"; +export * from "./project-split-backfill-ids"; export * from "./project-templates"; export * from "./project-user-additional-privilege"; export * from "./project-user-membership-roles"; diff --git a/backend/src/db/schemas/project-split-backfill-ids.ts b/backend/src/db/schemas/project-split-backfill-ids.ts new file mode 100644 index 000000000..182d85049 --- /dev/null +++ b/backend/src/db/schemas/project-split-backfill-ids.ts @@ -0,0 +1,21 @@ +// Code generated by automation script, DO NOT EDIT. +// Automated by pulling database and generating zod schema +// To update. Just run npm run generate:schema +// Written by akhilmhdh. + +import { z } from "zod"; + +import { TImmutableDBKeys } from "./models"; + +export const ProjectSplitBackfillIdsSchema = z.object({ + id: z.string().uuid(), + sourceProjectId: z.string(), + destinationProjectType: z.string(), + destinationProjectId: z.string() +}); + +export type TProjectSplitBackfillIds = z.infer; +export type TProjectSplitBackfillIdsInsert = Omit, TImmutableDBKeys>; +export type TProjectSplitBackfillIdsUpdate = Partial< + Omit, TImmutableDBKeys> +>; diff --git a/backend/src/server/routes/index.ts b/backend/src/server/routes/index.ts index df1d83dda..8890b0f4d 100644 --- a/backend/src/server/routes/index.ts +++ b/backend/src/server/routes/index.ts @@ -757,7 +757,8 @@ export const registerRoutes = async ( pkiAlertDAL, pkiCollectionDAL, permissionService, - smtpService + smtpService, + projectDAL }); const pkiCollectionService = pkiCollectionServiceFactory({ @@ -765,7 +766,8 @@ export const registerRoutes = async ( pkiCollectionItemDAL, certificateAuthorityDAL, certificateDAL, - permissionService + permissionService, + projectDAL }); const projectTemplateService = projectTemplateServiceFactory({ @@ -1273,7 +1275,8 @@ export const registerRoutes = async ( const cmekService = cmekServiceFactory({ kmsDAL, kmsService, - permissionService + permissionService, + projectDAL }); const externalMigrationQueue = externalMigrationQueueFactory({ diff --git a/backend/src/services/certificate-authority/certificate-authority-service.ts b/backend/src/services/certificate-authority/certificate-authority-service.ts index 52323c224..f61a39a00 100644 --- a/backend/src/services/certificate-authority/certificate-authority-service.ts +++ b/backend/src/services/certificate-authority/certificate-authority-service.ts @@ -77,7 +77,10 @@ type TCertificateAuthorityServiceFactoryDep = { certificateBodyDAL: Pick; pkiCollectionDAL: Pick; pkiCollectionItemDAL: Pick; - projectDAL: Pick; + projectDAL: Pick< + TProjectDALFactory, + "findProjectBySlug" | "findOne" | "updateById" | "findById" | "transaction" | "getProjectFromSplitId" + >; kmsService: Pick; permissionService: Pick; }; @@ -123,11 +126,20 @@ export const certificateAuthorityServiceFactory = ({ }: TCreateCaDTO) => { const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId); if (!project) throw new NotFoundError({ message: `Project with slug '${projectSlug}' not found` }); + let projectId = project.id; + + const certManagerProjectFromSplit = await projectDAL.getProjectFromSplitId( + projectId, + ProjectType.CertificateManager + ); + if (certManagerProjectFromSplit) { + projectId = certManagerProjectFromSplit.id; + } const { permission, ForbidOnInvalidProjectType } = await permissionService.getProjectPermission( actor, actorId, - project.id, + projectId, actorAuthMethod, actorOrgId ); @@ -162,7 +174,7 @@ export const certificateAuthorityServiceFactory = ({ const ca = await certificateAuthorityDAL.create( { - projectId: project.id, + projectId, type, organization, ou, @@ -186,7 +198,7 @@ export const certificateAuthorityServiceFactory = ({ ); const certificateManagerKmsId = await getProjectKmsCertificateKeyId({ - projectId: project.id, + projectId, projectDAL, kmsService }); diff --git a/backend/src/services/cmek/cmek-service.ts b/backend/src/services/cmek/cmek-service.ts index 493d5180d..1059c0eb1 100644 --- a/backend/src/services/cmek/cmek-service.ts +++ b/backend/src/services/cmek/cmek-service.ts @@ -15,16 +15,25 @@ import { import { TKmsKeyDALFactory } from "@app/services/kms/kms-key-dal"; import { TKmsServiceFactory } from "@app/services/kms/kms-service"; +import { TProjectDALFactory } from "../project/project-dal"; + type TCmekServiceFactoryDep = { kmsService: TKmsServiceFactory; kmsDAL: TKmsKeyDALFactory; permissionService: TPermissionServiceFactory; + projectDAL: Pick; }; export type TCmekServiceFactory = ReturnType; -export const cmekServiceFactory = ({ kmsService, kmsDAL, permissionService }: TCmekServiceFactoryDep) => { - const createCmek = async ({ projectId, ...dto }: TCreateCmekDTO, actor: OrgServiceActor) => { +export const cmekServiceFactory = ({ kmsService, kmsDAL, permissionService, projectDAL }: TCmekServiceFactoryDep) => { + const createCmek = async ({ projectId: preSplitProjectId, ...dto }: TCreateCmekDTO, actor: OrgServiceActor) => { + let projectId = preSplitProjectId; + const cmekProjectFromSplit = await projectDAL.getProjectFromSplitId(projectId, ProjectType.Cmek); + if (cmekProjectFromSplit) { + projectId = cmekProjectFromSplit.id; + } + const { permission, ForbidOnInvalidProjectType } = await permissionService.getProjectPermission( actor.type, actor.id, @@ -90,7 +99,16 @@ export const cmekServiceFactory = ({ kmsService, kmsDAL, permissionService }: TC return cmek; }; - const listCmeksByProjectId = async ({ projectId, ...filters }: TListCmeksByProjectIdDTO, actor: OrgServiceActor) => { + const listCmeksByProjectId = async ( + { projectId: preSplitProjectId, ...filters }: TListCmeksByProjectIdDTO, + actor: OrgServiceActor + ) => { + let projectId = preSplitProjectId; + const cmekProjectFromSplit = await projectDAL.getProjectFromSplitId(preSplitProjectId, ProjectType.Cmek); + if (cmekProjectFromSplit) { + projectId = cmekProjectFromSplit.id; + } + const { permission } = await permissionService.getProjectPermission( actor.type, actor.id, diff --git a/backend/src/services/pki-alert/pki-alert-service.ts b/backend/src/services/pki-alert/pki-alert-service.ts index c11a31832..f002c393b 100644 --- a/backend/src/services/pki-alert/pki-alert-service.ts +++ b/backend/src/services/pki-alert/pki-alert-service.ts @@ -9,6 +9,7 @@ import { TPkiCollectionDALFactory } from "@app/services/pki-collection/pki-colle import { pkiItemTypeToNameMap } from "@app/services/pki-collection/pki-collection-types"; import { SmtpTemplates, TSmtpService } from "@app/services/smtp/smtp-service"; +import { TProjectDALFactory } from "../project/project-dal"; import { TPkiAlertDALFactory } from "./pki-alert-dal"; import { TCreateAlertDTO, TDeleteAlertDTO, TGetAlertByIdDTO, TUpdateAlertDTO } from "./pki-alert-types"; @@ -20,6 +21,7 @@ type TPkiAlertServiceFactoryDep = { pkiCollectionDAL: Pick; permissionService: Pick; smtpService: Pick; + projectDAL: Pick; }; export type TPkiAlertServiceFactory = ReturnType; @@ -28,7 +30,8 @@ export const pkiAlertServiceFactory = ({ pkiAlertDAL, pkiCollectionDAL, permissionService, - smtpService + smtpService, + projectDAL }: TPkiAlertServiceFactoryDep) => { const sendPkiItemExpiryNotices = async () => { const allAlertItems = await pkiAlertDAL.getExpiringPkiCollectionItemsForAlerting(); @@ -64,7 +67,7 @@ export const pkiAlertServiceFactory = ({ }; const createPkiAlert = async ({ - projectId, + projectId: preSplitProjectId, name, pkiCollectionId, alertBeforeDays, @@ -74,6 +77,15 @@ export const pkiAlertServiceFactory = ({ actor, actorOrgId }: TCreateAlertDTO) => { + let projectId = preSplitProjectId; + const certManagerProjectFromSplit = await projectDAL.getProjectFromSplitId( + projectId, + ProjectType.CertificateManager + ); + if (certManagerProjectFromSplit) { + projectId = certManagerProjectFromSplit.id; + } + const { permission, ForbidOnInvalidProjectType } = await permissionService.getProjectPermission( actor, actorId, diff --git a/backend/src/services/pki-collection/pki-collection-service.ts b/backend/src/services/pki-collection/pki-collection-service.ts index d7693fbcf..93b3b65b6 100644 --- a/backend/src/services/pki-collection/pki-collection-service.ts +++ b/backend/src/services/pki-collection/pki-collection-service.ts @@ -7,6 +7,7 @@ import { BadRequestError, NotFoundError } from "@app/lib/errors"; import { TCertificateDALFactory } from "@app/services/certificate/certificate-dal"; import { TCertificateAuthorityDALFactory } from "@app/services/certificate-authority/certificate-authority-dal"; +import { TProjectDALFactory } from "../project/project-dal"; import { TPkiCollectionDALFactory } from "./pki-collection-dal"; import { transformPkiCollectionItem } from "./pki-collection-fns"; import { TPkiCollectionItemDALFactory } from "./pki-collection-item-dal"; @@ -30,6 +31,7 @@ type TPkiCollectionServiceFactoryDep = { certificateAuthorityDAL: Pick; certificateDAL: Pick; permissionService: Pick; + projectDAL: Pick; }; export type TPkiCollectionServiceFactory = ReturnType; @@ -39,17 +41,27 @@ export const pkiCollectionServiceFactory = ({ pkiCollectionItemDAL, certificateAuthorityDAL, certificateDAL, - permissionService + permissionService, + projectDAL }: TPkiCollectionServiceFactoryDep) => { const createPkiCollection = async ({ name, description, - projectId, + projectId: preSplitProjectId, actorId, actorAuthMethod, actor, actorOrgId }: TCreatePkiCollectionDTO) => { + let projectId = preSplitProjectId; + const certManagerProjectFromSplit = await projectDAL.getProjectFromSplitId( + projectId, + ProjectType.CertificateManager + ); + if (certManagerProjectFromSplit) { + projectId = certManagerProjectFromSplit.id; + } + const { permission, ForbidOnInvalidProjectType } = await permissionService.getProjectPermission( actor, actorId, diff --git a/backend/src/services/project/project-dal.ts b/backend/src/services/project/project-dal.ts index c13258a39..992789da2 100644 --- a/backend/src/services/project/project-dal.ts +++ b/backend/src/services/project/project-dal.ts @@ -336,6 +336,22 @@ export const projectDALFactory = (db: TDbClient) => { }; }; + const getProjectFromSplitId = async (projectId: string, projectType: ProjectType) => { + try { + const project = await db(TableName.ProjectSplitBackfillIds) + .where({ + sourceProjectId: projectId, + destinationProjectType: projectType + }) + .join(TableName.Project, `${TableName.Project}.id`, `${TableName.ProjectSplitBackfillIds}.destinationProjectId`) + .select(selectAllTableCols(TableName.Project)) + .first(); + return project; + } catch (error) { + throw new DatabaseError({ error, name: `Failed to find split project with id ${projectId}` }); + } + }; + return { ...projectOrm, findAllProjects, @@ -346,6 +362,7 @@ export const projectDALFactory = (db: TDbClient) => { findProjectByFilter, findProjectBySlug, findProjectWithOrg, - checkProjectUpgradeStatus + checkProjectUpgradeStatus, + getProjectFromSplitId }; }; diff --git a/backend/src/services/project/project-service.ts b/backend/src/services/project/project-service.ts index 47cc48b1d..9489c8859 100644 --- a/backend/src/services/project/project-service.ts +++ b/backend/src/services/project/project-service.ts @@ -688,11 +688,19 @@ export const projectServiceFactory = ({ actor }: TListProjectCasDTO) => { const project = await projectDAL.findProjectByFilter(filter); + let projectId = project.id; + const certManagerProjectFromSplit = await projectDAL.getProjectFromSplitId( + projectId, + ProjectType.CertificateManager + ); + if (certManagerProjectFromSplit) { + projectId = certManagerProjectFromSplit.id; + } const { permission } = await permissionService.getProjectPermission( actor, actorId, - project.id, + projectId, actorAuthMethod, actorOrgId ); @@ -704,7 +712,7 @@ export const projectServiceFactory = ({ const cas = await certificateAuthorityDAL.find( { - projectId: project.id, + projectId, ...(status && { status }), ...(friendlyName && { friendlyName }), ...(commonName && { commonName }) @@ -730,18 +738,26 @@ export const projectServiceFactory = ({ actor }: TListProjectCertsDTO) => { const project = await projectDAL.findProjectByFilter(filter); + let projectId = project.id; + const certManagerProjectFromSplit = await projectDAL.getProjectFromSplitId( + projectId, + ProjectType.CertificateManager + ); + if (certManagerProjectFromSplit) { + projectId = certManagerProjectFromSplit.id; + } const { permission } = await permissionService.getProjectPermission( actor, actorId, - project.id, + projectId, actorAuthMethod, actorOrgId ); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Certificates); - const cas = await certificateAuthorityDAL.find({ projectId: project.id }); + const cas = await certificateAuthorityDAL.find({ projectId }); const certificates = await certificateDAL.find( { @@ -755,7 +771,7 @@ export const projectServiceFactory = ({ ); const count = await certificateDAL.countCertificatesInProject({ - projectId: project.id, + projectId, friendlyName, commonName }); @@ -770,12 +786,21 @@ export const projectServiceFactory = ({ * Return list of (PKI) alerts configured for project */ const listProjectAlerts = async ({ - projectId, + projectId: preSplitProjectId, actor, actorId, actorAuthMethod, actorOrgId }: TListProjectAlertsDTO) => { + let projectId = preSplitProjectId; + const certManagerProjectFromSplit = await projectDAL.getProjectFromSplitId( + projectId, + ProjectType.CertificateManager + ); + if (certManagerProjectFromSplit) { + projectId = certManagerProjectFromSplit.id; + } + const { permission } = await permissionService.getProjectPermission( actor, actorId, @@ -797,12 +822,20 @@ export const projectServiceFactory = ({ * Return list of PKI collections for project */ const listProjectPkiCollections = async ({ - projectId, + projectId: preSplitProjectId, actor, actorId, actorAuthMethod, actorOrgId }: TListProjectAlertsDTO) => { + let projectId = preSplitProjectId; + const certManagerProjectFromSplit = await projectDAL.getProjectFromSplitId( + projectId, + ProjectType.CertificateManager + ); + if (certManagerProjectFromSplit) { + projectId = certManagerProjectFromSplit.id; + } const { permission } = await permissionService.getProjectPermission( actor, actorId, @@ -824,12 +857,21 @@ export const projectServiceFactory = ({ * Return list of certificate templates for project */ const listProjectCertificateTemplates = async ({ - projectId, + projectId: preSplitProjectId, actorId, actorOrgId, actorAuthMethod, actor }: TListProjectCertificateTemplatesDTO) => { + let projectId = preSplitProjectId; + const certManagerProjectFromSplit = await projectDAL.getProjectFromSplitId( + projectId, + ProjectType.CertificateManager + ); + if (certManagerProjectFromSplit) { + projectId = certManagerProjectFromSplit.id; + } + const { permission } = await permissionService.getProjectPermission( actor, actorId,