Files

343 lines
12 KiB
JavaScript

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);
});