UNPKG

@monkeyscanjump/cloudflare-dyndns

Version:

A robust TypeScript application that automatically updates Cloudflare DNS records when your public IP address changes. Perfect for maintaining consistent domain names for home servers, WireGuard VPN, self-hosted services, or any system with a dynamic IP a

242 lines (238 loc) 10.5 kB
#!/usr/bin/env node "use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); const fs = __importStar(require("fs")); const path = __importStar(require("path")); const os = __importStar(require("os")); const readline = __importStar(require("readline")); const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); /** * Prompts the user with a question and returns their answer * @param question Text to display to the user * @returns User's response as a string */ async function promptUser(question) { return new Promise((resolve) => { rl.question(question, (answer) => { resolve(answer); }); }); } /** * Returns all possible configuration file locations across different platforms * @returns Array of possible configuration file paths */ function findConfigLocations() { return [ path.join(process.cwd(), '.env'), path.join(os.homedir(), '.cloudflare-dyndns', '.env'), ...(process.platform === 'win32' ? [path.join(process.env.ProgramData || 'C:\\ProgramData', 'cloudflare-dyndns', '.env')] : ['/etc/cloudflare-dyndns/.env']) ]; } /** * Interactive setup wizard for configuring the Cloudflare DynDNS application * Handles both creating new configurations and editing existing ones */ async function setupConfig() { console.log('Cloudflare DynDNS Setup'); console.log('======================='); console.log('This wizard will help you set up the configuration for Cloudflare DynDNS.\n'); const configLocations = findConfigLocations(); const existingConfigs = configLocations.filter(loc => fs.existsSync(loc)); let overwriteChoice = 'new'; if (existingConfigs.length > 0) { console.log('Existing configuration files found:'); existingConfigs.forEach((loc, idx) => { console.log(` ${idx + 1}. ${loc}`); }); overwriteChoice = await promptUser('\nDo you want to create a new configuration or edit an existing one? (new/edit): '); if (overwriteChoice.toLowerCase() === 'edit') { let fileToEdit = ''; if (existingConfigs.length === 1) { fileToEdit = existingConfigs[0]; } else { const fileChoice = await promptUser(`Enter the number of the file to edit (1-${existingConfigs.length}): `); const fileIndex = parseInt(fileChoice, 10) - 1; if (fileIndex >= 0 && fileIndex < existingConfigs.length) { fileToEdit = existingConfigs[fileIndex]; } else { console.log('Invalid choice. Creating a new configuration.'); } } if (fileToEdit) { // Parse existing config const existingConfig = fs.readFileSync(fileToEdit, 'utf8'); const configMap = new Map(); existingConfig.split('\n').forEach(line => { if (line && !line.startsWith('#')) { const parts = line.split('='); if (parts.length === 2) { configMap.set(parts[0].trim(), parts[1].trim()); } } }); // Update with prompts, showing current values const apiToken = await promptUser(`Cloudflare API Token [${configMap.get('API_TOKEN') || ''}]: `); const zoneId = await promptUser(`Cloudflare Zone ID (leave blank to auto-detect) [${configMap.get('ZONE_ID') || ''}]: `); const recordId = await promptUser(`DNS Record ID (leave blank to auto-detect) [${configMap.get('RECORD_ID') || ''}]: `); const domain = await promptUser(`Domain (e.g., example.com) [${configMap.get('DOMAIN') || ''}]: `); const subdomain = await promptUser(`Subdomain (e.g., wireguard) [${configMap.get('SUBDOMAIN') || ''}]: `); // Update config map with new values (or keep old if empty) if (apiToken) configMap.set('API_TOKEN', apiToken); if (zoneId) configMap.set('ZONE_ID', zoneId); if (recordId) configMap.set('RECORD_ID', recordId); if (domain) configMap.set('DOMAIN', domain); if (subdomain) configMap.set('SUBDOMAIN', subdomain); // Build updated config let updatedConfig = ''; for (const [key, value] of configMap.entries()) { updatedConfig += `${key}=${value}\n`; } // Write back to file try { fs.writeFileSync(fileToEdit, updatedConfig); console.log(`\nConfiguration updated at: ${fileToEdit}`); rl.close(); return; } catch (error) { console.error(`Error writing to ${fileToEdit}:`, error); console.log('Trying to create a new configuration instead...'); } } } } // Determine where to save the new config let configDir; let configFile; // Choose appropriate location based on installation type if (process.env.npm_config_global === 'true') { configDir = path.join(os.homedir(), '.cloudflare-dyndns'); configFile = path.join(configDir, '.env'); } else { configDir = process.cwd(); configFile = path.join(configDir, '.env'); } // Create directory if needed if (!fs.existsSync(configDir)) { try { fs.mkdirSync(configDir, { recursive: true }); console.log(`Created configuration directory: ${configDir}`); } catch (error) { console.error(`Error creating directory ${configDir}:`, error); configDir = process.cwd(); configFile = path.join(configDir, '.env'); console.log(`Falling back to current directory: ${configDir}`); } } // Prompt for configuration values console.log('\nEnter your Cloudflare configuration:'); console.log('(Only API Token is required, other values can be auto-detected)'); const apiToken = await promptUser('Cloudflare API Token: '); console.log('\nThe following values can be auto-detected in most cases. Leave blank to auto-detect:'); const zoneId = await promptUser('Cloudflare Zone ID (optional): '); const recordId = await promptUser('DNS Record ID (optional): '); console.log('\nIf you leave these blank, the program will try to find a suitable DNS record to update:'); const domain = await promptUser('Domain (e.g., example.com): '); const subdomain = await promptUser('Subdomain (e.g., wireguard): '); console.log('\nAdditional options (press Enter to use defaults):'); const ttl = await promptUser('TTL in seconds (default: 120): ') || '120'; const proxied = await promptUser('Enable Cloudflare proxy? (true/false, default: false): ') || 'false'; // Create the configuration file const configContent = `# Cloudflare API credentials API_TOKEN=${apiToken} # Cloudflare zone and record identifiers ${zoneId ? `ZONE_ID=${zoneId}` : '# ZONE_ID will be auto-detected'} ${recordId ? `RECORD_ID=${recordId}` : '# RECORD_ID will be auto-detected'} # Domain configuration ${domain ? `DOMAIN=${domain}` : '# DOMAIN will be extracted from detected record'} ${subdomain ? `SUBDOMAIN=${subdomain}` : '# SUBDOMAIN will be extracted from detected record'} # Optional configuration TTL=${ttl} PROXIED=${proxied} RETRY_ATTEMPTS=3 RETRY_DELAY=5000 IP_SERVICES=ipify,ifconfig,ipinfo,seeip # Continuous monitoring settings CHECK_INTERVAL=60000 ADAPTIVE_INTERVAL=true `; try { fs.writeFileSync(configFile, configContent); console.log(`\nConfiguration file created at: ${configFile}`); if (fs.existsSync(configFile)) { try { // Secure the config file (contains API tokens) if (process.platform !== 'win32') { fs.chmodSync(configFile, 0o600); } } catch (error) { console.warn('Warning: Could not set secure permissions on config file:', error); } } console.log('\nYou can now run "cloudflare-dyndns" to update your DNS record once,'); console.log('or "cloudflare-dyndns --continuous" to run in continuous monitoring mode.'); if (!zoneId || !recordId) { console.log('\nNOTE: Since you opted for auto-detection, the first run may take longer'); console.log('as the program discovers your Cloudflare zones and records.'); } } catch (error) { console.error('Error creating configuration file:', error); process.exit(1); } rl.close(); } setupConfig().catch(error => { console.error('Error during setup:', error); process.exit(1); }); //# sourceMappingURL=setup.js.map