diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..0f14b00 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,24 @@ +# NebuleAir Pro 4G Development Guidelines + +## Commands +- `sudo systemctl restart master_nebuleair.service` - Restart main service +- `sudo systemctl status master_nebuleair.service` - Check service status +- Manual testing: Run individual Python scripts (e.g., `sudo python3 NPM/get_data_modbus_v3.py`) +- Installation: `sudo ./installation_part1.sh` followed by `sudo ./installation_part2.sh` + +## Code Style +- **Language:** Python 3 with HTML/JS/CSS for web interface +- **Structure:** Organized by component (BME280, NPM, RTC, SARA, etc.) +- **Naming:** snake_case for variables/functions, version suffix for iterations (e.g., `_v2.py`) +- **Documentation:** Include docstrings with script purpose and usage instructions +- **Error Handling:** Use try/except blocks for I/O operations, print errors to logs +- **Configuration:** All settings in `config.json`, avoid hardcoding values +- **Web Components:** Follow Bootstrap patterns, use fetch() for AJAX + +## Best Practices +- Check if features are enabled in config before execution +- Close database connections after use +- Round sensor readings to appropriate precision +- Keep web interface mobile-responsive +- Include error handling for network operations +- Follow existing patterns when adding new functionality \ No newline at end of file diff --git a/html/config.html b/html/config.html new file mode 100644 index 0000000..aafbc8c --- /dev/null +++ b/html/config.html @@ -0,0 +1,344 @@ + + + + + + NebuleAir - Config Editor + + + + + + + + +
+
+
NebuleAir
+ +
+ +
+ +
+
+ + + +
+

Configuration Editor

+ +
+
+
+ Warning: Editing the configuration file directly can affect system functionality. + Make changes carefully and ensure valid JSON format. +
+ +
+
+
config.json
+
+ + + +
+
+
+
+ +
+
+
+
+
+
+
+ + +
+
+
Authentication Required
+

Please enter the admin password to edit configuration:

