From aa62e465a0a2d49c4e84897c89390c7713c2ecdd Mon Sep 17 00:00:00 2001 From: Fang-Pen Lin Date: Fri, 31 Oct 2025 13:32:29 -0700 Subject: [PATCH] Revert queue stuff --- .../pki-acme/pki-acme-challenge-queue.ts | 56 ------------------- .../pki-acme/pki-acme-challenge-service.ts | 6 +- .../ee/services/pki-acme/pki-acme-errors.ts | 24 ++++++++ .../ee/services/pki-acme/pki-acme-service.ts | 34 ++--------- backend/src/queue/queue-service.ts | 11 +--- 5 files changed, 34 insertions(+), 97 deletions(-) delete mode 100644 backend/src/ee/services/pki-acme/pki-acme-challenge-queue.ts diff --git a/backend/src/ee/services/pki-acme/pki-acme-challenge-queue.ts b/backend/src/ee/services/pki-acme/pki-acme-challenge-queue.ts deleted file mode 100644 index 1c42f6327..000000000 --- a/backend/src/ee/services/pki-acme/pki-acme-challenge-queue.ts +++ /dev/null @@ -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; - acmeChallengeDAL: Pick; - acmeAuthDAL: Pick; - acmeChallengeService: TPkiAcmeChallengeServiceFactory; -}; - -export type TFolderCommitQueueServiceFactory = ReturnType; - -export const challengeQueueServiceFactory = ({ - queueService, - acmeChallengeService -}: TChallengeQueueServiceFactoryDep) => { - const scheduleChallengeValidation = async (payload: TValidateAcmeChallengeResponseDTO) => { - const { challengeId } = payload; - await queueService.queuePg(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( - QueueJobs.ValidateAcmeChallengeResponse, - async ([job]) => { - await validateAcmeChallengeResponse(job.data as TValidateAcmeChallengeResponseDTO); - }, - { - workerCount: 5, - pollingIntervalSeconds: 30 - } - ); - }; - - return { - scheduleChallengeValidation, - init - }; -}; diff --git a/backend/src/ee/services/pki-acme/pki-acme-challenge-service.ts b/backend/src/ee/services/pki-acme/pki-acme-challenge-service.ts index 9091b6926..be46de35a 100644 --- a/backend/src/ee/services/pki-acme/pki-acme-challenge-service.ts +++ b/backend/src/ee/services/pki-acme/pki-acme-challenge-service.ts @@ -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; } }); diff --git a/backend/src/ee/services/pki-acme/pki-acme-errors.ts b/backend/src/ee/services/pki-acme/pki-acme-errors.ts index 85de5cb1c..b09499346 100644 --- a/backend/src/ee/services/pki-acme/pki-acme-errors.ts +++ b/backend/src/ee/services/pki-acme/pki-acme-errors.ts @@ -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"; + } +} diff --git a/backend/src/ee/services/pki-acme/pki-acme-service.ts b/backend/src/ee/services/pki-acme/pki-acme-service.ts index 8cc96c1b0..a4916c555 100644 --- a/backend/src/ee/services/pki-acme/pki-acme-service.ts +++ b/backend/src/ee/services/pki-acme/pki-acme-service.ts @@ -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 => { 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 diff --git a/backend/src/queue/queue-service.ts b/backend/src/queue/queue-service.ts index e0bd0204c..3e6b1dd19 100644 --- a/backend/src/queue/queue-service.ts +++ b/backend/src/queue/queue-service.ts @@ -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 = [