feat(integrations): add support for self-signed-cert-in-chain request error (#3399)

This commit is contained in:
Meier Lukas
2025-06-15 21:42:25 +02:00
committed by GitHub
parent cad59aed00
commit e6cb35b7c2
3 changed files with 20 additions and 6 deletions

View File

@@ -30,6 +30,8 @@ export const CertificateErrorDetails = ({ error, url }: CertificateErrorDetailsP
const { mutateAsync: trustHostnameAsync } = clientApi.certificates.trustHostnameMismatch.useMutation();
const { mutateAsync: addCertificateAsync } = clientApi.certificates.addCertificate.useMutation();
const rootCertificate = getHeighestCertificate(error.data.certificate);
const handleTrustHostname = () => {
const { hostname } = new URL(url);
openConfirmModal({
@@ -72,7 +74,7 @@ export const CertificateErrorDetails = ({ error, url }: CertificateErrorDetailsP
const formData = new FormData();
formData.append(
"file",
new File([error.data.certificate.pem], `${hostname}-${createId()}.crt`, {
new File([rootCertificate.pem], `${hostname}-${createId()}.crt`, {
type: "application/x-x509-ca-cert",
}),
);
@@ -110,11 +112,11 @@ export const CertificateErrorDetails = ({ error, url }: CertificateErrorDetailsP
<>
{description}
<CertificateDetailsCard certificate={error.data.certificate} />
<CertificateDetailsCard certificate={rootCertificate} />
{error.data.reason === "hostnameMismatch" && <HostnameMismatchAlert />}
{!error.data.certificate.isSelfSigned && error.data.reason === "untrusted" && <CertificateExtractAlert />}
{!rootCertificate.isSelfSigned && error.data.reason === "untrusted" && <CertificateExtractAlert />}
{showRetryButton && (
<Button
@@ -127,7 +129,7 @@ export const CertificateErrorDetails = ({ error, url }: CertificateErrorDetailsP
</Button>
)}
{(error.data.reason === "untrusted" && error.data.certificate.isSelfSigned) ||
{(error.data.reason === "untrusted" && rootCertificate.isSelfSigned) ||
error.data.reason === "hostnameMismatch" ? (
<Button
variant="default"
@@ -137,7 +139,7 @@ export const CertificateErrorDetails = ({ error, url }: CertificateErrorDetailsP
{tError("certificate.action.trust.label")}
</Button>
) : null}
{error.data.reason === "untrusted" && !error.data.certificate.isSelfSigned ? (
{error.data.reason === "untrusted" && !rootCertificate.isSelfSigned ? (
<Button
variant="default"
fullWidth
@@ -325,3 +327,8 @@ const PemContentModal = createModal<{ content: string }>(({ actions, innerProps
},
size: "lg",
});
const getHeighestCertificate = (certificate: MappedCertificate): MappedCertificate => {
if (certificate.issuerCertificate) return getHeighestCertificate(certificate.issuerCertificate);
return certificate;
};

View File

@@ -36,6 +36,7 @@ const mapError = (error: Error): MappedError => {
export interface MappedCertificate {
isSelfSigned: boolean;
issuer: string;
issuerCertificate?: MappedCertificate;
subject: string;
serialNumber: string;
validFrom: Date;
@@ -47,6 +48,7 @@ export interface MappedCertificate {
const mapCertificate = (certificate: X509Certificate, code: RequestErrorCode): MappedCertificate => ({
isSelfSigned: certificate.ca || code === "DEPTH_ZERO_SELF_SIGNED_CERT",
issuer: certificate.issuer,
issuerCertificate: certificate.issuerCertificate ? mapCertificate(certificate.issuerCertificate, code) : undefined,
subject: certificate.subject,
serialNumber: certificate.serialNumber,
validFrom: certificate.validFromDate,

View File

@@ -36,7 +36,12 @@ export const requestErrorMap = {
expired: ["CERT_HAS_EXPIRED"],
hostnameMismatch: ["ERR_TLS_CERT_ALTNAME_INVALID", "CERT_COMMON_NAME_INVALID"],
notYetValid: ["CERT_NOT_YET_VALID"],
untrusted: ["DEPTH_ZERO_SELF_SIGNED_CERT", "UNABLE_TO_VERIFY_LEAF_SIGNATURE", "UNABLE_TO_GET_ISSUER_CERT_LOCALLY"],
untrusted: [
"DEPTH_ZERO_SELF_SIGNED_CERT",
"UNABLE_TO_VERIFY_LEAF_SIGNATURE",
"UNABLE_TO_GET_ISSUER_CERT_LOCALLY",
"SELF_SIGNED_CERT_IN_CHAIN",
],
},
connection: {
hostUnreachable: "EHOSTUNREACH",