Sync domain SSL status on a 2-hour cron and capture owner FA/EN names.
List pages stay cheap by reading ssl_enabled while Nest probes apex hosts in the background; create-business now stores first/last name in both locales. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
co-authored by
Cursor
parent
f233665d13
commit
267a218c26
@@ -0,0 +1,84 @@
|
||||
import * as tls from 'tls';
|
||||
|
||||
const DEFAULT_TIMEOUT_MS = 2500;
|
||||
|
||||
/**
|
||||
* Live TLS check: connect to host:443 with SNI and require a trusted cert.
|
||||
* Returns false on timeout, DNS failure, or cert/hostname errors.
|
||||
*/
|
||||
export function probeTlsHost(
|
||||
hostRaw: string,
|
||||
timeoutMs = DEFAULT_TIMEOUT_MS,
|
||||
): Promise<boolean> {
|
||||
const host = hostRaw.trim().toLowerCase();
|
||||
if (!host || host.includes(':') || host.endsWith('.local')) {
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
|
||||
return new Promise((resolve) => {
|
||||
let settled = false;
|
||||
const finish = (ok: boolean) => {
|
||||
if (settled) return;
|
||||
settled = true;
|
||||
resolve(ok);
|
||||
};
|
||||
|
||||
let socket: tls.TLSSocket;
|
||||
try {
|
||||
socket = tls.connect(
|
||||
{
|
||||
host,
|
||||
port: 443,
|
||||
servername: host,
|
||||
rejectUnauthorized: true,
|
||||
timeout: timeoutMs,
|
||||
},
|
||||
() => {
|
||||
const ok = socket.authorized === true;
|
||||
socket.destroy();
|
||||
finish(ok);
|
||||
},
|
||||
);
|
||||
} catch {
|
||||
finish(false);
|
||||
return;
|
||||
}
|
||||
|
||||
socket.on('error', () => {
|
||||
socket.destroy();
|
||||
finish(false);
|
||||
});
|
||||
|
||||
socket.on('timeout', () => {
|
||||
socket.destroy();
|
||||
finish(false);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/** Probe many hosts in parallel (chunked); returns Map host → ssl ok. */
|
||||
export async function probeTlsHosts(
|
||||
hosts: Array<string | null | undefined>,
|
||||
chunkSize = 10,
|
||||
): Promise<Map<string, boolean>> {
|
||||
const unique = [
|
||||
...new Set(
|
||||
hosts
|
||||
.map((h) => h?.trim().toLowerCase())
|
||||
.filter((h): h is string => !!h),
|
||||
),
|
||||
];
|
||||
|
||||
const results = new Map<string, boolean>();
|
||||
for (let i = 0; i < unique.length; i += chunkSize) {
|
||||
const chunk = unique.slice(i, i + chunkSize);
|
||||
const probed = await Promise.all(
|
||||
chunk.map(async (host) => [host, await probeTlsHost(host)] as const),
|
||||
);
|
||||
for (const [host, ok] of probed) {
|
||||
results.set(host, ok);
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
Reference in New Issue
Block a user