+
+ +
+
+ + +
+ +
+
+ + + + + + + + + + + + \ No newline at end of file diff --git a/html/launcher.php b/html/launcher.php index bb60cbe..5537647 100755 --- a/html/launcher.php +++ b/html/launcher.php @@ -4,7 +4,8 @@ header("Content-Type: application/json"); header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0"); header("Pragma: no-cache"); -$type=$_GET['type']; +// Get request type from GET or POST parameters +$type = isset($_GET['type']) ? $_GET['type'] : (isset($_POST['type']) ? $_POST['type'] : ''); if ($type == "get_npm_sqlite_data") { $database_path = "/var/www/nebuleair_pro_4g/sqlite/sensors.db"; @@ -484,3 +485,193 @@ if ($type == "wifi_scan_old") { echo $json_data; } + +// Save config.json with password protection +if ($type == "save_config") { + // Verify that the request is using POST method + if ($_SERVER['REQUEST_METHOD'] !== 'POST') { + echo json_encode(['success' => false, 'message' => 'Invalid request method']); + exit; + } + + // Get the config content from POST data + $config = isset($_POST['config']) ? $_POST['config'] : ''; + + if (empty($config)) { + echo json_encode(['success' => false, 'message' => 'No configuration data provided']); + exit; + } + + // Validate that the content is valid JSON + $decodedConfig = json_decode($config); + if (json_last_error() !== JSON_ERROR_NONE) { + echo json_encode([ + 'success' => false, + 'message' => 'Invalid JSON format: ' . json_last_error_msg() + ]); + exit; + } + + // Path to the configuration file + $configFile = '/var/www/nebuleair_pro_4g/config.json'; + + // Create a backup of the current config + $backupFile = '/var/www/nebuleair_pro_4g/config.json.backup-' . date('Y-m-d-H-i-s'); + if (file_exists($configFile)) { + copy($configFile, $backupFile); + } + + // Write the updated configuration to the file + $result = file_put_contents($configFile, $config); + + if ($result === false) { + echo json_encode([ + 'success' => false, + 'message' => 'Failed to write configuration file. Check permissions.' + ]); + } else { + echo json_encode([ + 'success' => true, + 'message' => 'Configuration saved successfully', + 'bytes_written' => $result + ]); + } +} + +// Execute shell command with security restrictions +if ($type == "execute_command") { + // Verify that the request is using POST method + if ($_SERVER['REQUEST_METHOD'] !== 'POST') { + echo json_encode(['success' => false, 'message' => 'Invalid request method']); + exit; + } + + // Get the command from POST data + $command = isset($_POST['command']) ? $_POST['command'] : ''; + + if (empty($command)) { + echo json_encode(['success' => false, 'message' => 'No command provided']); + exit; + } + + // List of allowed commands (prefixes) + $allowedCommands = [ + 'ls', 'cat', 'cd', 'pwd', 'df', 'free', 'ifconfig', 'ip', 'ps', 'date', 'uptime', + 'systemctl status', 'whoami', 'hostname', 'uname', 'grep', 'tail', 'head', 'find', + 'less', 'more', 'du', 'echo' + ]; + + // Check if command is allowed + $allowed = false; + foreach ($allowedCommands as $allowedCmd) { + if (strpos($command, $allowedCmd) === 0) { + $allowed = true; + break; + } + } + + // Special case for systemctl restart and reboot + if (strpos($command, 'systemctl restart') === 0 || $command === 'reboot') { + // These commands don't return output through shell_exec since they change process state + // We'll just acknowledge them + if ($command === 'reboot') { + // Execute the command with exec to avoid waiting for output + exec('sudo reboot > /dev/null 2>&1 &'); + echo json_encode([ + 'success' => true, + 'output' => 'System is rebooting...' + ]); + } else { + // For systemctl restart, execute it and acknowledge + $serviceName = str_replace('systemctl restart ', '', $command); + exec('sudo systemctl restart ' . escapeshellarg($serviceName) . ' > /dev/null 2>&1 &'); + echo json_encode([ + 'success' => true, + 'output' => 'Service ' . $serviceName . ' is restarting...' + ]); + } + exit; + } + + // Check for prohibited patterns + $prohibitedPatterns = [ + 'sudo rm', ';', '&&', '||', '|', '>', '>>', '&', + 'wget', 'curl', 'nc', 'ssh', 'scp', 'ftp', 'telnet', + 'iptables', 'passwd', 'chown', 'chmod', 'mkfs', 'dd', + 'mount', 'umount', 'kill', 'killall' + ]; + + foreach ($prohibitedPatterns as $pattern) { + if (strpos($command, $pattern) !== false) { + echo json_encode([ + 'success' => false, + 'message' => 'Command contains prohibited operation: ' . $pattern + ]); + exit; + } + } + + if (!$allowed) { + echo json_encode([ + 'success' => false, + 'message' => 'Command not allowed for security reasons' + ]); + exit; + } + + // Execute the command with timeout protection + $descriptorspec = [ + 0 => ["pipe", "r"], // stdin + 1 => ["pipe", "w"], // stdout + 2 => ["pipe", "w"] // stderr + ]; + + // Escape the command to prevent shell injection + $escapedCommand = escapeshellcmd($command); + + // Add timeout of 5 seconds to prevent long-running commands + $process = proc_open("timeout 5 $escapedCommand", $descriptorspec, $pipes); + + if (is_resource($process)) { + // Close stdin pipe + fclose($pipes[0]); + + // Get output from stdout + $output = stream_get_contents($pipes[1]); + fclose($pipes[1]); + + // Get any errors + $errors = stream_get_contents($pipes[2]); + fclose($pipes[2]); + + // Close the process + $returnValue = proc_close($process); + + // Check for errors + if ($returnValue !== 0) { + // If there was an error, but we have output, consider it a partial success + if (!empty($output)) { + echo json_encode([ + 'success' => true, + 'output' => $output . "\n" . $errors . "\nCommand exited with code $returnValue" + ]); + } else { + echo json_encode([ + 'success' => false, + 'message' => empty($errors) ? "Command failed with exit code $returnValue" : $errors + ]); + } + } else { + // Success + echo json_encode([ + 'success' => true, + 'output' => $output + ]); + } + } else { + echo json_encode([ + 'success' => false, + 'message' => 'Failed to execute command' + ]); + } +} diff --git a/html/sidebar.html b/html/sidebar.html index a7b8d97..782127b 100755 --- a/html/sidebar.html +++ b/html/sidebar.html @@ -47,6 +47,18 @@ Carte + + + + + Config + + + + + + Terminal + diff --git a/html/terminal.html b/html/terminal.html new file mode 100644 index 0000000..9470c10 --- /dev/null +++ b/html/terminal.html @@ -0,0 +1,401 @@ + + + + + + NebuleAir - Terminal + + + + + + + + +
+
+
NebuleAir
+ +
+ +
+ +
+
+ + + +
+

Terminal Console

+ +
+
+
+ Warning: This terminal provides direct access to system commands. + Use with caution as improper commands may affect system functionality. +
+ +
+
Quick Commands:
+
+ ls -la + df -h + free -h + uptime + service status + view config +
+
+ +
+
+
Command Console
+
+ + +
+
+
+
+
Welcome to NebuleAir Terminal Console +Type your commands below. Type 'help' for a list of commands. +
+ +
+ +
+
+
+
+
+
+
+ + +
+
+
Authentication Required
+

Please enter the admin password to access the terminal:

+
+ +
+
+ + +
+ +
+
+ + + + + + + + + + \ No newline at end of file