Rename pki alerting structures

This commit is contained in:
Tuan Dang
2024-08-09 08:27:53 -07:00
parent 556e4d62c4
commit fc4a20caf2
54 changed files with 1443 additions and 161 deletions
@@ -0,0 +1,30 @@
import { TPkiCollectionItems } from "@app/db/schemas";
import { PkiItemType } from "./pki-collection-types";
/**
* Transforms a PKI Collection Item from the database to the expected API response format
*/
export const transformPkiCollectionItem = (pkiCollectionItem: TPkiCollectionItems) => {
let type: PkiItemType;
let itemId: string;
if (pkiCollectionItem.caId) {
type = PkiItemType.CA;
itemId = pkiCollectionItem.caId;
} else if (pkiCollectionItem.certId) {
type = PkiItemType.CERTIFICATE;
itemId = pkiCollectionItem.certId;
} else {
throw new Error("Invalid PKI Collection Item: must have either caId or certId");
}
return {
id: pkiCollectionItem.id,
pkiCollectionId: pkiCollectionItem.pkiCollectionId,
type,
itemId,
createdAt: pkiCollectionItem.createdAt,
updatedAt: pkiCollectionItem.updatedAt
};
};
@@ -0,0 +1,33 @@
import { TDbClient } from "@app/db";
import { TableName } from "@app/db/schemas";
import { DatabaseError } from "@app/lib/errors";
import { ormify } from "@app/lib/knex";
export type TPkiCollectionItemDALFactory = ReturnType<typeof pkiCollectionItemDALFactory>;
export const pkiCollectionItemDALFactory = (db: TDbClient) => {
const pkiCollectionItemOrm = ormify(db, TableName.PkiCollectionItem);
const countItemsInPkiCollection = async (collectionId: string) => {
try {
interface CountResult {
count: string;
}
const query = db
.replicaNode()(TableName.PkiCollectionItem)
.where(`${TableName.PkiCollectionItem}.pkiCollectionId`, collectionId);
const count = await query.count("*").first();
return parseInt((count as unknown as CountResult).count || "0", 10);
} catch (error) {
throw new DatabaseError({ error, name: "Count all project certificates" });
}
};
return {
...pkiCollectionItemOrm,
countItemsInPkiCollection
};
};
@@ -1,19 +1,31 @@
import { ForbiddenError } from "@casl/ability";
import { TPkiCollectionItems } from "@app/db/schemas";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
import { NotFoundError } from "@app/lib/errors";
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 { TPkiCollectionDALFactory } from "./pki-collection-dal";
import { transformPkiCollectionItem } from "./pki-collection-fns";
import { TPkiCollectionItemDALFactory } from "./pki-collection-item-dal";
import {
PkiItemType,
TAddItemToPkiCollectionDTO,
TCreatePkiCollectionDTO,
TDeletePkiCollectionDTO,
TGetPkiCollectionByIdDTO,
TGetPkiCollectionItems,
TRemoveItemFromPkiCollectionDTO,
TUpdatePkiCollectionDTO
} from "./pki-collection-types";
type TPkiCollectionServiceFactoryDep = {
pkiCollectionDAL: TPkiCollectionDALFactory;
pkiCollectionDAL: TPkiCollectionDALFactory; // TODO: Pick
pkiCollectionItemDAL: TPkiCollectionItemDALFactory;
certificateAuthorityDAL: TCertificateAuthorityDALFactory;
certificateDAL: TCertificateDALFactory;
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
};
@@ -21,6 +33,9 @@ export type TPkiCollectionServiceFactory = ReturnType<typeof pkiCollectionServic
export const pkiCollectionServiceFactory = ({
pkiCollectionDAL,
pkiCollectionItemDAL,
certificateAuthorityDAL,
certificateDAL,
permissionService
}: TPkiCollectionServiceFactoryDep) => {
const createPkiCollection = async ({
@@ -127,12 +142,168 @@ export const pkiCollectionServiceFactory = ({
return pkiCollection;
};
// TODO: add/remove pki collection items
const getPkiCollectionItems = async ({
collectionId,
offset = 0,
limit = 25,
actorId,
actorAuthMethod,
actor,
actorOrgId
}: TGetPkiCollectionItems) => {
const pkiCollection = await pkiCollectionDAL.findById(collectionId);
if (!pkiCollection) throw new NotFoundError({ message: "PKI collection not found" });
const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
pkiCollection.projectId,
actorAuthMethod,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.PkiCollections);
const pkiCollectionItems = await pkiCollectionItemDAL.find(
{ pkiCollectionId: collectionId },
{ offset, limit, sort: [["createdAt", "desc"]] }
);
const count = await pkiCollectionItemDAL.countItemsInPkiCollection(collectionId);
return {
pkiCollectionItems: pkiCollectionItems.map(transformPkiCollectionItem),
totalCount: count
};
};
const addItemToPkiCollection = async ({
collectionId,
actorId,
actorAuthMethod,
actor,
actorOrgId,
type,
itemId
}: TAddItemToPkiCollectionDTO) => {
const pkiCollection = await pkiCollectionDAL.findById(collectionId);
if (!pkiCollection) throw new NotFoundError({ message: "PKI collection not found" });
const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
pkiCollection.projectId,
actorAuthMethod,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Create,
ProjectPermissionSub.PkiCollections
);
let pkiCollectionItem: TPkiCollectionItems;
switch (type) {
case PkiItemType.CA: {
// validate that CA has not already been added to PKI collection
const isCaAdded = await pkiCollectionItemDAL.findOne({
pkiCollectionId: collectionId,
caId: itemId
});
if (isCaAdded) throw new BadRequestError({ message: "CA is already part of the PKI collection" });
// validate that there exists a CA in same project as PKI collection
const ca = await certificateAuthorityDAL.findOne({
id: itemId,
projectId: pkiCollection.projectId
});
if (!ca) throw new NotFoundError({ message: "CA not found" });
pkiCollectionItem = await pkiCollectionItemDAL.create({
pkiCollectionId: collectionId,
caId: itemId
});
break;
}
case PkiItemType.CERTIFICATE: {
// validate that certificate has not already been added to PKI collection
const isCertAdded = await pkiCollectionItemDAL.findOne({
pkiCollectionId: collectionId,
certId: itemId
});
if (isCertAdded) throw new BadRequestError({ message: "Certificate already part of the PKI collection" });
// validate that there exists a certificate in same project as PKI collection
const cas = await certificateAuthorityDAL.find({ projectId: pkiCollection.projectId });
// TODO: consider making this more efficient
const [certificate] = await certificateDAL.find({
$in: {
caId: cas.map((ca) => ca.id)
},
id: itemId
});
if (!certificate) throw new NotFoundError({ message: "Certificate not found" });
pkiCollectionItem = await pkiCollectionItemDAL.create({
pkiCollectionId: collectionId,
certId: itemId
});
break;
}
default: {
throw new BadRequestError({ message: "Invalid PKI item type" });
}
}
return transformPkiCollectionItem(pkiCollectionItem);
};
const removeItemFromPkiCollection = async ({
collectionId,
actorId,
actorAuthMethod,
actor,
actorOrgId,
itemId
}: TRemoveItemFromPkiCollectionDTO) => {
const pkiCollection = await pkiCollectionDAL.findById(collectionId);
if (!pkiCollection) throw new NotFoundError({ message: "PKI collection not found" });
let pkiCollectionItem = await pkiCollectionItemDAL.findOne({
pkiCollectionId: collectionId,
id: itemId
});
if (!pkiCollectionItem) throw new NotFoundError({ message: "PKI collection item not found" });
const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
pkiCollection.projectId,
actorAuthMethod,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Delete,
ProjectPermissionSub.PkiCollections
);
pkiCollectionItem = await pkiCollectionItemDAL.deleteById(itemId);
return transformPkiCollectionItem(pkiCollectionItem);
};
return {
createPkiCollection,
getPkiCollectionById,
updatePkiCollection,
deletePkiCollection
deletePkiCollection,
getPkiCollectionItems,
addItemToPkiCollection,
removeItemFromPkiCollection
};
};
@@ -16,3 +16,25 @@ export type TUpdatePkiCollectionDTO = {
export type TDeletePkiCollectionDTO = {
collectionId: string;
} & Omit<TProjectPermission, "projectId">;
export enum PkiItemType {
CERTIFICATE = "certificate",
CA = "ca"
}
export type TGetPkiCollectionItems = {
collectionId: string;
offset: number;
limit: number;
} & Omit<TProjectPermission, "projectId">;
export type TAddItemToPkiCollectionDTO = {
collectionId: string;
type: PkiItemType;
itemId: string;
} & Omit<TProjectPermission, "projectId">;
export type TRemoveItemFromPkiCollectionDTO = {
collectionId: string;
itemId: string;
} & Omit<TProjectPermission, "projectId">;