const readline = require('readline'); const os = require('os'); const fs = require('fs'); const path = require('path'); const config = require('./config'); const passwordManager = require('./password_manager'); const { execSync } = require('child_process'); const rl = readline.createInterface({ input: process.stdin, output: process.stdout, }); function ask(question) { return new Promise(resolve => rl.question(question, resolve)); } function clearScreen() { process.stdout.write(process.platform === 'win32' ? '\x1Bc' : '\033[2J\033[H'); } let detectedPlatform = null; function printBanner() { const user = os.userInfo().username; const photosPath = config.getPhotosPath() || 'NOT SET'; const shortPath = photosPath.length > 25 ? '...' + photosPath.slice(-22) : photosPath; console.log(''); console.log('╔══════════════════════════════════════════════╗'); console.log('║ NAS Photo Server - CLI Client ║'); console.log('╠══════════════════════════════════════════════╣'); console.log(`║ User: ${user.padEnd(32)}║`); if (passwordManager.hasStoredPassword()) { console.log('║ Password: [STORED - Press P to view] ║'); } else { console.log('║ Password: [NOT SET] ║'); } console.log(`║ Platform: ${(detectedPlatform || 'Unknown').padEnd(32)}║`); console.log(`║ Photos: ${shortPath.padEnd(32)}║`); console.log(`║ Port: ${String(config.DEFAULT_PORT).padEnd(32)}║`); console.log('╚══════════════════════════════════════════════╝'); console.log(''); } async function detectOrAskPlatform() { const plat = process.platform; if (plat === 'win32') { detectedPlatform = 'Windows'; console.log('[*] Detected platform: Windows'); return 'windows'; } else if (plat === 'linux') { detectedPlatform = 'Linux (Ubuntu)'; console.log('[*] Detected platform: Linux (assuming Ubuntu)'); return 'linux'; } else { console.log(''); console.log('What operating system are you running?'); console.log(' [1] Windows'); console.log(' [2] Linux (Ubuntu)'); const choice = await ask('Select (1/2): '); if (choice.trim() === '1') { detectedPlatform = 'Windows'; return 'windows'; } else { detectedPlatform = 'Linux (Ubuntu)'; return 'linux'; } } } function checkDependencies() { console.log('[*] Checking dependencies...'); try { execSync('node --version', { stdio: 'ignore' }); console.log(' [OK] Node.js found'); } catch { console.log(' [!!] Node.js not found. Please install Node.js.'); return false; } const nodeModules = path.join(__dirname, 'node_modules'); if (!fs.existsSync(nodeModules)) { console.log('[*] Installing dependencies...'); try { execSync('npm install', { cwd: __dirname, stdio: 'inherit' }); console.log(' [OK] Dependencies installed'); } catch { console.log(' [!!] Failed to install dependencies. Run "npm install" manually in ServerFiles/'); return false; } } else { console.log(' [OK] Dependencies already installed'); } return true; } async function setupPhotosPath(platform) { const current = config.getPhotosPath(); if (current) { console.log(`[*] Current photos path: ${current}`); const change = await ask('Change photos path? (Y/N): '); if (change.trim().toUpperCase() !== 'Y') return; } let defaultPath; if (platform === 'windows') { defaultPath = path.join(os.homedir(), 'NASPhotos'); } else { defaultPath = path.join(os.homedir(), 'nas-photos'); } console.log(`Default path: ${defaultPath}`); const inputPath = await ask('Enter photos storage path (or press Enter for default): '); const finalPath = inputPath.trim() || defaultPath; if (!fs.existsSync(finalPath)) { console.log(`[*] Creating directory: ${finalPath}`); fs.mkdirSync(finalPath, { recursive: true }); } config.setPhotosPath(finalPath); console.log(`[OK] Photos path set to: ${finalPath}`); } async function handlePassword() { console.log(''); console.log('╔══════════════════════════════════════════════╗'); console.log('║ Password Management ║'); console.log('╠══════════════════════════════════════════════╣'); if (passwordManager.hasStoredPassword()) { console.log('║ A password is currently stored. ║'); console.log('║ [V] View password ║'); console.log('║ [C] Change password ║'); console.log('║ [D] Delete password ║'); console.log('║ [B] Back ║'); console.log('╚══════════════════════════════════════════════╝'); const choice = await ask('Select option: '); switch (choice.trim().toUpperCase()) { case 'V': { const pw = passwordManager.retrievePassword(); if (pw) { console.log(''); console.log(` User: ${os.userInfo().username}`); console.log(` Password: ${pw}`); console.log(''); } else { console.log('[!!] Could not decrypt password. It may have been created on another machine.'); } await ask('Press Enter to continue...'); break; } case 'C': { const newPw = await ask('Enter new password: '); if (newPw.trim().length > 0) { passwordManager.storePassword(newPw.trim()); console.log('[OK] Password updated.'); console.log(` New password: ${newPw.trim()}`); } else { console.log('[!] Empty password not saved.'); } await ask('Press Enter to continue...'); break; } case 'D': { const confirm = await ask('Are you sure? (Y/N): '); if (confirm.trim().toUpperCase() === 'Y') { passwordManager.deletePassword(); console.log('[OK] Password deleted.'); } await ask('Press Enter to continue...'); break; } default: break; } } else { console.log('║ No password is stored. ║'); console.log('╚══════════════════════════════════════════════╝'); const store = await ask('Do you want to store a password? (Y/N): '); if (store.trim().toUpperCase() === 'Y') { const pw = await ask('Enter password: '); if (pw.trim().length > 0) { passwordManager.storePassword(pw.trim()); console.log(`[OK] Password stored successfully.`); console.log(` Your password: ${pw.trim()}`); } else { console.log('[!] Empty password not saved.'); } await ask('Press Enter to continue...'); } } } function showConnectionInfo() { const interfaces = os.networkInterfaces(); const addresses = []; for (const [name, nets] of Object.entries(interfaces)) { for (const net of nets) { if (net.family === 'IPv4' && !net.internal) { addresses.push({ name, address: net.address }); } } } console.log(''); console.log('╔══════════════════════════════════════════════╗'); console.log('║ Connection Information ║'); console.log('╠══════════════════════════════════════════════╣'); console.log(`║ User: ${os.userInfo().username.padEnd(35)}║`); if (passwordManager.hasStoredPassword()) { console.log('║ Pass: [STORED] ║'); } else { console.log('║ Pass: [NOT SET] ║'); } console.log(`║ Port: ${String(config.DEFAULT_PORT).padEnd(35)}║`); console.log('║ ║'); if (addresses.length > 0) { console.log('║ Network Addresses: ║'); for (const addr of addresses) { const line = ` ${addr.name}: http://${addr.address}:${config.DEFAULT_PORT}`; console.log(`║${line.padEnd(46)}║`); } } else { console.log('║ No network interfaces found ║'); } console.log('╚══════════════════════════════════════════════╝'); } async function startServerInteractive() { const photosPath = config.getPhotosPath(); if (!photosPath) { console.log('[!!] Photos path not set. Please configure it first.'); await ask('Press Enter to continue...'); return false; } const portInput = await ask(`Enter port (default ${config.DEFAULT_PORT}): `); const port = parseInt(portInput.trim()) || config.DEFAULT_PORT; console.log(`[*] Starting NAS server on port ${port}...`); console.log(`[*] Photos path: ${photosPath}`); console.log('[*] Press Ctrl+C to stop the server.'); console.log(''); const { startServer } = require('./server'); startServer(port); return true; // Server takes over the process } async function mainMenu(platform) { while (true) { clearScreen(); printBanner(); console.log(' [1] Start NAS Server'); console.log(' [2] Configure Photos Path'); console.log(' [3] Password Management (P)'); console.log(' [4] Show Connection Info'); console.log(' [5] Exit'); console.log(''); const choice = await ask('Select option: '); switch (choice.trim().toUpperCase()) { case '1': { const started = await startServerInteractive(); if (started) return; // Server is now running break; } case '2': await setupPhotosPath(platform); break; case '3': case 'P': await handlePassword(); break; case '4': showConnectionInfo(); await ask('\nPress Enter to continue...'); break; case '5': console.log('Goodbye!'); rl.close(); process.exit(0); default: break; } } } async function main() { clearScreen(); console.log('Welcome to NAS Photo Server Setup'); console.log(''); const platform = await detectOrAskPlatform(); console.log(''); if (!checkDependencies()) { rl.close(); process.exit(1); } console.log(''); // First-time setup: photos path if (!config.getPhotosPath()) { console.log('[!] No photos path configured. Let\'s set one up.'); await setupPhotosPath(platform); console.log(''); } // Ask about password on first run if (!passwordManager.hasStoredPassword()) { const storePw = await ask('Do you want to store a password? (Y/N): '); if (storePw.trim().toUpperCase() === 'Y') { const pw = await ask('Enter password: '); if (pw.trim().length > 0) { passwordManager.storePassword(pw.trim()); console.log(`[OK] Password stored. Your password: ${pw.trim()}`); } } console.log(''); } await mainMenu(platform); } main().catch(err => { console.error('Fatal error:', err); process.exit(1); });