{ "id": "ERCWB3oSYbgsUiqL", "name": "NPM SSL Certificate Monitor", "nodes": [ { "parameters": { "rule": { "interval": [ { "field": "cronExpression", "expression": "0 9 * * *" } ] } }, "id": "schedule-trigger", "name": "Daily SSL Check", "type": "n8n-nodes-base.scheduleTrigger", "typeVersion": 1.2, "position": [ 240, 400 ] }, { "parameters": { "jsCode": "// Process SSL certificates and check expiration\nconst certificates = $input.all();\nconst today = new Date();\nconst WARNING_DAYS = 7;\n\nconsole.log('=== NPM SSL Certificate Monitor ===');\nconsole.log('Total certificates:', certificates.length);\n\nconst certificateStatus = [];\nlet expiringCerts = [];\nlet skippedCount = 0;\n\nfor (const item of certificates) {\n const cert = item.json;\n \n // Skip if no expiration date or invalid\n if (!cert.expires_on || cert.expires_on === 0) {\n console.log('Skipping certificate (no expiration):', cert.nice_name || cert.id);\n skippedCount++;\n continue;\n }\n \n const domainNames = cert.domain_names?.join(', ') || cert.nice_name || `Certificate ${cert.id}`;\n \n // Create date and validate it\n const expiryDate = new Date(cert.expires_on * 1000);\n if (isNaN(expiryDate.getTime())) {\n console.log('Skipping certificate (invalid date):', domainNames);\n skippedCount++;\n continue;\n }\n \n const daysRemaining = Math.ceil((expiryDate - today) / (1000 * 60 * 60 * 24));\n const isExpiring = daysRemaining <= WARNING_DAYS;\n \n let status = 'OK';\n if (daysRemaining < 0) {\n status = 'EXPIRED';\n } else if (isExpiring) {\n status = 'EXPIRING SOON';\n }\n \n const certInfo = {\n domain: domainNames,\n expiryDate: expiryDate.toISOString().split('T')[0],\n daysRemaining: daysRemaining,\n status: status,\n isExpiring: isExpiring\n };\n \n certificateStatus.push(certInfo);\n \n if (isExpiring) {\n expiringCerts.push(certInfo);\n console.log(`🔴 ${domainNames}: ${daysRemaining} days (expires ${certInfo.expiryDate})`);\n } else {\n console.log(`✅ ${domainNames}: ${daysRemaining} days`);\n }\n}\n\nconsole.log('\\n=== Summary ===');\nconsole.log('Valid certificates:', certificateStatus.length);\nconsole.log('Skipped (invalid/missing expiration):', skippedCount);\nconsole.log('Expiring within', WARNING_DAYS, 'days:', expiringCerts.length);\n\nreturn [{\n json: {\n totalCerts: certificateStatus.length,\n expiringCount: expiringCerts.length,\n hasExpiringCerts: expiringCerts.length > 0,\n allCertificates: certificateStatus,\n expiringCertificates: expiringCerts\n }\n}];" }, "id": "process-certificates", "name": "Process SSL Certificates", "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 848, 400 ] }, { "parameters": { "conditions": { "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict", "version": 1 }, "conditions": [ { "id": "f5646765-356f-4270-b42b-8e86a3a64568", "leftValue": "={{ $json.hasExpiringCerts }}", "rightValue": "", "operator": { "type": "boolean", "operation": "true", "singleValue": true } } ], "combinator": "and" }, "options": {} }, "id": "check-expiring", "name": "Any Expiring Certs?", "type": "n8n-nodes-base.if", "typeVersion": 2, "position": [ 1040, 400 ] }, { "parameters": { "jsCode": "// Format warning email for expiring certificates\nconst data = $input.item.json;\nconst expiringCerts = data.expiringCertificates || [];\n\nlet tableRows = '';\nfor (const cert of expiringCerts) {\n const statusIcon = cert.status === 'EXPIRED' ? '🔴' : '⚠️';\n tableRows += `\n
| Domain | \nExpiration Date | \nDays Remaining | \nStatus | \n
|---|