mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-18 09:00:35 +00:00
PKI revamp: frontend implementation
This commit is contained in:
@@ -127,11 +127,21 @@ export const certificateProfileDALFactory = (db: TDbClient) => {
|
||||
search?: string;
|
||||
enrollmentType?: EnrollmentType;
|
||||
caId?: string;
|
||||
includeMetrics?: boolean;
|
||||
expiringDays?: number;
|
||||
} = {},
|
||||
tx?: Knex
|
||||
) => {
|
||||
try {
|
||||
const { offset = 0, limit = 20, search, enrollmentType, caId } = options;
|
||||
const {
|
||||
offset = 0,
|
||||
limit = 20,
|
||||
search,
|
||||
enrollmentType,
|
||||
caId,
|
||||
includeMetrics = false,
|
||||
expiringDays = 7
|
||||
} = options;
|
||||
|
||||
let query = (tx || db)(TableName.CertificateProfile).where(
|
||||
`${TableName.CertificateProfile}.projectId`,
|
||||
@@ -155,6 +165,38 @@ export const certificateProfileDALFactory = (db: TDbClient) => {
|
||||
query = query.where(`${TableName.CertificateProfile}.caId`, caId);
|
||||
}
|
||||
|
||||
if (includeMetrics) {
|
||||
const now = new Date();
|
||||
const expiringDate = new Date();
|
||||
expiringDate.setDate(now.getDate() + expiringDays);
|
||||
|
||||
const certificateProfiles = await query
|
||||
.leftJoin(TableName.Certificate, `${TableName.CertificateProfile}.id`, `${TableName.Certificate}.profileId`)
|
||||
.select(
|
||||
selectAllTableCols(TableName.CertificateProfile),
|
||||
db.raw("COUNT(certificates.id) as total_certificates"),
|
||||
db.raw(
|
||||
'COUNT(CASE WHEN certificates."revokedAt" IS NULL AND certificates."notAfter" > ? THEN 1 END) as active_certificates',
|
||||
[expiringDate]
|
||||
),
|
||||
db.raw(
|
||||
'COUNT(CASE WHEN certificates."revokedAt" IS NULL AND certificates."notAfter" <= ? THEN 1 END) as expired_certificates',
|
||||
[now]
|
||||
),
|
||||
db.raw(
|
||||
'COUNT(CASE WHEN certificates."revokedAt" IS NULL AND certificates."notAfter" > ? AND certificates."notAfter" <= ? THEN 1 END) as expiring_certificates',
|
||||
[now, expiringDate]
|
||||
),
|
||||
db.raw('COUNT(CASE WHEN certificates."revokedAt" IS NOT NULL THEN 1 END) as revoked_certificates')
|
||||
)
|
||||
.groupBy(`${TableName.CertificateProfile}.id`)
|
||||
.orderBy(`${TableName.CertificateProfile}.createdAt`, "desc")
|
||||
.offset(offset)
|
||||
.limit(limit);
|
||||
|
||||
return certificateProfiles;
|
||||
}
|
||||
|
||||
const certificateProfiles = await query
|
||||
.select(selectAllTableCols(TableName.CertificateProfile))
|
||||
.orderBy(`${TableName.CertificateProfile}.createdAt`, "desc")
|
||||
@@ -239,13 +281,13 @@ export const certificateProfileDALFactory = (db: TDbClient) => {
|
||||
if (status) {
|
||||
switch (status) {
|
||||
case "active":
|
||||
query = query.where("notAfter", ">", now).where("isRevoked", false);
|
||||
query = query.where("notAfter", ">", now).whereNull("revokedAt");
|
||||
break;
|
||||
case "expired":
|
||||
query = query.where("notAfter", "<=", now).where("isRevoked", false);
|
||||
query = query.where("notAfter", "<=", now).whereNull("revokedAt");
|
||||
break;
|
||||
case "revoked":
|
||||
query = query.where("isRevoked", true);
|
||||
query = query.whereNotNull("revokedAt");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -259,7 +301,7 @@ export const certificateProfileDALFactory = (db: TDbClient) => {
|
||||
.select((tx || db).ref("status").withSchema(TableName.Certificate))
|
||||
.select((tx || db).ref("notBefore").withSchema(TableName.Certificate))
|
||||
.select((tx || db).ref("notAfter").withSchema(TableName.Certificate))
|
||||
.select((tx || db).ref("isRevoked").withSchema(TableName.Certificate))
|
||||
.select((tx || db).ref("revokedAt").withSchema(TableName.Certificate))
|
||||
.select((tx || db).ref("createdAt").withSchema(TableName.Certificate))
|
||||
.orderBy("createdAt", "desc")
|
||||
.offset(offset)
|
||||
@@ -273,7 +315,7 @@ export const certificateProfileDALFactory = (db: TDbClient) => {
|
||||
|
||||
const getProfileMetrics = async (
|
||||
profileId: string,
|
||||
expiringDays: number = 30,
|
||||
expiringDays: number = 7,
|
||||
tx?: Knex
|
||||
): Promise<TCertificateProfileMetrics> => {
|
||||
try {
|
||||
@@ -285,13 +327,15 @@ export const certificateProfileDALFactory = (db: TDbClient) => {
|
||||
.where("profileId", profileId)
|
||||
.select(
|
||||
db.raw("COUNT(*) as total_certificates"),
|
||||
db.raw("COUNT(CASE WHEN NOT is_revoked AND not_after > ? THEN 1 END) as active_certificates", [now]),
|
||||
db.raw("COUNT(CASE WHEN NOT is_revoked AND not_after <= ? THEN 1 END) as expired_certificates", [now]),
|
||||
db.raw('COUNT(CASE WHEN "revokedAt" IS NULL AND "notAfter" > ? THEN 1 END) as active_certificates', [
|
||||
expiringDate
|
||||
]),
|
||||
db.raw('COUNT(CASE WHEN "revokedAt" IS NULL AND "notAfter" <= ? THEN 1 END) as expired_certificates', [now]),
|
||||
db.raw(
|
||||
"COUNT(CASE WHEN NOT is_revoked AND not_after > ? AND not_after <= ? THEN 1 END) as expiring_certificates",
|
||||
'COUNT(CASE WHEN "revokedAt" IS NULL AND "notAfter" > ? AND "notAfter" <= ? THEN 1 END) as expiring_certificates',
|
||||
[now, expiringDate]
|
||||
),
|
||||
db.raw("COUNT(CASE WHEN is_revoked THEN 1 END) as revoked_certificates")
|
||||
db.raw('COUNT(CASE WHEN "revokedAt" IS NOT NULL THEN 1 END) as revoked_certificates')
|
||||
)
|
||||
.first();
|
||||
|
||||
|
||||
@@ -466,7 +466,9 @@ describe("CertificateProfileService", () => {
|
||||
limit: 20,
|
||||
search: undefined,
|
||||
enrollmentType: undefined,
|
||||
caId: undefined
|
||||
caId: undefined,
|
||||
includeMetrics: false,
|
||||
expiringDays: 30
|
||||
});
|
||||
});
|
||||
|
||||
@@ -486,7 +488,51 @@ describe("CertificateProfileService", () => {
|
||||
limit: 5,
|
||||
search: "test",
|
||||
enrollmentType: EnrollmentType.API,
|
||||
caId: "ca-123"
|
||||
caId: "ca-123",
|
||||
includeMetrics: false,
|
||||
expiringDays: 30
|
||||
});
|
||||
});
|
||||
|
||||
it("should list profiles with metrics when includeMetrics is true", async () => {
|
||||
const mockProfilesWithMetrics = [
|
||||
{
|
||||
...sampleProfile,
|
||||
total_certificates: 10,
|
||||
active_certificates: 8,
|
||||
expired_certificates: 1,
|
||||
expiring_certificates: 1,
|
||||
revoked_certificates: 0
|
||||
}
|
||||
];
|
||||
(mockCertificateProfileDAL.findByProjectId as any).mockResolvedValue(mockProfilesWithMetrics);
|
||||
|
||||
const result = await service.listProfiles({
|
||||
...mockActor,
|
||||
projectId: "project-123",
|
||||
includeMetrics: true,
|
||||
expiringDays: 15
|
||||
});
|
||||
|
||||
expect(result.profiles).toHaveLength(1);
|
||||
expect(result.profiles[0]).toHaveProperty("metrics");
|
||||
expect(result.profiles[0].metrics).toEqual({
|
||||
profileId: sampleProfile.id,
|
||||
totalCertificates: 10,
|
||||
activeCertificates: 8,
|
||||
expiredCertificates: 1,
|
||||
expiringCertificates: 1,
|
||||
revokedCertificates: 0
|
||||
});
|
||||
|
||||
expect(mockCertificateProfileDAL.findByProjectId).toHaveBeenCalledWith("project-123", {
|
||||
offset: 0,
|
||||
limit: 20,
|
||||
search: undefined,
|
||||
enrollmentType: undefined,
|
||||
caId: undefined,
|
||||
includeMetrics: true,
|
||||
expiringDays: 15
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -23,7 +23,8 @@ import {
|
||||
TCertificateProfileInsert,
|
||||
TCertificateProfileMetrics,
|
||||
TCertificateProfileUpdate,
|
||||
TCertificateProfileWithConfigs
|
||||
TCertificateProfileWithConfigs,
|
||||
TCertificateProfileWithRawMetrics
|
||||
} from "./certificate-profile-types";
|
||||
|
||||
export type TCertificateProfileCreateData = Omit<TCertificateProfileInsert, "estConfigId" | "apiConfigId"> & {
|
||||
@@ -48,10 +49,6 @@ const convertDalToService = (dalResult: Record<string, unknown>): TCertificatePr
|
||||
} as TCertificateProfile;
|
||||
};
|
||||
|
||||
const convertDalArrayToService = (dalResults: Record<string, unknown>[]): TCertificateProfile[] => {
|
||||
return dalResults.map(convertDalToService);
|
||||
};
|
||||
|
||||
const validateEnrollmentConfig = async (data: {
|
||||
enrollmentType: EnrollmentType;
|
||||
estConfig?: TEstConfigData | null;
|
||||
@@ -289,14 +286,18 @@ export const certificateProfileServiceFactory = ({
|
||||
actorId,
|
||||
actorAuthMethod,
|
||||
actorOrgId,
|
||||
profileId
|
||||
profileId,
|
||||
includeMetrics = false,
|
||||
expiringDays = 30
|
||||
}: {
|
||||
actor: ActorType;
|
||||
actorId: string;
|
||||
actorAuthMethod: ActorAuthMethod;
|
||||
actorOrgId: string;
|
||||
profileId: string;
|
||||
}): Promise<TCertificateProfile> => {
|
||||
includeMetrics?: boolean;
|
||||
expiringDays?: number;
|
||||
}): Promise<TCertificateProfile & { metrics?: TCertificateProfileMetrics }> => {
|
||||
const profile = await certificateProfileDAL.findById(profileId);
|
||||
if (!profile) {
|
||||
throw new NotFoundError({ message: "Certificate profile not found" });
|
||||
@@ -315,7 +316,17 @@ export const certificateProfileServiceFactory = ({
|
||||
ProjectPermissionSub.CertificateProfiles
|
||||
);
|
||||
|
||||
return convertDalToService(profile);
|
||||
const converted = convertDalToService(profile);
|
||||
|
||||
if (includeMetrics) {
|
||||
const metrics = await certificateProfileDAL.getProfileMetrics(profileId, expiringDays);
|
||||
return {
|
||||
...converted,
|
||||
metrics
|
||||
};
|
||||
}
|
||||
|
||||
return converted;
|
||||
};
|
||||
|
||||
const getProfileByIdWithConfigs = async ({
|
||||
@@ -401,7 +412,9 @@ export const certificateProfileServiceFactory = ({
|
||||
limit = 20,
|
||||
search,
|
||||
enrollmentType,
|
||||
caId
|
||||
caId,
|
||||
includeMetrics = false,
|
||||
expiringDays = 30
|
||||
}: {
|
||||
actor: ActorType;
|
||||
actorId: string;
|
||||
@@ -413,8 +426,10 @@ export const certificateProfileServiceFactory = ({
|
||||
search?: string;
|
||||
enrollmentType?: EnrollmentType;
|
||||
caId?: string;
|
||||
includeMetrics?: boolean;
|
||||
expiringDays?: number;
|
||||
}): Promise<{
|
||||
profiles: TCertificateProfile[];
|
||||
profiles: (TCertificateProfile & { metrics?: TCertificateProfileMetrics })[];
|
||||
totalCount: number;
|
||||
}> => {
|
||||
const { permission } = await permissionService.getProjectPermission({
|
||||
@@ -435,7 +450,9 @@ export const certificateProfileServiceFactory = ({
|
||||
limit,
|
||||
search,
|
||||
enrollmentType,
|
||||
caId
|
||||
caId,
|
||||
includeMetrics,
|
||||
expiringDays
|
||||
});
|
||||
|
||||
const totalCount = await certificateProfileDAL.countByProjectId(projectId, {
|
||||
@@ -444,8 +461,27 @@ export const certificateProfileServiceFactory = ({
|
||||
caId
|
||||
});
|
||||
|
||||
const convertedProfiles = profiles.map((profile) => {
|
||||
const converted = convertDalToService(profile);
|
||||
if (includeMetrics) {
|
||||
const profileWithMetrics = profile as TCertificateProfileWithRawMetrics;
|
||||
return {
|
||||
...converted,
|
||||
metrics: {
|
||||
profileId: converted.id,
|
||||
totalCertificates: parseInt(String(profileWithMetrics.total_certificates || 0), 10),
|
||||
activeCertificates: parseInt(String(profileWithMetrics.active_certificates || 0), 10),
|
||||
expiredCertificates: parseInt(String(profileWithMetrics.expired_certificates || 0), 10),
|
||||
expiringCertificates: parseInt(String(profileWithMetrics.expiring_certificates || 0), 10),
|
||||
revokedCertificates: parseInt(String(profileWithMetrics.revoked_certificates || 0), 10)
|
||||
}
|
||||
};
|
||||
}
|
||||
return converted;
|
||||
});
|
||||
|
||||
return {
|
||||
profiles: convertDalArrayToService(profiles),
|
||||
profiles: convertedProfiles,
|
||||
totalCount
|
||||
};
|
||||
};
|
||||
|
||||
@@ -45,6 +45,7 @@ export type TCertificateProfileWithConfigs = TCertificateProfile & {
|
||||
autoRenew: boolean;
|
||||
autoRenewDays?: number;
|
||||
};
|
||||
metrics?: TCertificateProfileMetrics;
|
||||
};
|
||||
|
||||
export interface TCertificateProfileMetrics {
|
||||
@@ -63,6 +64,14 @@ export interface TCertificateProfileCertificate {
|
||||
status: string;
|
||||
notBefore: Date;
|
||||
notAfter: Date;
|
||||
isRevoked: boolean;
|
||||
revokedAt: Date | null | undefined;
|
||||
createdAt: Date;
|
||||
}
|
||||
|
||||
export type TCertificateProfileWithRawMetrics = TCertificateProfile & {
|
||||
total_certificates?: string;
|
||||
active_certificates?: string;
|
||||
expired_certificates?: string;
|
||||
expiring_certificates?: string;
|
||||
revoked_certificates?: string;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user