mirror of
https://github.com/Infisical/infisical.git
synced 2026-01-08 15:13:55 -05:00
Check and sync status
This commit is contained in:
@@ -4,6 +4,7 @@ import { TDbClient } from "@app/db";
|
||||
import { TableName } from "@app/db/schemas";
|
||||
import { DatabaseError } from "@app/lib/errors";
|
||||
import { ormify, selectAllTableCols, sqlNestRelationships } from "@app/lib/knex";
|
||||
import { CertificateRequestStatus } from "@app/services/certificate-request/certificate-request-types";
|
||||
|
||||
export type TPkiAcmeOrderDALFactory = ReturnType<typeof pkiAcmeOrderDALFactory>;
|
||||
|
||||
@@ -19,6 +20,42 @@ export const pkiAcmeOrderDALFactory = (db: TDbClient) => {
|
||||
}
|
||||
};
|
||||
|
||||
const findWithCertificateRequestForSync = async (id: string, tx?: Knex) => {
|
||||
try {
|
||||
const order = await (tx || db)(TableName.PkiAcmeOrder)
|
||||
.leftJoin(
|
||||
TableName.CertificateRequests,
|
||||
`${TableName.PkiAcmeOrder}.id`,
|
||||
`${TableName.CertificateRequests}.certificateId`
|
||||
)
|
||||
.select(
|
||||
selectAllTableCols(TableName.PkiAcmeOrder),
|
||||
db.ref("id").withSchema(TableName.CertificateRequests).as("certificateRequestId"),
|
||||
db.ref("status").withSchema(TableName.CertificateRequests).as("certificateRequestStatus")
|
||||
)
|
||||
.forUpdate(TableName.PkiAcmeOrder)
|
||||
.where(`${TableName.PkiAcmeOrder}.id`, id)
|
||||
.first();
|
||||
if (!order) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
...order,
|
||||
certificateRequest:
|
||||
order.certificateRequestId && order.certificateRequestStatus
|
||||
? {
|
||||
id: order.certificateRequestId,
|
||||
status: order.certificateRequestStatus as CertificateRequestStatus,
|
||||
// The certificate id for async certificate request is the same as the order id
|
||||
certificateId: order.id
|
||||
}
|
||||
: undefined
|
||||
};
|
||||
} catch (error) {
|
||||
throw new DatabaseError({ error, name: "Find PKI ACME order by id with certificate request" });
|
||||
}
|
||||
};
|
||||
|
||||
const findByAccountAndOrderIdWithAuthorizations = async (accountId: string, orderId: string, tx?: Knex) => {
|
||||
try {
|
||||
const rows = await (tx || db)(TableName.PkiAcmeOrder)
|
||||
@@ -72,6 +109,7 @@ export const pkiAcmeOrderDALFactory = (db: TDbClient) => {
|
||||
return {
|
||||
...pkiAcmeOrderOrm,
|
||||
findByIdForFinalization,
|
||||
findWithCertificateRequestForSync,
|
||||
findByAccountAndOrderIdWithAuthorizations,
|
||||
listByAccountId
|
||||
};
|
||||
|
||||
@@ -104,6 +104,7 @@ import {
|
||||
TRawJwsPayload,
|
||||
TRespondToAcmeChallengeResponse
|
||||
} from "./pki-acme-types";
|
||||
import { TPkiAcmeOrders } from "@app/db/schemas";
|
||||
|
||||
type TPkiAcmeServiceFactoryDep = {
|
||||
projectDAL: Pick<TProjectDALFactory, "findOne" | "updateById" | "transaction" | "findById">;
|
||||
@@ -117,11 +118,13 @@ type TPkiAcmeServiceFactoryDep = {
|
||||
>;
|
||||
acmeOrderDAL: Pick<
|
||||
TPkiAcmeOrderDALFactory,
|
||||
| "findById"
|
||||
| "create"
|
||||
| "transaction"
|
||||
| "updateById"
|
||||
| "findByAccountAndOrderIdWithAuthorizations"
|
||||
| "findByIdForFinalization"
|
||||
| "findWithCertificateRequestForSync"
|
||||
| "listByAccountId"
|
||||
>;
|
||||
acmeAuthDAL: Pick<TPkiAcmeAuthDALFactory, "create" | "findByAccountIdAndAuthIdWithChallenges">;
|
||||
@@ -370,6 +373,50 @@ export const pkiAcmeServiceFactory = ({
|
||||
};
|
||||
};
|
||||
|
||||
const checkAndSyncAcmeOrderStatus = async ({ orderId }: { orderId: string }): Promise<TPkiAcmeOrders> => {
|
||||
const order = await acmeOrderDAL.findById(orderId);
|
||||
if (!order) {
|
||||
throw new NotFoundError({ message: "ACME order not found" });
|
||||
}
|
||||
if (order.status !== AcmeOrderStatus.Ready) {
|
||||
return order;
|
||||
}
|
||||
return acmeOrderDAL.transaction(async (tx) => {
|
||||
// Lock the order for syncing with async cert request
|
||||
const orderWithCertificateRequest = await acmeOrderDAL.findWithCertificateRequestForSync(orderId, tx);
|
||||
if (!orderWithCertificateRequest) {
|
||||
throw new NotFoundError({ message: "ACME order not found" });
|
||||
}
|
||||
if (
|
||||
orderWithCertificateRequest.status !== AcmeOrderStatus.Ready ||
|
||||
!orderWithCertificateRequest.certificateRequest
|
||||
) {
|
||||
return orderWithCertificateRequest;
|
||||
}
|
||||
let newStatus: AcmeOrderStatus | undefined;
|
||||
let newCertificateId: string | undefined;
|
||||
switch (orderWithCertificateRequest.certificateRequest.status) {
|
||||
case CertificateRequestStatus.PENDING:
|
||||
break;
|
||||
case CertificateRequestStatus.ISSUED:
|
||||
newStatus = AcmeOrderStatus.Valid;
|
||||
newCertificateId = orderWithCertificateRequest.certificateRequest.certificateId;
|
||||
break;
|
||||
case CertificateRequestStatus.FAILED:
|
||||
newStatus = AcmeOrderStatus.Invalid;
|
||||
break;
|
||||
default:
|
||||
throw new AcmeServerInternalError({
|
||||
message: `Invalid certificate request status: ${orderWithCertificateRequest.certificateRequest.status as string}`
|
||||
});
|
||||
}
|
||||
if (newStatus) {
|
||||
return acmeOrderDAL.updateById(orderId, { status: newStatus, certificateId: newCertificateId }, tx);
|
||||
}
|
||||
return orderWithCertificateRequest;
|
||||
});
|
||||
};
|
||||
|
||||
const getAcmeDirectory = async (profileId: string): Promise<TGetAcmeDirectoryResponse> => {
|
||||
const profile = await validateAcmeProfile(profileId);
|
||||
return {
|
||||
@@ -737,9 +784,11 @@ export const pkiAcmeServiceFactory = ({
|
||||
if (!order) {
|
||||
throw new NotFoundError({ message: "ACME order not found" });
|
||||
}
|
||||
// Sync order first in case if there is a certificate request that needs to be processed
|
||||
const syncedOrder = await checkAndSyncAcmeOrderStatus({ orderId });
|
||||
return {
|
||||
status: 200,
|
||||
body: buildAcmeOrderResource({ profileId, order }),
|
||||
body: buildAcmeOrderResource({ profileId, order: syncedOrder }),
|
||||
headers: {
|
||||
Location: buildUrl(profileId, `/orders/${orderId}`),
|
||||
Link: `<${buildUrl(profileId, "/directory")}>;rel="index"`
|
||||
@@ -1001,7 +1050,7 @@ export const pkiAcmeServiceFactory = ({
|
||||
}
|
||||
if (certIssuanceJobData) {
|
||||
// TODO: ideally, this should be done inside the transaction, but the pg-boss queue doesn't support external transactions
|
||||
// as it seems to be.
|
||||
// as it seems to be. we need to commit the transaction before queuing the job, otherwise the job will fail (not found error).
|
||||
await certificateIssuanceQueue.queueCertificateIssuance(certIssuanceJobData);
|
||||
}
|
||||
order = updatedOrder;
|
||||
@@ -1049,14 +1098,16 @@ export const pkiAcmeServiceFactory = ({
|
||||
if (!order) {
|
||||
throw new NotFoundError({ message: "ACME order not found" });
|
||||
}
|
||||
if (order.status !== AcmeOrderStatus.Valid) {
|
||||
// Sync order first in case if there is a certificate request that needs to be processed
|
||||
const syncedOrder = await checkAndSyncAcmeOrderStatus({ orderId });
|
||||
if (syncedOrder.status !== AcmeOrderStatus.Valid) {
|
||||
throw new AcmeOrderNotReadyError({ message: "ACME order is not valid" });
|
||||
}
|
||||
if (!order.certificateId) {
|
||||
if (!syncedOrder.certificateId) {
|
||||
throw new NotFoundError({ message: "The certificate for this ACME order no longer exists" });
|
||||
}
|
||||
|
||||
const certBody = await certificateBodyDAL.findOne({ certId: order.certificateId });
|
||||
const certBody = await certificateBodyDAL.findOne({ certId: syncedOrder.certificateId });
|
||||
const certificateManagerKeyId = await getProjectKmsCertificateKeyId({
|
||||
projectId: profile.projectId,
|
||||
projectDAL,
|
||||
|
||||
Reference in New Issue
Block a user