Revert queue stuff

This commit is contained in:
Fang-Pen Lin
2025-10-31 13:32:29 -07:00
parent 0613a49795
commit aa62e465a0
5 changed files with 34 additions and 97 deletions

View File

@@ -1,56 +0,0 @@
import { Knex } from "knex";
import { QueueJobs, QueueName, TQueueServiceFactory } from "@app/queue";
import { TPkiAcmeAuthDALFactory } from "./pki-acme-auth-dal";
import { TPkiAcmeChallengeDALFactory } from "./pki-acme-challenge-dal";
import { TPkiAcmeChallengeServiceFactory } from "./pki-acme-types";
// Define types for job data
export type TValidateAcmeChallengeResponseDTO = {
challengeId: string;
};
type TChallengeQueueServiceFactoryDep = {
queueService: Pick<TQueueServiceFactory, "queuePg" | "startPg">;
acmeChallengeDAL: Pick<TPkiAcmeChallengeDALFactory, "transaction" | "findByIdForChallengeValidation" | "updateById">;
acmeAuthDAL: Pick<TPkiAcmeAuthDALFactory, "updateById">;
acmeChallengeService: TPkiAcmeChallengeServiceFactory;
};
export type TFolderCommitQueueServiceFactory = ReturnType<typeof challengeQueueServiceFactory>;
export const challengeQueueServiceFactory = ({
queueService,
acmeChallengeService
}: TChallengeQueueServiceFactoryDep) => {
const scheduleChallengeValidation = async (payload: TValidateAcmeChallengeResponseDTO) => {
const { challengeId } = payload;
await queueService.queuePg<QueueName.PkiAcmeChallengeValidation>(QueueJobs.ValidateAcmeChallengeResponse, payload, {
// TODO: maybe we should retry, but let's keep it simple for now
});
};
const validateAcmeChallengeResponse = async (jobData: TValidateAcmeChallengeResponseDTO, tx?: Knex) => {
const { challengeId } = jobData;
await acmeChallengeService.validateChallengeResponse(challengeId);
};
const init = async () => {
await queueService.startPg<QueueName.PkiAcmeChallengeValidation>(
QueueJobs.ValidateAcmeChallengeResponse,
async ([job]) => {
await validateAcmeChallengeResponse(job.data as TValidateAcmeChallengeResponseDTO);
},
{
workerCount: 5,
pollingIntervalSeconds: 30
}
);
};
return {
scheduleChallengeValidation,
init
};
};

View File

@@ -5,6 +5,7 @@ import { BadRequestError, NotFoundError } from "@app/lib/errors";
import { logger } from "@app/lib/logger";
import { TPkiAcmeAuthDALFactory } from "./pki-acme-auth-dal";
import { TPkiAcmeChallengeDALFactory } from "./pki-acme-challenge-dal";
import { AcmeIncorrectResponseError } from "./pki-acme-errors";
import { AcmeAuthStatus, AcmeChallengeStatus, AcmeChallengeType } from "./pki-acme-schemas";
import { TPkiAcmeChallengeServiceFactory } from "./pki-acme-types";
@@ -62,7 +63,7 @@ export const pkiAcmeChallengeServiceFactory = ({
const thumbprint = Buffer.from(challenge.auth.account.publicKeyThumbprint, "utf-8").toString("base64url");
const expectedChallengeResponseBody = `${challenge.auth.token}.${thumbprint}`;
if (challengeResponseBody !== expectedChallengeResponseBody) {
throw new BadRequestError({ message: "ACME challenge response is not correct" });
throw new AcmeIncorrectResponseError({ message: "ACME challenge response is not correct" });
}
await acmeChallengeDAL.updateById(
challengeId,
@@ -70,12 +71,13 @@ export const pkiAcmeChallengeServiceFactory = ({
tx
);
await acmeAuthDAL.updateById(challenge.auth.account.id, { status: AcmeAuthStatus.Valid }, tx);
await acmeAuthDAL.updateById(challenge.auth.account.id, { status: AcmeAuthStatus.Valid }, tx);
// TODO: trigger a check for order status as well
} catch (error) {
logger.error(error, "Error validating ACME challenge response");
// TODO: we should retry the challenge validation a few times, but let's keep it simple for now
await acmeChallengeDAL.updateById(challengeId, { status: AcmeChallengeStatus.Invalid }, tx);
await acmeAuthDAL.updateById(challenge.auth.account.id, { status: AcmeAuthStatus.Invalid }, tx);
// TODO: trigger a check for order status as well
throw error;
}
});

View File

@@ -434,3 +434,27 @@ export class AcmeUserActionRequiredError extends AcmeError {
};
}
}
/**
* incorrectResponse - The response is incorrect (RFC 8555 Section 6.7.16)
*/
export class AcmeIncorrectResponseError extends AcmeError {
constructor({
detail = "The response is incorrect",
error,
message
}: {
detail?: string;
error?: unknown;
message?: string;
} = {}) {
super({
type: "incorrectResponse",
detail,
status: 400,
error,
message
});
this.name = "AcmeIncorrectResponseError";
}
}

