PKI revamp: UI improvements

This commit is contained in:
Carlos Monastyrski
2025-10-10 19:49:15 -03:00
parent ef9a1961f1
commit 8905885254
45 changed files with 1156 additions and 2089 deletions
@@ -68,18 +68,24 @@ export const certificateProfileDALFactory = (db: TDbClient) => {
(tx || db).ref("name").withSchema(TableName.CertificateAuthority).as("caName"),
(tx || db).ref("id").withSchema(TableName.CertificateTemplateV2).as("templateId"),
(tx || db).ref("projectId").withSchema(TableName.CertificateTemplateV2).as("templateProjectId"),
(tx || db).ref("name").withSchema(TableName.CertificateTemplateV2).as("templateName"),
(tx || db).ref("slug").withSchema(TableName.CertificateTemplateV2).as("templateName"),
(tx || db).ref("description").withSchema(TableName.CertificateTemplateV2).as("templateDescription"),
(tx || db).ref("id").withSchema(TableName.EstEnrollmentConfig).as("estConfigId"),
(tx || db).ref("id").withSchema(TableName.PkiEstEnrollmentConfig).as("estConfigId"),
(tx || db)
.ref("disableBootstrapCaValidation")
.withSchema(TableName.EstEnrollmentConfig)
.withSchema(TableName.PkiEstEnrollmentConfig)
.as("estConfigDisableBootstrapCaValidation"),
(tx || db).ref("hashedPassphrase").withSchema(TableName.EstEnrollmentConfig).as("estConfigHashedPassphrase"),
(tx || db).ref("encryptedCaChain").withSchema(TableName.EstEnrollmentConfig).as("estConfigEncryptedCaChain"),
(tx || db).ref("id").withSchema(TableName.ApiEnrollmentConfig).as("apiConfigId"),
(tx || db).ref("autoRenew").withSchema(TableName.ApiEnrollmentConfig).as("apiConfigAutoRenew"),
(tx || db).ref("autoRenewDays").withSchema(TableName.ApiEnrollmentConfig).as("apiConfigAutoRenewDays")
(tx || db)
.ref("hashedPassphrase")
.withSchema(TableName.PkiEstEnrollmentConfig)
.as("estConfigHashedPassphrase"),
(tx || db)
.ref("encryptedCaChain")
.withSchema(TableName.PkiEstEnrollmentConfig)
.as("estConfigEncryptedCaChain"),
(tx || db).ref("id").withSchema(TableName.PkiApiEnrollmentConfig).as("apiConfigId"),
(tx || db).ref("autoRenew").withSchema(TableName.PkiApiEnrollmentConfig).as("apiConfigAutoRenew"),
(tx || db).ref("autoRenewDays").withSchema(TableName.PkiApiEnrollmentConfig).as("apiConfigAutoRenewDays")
)
.leftJoin(
TableName.CertificateAuthority,
@@ -92,14 +98,14 @@ export const certificateProfileDALFactory = (db: TDbClient) => {
`${TableName.CertificateTemplateV2}.id`
)
.leftJoin(
TableName.EstEnrollmentConfig,
TableName.PkiEstEnrollmentConfig,
`${TableName.CertificateProfile}.estConfigId`,
`${TableName.EstEnrollmentConfig}.id`
`${TableName.PkiEstEnrollmentConfig}.id`
)
.leftJoin(
TableName.ApiEnrollmentConfig,
TableName.PkiApiEnrollmentConfig,
`${TableName.CertificateProfile}.apiConfigId`,
`${TableName.ApiEnrollmentConfig}.id`
`${TableName.PkiApiEnrollmentConfig}.id`
)
.where(`${TableName.CertificateProfile}.id`, id)
.first();
@@ -151,9 +157,8 @@ export const certificateProfileDALFactory = (db: TDbClient) => {
if (search) {
query = query.where((builder) => {
void builder
.whereILike(`${TableName.CertificateProfile}.name`, `%${search}%`)
.orWhereILike(`${TableName.CertificateProfile}.description`, `%${search}%`)
.orWhereILike(`${TableName.CertificateProfile}.slug`, `%${search}%`);
.whereILike(`${TableName.CertificateProfile}.slug`, `%${search}%`)
.orWhereILike(`${TableName.CertificateProfile}.description`, `%${search}%`);
});
}
@@ -225,10 +230,7 @@ export const certificateProfileDALFactory = (db: TDbClient) => {
if (search) {
query = query.where((builder) => {
void builder
.whereILike("name", `%${search}%`)
.orWhereILike("description", `%${search}%`)
.orWhereILike("slug", `%${search}%`);
void builder.orWhereILike("description", `%${search}%`).orWhereILike("slug", `%${search}%`);
});
}
@@ -249,7 +251,9 @@ export const certificateProfileDALFactory = (db: TDbClient) => {
const findByNameAndProjectId = async (name: string, projectId: string, tx?: Knex) => {
try {
const certificateProfile = await (tx || db)(TableName.CertificateProfile).where({ name, projectId }).first();
const certificateProfile = await (tx || db)(TableName.CertificateProfile)
.where({ slug: name, projectId })
.first();
return certificateProfile;
} catch (error) {
throw new DatabaseError({ error, name: "Find certificate profile by name and project id" });
@@ -8,7 +8,6 @@ export const createCertificateProfileSchema = z
projectId: z.string().min(1),
caId: z.string().uuid(),
certificateTemplateId: z.string().uuid(),
name: z.string().min(1).max(255),
slug: z
.string()
.min(1)
@@ -46,7 +45,6 @@ export const createCertificateProfileSchema = z
);
export const updateCertificateProfileSchema = z.object({
name: z.string().min(1).max(255).optional(),
slug: z
.string()
.min(1)
@@ -80,7 +80,6 @@ describe("CertificateProfileService", () => {
const sampleProfile: TCertificateProfile = {
id: "profile-123",
projectId: "project-123",
name: "Test Profile",
description: "Test certificate profile",
slug: "test-profile",
enrollmentType: EnrollmentType.API,
@@ -174,9 +173,8 @@ describe("CertificateProfileService", () => {
describe("createProfile", () => {
const validProfileData = {
name: "New Profile",
description: "New test profile",
slug: "new-profile",
description: "New test profile",
enrollmentType: EnrollmentType.API,
caId: "ca-123",
certificateTemplateId: "template-123",
@@ -204,9 +202,8 @@ describe("CertificateProfileService", () => {
expect(mockCertificateTemplateV2DAL.findById).toHaveBeenCalledWith("template-123");
expect(mockCertificateProfileDAL.findBySlugAndProjectId).toHaveBeenCalledWith("new-profile", "project-123");
expect(mockCertificateProfileDAL.create).toHaveBeenCalledWith({
name: "New Profile",
description: "New test profile",
slug: "new-profile",
description: "New test profile",
enrollmentType: EnrollmentType.API,
caId: "ca-123",
certificateTemplateId: "template-123",
@@ -273,9 +270,8 @@ describe("CertificateProfileService", () => {
it("should throw ForbiddenRequestError for API enrollment without API config", async () => {
const invalidData = {
name: "Invalid Profile",
description: "Invalid test profile",
slug: "invalid-profile",
description: "Invalid test profile",
enrollmentType: EnrollmentType.API,
caId: "ca-123",
certificateTemplateId: "template-123"
@@ -292,9 +288,8 @@ describe("CertificateProfileService", () => {
it("should create profile with API enrollment", async () => {
const apiProfileData = {
name: "API Profile",
description: "Profile with API enrollment",
slug: "api-profile",
description: "Profile with API enrollment",
enrollmentType: EnrollmentType.API,
caId: "ca-123",
certificateTemplateId: "template-123",
@@ -317,7 +312,7 @@ describe("CertificateProfileService", () => {
describe("updateProfile", () => {
const updateData = {
name: "Updated Profile",
slug: "updated-profile",
description: "Updated description"
};
@@ -333,7 +328,7 @@ describe("CertificateProfileService", () => {
data: updateData
});
expect(result.name).toBe("Updated Profile");
expect(result.slug).toBe("updated-profile");
expect(mockCertificateProfileDAL.findById).toHaveBeenCalledWith("profile-123");
expect(mockCertificateProfileDAL.updateById).toHaveBeenCalledWith("profile-123", updateData);
});
@@ -697,9 +692,8 @@ describe("CertificateProfileService", () => {
describe("profile configuration validation", () => {
it("should validate EST enrollment configuration", async () => {
const estProfileData = {
name: "EST Profile",
description: "Profile with EST enrollment",
slug: "est-profile",
description: "Profile with EST enrollment",
enrollmentType: EnrollmentType.EST,
caId: "ca-123",
certificateTemplateId: "template-123",
@@ -737,9 +731,8 @@ describe("CertificateProfileService", () => {
vi.clearAllMocks();
const duplicateSlugData = {
name: "Different Profile Name",
slug: "different-profile-name",
description: "Profile with duplicate slug",
slug: "test-profile",
enrollmentType: EnrollmentType.API,
caId: "ca-123",
certificateTemplateId: "template-123",
@@ -763,9 +756,8 @@ describe("CertificateProfileService", () => {
it("should validate auto-renewal configuration", async () => {
const autoRenewData = {
name: "Auto Renew Profile",
slug: "auto-renew-profile",
description: "Profile with auto-renewal",
slug: "auto-renew",
enrollmentType: EnrollmentType.API,
caId: "ca-123",
certificateTemplateId: "template-123",
@@ -987,9 +979,8 @@ describe("CertificateProfileService", () => {
it("should handle invalid template reference during profile creation", async () => {
const profileData = {
name: "Invalid Template Profile",
slug: "invalid-template-profile",
description: "Profile with invalid template",
slug: "invalid-template",
enrollmentType: EnrollmentType.API,
caId: "ca-123",
certificateTemplateId: "nonexistent-template",
@@ -1013,9 +1004,8 @@ describe("CertificateProfileService", () => {
it("should handle concurrent profile creation conflicts", async () => {
const conflictingData = {
name: "Concurrent Profile",
description: "Profile created concurrently",
slug: "concurrent-profile",
description: "Profile created concurrently",
enrollmentType: EnrollmentType.API,
caId: "ca-123",
certificateTemplateId: "template-123",
@@ -1042,9 +1032,8 @@ describe("CertificateProfileService", () => {
describe("permission and security", () => {
it("should validate project ownership for cross-project template access", async () => {
const crossProjectData = {
name: "Cross Project Profile",
slug: "cross-project-profile",
description: "Profile using template from different project",
slug: "cross-project",
enrollmentType: EnrollmentType.API,
caId: "ca-123",
certificateTemplateId: "template-456",
@@ -1056,7 +1045,7 @@ describe("CertificateProfileService", () => {
const foreignTemplate = {
id: "template-456",
projectId: "different-project-456",
name: "Foreign Template"
slug: "foreign-template"
};
(mockCertificateTemplateV2DAL.findById as any).mockResolvedValue(foreignTemplate);
@@ -1072,9 +1061,8 @@ describe("CertificateProfileService", () => {
it("should validate slug format constraints", async () => {
const invalidSlugData = {
name: "Invalid Slug Profile",
slug: "invalid-slug-profile",
description: "Profile with invalid slug format",
slug: "Invalid_Slug_With_Underscores_And_Caps",
enrollmentType: EnrollmentType.API,
caId: "ca-123",
certificateTemplateId: "template-123",
@@ -277,7 +277,28 @@ export const certificateProfileServiceFactory = ({
});
}
const updatedProfile = await certificateProfileDAL.updateById(profileId, data);
const { estConfig, apiConfig, ...profileUpdateData } = data;
if (estConfig && existingProfile.estConfigId) {
await estEnrollmentConfigDAL.updateById(existingProfile.estConfigId, {
disableBootstrapCaValidation: estConfig.disableBootstrapCaValidation,
...(estConfig.passphrase && {
hashedPassphrase: await crypto.hashing().createHash(estConfig.passphrase, getConfig().SALT_ROUNDS)
}),
...(estConfig.caChain && {
encryptedCaChain: Buffer.from(estConfig.caChain, "base64")
})
});
}
if (apiConfig && existingProfile.apiConfigId) {
await apiEnrollmentConfigDAL.updateById(existingProfile.apiConfigId, {
autoRenew: apiConfig.autoRenew,
autoRenewDays: apiConfig.autoRenewDays
});
}
const updatedProfile = await certificateProfileDAL.updateById(profileId, profileUpdateData);
return convertDalToService(updatedProfile);
};
@@ -19,6 +19,15 @@ export type TCertificateProfileInsert = Omit<TCertificateProfilesInsert, "enroll
export type TCertificateProfileUpdate = Omit<TCertificateProfilesUpdate, "enrollmentType"> & {
enrollmentType?: EnrollmentType;
estConfig?: {
disableBootstrapCaValidation?: boolean;
passphrase?: string;
caChain?: string;
};
apiConfig?: {
autoRenew?: boolean;
autoRenewDays?: number;
};
};
export type TCertificateProfileWithConfigs = TCertificateProfile & {
@@ -139,7 +139,7 @@ export const certificateTemplateV2DALFactory = (db: TDbClient) => {
if (search) {
query = query.where((builder) => {
void builder.whereILike("name", `%${search}%`).orWhereILike("description", `%${search}%`);
void builder.whereILike("slug", `%${search}%`).orWhereILike("description", `%${search}%`);
});
}
@@ -165,7 +165,7 @@ export const certificateTemplateV2DALFactory = (db: TDbClient) => {
if (search) {
query = query.where((builder) => {
void builder.whereILike("name", `%${search}%`).orWhereILike("description", `%${search}%`);
void builder.whereILike("slug", `%${search}%`).orWhereILike("description", `%${search}%`);
});
}
@@ -176,10 +176,10 @@ export const certificateTemplateV2DALFactory = (db: TDbClient) => {
}
};
const findByNameAndProjectId = async (name: string, projectId: string, tx?: Knex) => {
const findBySlugAndProjectId = async (slug: string, projectId: string, tx?: Knex) => {
try {
const certificateTemplateV2 = await (tx || db)(TableName.CertificateTemplateV2)
.where({ name, projectId })
.where({ slug, projectId })
.first();
if (!certificateTemplateV2) {
@@ -188,7 +188,7 @@ export const certificateTemplateV2DALFactory = (db: TDbClient) => {
return parseJsonFields(certificateTemplateV2);
} catch (error) {
throw new DatabaseError({ error, name: "Find certificate template v2 by name and project id" });
throw new DatabaseError({ error, name: "Find certificate template v2 by slug and project id" });
}
};
@@ -213,7 +213,7 @@ export const certificateTemplateV2DALFactory = (db: TDbClient) => {
findById,
findByProjectId,
countByProjectId,
findByNameAndProjectId,
findBySlugAndProjectId,
isTemplateInUse
};
};
@@ -1,3 +1,4 @@
import RE2 from "re2";
import { z } from "zod";
const attributeTypeSchema = z.enum(["common_name"]);
@@ -87,7 +88,11 @@ export const templateV2KeyAlgorithmSchema = z.object({
export const createCertificateTemplateV2Schema = z.object({
projectId: z.string().min(1),
name: z.string().min(1).max(255),
slug: z
.string()
.min(1)
.max(255)
.regex(new RE2("^[a-z0-9-]+$"), "Slug must contain only lowercase letters, numbers, and hyphens"),
description: z.string().max(1000).optional(),
attributes: z.array(templateV2AttributeSchema).optional(),
keyUsages: templateV2KeyUsagesSchema.optional(),
@@ -99,7 +104,12 @@ export const createCertificateTemplateV2Schema = z.object({
});
export const updateCertificateTemplateV2Schema = z.object({
name: z.string().min(1).max(255).optional(),
slug: z
.string()
.min(1)
.max(255)
.regex(new RE2("^[a-z0-9-]+$"), "Slug must contain only lowercase letters, numbers, and hyphens")
.optional(),
description: z.string().max(1000).optional(),
attributes: z.array(templateV2AttributeSchema).optional(),
keyUsages: templateV2KeyUsagesSchema.optional(),
@@ -114,6 +124,11 @@ export const getCertificateTemplateV2ByIdSchema = z.object({
id: z.string().uuid()
});
export const getCertificateTemplateV2BySlugSchema = z.object({
projectId: z.string().min(1),
slug: z.string().min(1)
});
export const listCertificateTemplatesV2Schema = z.object({
projectId: z.string().min(1),
offset: z.coerce.number().min(0).default(0),
@@ -27,6 +27,7 @@ describe("CertificateTemplateV2Service", () => {
let service: TCertificateTemplateV2ServiceFactory;
const mockCertificateTemplateV2DAL = {
findBySlugAndProjectId: vi.fn(),
create: vi.fn(),
findById: vi.fn(),
updateById: vi.fn(),
@@ -99,7 +100,7 @@ describe("CertificateTemplateV2Service", () => {
const sampleTemplate: TCertificateTemplateV2 = {
id: "template-123",
projectId: "project-123",
name: "Web Server Template",
slug: "web-server-template",
description: "Template for web server certificates",
...samplePolicy,
createdAt: new Date(),
@@ -136,6 +137,7 @@ describe("CertificateTemplateV2Service", () => {
});
mockCertificateTemplateV2DAL.findByNameAndProjectId.mockResolvedValue(null);
mockCertificateTemplateV2DAL.findBySlugAndProjectId.mockResolvedValue(null);
service = certificateTemplateV2ServiceFactory({
certificateTemplateV2DAL: mockCertificateTemplateV2DAL as TCertificateTemplateV2DALFactory,
@@ -149,7 +151,7 @@ describe("CertificateTemplateV2Service", () => {
describe("createTemplateV2", () => {
const createData: Omit<TCertificateTemplateV2Insert, "projectId"> = {
name: "Test Template",
slug: "test-template",
description: "Test description",
...samplePolicy
};
@@ -239,7 +241,7 @@ describe("CertificateTemplateV2Service", () => {
describe("updateTemplateV2", () => {
it("should update template with valid data", async () => {
const updateData = { name: "Updated Template Name" };
const updateData = { slug: "updated-template-name" };
const updatedTemplate = { ...sampleTemplate, ...updateData };
mockCertificateTemplateV2DAL.findById.mockResolvedValue(sampleTemplate);
@@ -263,7 +265,7 @@ describe("CertificateTemplateV2Service", () => {
service.updateTemplateV2({
...mockActor,
templateId: "nonexistent-template",
data: { name: "Updated Name" }
data: { slug: "updated-name" }
})
).rejects.toThrow(NotFoundError);
});
@@ -1,4 +1,5 @@
import { ForbiddenError } from "@casl/ability";
import slugify from "@sindresorhus/slugify";
import RE2 from "re2";
import { ActionProjectType } from "@app/db/schemas";
@@ -8,6 +9,7 @@ import {
ProjectPermissionSub
} from "@app/ee/services/permission/project-permission";
import { ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
import { alphaNumericNanoId } from "@app/lib/nanoid";
import { ActorAuthMethod, ActorType } from "../auth/auth-type";
import { TCertificateTemplateV2DALFactory } from "./certificate-template-v2-dal";
@@ -115,6 +117,28 @@ export const certificateTemplateV2ServiceFactory = ({
);
};
const generateTemplateSlug = (baseSlug?: string): string => {
if (baseSlug) {
return slugify(baseSlug);
}
return slugify(alphaNumericNanoId(12));
};
const ensureUniqueSlug = async (projectId: string, desiredSlug: string, templateId?: string): Promise<string> => {
const existingTemplate = await certificateTemplateV2DAL.findBySlugAndProjectId(desiredSlug, projectId);
if (!existingTemplate || (templateId && existingTemplate.id === templateId)) {
return desiredSlug;
}
const alternativeSlug = `${desiredSlug}-${alphaNumericNanoId(8)}`;
const existingAlternative = await certificateTemplateV2DAL.findBySlugAndProjectId(alternativeSlug, projectId);
if (!existingAlternative) {
return alternativeSlug;
}
const randomSlug = slugify(alphaNumericNanoId(12));
return randomSlug;
};
const validateRequestAgainstPolicy = (
template: TCertificateTemplateV2,
request: TCertificateRequest
@@ -361,8 +385,12 @@ export const certificateTemplateV2ServiceFactory = ({
keyAlgorithm: data.keyAlgorithm
});
const slug = data.slug || generateTemplateSlug();
const uniqueSlug = await ensureUniqueSlug(projectId, slug);
const template = await certificateTemplateV2DAL.create({
...data,
slug: uniqueSlug,
projectId
});
@@ -417,7 +445,13 @@ export const certificateTemplateV2ServiceFactory = ({
validateTemplatePolicy(mergedPolicy);
}
const updatedTemplate = await certificateTemplateV2DAL.updateById(templateId, data);
const updateData = { ...data };
if (data.slug && typeof data.slug === "string" && data.slug !== existingTemplate.slug) {
const uniqueSlug = await ensureUniqueSlug(existingTemplate.projectId, data.slug, templateId);
updateData.slug = uniqueSlug;
}
const updatedTemplate = await certificateTemplateV2DAL.updateById(templateId, updateData);
if (!updatedTemplate) {
throw new NotFoundError({ message: "Failed to update certificate template" });
}
@@ -459,6 +493,43 @@ export const certificateTemplateV2ServiceFactory = ({
return template;
};
const getTemplateV2BySlug = async ({
actor,
actorId,
actorAuthMethod,
actorOrgId,
projectId,
slug
}: {
actor: ActorType;
actorId: string;
actorAuthMethod: ActorAuthMethod;
actorOrgId: string;
projectId: string;
slug: string;
}): Promise<TCertificateTemplateV2> => {
const { permission } = await permissionService.getProjectPermission({
actor,
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
});
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionPkiTemplateActions.Read,
ProjectPermissionSub.CertificateTemplates
);
const template = await certificateTemplateV2DAL.findBySlugAndProjectId(slug, projectId);
if (!template) {
throw new NotFoundError({ message: "Certificate template not found" });
}
return template;
};
const listTemplatesV2 = async ({
actor,
actorId,
@@ -571,6 +642,7 @@ export const certificateTemplateV2ServiceFactory = ({
createTemplateV2,
updateTemplateV2,
getTemplateV2ById,
getTemplateV2BySlug,
listTemplatesV2,
deleteTemplateV2,
validateCertificateRequest
@@ -74,7 +74,7 @@ export type TCertificateTemplateV2Insert = Omit<
export type TCertificateTemplateV2Update = Partial<
Pick<
TCertificateTemplateV2,
| "name"
| "slug"
| "description"
| "attributes"
| "keyUsages"
@@ -347,7 +347,7 @@ describe("CertificateV3Service", () => {
describe("orderCertificateFromProfile", () => {
const mockCertificateOrder = {
identifiers: [{ type: "dns" as const, value: "example.com" }],
subjectAlternativeNames: [{ type: "dns" as const, value: "example.com" }],
validity: { ttl: "30d" },
commonName: "example.com",
keyUsages: [CertKeyUsage.DIGITAL_SIGNATURE],
@@ -411,8 +411,8 @@ describe("CertificateV3Service", () => {
expect(result).toHaveProperty("orderId");
expect(result).toHaveProperty("status", "valid");
expect(result).toHaveProperty("certificate");
expect(result.identifiers).toHaveLength(1);
expect(result.identifiers[0]).toEqual({
expect(result.subjectAlternativeNames).toHaveLength(1);
expect(result.subjectAlternativeNames[0]).toEqual({
type: "dns",
value: "example.com",
status: "valid"
@@ -293,9 +293,9 @@ export const certificateV3ServiceFactory = ({
commonName: certificateOrder.commonName,
keyUsages: certificateOrder.keyUsages,
extendedKeyUsages: certificateOrder.extendedKeyUsages,
subjectAlternativeNames: certificateOrder.identifiers.map((id) => ({
type: id.type === "dns" ? ("dns_name" as const) : ("ip_address" as const),
value: id.value
subjectAlternativeNames: certificateOrder.subjectAlternativeNames.map((san) => ({
type: san.type === "dns" ? ("dns_name" as const) : ("ip_address" as const),
value: san.value
})),
validity: certificateOrder.validity,
notBefore: certificateOrder.notBefore,
@@ -334,16 +334,16 @@ export const certificateV3ServiceFactory = ({
});
const orderId = randomUUID();
const identifiers = certificateOrder.identifiers.map((id) => ({
type: id.type,
value: id.value,
const subjectAlternativeNames = certificateOrder.subjectAlternativeNames.map((san) => ({
type: san.type,
value: san.value,
status: "valid" as const
}));
const authorizations = certificateOrder.identifiers.map((id) => ({
const authorizations = certificateOrder.subjectAlternativeNames.map((san) => ({
identifier: {
type: id.type,
value: id.value
type: san.type,
value: san.value
},
status: "valid" as const,
expires: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString(),
@@ -360,7 +360,7 @@ export const certificateV3ServiceFactory = ({
return {
orderId,
status: "valid",
identifiers,
subjectAlternativeNames,
authorizations,
finalize: `/api/v3/certificates/orders/${orderId}/finalize`,
certificate: certificateResult.certificate
@@ -35,7 +35,7 @@ export type TSignCertificateFromProfileDTO = {
export type TOrderCertificateFromProfileDTO = {
profileId: string;
certificateOrder: {
identifiers: Array<{
subjectAlternativeNames: Array<{
type: "dns" | "ip";
value: string;
}>;
@@ -64,7 +64,7 @@ export type TCertificateFromProfileResponse = {
export type TCertificateOrderResponse = {
orderId: string;
status: "pending" | "processing" | "valid" | "invalid";
identifiers: Array<{
subjectAlternativeNames: Array<{
type: "dns" | "ip";
value: string;
status: "pending" | "processing" | "valid" | "invalid";
@@ -10,11 +10,11 @@ import { TApiEnrollmentConfigInsert, TApiEnrollmentConfigUpdate } from "./enroll
export type TApiEnrollmentConfigDALFactory = ReturnType<typeof apiEnrollmentConfigDALFactory>;
export const apiEnrollmentConfigDALFactory = (db: TDbClient) => {
const apiEnrollmentConfigOrm = ormify(db, TableName.ApiEnrollmentConfig);
const apiEnrollmentConfigOrm = ormify(db, TableName.PkiApiEnrollmentConfig);
const create = async (data: TApiEnrollmentConfigInsert, tx?: Knex) => {
try {
const [apiConfig] = await (tx || db)(TableName.ApiEnrollmentConfig).insert(data).returning("*");
const [apiConfig] = await (tx || db)(TableName.PkiApiEnrollmentConfig).insert(data).returning("*");
return apiConfig;
} catch (error) {
@@ -24,7 +24,7 @@ export const apiEnrollmentConfigDALFactory = (db: TDbClient) => {
const updateById = async (id: string, data: TApiEnrollmentConfigUpdate, tx?: Knex) => {
try {
const [apiConfig] = await (tx || db)(TableName.ApiEnrollmentConfig).where({ id }).update(data).returning("*");
const [apiConfig] = await (tx || db)(TableName.PkiApiEnrollmentConfig).where({ id }).update(data).returning("*");
return apiConfig;
} catch (error) {
@@ -34,7 +34,7 @@ export const apiEnrollmentConfigDALFactory = (db: TDbClient) => {
const deleteById = async (id: string, tx?: Knex) => {
try {
const [apiConfig] = await (tx || db)(TableName.ApiEnrollmentConfig).where({ id }).del().returning("*");
const [apiConfig] = await (tx || db)(TableName.PkiApiEnrollmentConfig).where({ id }).del().returning("*");
return apiConfig;
} catch (error) {
@@ -44,7 +44,7 @@ export const apiEnrollmentConfigDALFactory = (db: TDbClient) => {
const findById = async (id: string, tx?: Knex) => {
try {
const apiConfig = await (tx || db)(TableName.ApiEnrollmentConfig).where({ id }).first();
const apiConfig = await (tx || db)(TableName.PkiApiEnrollmentConfig).where({ id }).first();
return apiConfig;
} catch (error) {
@@ -60,15 +60,15 @@ export const apiEnrollmentConfigDALFactory = (db: TDbClient) => {
const profiles = await (tx || db)(TableName.CertificateProfile)
.join(
TableName.ApiEnrollmentConfig,
TableName.PkiApiEnrollmentConfig,
`${TableName.CertificateProfile}.apiConfigId`,
`${TableName.ApiEnrollmentConfig}.id`
`${TableName.PkiApiEnrollmentConfig}.id`
)
.where(`${TableName.ApiEnrollmentConfig}.autoRenew`, true)
.where(`${TableName.PkiApiEnrollmentConfig}.autoRenew`, true)
.where((query) => {
void query
.whereNull(`${TableName.ApiEnrollmentConfig}.autoRenewDays`)
.orWhere(`${TableName.ApiEnrollmentConfig}.autoRenewDays`, "<=", renewalThresholdDays);
.whereNull(`${TableName.PkiApiEnrollmentConfig}.autoRenewDays`)
.orWhere(`${TableName.PkiApiEnrollmentConfig}.autoRenewDays`, "<=", renewalThresholdDays);
})
.select((tx || db).ref("id").withSchema(TableName.CertificateProfile))
.select((tx || db).ref("name").withSchema(TableName.CertificateProfile))
@@ -1,21 +1,21 @@
import {
TApiEnrollmentConfigs,
TApiEnrollmentConfigsInsert,
TApiEnrollmentConfigsUpdate
} from "@app/db/schemas/api-enrollment-configs";
TPkiApiEnrollmentConfigs,
TPkiApiEnrollmentConfigsInsert,
TPkiApiEnrollmentConfigsUpdate
} from "@app/db/schemas/pki-api-enrollment-configs";
import {
TEstEnrollmentConfigs,
TEstEnrollmentConfigsInsert,
TEstEnrollmentConfigsUpdate
} from "@app/db/schemas/est-enrollment-configs";
TPkiEstEnrollmentConfigs,
TPkiEstEnrollmentConfigsInsert,
TPkiEstEnrollmentConfigsUpdate
} from "@app/db/schemas/pki-est-enrollment-configs";
export type TEstEnrollmentConfig = TEstEnrollmentConfigs;
export type TEstEnrollmentConfigInsert = TEstEnrollmentConfigsInsert;
export type TEstEnrollmentConfigUpdate = TEstEnrollmentConfigsUpdate;
export type TEstEnrollmentConfig = TPkiEstEnrollmentConfigs;
export type TEstEnrollmentConfigInsert = TPkiEstEnrollmentConfigsInsert;
export type TEstEnrollmentConfigUpdate = TPkiEstEnrollmentConfigsUpdate;
export type TApiEnrollmentConfig = TApiEnrollmentConfigs;
export type TApiEnrollmentConfigInsert = TApiEnrollmentConfigsInsert;
export type TApiEnrollmentConfigUpdate = TApiEnrollmentConfigsUpdate;
export type TApiEnrollmentConfig = TPkiApiEnrollmentConfigs;
export type TApiEnrollmentConfigInsert = TPkiApiEnrollmentConfigsInsert;
export type TApiEnrollmentConfigUpdate = TPkiApiEnrollmentConfigsUpdate;
export interface TEstConfigData {
disableBootstrapCaValidation: boolean;
@@ -10,11 +10,11 @@ import { TEstEnrollmentConfigInsert, TEstEnrollmentConfigUpdate } from "./enroll
export type TEstEnrollmentConfigDALFactory = ReturnType<typeof estEnrollmentConfigDALFactory>;
export const estEnrollmentConfigDALFactory = (db: TDbClient) => {
const estEnrollmentConfigOrm = ormify(db, TableName.EstEnrollmentConfig);
const estEnrollmentConfigOrm = ormify(db, TableName.PkiEstEnrollmentConfig);
const create = async (data: TEstEnrollmentConfigInsert, tx?: Knex) => {
try {
const [estConfig] = await (tx || db)(TableName.EstEnrollmentConfig).insert(data).returning("*");
const [estConfig] = await (tx || db)(TableName.PkiEstEnrollmentConfig).insert(data).returning("*");
return estConfig;
} catch (error) {
@@ -24,7 +24,7 @@ export const estEnrollmentConfigDALFactory = (db: TDbClient) => {
const updateById = async (id: string, data: TEstEnrollmentConfigUpdate, tx?: Knex) => {
try {
const [estConfig] = await (tx || db)(TableName.EstEnrollmentConfig).where({ id }).update(data).returning("*");
const [estConfig] = await (tx || db)(TableName.PkiEstEnrollmentConfig).where({ id }).update(data).returning("*");
return estConfig;
} catch (error) {
@@ -34,7 +34,7 @@ export const estEnrollmentConfigDALFactory = (db: TDbClient) => {
const deleteById = async (id: string, tx?: Knex) => {
try {
const [estConfig] = await (tx || db)(TableName.EstEnrollmentConfig).where({ id }).del().returning("*");
const [estConfig] = await (tx || db)(TableName.PkiEstEnrollmentConfig).where({ id }).del().returning("*");
return estConfig;
} catch (error) {
@@ -44,7 +44,7 @@ export const estEnrollmentConfigDALFactory = (db: TDbClient) => {
const findById = async (id: string, tx?: Knex) => {
try {
const estConfig = await (tx || db)(TableName.EstEnrollmentConfig).where({ id }).first();
const estConfig = await (tx || db)(TableName.PkiEstEnrollmentConfig).where({ id }).first();
return estConfig;
} catch (error) {