mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-04 17:26:19 +00:00
Lint
This commit is contained in:
@@ -33,8 +33,9 @@ export interface MyRequestInterface {
|
|||||||
|
|
||||||
export const registerPkiAcmeRouter = async (server: FastifyZodProvider) => {
|
export const registerPkiAcmeRouter = async (server: FastifyZodProvider) => {
|
||||||
const validateExistingAccount = async <
|
const validateExistingAccount = async <
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
R extends FastifyRequest<any>,
|
R extends FastifyRequest<any>,
|
||||||
TSchema extends z.ZodSchema<any> | undefined = undefined,
|
TSchema extends z.ZodSchema<unknown> | undefined = undefined,
|
||||||
T = TSchema extends z.ZodSchema<infer R> ? R : string
|
T = TSchema extends z.ZodSchema<infer R> ? R : string
|
||||||
>({
|
>({
|
||||||
req,
|
req,
|
||||||
@@ -70,7 +71,7 @@ export const registerPkiAcmeRouter = async (server: FastifyZodProvider) => {
|
|||||||
if (!strBody) {
|
if (!strBody) {
|
||||||
done(null, undefined);
|
done(null, undefined);
|
||||||
}
|
}
|
||||||
const json: unknown = JSON.parse(strBody as string);
|
const json = JSON.parse(strBody as string);
|
||||||
done(null, json);
|
done(null, json);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
const error = err as Error;
|
const error = err as Error;
|
||||||
|
|||||||
@@ -2,7 +2,12 @@ import { getConfig } from "@app/lib/config/env";
|
|||||||
import { BadRequestError, 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 { TPkiAcmeChallengeDALFactory } from "./pki-acme-challenge-dal";
|
import { TPkiAcmeChallengeDALFactory } from "./pki-acme-challenge-dal";
|
||||||
import { AcmeConnectionError, AcmeDnsFailureError, AcmeIncorrectResponseError } from "./pki-acme-errors";
|
import {
|
||||||
|
AcmeConnectionError,
|
||||||
|
AcmeDnsFailureError,
|
||||||
|
AcmeIncorrectResponseError,
|
||||||
|
AcmeServerInternalError
|
||||||
|
} from "./pki-acme-errors";
|
||||||
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";
|
||||||
|
|
||||||
@@ -23,7 +28,7 @@ export const pkiAcmeChallengeServiceFactory = ({
|
|||||||
const appCfg = getConfig();
|
const appCfg = getConfig();
|
||||||
|
|
||||||
const validateChallengeResponse = async (challengeId: string): Promise<void> => {
|
const validateChallengeResponse = async (challengeId: string): Promise<void> => {
|
||||||
const error = await acmeChallengeDAL.transaction(async (tx) => {
|
const error: Error | undefined = await acmeChallengeDAL.transaction(async (tx) => {
|
||||||
logger.info({ challengeId }, "Validating ACME challenge response");
|
logger.info({ challengeId }, "Validating ACME challenge response");
|
||||||
const challenge = await acmeChallengeDAL.findByIdForChallengeValidation(challengeId, tx);
|
const challenge = await acmeChallengeDAL.findByIdForChallengeValidation(challengeId, tx);
|
||||||
if (!challenge) {
|
if (!challenge) {
|
||||||
@@ -98,6 +103,7 @@ export const pkiAcmeChallengeServiceFactory = ({
|
|||||||
logger.error(exp, "Error validating ACME challenge response");
|
logger.error(exp, "Error validating ACME challenge response");
|
||||||
} else {
|
} else {
|
||||||
logger.error(exp, "Unknown error validating ACME challenge response");
|
logger.error(exp, "Unknown error validating ACME challenge response");
|
||||||
|
return new AcmeServerInternalError({ message: "Unknown error validating ACME challenge response" });
|
||||||
}
|
}
|
||||||
return exp;
|
return exp;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,8 +48,8 @@ export const pkiAcmeOrderDALFactory = (db: TDbClient) => {
|
|||||||
label: "authorizations" as const,
|
label: "authorizations" as const,
|
||||||
mapper: ({ authId, identifierType, identifierValue, authExpiresAt }) => ({
|
mapper: ({ authId, identifierType, identifierValue, authExpiresAt }) => ({
|
||||||
id: authId,
|
id: authId,
|
||||||
identifierType: identifierType,
|
identifierType,
|
||||||
identifierValue: identifierValue,
|
identifierValue,
|
||||||
expiresAt: authExpiresAt
|
expiresAt: authExpiresAt
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -441,14 +441,13 @@ export const pkiAcmeServiceFactory = ({
|
|||||||
|
|
||||||
const deactivateAcmeAccount = async ({
|
const deactivateAcmeAccount = async ({
|
||||||
profileId,
|
profileId,
|
||||||
accountId,
|
accountId
|
||||||
payload: { status } = { status: "deactivated" }
|
|
||||||
}: {
|
}: {
|
||||||
profileId: string;
|
profileId: string;
|
||||||
accountId: string;
|
accountId: string;
|
||||||
payload?: TDeactivateAcmeAccountPayload;
|
payload?: TDeactivateAcmeAccountPayload;
|
||||||
}): Promise<TAcmeResponse<TDeactivateAcmeAccountResponse>> => {
|
}): Promise<TAcmeResponse<TDeactivateAcmeAccountResponse>> => {
|
||||||
const profile = await validateAcmeProfile(profileId);
|
await validateAcmeProfile(profileId);
|
||||||
// FIXME: Implement ACME account deactivation
|
// FIXME: Implement ACME account deactivation
|
||||||
return {
|
return {
|
||||||
status: 200,
|
status: 200,
|
||||||
@@ -494,36 +493,35 @@ export const pkiAcmeServiceFactory = ({
|
|||||||
);
|
);
|
||||||
const authorizations: TPkiAcmeAuths[] = await Promise.all(
|
const authorizations: TPkiAcmeAuths[] = await Promise.all(
|
||||||
payload.identifiers.map(async (identifier) => {
|
payload.identifiers.map(async (identifier) => {
|
||||||
if (identifier.type === AcmeIdentifierType.DNS) {
|
if (identifier.type !== AcmeIdentifierType.DNS) {
|
||||||
// TODO: reuse existing authorizations for this identifier if they exist
|
|
||||||
const auth = await acmeAuthDAL.create(
|
|
||||||
{
|
|
||||||
accountId: account.id,
|
|
||||||
status: AcmeAuthStatus.Pending,
|
|
||||||
identifierType: identifier.type,
|
|
||||||
identifierValue: identifier.value,
|
|
||||||
// RFC 8555 suggests a token with at least 128 bits of entropy
|
|
||||||
// We are using 256 bits of entropy here, should be enough for now
|
|
||||||
// ref: https://datatracker.ietf.org/doc/html/rfc8555#section-11.3
|
|
||||||
token: crypto.randomBytes(32).toString("base64url"),
|
|
||||||
// TODO: read config from the profile to get the expiration time instead
|
|
||||||
expiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000)
|
|
||||||
},
|
|
||||||
tx
|
|
||||||
);
|
|
||||||
// TODO: support other challenge types here. Currently only HTTP-01 is supported.
|
|
||||||
await acmeChallengeDAL.create(
|
|
||||||
{
|
|
||||||
authId: auth.id,
|
|
||||||
status: AcmeChallengeStatus.Pending,
|
|
||||||
type: AcmeChallengeType.HTTP_01
|
|
||||||
},
|
|
||||||
tx
|
|
||||||
);
|
|
||||||
return auth;
|
|
||||||
} else {
|
|
||||||
throw new AcmeUnsupportedIdentifierError({ detail: "Only DNS identifiers are supported" });
|
throw new AcmeUnsupportedIdentifierError({ detail: "Only DNS identifiers are supported" });
|
||||||
}
|
}
|
||||||
|
// TODO: reuse existing authorizations for this identifier if they exist
|
||||||
|
const auth = await acmeAuthDAL.create(
|
||||||
|
{
|
||||||
|
accountId: account.id,
|
||||||
|
status: AcmeAuthStatus.Pending,
|
||||||
|
identifierType: identifier.type,
|
||||||
|
identifierValue: identifier.value,
|
||||||
|
// RFC 8555 suggests a token with at least 128 bits of entropy
|
||||||
|
// We are using 256 bits of entropy here, should be enough for now
|
||||||
|
// ref: https://datatracker.ietf.org/doc/html/rfc8555#section-11.3
|
||||||
|
token: crypto.randomBytes(32).toString("base64url"),
|
||||||
|
// TODO: read config from the profile to get the expiration time instead
|
||||||
|
expiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000)
|
||||||
|
},
|
||||||
|
tx
|
||||||
|
);
|
||||||
|
// TODO: support other challenge types here. Currently only HTTP-01 is supported.
|
||||||
|
await acmeChallengeDAL.create(
|
||||||
|
{
|
||||||
|
authId: auth.id,
|
||||||
|
status: AcmeChallengeStatus.Pending,
|
||||||
|
type: AcmeChallengeType.HTTP_01
|
||||||
|
},
|
||||||
|
tx
|
||||||
|
);
|
||||||
|
return auth;
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -591,13 +589,13 @@ export const pkiAcmeServiceFactory = ({
|
|||||||
}
|
}
|
||||||
if (order.status === AcmeOrderStatus.Ready) {
|
if (order.status === AcmeOrderStatus.Ready) {
|
||||||
const { order: updatedOrder, error } = await acmeOrderDAL.transaction(async (tx) => {
|
const { order: updatedOrder, error } = await acmeOrderDAL.transaction(async (tx) => {
|
||||||
const order = (await acmeOrderDAL.findByIdForFinalization(orderId, tx))!;
|
const finalizingOrder = (await acmeOrderDAL.findByIdForFinalization(orderId, tx))!;
|
||||||
// TODO: ideally, this should be doen with onRequest: verifyAuth([AuthMode.ACME_JWS_SIGNATURE]), instead?
|
// TODO: ideally, this should be doen with onRequest: verifyAuth([AuthMode.ACME_JWS_SIGNATURE]), instead?
|
||||||
const { ownerOrgId: actorOrgId } = (await certificateProfileDAL.findByIdWithOwnerOrgId(profileId, tx))!;
|
const { ownerOrgId: actorOrgId } = (await certificateProfileDAL.findByIdWithOwnerOrgId(profileId, tx))!;
|
||||||
if (order.status !== AcmeOrderStatus.Ready) {
|
if (finalizingOrder.status !== AcmeOrderStatus.Ready) {
|
||||||
throw new AcmeOrderNotReadyError({ message: "ACME order is not ready" });
|
throw new AcmeOrderNotReadyError({ message: "ACME order is not ready" });
|
||||||
}
|
}
|
||||||
if (order.expiresAt < new Date()) {
|
if (finalizingOrder.expiresAt < new Date()) {
|
||||||
throw new AcmeOrderNotReadyError({ message: "ACME order has expired" });
|
throw new AcmeOrderNotReadyError({ message: "ACME order has expired" });
|
||||||
}
|
}
|
||||||
const { csr } = payload;
|
const { csr } = payload;
|
||||||
@@ -612,8 +610,8 @@ export const pkiAcmeServiceFactory = ({
|
|||||||
actorOrgId,
|
actorOrgId,
|
||||||
profileId,
|
profileId,
|
||||||
csr,
|
csr,
|
||||||
notBefore: order.notBefore ? new Date(order.notBefore) : undefined,
|
notBefore: finalizingOrder.notBefore ? new Date(finalizingOrder.notBefore) : undefined,
|
||||||
notAfter: order.notAfter ? new Date(order.notAfter) : undefined,
|
notAfter: finalizingOrder.notAfter ? new Date(finalizingOrder.notAfter) : undefined,
|
||||||
validity: {
|
validity: {
|
||||||
// TODO: read config from the profile to get the expiration time instead
|
// TODO: read config from the profile to get the expiration time instead
|
||||||
ttl: (24 * 60 * 60 * 1000).toString()
|
ttl: (24 * 60 * 60 * 1000).toString()
|
||||||
@@ -630,20 +628,20 @@ export const pkiAcmeServiceFactory = ({
|
|||||||
},
|
},
|
||||||
tx
|
tx
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (exp) {
|
||||||
await acmeOrderDAL.updateById(
|
await acmeOrderDAL.updateById(
|
||||||
orderId,
|
orderId,
|
||||||
{
|
{
|
||||||
csr,
|
csr,
|
||||||
status: AcmeOrderStatus.Invalid,
|
status: AcmeOrderStatus.Invalid,
|
||||||
error: error instanceof Error ? error.message : "Unknown error"
|
error: exp instanceof Error ? exp.message : "Unknown error"
|
||||||
},
|
},
|
||||||
tx
|
tx
|
||||||
);
|
);
|
||||||
logger.error(error, "Failed to sign certificate");
|
logger.error(exp, "Failed to sign certificate");
|
||||||
// TODO: audit log the error
|
// TODO: audit log the error
|
||||||
if (error instanceof BadRequestError) {
|
if (exp instanceof BadRequestError) {
|
||||||
errorToReturn = new AcmeBadCSRError({ detail: `Invalid CSR: ${error.message}` });
|
errorToReturn = new AcmeBadCSRError({ detail: `Invalid CSR: ${exp.message}` });
|
||||||
} else {
|
} else {
|
||||||
errorToReturn = new AcmeServerInternalError({ detail: "Failed to sign certificate with internal error" });
|
errorToReturn = new AcmeServerInternalError({ detail: "Failed to sign certificate with internal error" });
|
||||||
}
|
}
|
||||||
@@ -710,15 +708,14 @@ export const pkiAcmeServiceFactory = ({
|
|||||||
});
|
});
|
||||||
const certificateChain = decryptedCertChain.toString();
|
const certificateChain = decryptedCertChain.toString();
|
||||||
|
|
||||||
|
const certLeaf = certObj.toString("pem").trim().replace("\n", "\r\n");
|
||||||
|
const certChain = certificateChain.trim().replace("\n", "\r\n");
|
||||||
return {
|
return {
|
||||||
status: 200,
|
status: 200,
|
||||||
body:
|
body:
|
||||||
certObj.toString("pem").trim().replace("\n", "\r\n") +
|
|
||||||
"\r\n" +
|
|
||||||
certificateChain.trim().replace("\n", "\r\n") +
|
|
||||||
// The final line is needed, otherwise some clients will not parse the certificate chain correctly
|
// The final line is needed, otherwise some clients will not parse the certificate chain correctly
|
||||||
// ref: https://github.com/certbot/certbot/blob/4d5d5f7ae8164884c841969e46caed8db1ad34af/certbot/src/certbot/crypto_util.py#L506-L514
|
// ref: https://github.com/certbot/certbot/blob/4d5d5f7ae8164884c841969e46caed8db1ad34af/certbot/src/certbot/crypto_util.py#L506-L514
|
||||||
"\r\n",
|
`${certLeaf}\r\n${certChain}\r\n`,
|
||||||
headers: {
|
headers: {
|
||||||
Location: buildUrl(profileId, `/orders/${orderId}/certificate`),
|
Location: buildUrl(profileId, `/orders/${orderId}/certificate`),
|
||||||
Link: `<${buildUrl(profileId, "/directory")}>;rel="index"`
|
Link: `<${buildUrl(profileId, "/directory")}>;rel="index"`
|
||||||
|
|||||||
Reference in New Issue
Block a user