View File

@@ -75,6 +75,7 @@ type TPkiAcmeServiceFactoryDep = {
TPkiAcmeChallengeDALFactory,
"create" | "transaction" | "updateById" | "findByAccountAuthAndChallengeId" | "findByIdForChallengeValidation"
>;
acmeChallengeService: TPkiAcmeChallengeServiceFactory;
};
export const pkiAcmeServiceFactory = ({
@@ -83,7 +84,8 @@ export const pkiAcmeServiceFactory = ({
acmeOrderDAL,
acmeAuthDAL,
acmeOrderAuthDAL,
acmeChallengeDAL
acmeChallengeDAL,
acmeChallengeService
}: TPkiAcmeServiceFactoryDep): TPkiAcmeServiceFactory => {
const validateAcmeProfile = async (profileId: string): Promise<TCertificateProfileWithConfigs> => {
const profile = await certificateProfileDAL.findById(profileId);
@@ -610,35 +612,7 @@ export const pkiAcmeServiceFactory = ({
throw new NotFoundError({ message: "ACME challenge not found" });
}
const challenge = await acmeChallengeDAL.transaction(async (tx) => {
const challenge = await acmeChallengeDAL.findByIdForChallengeValidation(challengeId, tx);
if (!challenge) {
throw new NotFoundError({ message: "ACME challenge not found" });
}
if (challenge.status !== AcmeChallengeStatus.Pending) {
// Ideally this should be an ACME error, but RFC 8555 doesn't say much about corner cases like this...
throw new BadRequestError({
message: `ACME challenge is ${challenge.status} instead of ${AcmeChallengeStatus.Pending}`
});
}
if (challenge.auth.expiresAt < new Date()) {
throw new BadRequestError({ message: "ACME auth has expired" });
}
if (challenge.auth.status !== AcmeAuthStatus.Pending) {
throw new BadRequestError({
message: `ACME auth status is ${challenge.auth.status} instead of ${AcmeAuthStatus.Pending}`
});
}
if (!challenge.auth.token) {
throw new AcmeServerInternalError({ message: "ACME challenge token is required" });
}
if (challenge.type !== AcmeChallengeType.HTTP_01) {
throw new BadRequestError({ message: "Only HTTP-01 challenges are supported for now" });
}
const updatedChallenge = await acmeChallengeDAL.updateById(
challengeId,
{ status: AcmeChallengeStatus.Pending },
tx
);
await acmeChallengeService.validateChallengeResponse(challengeId, tx);
return {
...challenge,
...updatedChallenge

View File

@@ -42,7 +42,6 @@ import {
} from "@app/services/secret-sync/secret-sync-types";
import { CacheType } from "@app/services/super-admin/super-admin-types";
import { TWebhookPayloads } from "@app/services/webhook/webhook-types";
import { TValidateAcmeChallengeResponseDTO } from "@app/ee/services/pki-acme/pki-acme-challenge-queue";
export enum QueueName {
SecretRotation = "secret-rotation",
@@ -80,8 +79,7 @@ export enum QueueName {
UserNotification = "user-notification",
HealthAlert = "health-alert",
CertificateV3AutoRenewal = "certificate-v3-auto-renewal",
PamAccountRotation = "pam-account-rotation",
PkiAcmeChallengeValidation = "pki-acme-challenge-validation"
PamAccountRotation = "pam-account-rotation"
}
export enum QueueJobs {
@@ -132,8 +130,7 @@ export enum QueueJobs {
UserNotification = "user-notification-job",
HealthAlert = "health-alert",
CertificateV3DailyAutoRenewal = "certificate-v3-daily-auto-renewal",
PamAccountRotation = "pam-account-rotation",
ValidateAcmeChallengeResponse = "validate-acme-challenge-response"
PamAccountRotation = "pam-account-rotation"
}
export type TQueueJobTypes = {
@@ -372,10 +369,6 @@ export type TQueueJobTypes = {
name: QueueJobs.PamAccountRotation;
payload: undefined;
};
[QueueName.PkiAcmeChallengeValidation]: {
name: QueueJobs.ValidateAcmeChallengeResponse;
payload: TValidateAcmeChallengeResponseDTO;
};
};
const SECRET_SCANNING_JOBS = [