mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-09 18:28:27 +00:00
Add queue stuff
This commit is contained in:
@@ -107,7 +107,7 @@ export async function up(knex: Knex): Promise<void> {
|
|||||||
t.string("status").notNullable(); // pending, valid, invalid, deactivated, expired, revoked
|
t.string("status").notNullable(); // pending, valid, invalid, deactivated, expired, revoked
|
||||||
|
|
||||||
// Token used to validate the authorization through ACME challenge
|
// Token used to validate the authorization through ACME challenge
|
||||||
t.timestamp("token").nullable();
|
t.string("token").nullable();
|
||||||
|
|
||||||
// Identifier type and value
|
// Identifier type and value
|
||||||
t.string("identifierType").notNullable(); // dns
|
t.string("identifierType").notNullable(); // dns
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export const PkiAcmeAuthsSchema = z.object({
|
|||||||
id: z.string().uuid(),
|
id: z.string().uuid(),
|
||||||
accountId: z.string().uuid(),
|
accountId: z.string().uuid(),
|
||||||
status: z.string(),
|
status: z.string(),
|
||||||
token: z.date().nullable().optional(),
|
token: z.string().nullable().optional(),
|
||||||
identifierType: z.string(),
|
identifierType: z.string(),
|
||||||
identifierValue: z.string(),
|
identifierValue: z.string(),
|
||||||
expiresAt: z.date(),
|
expiresAt: z.date(),
|
||||||
|
|||||||
@@ -9,19 +9,11 @@ export type TPkiAcmeChallengeDALFactory = ReturnType<typeof pkiAcmeChallengeDALF
|
|||||||
export const pkiAcmeChallengeDALFactory = (db: TDbClient) => {
|
export const pkiAcmeChallengeDALFactory = (db: TDbClient) => {
|
||||||
const pkiAcmeChallengeOrm = ormify(db, TableName.PkiAcmeChallenge);
|
const pkiAcmeChallengeOrm = ormify(db, TableName.PkiAcmeChallenge);
|
||||||
|
|
||||||
const findByAccountAuthAndChallengeIdWithToken = async (
|
const findByAccountAuthAndChallengeId = async (accountId: string, authId: string, challengeId: string, tx?: Knex) => {
|
||||||
accountId: string,
|
|
||||||
authId: string,
|
|
||||||
challengeId: string,
|
|
||||||
tx?: Knex
|
|
||||||
) => {
|
|
||||||
try {
|
try {
|
||||||
const challenge = await (tx || db)(TableName.PkiAcmeChallenge)
|
const challenge = await (tx || db)(TableName.PkiAcmeChallenge)
|
||||||
.join(TableName.PkiAcmeAuth, `${TableName.PkiAcmeChallenge}.authId`, `${TableName.PkiAcmeAuth}.id`)
|
.join(TableName.PkiAcmeAuth, `${TableName.PkiAcmeChallenge}.authId`, `${TableName.PkiAcmeAuth}.id`)
|
||||||
.select(
|
.select(selectAllTableCols(TableName.PkiAcmeChallenge))
|
||||||
selectAllTableCols(TableName.PkiAcmeChallenge),
|
|
||||||
db.ref("token").withSchema(TableName.PkiAcmeAuth).as("token")
|
|
||||||
)
|
|
||||||
.where(`${TableName.PkiAcmeChallenge}.id`, challengeId)
|
.where(`${TableName.PkiAcmeChallenge}.id`, challengeId)
|
||||||
.where(`${TableName.PkiAcmeChallenge}.authId`, authId)
|
.where(`${TableName.PkiAcmeChallenge}.authId`, authId)
|
||||||
.where(`${TableName.PkiAcmeAuth}.accountId`, accountId)
|
.where(`${TableName.PkiAcmeAuth}.accountId`, accountId)
|
||||||
@@ -34,14 +26,11 @@ export const pkiAcmeChallengeDALFactory = (db: TDbClient) => {
|
|||||||
throw new DatabaseError({ error, name: "Find PKI ACME challenge by account id, auth id and challenge id" });
|
throw new DatabaseError({ error, name: "Find PKI ACME challenge by account id, auth id and challenge id" });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const findByIdForChallengeValidation = async (id: string, tx?: Knex) => {
|
const findByIdForChallengeValidation = async (id: string, tx?: Knex) => {
|
||||||
const rows = await (tx || db)(TableName.PkiAcmeChallenge)
|
const result = await (tx || db)(TableName.PkiAcmeChallenge)
|
||||||
.join<TPkiAcmeAuths>(TableName.PkiAcmeAuth, `${TableName.PkiAcmeChallenge}.authId`, `${TableName.PkiAcmeAuth}.id`)
|
.join(TableName.PkiAcmeAuth, `${TableName.PkiAcmeChallenge}.authId`, `${TableName.PkiAcmeAuth}.id`)
|
||||||
.join<TPkiAcmeAccounts>(
|
.join(TableName.PkiAcmeAccount, `${TableName.PkiAcmeAuth}.accountId`, `${TableName.PkiAcmeAccount}.id`)
|
||||||
TableName.PkiAcmeAccount,
|
|
||||||
`${TableName.PkiAcmeAuth}.accountId`,
|
|
||||||
`${TableName.PkiAcmeAccount}.id`
|
|
||||||
)
|
|
||||||
.select(
|
.select(
|
||||||
selectAllTableCols(TableName.PkiAcmeChallenge),
|
selectAllTableCols(TableName.PkiAcmeChallenge),
|
||||||
db.ref("id").withSchema(TableName.PkiAcmeAuth).as("authId"),
|
db.ref("id").withSchema(TableName.PkiAcmeAuth).as("authId"),
|
||||||
@@ -55,45 +44,41 @@ export const pkiAcmeChallengeDALFactory = (db: TDbClient) => {
|
|||||||
)
|
)
|
||||||
// For all challenges, acquire update lock on the auth to avoid race conditions
|
// For all challenges, acquire update lock on the auth to avoid race conditions
|
||||||
.forUpdate(TableName.PkiAcmeAuth)
|
.forUpdate(TableName.PkiAcmeAuth)
|
||||||
.where(`${TableName.PkiAcmeChallenge}.id`, id);
|
.where(`${TableName.PkiAcmeChallenge}.id`, id)
|
||||||
|
.first();
|
||||||
if (rows.length === 0) {
|
if (!result) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return sqlNestRelationships({
|
const {
|
||||||
data: rows,
|
authId,
|
||||||
key: "id",
|
authToken,
|
||||||
parentMapper: (row) => row,
|
authStatus,
|
||||||
childrenMapper: [
|
authIdentifierType,
|
||||||
{
|
authIdentifierValue,
|
||||||
key: "authId",
|
authExpiresAt,
|
||||||
label: "auth" as const,
|
accountId,
|
||||||
mapper: ({ authId, authToken, authStatus, authIdentifierType, authIdentifierValue, authExpiresAt }) => ({
|
accountPublicKeyThumbprint,
|
||||||
id: authId,
|
...challenge
|
||||||
token: authToken,
|
} = result;
|
||||||
status: authStatus,
|
return {
|
||||||
identifierType: authIdentifierType,
|
...challenge,
|
||||||
identifierValue: authIdentifierValue,
|
auth: {
|
||||||
expiresAt: authExpiresAt
|
token: authToken,
|
||||||
}),
|
status: authStatus,
|
||||||
childrenMapper: [
|
identifierType: authIdentifierType,
|
||||||
{
|
identifierValue: authIdentifierValue,
|
||||||
key: "accountId",
|
expiresAt: authExpiresAt,
|
||||||
label: "account" as const,
|
account: {
|
||||||
mapper: ({ accountId, accountPublicKeyThumbprint }) => ({
|
id: accountId,
|
||||||
id: accountId,
|
publicKeyThumbprint: accountPublicKeyThumbprint
|
||||||
publicKeyThumbprint: accountPublicKeyThumbprint
|
|
||||||
})
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
})?.[0];
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...pkiAcmeChallengeOrm,
|
...pkiAcmeChallengeOrm,
|
||||||
findByAccountAuthAndChallengeIdWithToken,
|
findByAccountAuthAndChallengeId,
|
||||||
findByIdForChallengeValidation
|
findByIdForChallengeValidation
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
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
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -1,21 +1,25 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { getConfig } from "@app/lib/config/env";
|
||||||
import { BadRequestError, NotFoundError } from "@app/lib/errors";
|
import { BadRequestError, NotFoundError } from "@app/lib/errors";
|
||||||
|
import { TPkiAcmeAuthDALFactory } from "./pki-acme-auth-dal";
|
||||||
import { TPkiAcmeChallengeDALFactory } from "./pki-acme-challenge-dal";
|
import { TPkiAcmeChallengeDALFactory } from "./pki-acme-challenge-dal";
|
||||||
import { AcmeAuthStatus, AcmeChallengeStatus, AcmeChallengeType } from "./pki-acme-schemas";
|
import { AcmeAuthStatus, AcmeChallengeStatus, AcmeChallengeType } from "./pki-acme-schemas";
|
||||||
import { TPkiAcmeChallengeServiceFactory } from "./pki-acme-types";
|
import { TPkiAcmeChallengeServiceFactory } from "./pki-acme-types";
|
||||||
import { getConfig } from "@app/lib/config/env";
|
|
||||||
import { calculateJwkThumbprint } from "jose";
|
|
||||||
|
|
||||||
type TPkiAcmeChallengeServiceFactoryDep = {
|
type TPkiAcmeChallengeServiceFactoryDep = {
|
||||||
acmeChallengeDAL: Pick<TPkiAcmeChallengeDALFactory, "transaction" | "findByIdForChallengeValidation">;
|
acmeAuthDAL: Pick<TPkiAcmeAuthDALFactory, "updateById">;
|
||||||
|
acmeChallengeDAL: Pick<TPkiAcmeChallengeDALFactory, "transaction" | "findByIdForChallengeValidation" | "updateById">;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const pkiAcmeChallengeServiceFactory = ({
|
export const pkiAcmeChallengeServiceFactory = ({
|
||||||
|
acmeAuthDAL,
|
||||||
acmeChallengeDAL
|
acmeChallengeDAL
|
||||||
}: TPkiAcmeChallengeServiceFactoryDep): TPkiAcmeChallengeServiceFactory => {
|
}: TPkiAcmeChallengeServiceFactoryDep): TPkiAcmeChallengeServiceFactory => {
|
||||||
const appCfg = getConfig();
|
const appCfg = getConfig();
|
||||||
|
|
||||||
const validateChallengeResponse = async (challengeId: string): Promise<void> => {
|
const validateChallengeResponse = async (challengeId: string): Promise<void> => {
|
||||||
return await acmeChallengeDAL.transaction(async (tx) => {
|
return await acmeChallengeDAL.transaction(async (tx: Knex) => {
|
||||||
const challenge = await acmeChallengeDAL.findByIdForChallengeValidation(challengeId, tx);
|
const challenge = await acmeChallengeDAL.findByIdForChallengeValidation(challengeId, tx);
|
||||||
if (!challenge) {
|
if (!challenge) {
|
||||||
throw new NotFoundError({ message: "ACME challenge not found" });
|
throw new NotFoundError({ message: "ACME challenge not found" });
|
||||||
@@ -43,13 +47,27 @@ export const pkiAcmeChallengeServiceFactory = ({
|
|||||||
? `${baseUrl}:${appCfg.ACME_DEVELOPMENT_HTTP01_CHALLENGE_PORT}`
|
? `${baseUrl}:${appCfg.ACME_DEVELOPMENT_HTTP01_CHALLENGE_PORT}`
|
||||||
: baseUrl;
|
: baseUrl;
|
||||||
|
|
||||||
const challengeUrl = new URL(`/.well-known/acme-challenge/${challenge.token}`, actualBaseUrl);
|
const challengeUrl = new URL(`/.well-known/acme-challenge/${challenge.auth.token}`, actualBaseUrl);
|
||||||
|
// Notice: well, we are in a transaction, ideally we should not hold transaction and perform
|
||||||
|
// a long running operation for long time. But assuming we are not performing a tons of
|
||||||
|
// challenge validation at the same time, it should be fine.
|
||||||
|
// TODO: bound it with timeout of the fetch request
|
||||||
const challengeResponse = await fetch(challengeUrl);
|
const challengeResponse = await fetch(challengeUrl);
|
||||||
if (challengeResponse.status !== 200) {
|
if (challengeResponse.status !== 200) {
|
||||||
throw new BadRequestError({ message: "ACME challenge response is not 200" });
|
throw new BadRequestError({ message: "ACME challenge response is not 200" });
|
||||||
}
|
}
|
||||||
const challengeResponseBody = await challengeResponse.text();
|
const challengeResponseBody = await challengeResponse.text();
|
||||||
const expectedChallengeResponseBody = `${challenge.token}.${challenge.auth.identifierValue}`;
|
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" });
|
||||||
|
}
|
||||||
|
await acmeChallengeDAL.updateById(
|
||||||
|
challengeId,
|
||||||
|
{ status: AcmeChallengeStatus.Valid, validatedAt: new Date() },
|
||||||
|
tx
|
||||||
|
);
|
||||||
|
await acmeAuthDAL.updateById(challenge.auth.account.id, { status: AcmeAuthStatus.Valid }, tx);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -13,16 +13,8 @@ export const pkiAcmeOrderDALFactory = (db: TDbClient) => {
|
|||||||
const findByAccountAndOrderIdWithAuthorizations = async (accountId: string, orderId: string, tx?: Knex) => {
|
const findByAccountAndOrderIdWithAuthorizations = async (accountId: string, orderId: string, tx?: Knex) => {
|
||||||
try {
|
try {
|
||||||
const rows = await (tx || db)(TableName.PkiAcmeOrder)
|
const rows = await (tx || db)(TableName.PkiAcmeOrder)
|
||||||
.join<TPkiAcmeOrderAuths>(
|
.join(TableName.PkiAcmeOrderAuth, `${TableName.PkiAcmeOrderAuth}.orderId`, `${TableName.PkiAcmeOrder}.id`)
|
||||||
TableName.PkiAcmeOrderAuth,
|
.join(TableName.PkiAcmeAuth, `${TableName.PkiAcmeOrderAuth}.authId`, `${TableName.PkiAcmeAuth}.id`)
|
||||||
`${TableName.PkiAcmeOrderAuth}.orderId`,
|
|
||||||
`${TableName.PkiAcmeOrder}.id`
|
|
||||||
)
|
|
||||||
.join<TPkiAcmeAuths>(
|
|
||||||
TableName.PkiAcmeAuth,
|
|
||||||
`${TableName.PkiAcmeOrderAuth}.authId`,
|
|
||||||
`${TableName.PkiAcmeAuth}.id`
|
|
||||||
)
|
|
||||||
.select(
|
.select(
|
||||||
selectAllTableCols(TableName.PkiAcmeOrder),
|
selectAllTableCols(TableName.PkiAcmeOrder),
|
||||||
db.ref("id").withSchema(TableName.PkiAcmeAuth).as("authId"),
|
db.ref("id").withSchema(TableName.PkiAcmeAuth).as("authId"),
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { TPkiAcmeAccounts } from "@app/db/schemas/pki-acme-accounts";
|
|||||||
import { TPkiAcmeAuths } from "@app/db/schemas/pki-acme-auths";
|
import { TPkiAcmeAuths } from "@app/db/schemas/pki-acme-auths";
|
||||||
import { getConfig } from "@app/lib/config/env";
|
import { getConfig } from "@app/lib/config/env";
|
||||||
import { crypto } from "@app/lib/crypto/cryptography";
|
import { crypto } from "@app/lib/crypto/cryptography";
|
||||||
import { NotFoundError } from "@app/lib/errors";
|
import { BadRequestError, NotFoundError } from "@app/lib/errors";
|
||||||
import { logger } from "@app/lib/logger";
|
import { logger } from "@app/lib/logger";
|
||||||
import { TCertificateProfileDALFactory } from "@app/services/certificate-profile/certificate-profile-dal";
|
import { TCertificateProfileDALFactory } from "@app/services/certificate-profile/certificate-profile-dal";
|
||||||
|
|
||||||
@@ -71,7 +71,10 @@ type TPkiAcmeServiceFactoryDep = {
|
|||||||
acmeOrderDAL: Pick<TPkiAcmeOrderDALFactory, "create" | "transaction" | "findByAccountAndOrderIdWithAuthorizations">;
|
acmeOrderDAL: Pick<TPkiAcmeOrderDALFactory, "create" | "transaction" | "findByAccountAndOrderIdWithAuthorizations">;
|
||||||
acmeAuthDAL: Pick<TPkiAcmeAuthDALFactory, "create" | "findByAccountIdAndAuthIdWithChallenges">;
|
acmeAuthDAL: Pick<TPkiAcmeAuthDALFactory, "create" | "findByAccountIdAndAuthIdWithChallenges">;
|
||||||
acmeOrderAuthDAL: Pick<TPkiAcmeOrderAuthDALFactory, "insertMany">;
|
acmeOrderAuthDAL: Pick<TPkiAcmeOrderAuthDALFactory, "insertMany">;
|
||||||
acmeChallengeDAL: Pick<TPkiAcmeChallengeDALFactory, "create" | "findByAccountAuthAndChallengeIdWithToken">;
|
acmeChallengeDAL: Pick<
|
||||||
|
TPkiAcmeChallengeDALFactory,
|
||||||
|
"create" | "transaction" | "updateById" | "findByAccountAuthAndChallengeId" | "findByIdForChallengeValidation"
|
||||||
|
>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const pkiAcmeServiceFactory = ({
|
export const pkiAcmeServiceFactory = ({
|
||||||
@@ -575,7 +578,7 @@ export const pkiAcmeServiceFactory = ({
|
|||||||
type: auth.identifierType,
|
type: auth.identifierType,
|
||||||
value: auth.identifierValue
|
value: auth.identifierValue
|
||||||
},
|
},
|
||||||
challenges: auth.challenges.map((challenge: TPkiAcmeChallenges) => {
|
challenges: auth.challenges.map((challenge) => {
|
||||||
return {
|
return {
|
||||||
type: challenge.type,
|
type: challenge.type,
|
||||||
url: buildUrl(profileId, `/authorizations/${authzId}/challenges/${challenge.id}`),
|
url: buildUrl(profileId, `/authorizations/${authzId}/challenges/${challenge.id}`),
|
||||||
@@ -602,10 +605,42 @@ export const pkiAcmeServiceFactory = ({
|
|||||||
authzId: string;
|
authzId: string;
|
||||||
challengeId: string;
|
challengeId: string;
|
||||||
}): Promise<TAcmeResponse<TRespondToAcmeChallengeResponse>> => {
|
}): Promise<TAcmeResponse<TRespondToAcmeChallengeResponse>> => {
|
||||||
const challenge = await acmeChallengeDAL.findByAccountAuthAndChallengeIdWithToken(accountId, authzId, challengeId);
|
const result = await acmeChallengeDAL.findByAccountAuthAndChallengeId(accountId, authzId, challengeId);
|
||||||
if (!challenge) {
|
if (!result) {
|
||||||
throw new NotFoundError({ message: "ACME challenge not found" });
|
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" });
|
||||||
|
}
|
||||||
|
const updatedChallenge = await acmeChallengeDAL.updateById(
|
||||||
|
challengeId,
|
||||||
|
{ status: AcmeChallengeStatus.Pending },
|
||||||
|
tx
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
...challenge,
|
||||||
|
...updatedChallenge
|
||||||
|
};
|
||||||
|
});
|
||||||
// TODO: Implement ACME challenge response
|
// TODO: Implement ACME challenge response
|
||||||
return {
|
return {
|
||||||
status: 200,
|
status: 200,
|
||||||
@@ -613,7 +648,7 @@ export const pkiAcmeServiceFactory = ({
|
|||||||
type: challenge.type,
|
type: challenge.type,
|
||||||
url: buildUrl(profileId, `/authorizations/${authzId}/challenges/${challengeId}`),
|
url: buildUrl(profileId, `/authorizations/${authzId}/challenges/${challengeId}`),
|
||||||
status: challenge.status,
|
status: challenge.status,
|
||||||
token: challenge.token
|
token: challenge.auth.token!
|
||||||
},
|
},
|
||||||
headers: {
|
headers: {
|
||||||
Location: buildUrl(profileId, `/authorizations/${authzId}/challenges/${challengeId}`),
|
Location: buildUrl(profileId, `/authorizations/${authzId}/challenges/${challengeId}`),
|
||||||
|
|||||||
@@ -175,4 +175,6 @@ export type TPkiAcmeServiceFactory = {
|
|||||||
}) => Promise<TAcmeResponse<TRespondToAcmeChallengeResponse>>;
|
}) => Promise<TAcmeResponse<TRespondToAcmeChallengeResponse>>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TPkiAcmeChallengeServiceFactory = {};
|
export type TPkiAcmeChallengeServiceFactory = {
|
||||||
|
validateChallengeResponse: (challengeId: string) => Promise<void>;
|
||||||
|
};
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ import {
|
|||||||
} from "@app/services/secret-sync/secret-sync-types";
|
} from "@app/services/secret-sync/secret-sync-types";
|
||||||
import { CacheType } from "@app/services/super-admin/super-admin-types";
|
import { CacheType } from "@app/services/super-admin/super-admin-types";
|
||||||
import { TWebhookPayloads } from "@app/services/webhook/webhook-types";
|
import { TWebhookPayloads } from "@app/services/webhook/webhook-types";
|
||||||
|
import { TValidateAcmeChallengeResponseDTO } from "@app/ee/services/pki-acme/pki-acme-challenge-queue";
|
||||||
|
|
||||||
export enum QueueName {
|
export enum QueueName {
|
||||||
SecretRotation = "secret-rotation",
|
SecretRotation = "secret-rotation",
|
||||||
@@ -79,7 +80,8 @@ export enum QueueName {
|
|||||||
UserNotification = "user-notification",
|
UserNotification = "user-notification",
|
||||||
HealthAlert = "health-alert",
|
HealthAlert = "health-alert",
|
||||||
CertificateV3AutoRenewal = "certificate-v3-auto-renewal",
|
CertificateV3AutoRenewal = "certificate-v3-auto-renewal",
|
||||||
PamAccountRotation = "pam-account-rotation"
|
PamAccountRotation = "pam-account-rotation",
|
||||||
|
PkiAcmeChallengeValidation = "pki-acme-challenge-validation"
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum QueueJobs {
|
export enum QueueJobs {
|
||||||
@@ -130,7 +132,8 @@ export enum QueueJobs {
|
|||||||
UserNotification = "user-notification-job",
|
UserNotification = "user-notification-job",
|
||||||
HealthAlert = "health-alert",
|
HealthAlert = "health-alert",
|
||||||
CertificateV3DailyAutoRenewal = "certificate-v3-daily-auto-renewal",
|
CertificateV3DailyAutoRenewal = "certificate-v3-daily-auto-renewal",
|
||||||
PamAccountRotation = "pam-account-rotation"
|
PamAccountRotation = "pam-account-rotation",
|
||||||
|
ValidateAcmeChallengeResponse = "validate-acme-challenge-response"
|
||||||
}
|
}
|
||||||
|
|
||||||
export type TQueueJobTypes = {
|
export type TQueueJobTypes = {
|
||||||
@@ -369,6 +372,10 @@ export type TQueueJobTypes = {
|
|||||||
name: QueueJobs.PamAccountRotation;
|
name: QueueJobs.PamAccountRotation;
|
||||||
payload: undefined;
|
payload: undefined;
|
||||||
};
|
};
|
||||||
|
[QueueName.PkiAcmeChallengeValidation]: {
|
||||||
|
name: QueueJobs.ValidateAcmeChallengeResponse;
|
||||||
|
payload: TValidateAcmeChallengeResponseDTO;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const SECRET_SCANNING_JOBS = [
|
const SECRET_SCANNING_JOBS = [
|
||||||
|
|||||||
Reference in New Issue
Block a user