Add SSL certificate checker and tests

This commit is contained in:
Keith Casko
2026-07-23 03:53:19 -04:00
parent 28ccd40686
commit 820f271195
7 changed files with 700 additions and 2 deletions
+164
View File
@@ -199,3 +199,167 @@ dnsForm.addEventListener("submit", async (event) => {
dnsButton.textContent = "Look Up DNS";
}
});
// ---------------------------------------------------------
// SSL Certificate Checker
// ---------------------------------------------------------
// Get references to the SSL form and result elements.
const sslForm = document.getElementById("ssl-form");
const sslHostnameInput = document.getElementById(
"ssl-hostname-input"
);
const sslButton = document.getElementById("ssl-button");
const sslMessage = document.getElementById("ssl-message");
const sslResultPanel = document.getElementById(
"ssl-result-panel"
);
const sslStatusBadge = document.getElementById(
"ssl-status-badge"
);
const sslHostname = document.getElementById("ssl-hostname");
const sslDaysRemaining = document.getElementById(
"ssl-days-remaining"
);
const sslValidFrom = document.getElementById("ssl-valid-from");
const sslValidTo = document.getElementById("ssl-valid-to");
const sslProtocol = document.getElementById("ssl-protocol");
const sslCipher = document.getElementById("ssl-cipher");
const sslAddress = document.getElementById("ssl-address");
const sslCheckedAt = document.getElementById("ssl-checked-at");
const sslSubject = document.getElementById("ssl-subject");
const sslIssuer = document.getElementById("ssl-issuer");
const sslFingerprint = document.getElementById(
"ssl-fingerprint"
);
const sslAuthorizationErrorBlock = document.getElementById(
"ssl-authorization-error-block"
);
const sslAuthorizationError = document.getElementById(
"ssl-authorization-error"
);
// Convert certificate date strings into a readable local date.
function formatCertificateDate(value) {
if (!value) {
return "Unknown";
}
const date = new Date(value);
if (Number.isNaN(date.getTime())) {
return value;
}
return date.toLocaleString();
}
// Choose readable text for the certificate expiration state.
function getExpirationText(daysRemaining) {
if (daysRemaining === null || daysRemaining === undefined) {
return "Unknown";
}
if (daysRemaining < 0) {
return `${Math.abs(daysRemaining)} days expired`;
}
if (daysRemaining === 0) {
return "Expires today";
}
return `${daysRemaining} days`;
}
// Handle SSL certificate form submissions.
sslForm.addEventListener("submit", async (event) => {
event.preventDefault();
const hostname = sslHostnameInput.value.trim();
// Reset the SSL interface before beginning the request.
sslMessage.textContent = "Checking certificate...";
sslMessage.className = "status-message";
sslResultPanel.hidden = true;
sslButton.disabled = true;
sslButton.textContent = "Checking...";
try {
const response = await fetch("/api/ssl", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ hostname }),
});
const result = await response.json();
if (!response.ok) {
throw new Error(
result.error || "The SSL certificate check failed."
);
}
// Show whether Node trusted the certificate chain and hostname.
if (result.authorized) {
sslStatusBadge.textContent = "Valid";
sslStatusBadge.className = "status-badge online";
} else {
sslStatusBadge.textContent = "Not trusted";
sslStatusBadge.className = "status-badge offline";
}
// Populate the certificate summary.
sslHostname.textContent = result.hostname;
sslDaysRemaining.textContent = getExpirationText(
result.daysRemaining
);
sslValidFrom.textContent = formatCertificateDate(
result.validFrom
);
sslValidTo.textContent = formatCertificateDate(
result.validTo
);
sslProtocol.textContent = result.protocol || "Unknown";
sslCipher.textContent = result.cipher || "Unknown";
sslAddress.textContent = result.resolvedAddress
? `${result.resolvedAddress} (IPv${result.addressFamily})`
: "Unknown";
sslCheckedAt.textContent = formatCertificateDate(
result.checkedAt
);
// Populate the longer certificate values.
sslSubject.textContent = result.subject || "Unknown";
sslIssuer.textContent = result.issuer || "Unknown";
sslFingerprint.textContent =
result.fingerprint256 || "Unavailable";
// Show the authorization problem only when one exists.
if (result.authorizationError) {
sslAuthorizationError.textContent =
result.authorizationError;
sslAuthorizationErrorBlock.hidden = false;
} else {
sslAuthorizationError.textContent = "";
sslAuthorizationErrorBlock.hidden = true;
}
sslMessage.textContent =
"Certificate check completed.";
sslResultPanel.hidden = false;
} catch (error) {
sslMessage.textContent = error.message;
sslMessage.className = "status-message error";
} finally {
sslButton.disabled = false;
sslButton.textContent = "Check Certificate";
}
});