// sslCron.mjs import cron from "node-cron"; import axios from "axios"; // Base URL of your SSL manager Express API // e.g. the server where you defined /dns/domains and /ssl/refresh const API_BASE = process.env.SSL_MANAGER_URL || "https://api.hestiacp.metatronhost.com"; /** * Parse "notAfter" like: "Mar 11 19:08:24 2026 GMT" */ function parseNotAfter(notAfterStr) { if (!notAfterStr) return null; const d = new Date(notAfterStr); // JS can parse this format directly if (isNaN(d.getTime())) return null; return d; } /** * Return days left until SSL expiry from notAfter. * If invalid → return large negative number. */ function daysLeftFromSsl(notAfterStr) { const expiry = parseNotAfter(notAfterStr); if (!expiry) return -9999; const now = new Date(); const diffMs = expiry.getTime() - now.getTime(); const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24)); return diffDays; } /** * Decide if SSL is expired based on notAfter */ function isSslExpired(notAfterStr) { const expiry = parseNotAfter(notAfterStr); if (!expiry) return true; // if we can't parse it, treat as expired const now = new Date(); return now > expiry; } /** * One cycle: * - Fetch domain list (/dns/domains) * - For each domain, look at ssl.notAfter * - If expired -> (for now) just console.log the renew call */ async function checkAndRenewOnce() { try { console.log("🔍 [SSL CRON] Fetching domains..."); const res = await axios.get(`${API_BASE}/dns/domains`); if (!res.data?.success) { console.error("❌ [SSL CRON] /dns/domains failed:", res.data); return; } const rawParsed = res.data.rawParsed || []; console.log(`📦 [SSL CRON] Found ${rawParsed.length} DNS entries`); for (const row of rawParsed) { const { domain, ssl } = row; const notAfter = ssl?.notAfter || null; const left = daysLeftFromSsl(notAfter); const expired = isSslExpired(notAfter); console.log( `🌐 Domain: ${domain} | notAfter: ${notAfter} | daysLeft: ${left} | expired: ${expired}` ); if (!expired) { continue; // SSL still valid, skip } // 🔁 For now: only log what we *would* do console.log( `🔁 [SSL CRON] Would renew SSL for ${domain} via POST ${API_BASE}/ssl/refresh` ); // When you're ready to actually renew, uncomment this block: /* try { console.log(`🔁 [SSL CRON] Renewing SSL for ${domain}...`); const refreshRes = await axios.post(`${API_BASE}/ssl/refresh`, { domain, }); if (refreshRes.data?.success) { console.log(`✅ [SSL CRON] SSL renewed for ${domain}`); } else { console.error( `⚠️ [SSL CRON] Failed to renew ${domain}:`, refreshRes.data ); } } catch (err) { console.error( `❌ [SSL CRON] Error renewing ${domain}:`, err.response?.data || err.message ); } */ } console.log("🎯 [SSL CRON] Cycle completed."); } catch (err) { console.error( "❌ [SSL CRON] Error fetching domains:", err.response?.data || err.message ); } } // 🔁 Schedule to run once per day at 03:00 server time cron.schedule("0 3 * * *", () => { console.log("⏰ [SSL CRON] Daily job started..."); checkAndRenewOnce(); }); // Optional: run immediately when starting the script checkAndRenewOnce();