import { execSync } from 'node:child_process'; import fs from 'node:fs'; import os from 'node:os'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; import { logger } from './src/logger.js'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const certsDir = path.join(__dirname, 'certs'); const keyPath = path.join(certsDir, 'key.pem'); const certPath = path.join(certsDir, 'cert.pem'); fs.mkdirSync(certsDir, { recursive: true }); function isIp(value) { return /^(?:\d{1,3}\.){3}\d{1,3}$/.test(value) || value.includes(':'); } function localIpv4s() { const ips = []; for (const entries of Object.values(os.networkInterfaces())) { for (const entry of entries || []) { if (entry.family !== 'IPv4' || entry.internal) continue; // Skip link-local / docker / libvirt bridge noise by default — keep LAN + extras via args if (entry.address.startsWith('169.254.')) continue; if (entry.address.startsWith('172.17.')) continue; if (entry.address.startsWith('192.168.122.')) continue; ips.push(entry.address); } } return ips; } const dnsNames = new Set(['localhost']); const ipAddrs = new Set(['127.0.0.1', '0.0.0.0']); for (const ip of localIpv4s()) { ipAddrs.add(ip); } const extras = [ ...(process.env.CERT_SAN || '').split(/[,\s]+/).filter(Boolean), ...process.argv.slice(2), ]; for (const value of extras) { if (isIp(value)) ipAddrs.add(value); else dnsNames.add(value); } const sanParts = [ ...[...dnsNames].map((name) => `DNS:${name}`), ...[...ipAddrs].map((ip) => `IP:${ip}`), ]; const san = `subjectAltName=${sanParts.join(',')}`; const cn = [...dnsNames][0] || 'localhost'; const subject = `/CN=${cn}/O=JTL POS Sync/C=DE`; // ECDSA P-256 keeps pairing QR codes much smaller than RSA-2048 execSync( `openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:P-256 -nodes -keyout "${keyPath}" -out "${certPath}" -days 3650 -subj "${subject}" -addext "${san}"`, { stdio: 'inherit' } ); const sha1 = execSync(`openssl x509 -in "${certPath}" -noout -fingerprint -sha1`, { encoding: 'utf8', }) .trim() .split('=')[1]; const serial = execSync(`openssl x509 -in "${certPath}" -noout -serial`, { encoding: 'utf8', }) .trim() .split('=')[1]; logger.success(`Wrote ${keyPath}`); logger.success(`Wrote ${certPath}`); logger.info(`SAN: ${sanParts.join(', ')}`); logger.info(`Fingerprint: ${sha1.replace(/:/g, '')}`); logger.info(`Serial: ${serial}`);