diff --git a/UI/includes/enrollment.php b/UI/includes/enrollment.php index f69a656..dd0ae1f 100644 --- a/UI/includes/enrollment.php +++ b/UI/includes/enrollment.php @@ -179,41 +179,23 @@ class EnrollmentManager { return true; } - $this->reportProgress('INSTALL', 'Setting up OpenZiti package repository...'); + $this->reportProgress('INSTALL', 'Installing OpenZiti CLI from pre-configured repository...'); - // Add GPG key using enhanced method to handle PHP execution environment - if (!$this->addOpenZitiGpgKey()) { - throw new Exception('Failed to add OpenZiti GPG key'); + // Verify repository is configured + if (!file_exists('/etc/apt/sources.list.d/openziti-release.list')) { + throw new Exception('OpenZiti repository not configured. Please run install.sh first to set up the system.'); } - // Set proper permissions - if (!executeCommand('chmod a+r /usr/share/keyrings/openziti.gpg')) { - throw new Exception('Failed to set GPG key permissions'); + if (!file_exists('/usr/share/keyrings/openziti.gpg')) { + throw new Exception('OpenZiti GPG key not found. Please run install.sh first to set up the system.'); } - // Add repository to sources list - $repoContent = 'deb [signed-by=/usr/share/keyrings/openziti.gpg] https://packages.openziti.org/zitipax-openziti-deb-stable debian main'; - $tempFile = tempnam(sys_get_temp_dir(), 'openziti-repo'); - file_put_contents($tempFile, $repoContent); - - if (!executeCommand("cp '$tempFile' /etc/apt/sources.list.d/openziti-release.list")) { - unlink($tempFile); - throw new Exception('Failed to add OpenZiti repository'); - } - unlink($tempFile); - - // Update package list - $this->reportProgress('INSTALL', 'Updating package list...'); - if (!executeCommand('apt-get update')) { - throw new Exception('Failed to update package list'); - } - - // Install openziti-router package + // Install openziti-router package from pre-configured repository $this->reportProgress('INSTALL', 'Installing openziti-router package...'); if (!executeCommand('apt-get install -y openziti-router')) { $this->reportProgress('INSTALL', 'Trying to install ziti CLI only...'); if (!executeCommand('apt-get install -y ziti')) { - throw new Exception('Failed to install OpenZiti CLI'); + throw new Exception('Failed to install OpenZiti CLI. Repository may not be properly configured. Please run install.sh first.'); } } @@ -528,191 +510,6 @@ EOF; ); } - /** - * Add OpenZiti GPG key with enhanced error handling for CloudStack environments - */ - private function addOpenZitiGpgKey() { - $gpgKeyUrl = 'https://get.openziti.io/tun/package-repos.gpg'; - $gpgKeyPath = '/usr/share/keyrings/openziti.gpg'; - - // First, check if GPG key already exists and is valid - if (file_exists($gpgKeyPath) && filesize($gpgKeyPath) > 0) { - $this->reportProgress('INSTALL', 'OpenZiti GPG key already exists (' . filesize($gpgKeyPath) . ' bytes), skipping installation'); - logMessage('INFO', 'GPG key already exists at: ' . $gpgKeyPath); - return true; - } - - $this->reportProgress('INSTALL', 'Installing OpenZiti GPG key...'); - - // Ensure keyrings directory exists with proper permissions - if (!$this->ensureKeyringsDirectory()) { - logMessage('ERROR', 'Failed to create keyrings directory'); - return false; - } - - // Method 1: CloudStack-optimized approach - download and process separately - $this->reportProgress('INSTALL', 'Downloading GPG key...'); - $tempGpgFile = tempnam(sys_get_temp_dir(), 'openziti-gpg'); - - // Step 1: Download GPG key with detailed error reporting - $downloadCommand = 'curl -sSLf --connect-timeout 30 --max-time 60 ' . $gpgKeyUrl . ' -o ' . $tempGpgFile; - $output = ''; - - if (!executeCommand($downloadCommand, $output)) { - @unlink($tempGpgFile); - $errorMsg = 'Failed to download GPG key from ' . $gpgKeyUrl . '. Error: ' . $output; - logMessage('ERROR', $errorMsg); - $this->reportProgress('INSTALL', 'Download failed: ' . $output); - return false; - } - - // Step 2: Verify downloaded file - if (!file_exists($tempGpgFile) || filesize($tempGpgFile) == 0) { - @unlink($tempGpgFile); - $errorMsg = 'Downloaded GPG key file is empty or missing'; - logMessage('ERROR', $errorMsg); - $this->reportProgress('INSTALL', $errorMsg); - return false; - } - - $fileSize = filesize($tempGpgFile); - $this->reportProgress('INSTALL', "GPG key downloaded successfully ($fileSize bytes), processing..."); - logMessage('INFO', "Downloaded GPG key: $fileSize bytes to $tempGpgFile"); - - // Step 3: Try multiple processing methods with detailed error reporting - $methods = [ - 'sudo_gpg_dearmor' => [ - 'name' => 'Sudo GPG dearmor', - 'command' => "sudo /usr/bin/gpg --dearmor --output '$gpgKeyPath' '$tempGpgFile'" - ], - 'direct_gpg_dearmor' => [ - 'name' => 'Direct GPG dearmor', - 'command' => "/usr/bin/gpg --dearmor --output '$gpgKeyPath' '$tempGpgFile'" - ], - 'sudo_cat_pipe' => [ - 'name' => 'Sudo cat pipe', - 'command' => "sudo bash -c 'cat $tempGpgFile | /usr/bin/gpg --dearmor > $gpgKeyPath'" - ], - 'sudo_redirect' => [ - 'name' => 'Sudo redirect', - 'command' => "sudo bash -c '/usr/bin/gpg --dearmor < $tempGpgFile > $gpgKeyPath'" - ], - 'python_base64' => [ - 'name' => 'Python base64 decode', - 'command' => "sudo python3 -c \"import base64; open('$gpgKeyPath', 'wb').write(base64.b64decode(open('$tempGpgFile', 'rb').read()))\"" - ] - ]; - - foreach ($methods as $methodKey => $method) { - $this->reportProgress('INSTALL', "Trying method: {$method['name']}..."); - logMessage('INFO', "Attempting GPG processing method: {$method['name']}"); - - $output = ''; - if (executeCommand($method['command'], $output)) { - // Verify the processed file exists and has content - if (file_exists($gpgKeyPath) && filesize($gpgKeyPath) > 0) { - @unlink($tempGpgFile); - $processedSize = filesize($gpgKeyPath); - $this->reportProgress('INSTALL', "GPG key processed successfully using {$method['name']} ($processedSize bytes)"); - logMessage('INFO', "GPG key successfully processed: $processedSize bytes at $gpgKeyPath"); - return true; - } else { - logMessage('WARNING', "Method {$method['name']} completed but output file is missing or empty"); - } - } else { - logMessage('WARNING', "Method {$method['name']} failed: $output"); - } - } - - // Method 4: Last resort - try to use the raw file directly - $this->reportProgress('INSTALL', 'Trying raw file copy as last resort...'); - logMessage('INFO', 'Attempting raw file copy as final fallback'); - - if (executeCommand("sudo cp '$tempGpgFile' '$gpgKeyPath'", $output)) { - if (file_exists($gpgKeyPath) && filesize($gpgKeyPath) > 0) { - @unlink($tempGpgFile); - $this->reportProgress('INSTALL', 'GPG key copied as raw file - apt will handle format conversion'); - logMessage('INFO', 'GPG key copied as raw file for apt to process'); - return true; - } - } - - // Clean up and report final failure - @unlink($tempGpgFile); - $errorMsg = 'All GPG key installation methods failed. Check system permissions and network connectivity.'; - logMessage('ERROR', $errorMsg); - $this->reportProgress('INSTALL', $errorMsg); - - // Additional diagnostic information - $this->logDiagnosticInfo(); - - return false; - } - - /** - * Ensure keyrings directory exists with proper permissions - */ - private function ensureKeyringsDirectory() { - $keyringsDir = '/usr/share/keyrings'; - - // Check if directory exists - if (is_dir($keyringsDir)) { - logMessage('INFO', 'Keyrings directory already exists'); - return true; - } - - // Try to create directory - $output = ''; - if (executeCommand("sudo mkdir -p '$keyringsDir'", $output)) { - if (executeCommand("sudo chmod 755 '$keyringsDir'", $output)) { - logMessage('INFO', 'Keyrings directory created successfully'); - return true; - } else { - logMessage('ERROR', 'Failed to set keyrings directory permissions: ' . $output); - return false; - } - } else { - logMessage('ERROR', 'Failed to create keyrings directory: ' . $output); - return false; - } - } - - /** - * Log diagnostic information for troubleshooting - */ - private function logDiagnosticInfo() { - $diagnostics = []; - - // Check basic commands - $commands = ['curl', 'gpg', 'python3', 'sudo']; - foreach ($commands as $cmd) { - $output = ''; - $available = executeCommand("which $cmd", $output) ? 'available' : 'not found'; - $diagnostics[] = "$cmd: $available"; - } - - // Check permissions - $output = ''; - executeCommand('id', $output); - $diagnostics[] = "Current user: " . trim($output); - - // Check sudo permissions - $output = ''; - executeCommand('sudo -l | grep gpg', $output); - $diagnostics[] = "GPG sudo permissions: " . (empty(trim($output)) ? 'none found' : 'available'); - - // Check network connectivity - $output = ''; - $networkOk = executeCommand('curl -I --connect-timeout 5 https://get.openziti.io', $output) ? 'working' : 'failed'; - $diagnostics[] = "Network connectivity: $networkOk"; - - // Check disk space - $output = ''; - executeCommand('df -h /usr/share', $output); - $diagnostics[] = "Disk space: " . trim($output); - - logMessage('INFO', 'GPG Installation Diagnostics: ' . implode('; ', $diagnostics)); - } /** * Check if command exists diff --git a/UI/install.sh b/UI/install.sh index 711fe4b..f1ce855 100644 --- a/UI/install.sh +++ b/UI/install.sh @@ -337,6 +337,106 @@ configure_php() { log "SUCCESS" "PHP configured successfully" } +# Set up OpenZiti package repository +setup_openziti_repository() { + log "INFO" "Setting up OpenZiti package repository..." + + local gpgKeyUrl='https://get.openziti.io/tun/package-repos.gpg' + local gpgKeyPath='/usr/share/keyrings/openziti.gpg' + + # Check if GPG key already exists and is valid + if [[ -f "$gpgKeyPath" && -s "$gpgKeyPath" ]]; then + local keySize=$(wc -c < "$gpgKeyPath") + log "SUCCESS" "OpenZiti GPG key already exists ($keySize bytes), skipping installation" + else + log "INFO" "Installing OpenZiti GPG key..." + + # Ensure keyrings directory exists + mkdir -p /usr/share/keyrings || error_exit "Failed to create keyrings directory" + chmod 755 /usr/share/keyrings || error_exit "Failed to set keyrings directory permissions" + + # Download GPG key to temporary file + local tempGpgFile=$(mktemp) + log "INFO" "Downloading GPG key from $gpgKeyUrl..." + + if curl -sSLf --connect-timeout 30 --max-time 60 "$gpgKeyUrl" -o "$tempGpgFile"; then + local fileSize=$(wc -c < "$tempGpgFile") + log "SUCCESS" "GPG key downloaded successfully ($fileSize bytes)" + + # Try multiple methods to process the GPG key + local methods=( + "gpg --dearmor --output '$gpgKeyPath' '$tempGpgFile'" + "cat '$tempGpgFile' | gpg --dearmor > '$gpgKeyPath'" + "gpg --dearmor < '$tempGpgFile' > '$gpgKeyPath'" + ) + + local success=false + for method in "${methods[@]}"; do + log "INFO" "Trying GPG processing method: $method" + if eval "$method" 2>/dev/null; then + if [[ -f "$gpgKeyPath" && -s "$gpgKeyPath" ]]; then + local processedSize=$(wc -c < "$gpgKeyPath") + log "SUCCESS" "GPG key processed successfully ($processedSize bytes)" + success=true + break + fi + fi + done + + # Fallback: copy raw file and let apt handle it + if [[ "$success" != true ]]; then + log "WARNING" "GPG processing failed, trying raw file copy..." + if cp "$tempGpgFile" "$gpgKeyPath"; then + log "SUCCESS" "GPG key copied as raw file - apt will handle format conversion" + success=true + fi + fi + + rm -f "$tempGpgFile" + + if [[ "$success" != true ]]; then + error_exit "Failed to install OpenZiti GPG key" + fi + else + rm -f "$tempGpgFile" + error_exit "Failed to download OpenZiti GPG key from $gpgKeyUrl" + fi + fi + + # Set proper permissions on GPG key + chmod a+r "$gpgKeyPath" || error_exit "Failed to set GPG key permissions" + + # Configure OpenZiti repository + local repoFile='/etc/apt/sources.list.d/openziti-release.list' + local repoContent='deb [signed-by=/usr/share/keyrings/openziti.gpg] https://packages.openziti.org/zitipax-openziti-deb-stable debian main' + + if [[ -f "$repoFile" ]]; then + log "INFO" "OpenZiti repository already configured" + else + log "INFO" "Configuring OpenZiti repository..." + echo "$repoContent" > "$repoFile" || error_exit "Failed to create repository file" + log "SUCCESS" "OpenZiti repository configured" + fi + + # Update package list + log "INFO" "Updating package list..." + if apt update >/dev/null 2>&1; then + log "SUCCESS" "Package list updated successfully" + else + log "WARNING" "Package list update had issues, but continuing..." + fi + + # Verify repository is accessible + log "INFO" "Verifying OpenZiti repository accessibility..." + if apt-cache show openziti-router >/dev/null 2>&1; then + log "SUCCESS" "OpenZiti repository is accessible and openziti-router package is available" + elif apt-cache show ziti >/dev/null 2>&1; then + log "SUCCESS" "OpenZiti repository is accessible and ziti package is available" + else + log "WARNING" "OpenZiti packages not found in repositories, but repository is configured" + fi +} + # Set up sudo access setup_sudo() { log "INFO" "Setting up comprehensive sudo access for web server..." @@ -571,6 +671,9 @@ main() { # Set up sudo access setup_sudo + # Set up OpenZiti package repository + setup_openziti_repository + # Update hosts file update_hosts diff --git a/UI/public/pre-enrollment-check.php b/UI/public/pre-enrollment-check.php deleted file mode 100644 index 529b905..0000000 --- a/UI/public/pre-enrollment-check.php +++ /dev/null @@ -1,399 +0,0 @@ -&1', $outputLines, $returnCode); - $output = implode("\n", $outputLines); - $duration = round((microtime(true) - $startTime) * 1000, 2); - - return [ - 'command' => $command, - 'description' => $description, - 'success' => $returnCode === 0, - 'returnCode' => $returnCode, - 'output' => $output, - 'duration' => $duration . 'ms' - ]; -} - -/** - * Check file/directory status - */ -function checkPath($path, $description, $expectedType = 'file') { - $exists = false; - $readable = false; - $writable = false; - $size = 0; - $permissions = ''; - - if (file_exists($path)) { - $exists = true; - $readable = is_readable($path); - $writable = is_writable($path); - - if ($expectedType === 'file' && is_file($path)) { - $size = filesize($path); - } - - $permissions = substr(sprintf('%o', fileperms($path)), -4); - } - - return [ - 'path' => $path, - 'description' => $description, - 'exists' => $exists, - 'readable' => $readable, - 'writable' => $writable, - 'size' => $size, - 'permissions' => $permissions, - 'type' => $expectedType - ]; -} - -/** - * Run all pre-enrollment checks - */ -function runPreEnrollmentChecks() { - $results = [ - 'timestamp' => date('Y-m-d H:i:s T'), - 'environment' => [], - 'commands' => [], - 'permissions' => [], - 'network' => [], - 'files' => [], - 'recommendations' => [] - ]; - - // Environment checks - $results['environment'] = [ - 'php_version' => PHP_VERSION, - 'php_sapi' => php_sapi_name(), - 'os' => PHP_OS, - 'user' => get_current_user(), - 'uid' => function_exists('posix_getuid') ? posix_getuid() : 'unknown', - 'gid' => function_exists('posix_getgid') ? posix_getgid() : 'unknown', - 'working_dir' => getcwd(), - 'temp_dir' => sys_get_temp_dir() - ]; - - // Command availability checks - $commands = [ - 'curl' => 'curl --version', - 'gpg' => 'gpg --version', - 'sudo' => 'sudo --version', - 'systemctl' => 'systemctl --version', - 'python3' => 'python3 --version', - 'which' => 'which which', - 'apt-get' => 'apt-get --version', - 'jq' => 'jq --version' - ]; - - foreach ($commands as $name => $command) { - $results['commands'][$name] = checkCommand("which $name", "Check if $name is available"); - if ($results['commands'][$name]['success']) { - $results['commands'][$name . '_version'] = checkCommand($command, "Get $name version"); - } - } - - // Sudo permissions check - $results['permissions']['sudo_test'] = checkCommand('sudo -n whoami', 'Test sudo access without password'); - $results['permissions']['sudo_list'] = checkCommand('sudo -l', 'List sudo permissions'); - - // Network connectivity checks - $results['network']['dns_resolution'] = checkCommand('nslookup get.openziti.io', 'DNS resolution for OpenZiti'); - $results['network']['ping_test'] = checkCommand('ping -c 1 get.openziti.io', 'Ping OpenZiti server'); - $results['network']['https_test'] = checkCommand('curl -I --connect-timeout 10 https://get.openziti.io', 'HTTPS connectivity test'); - $results['network']['gpg_key_download'] = checkCommand('curl -I --connect-timeout 10 https://get.openziti.io/tun/package-repos.gpg', 'GPG key URL accessibility'); - - // File system checks - $paths = [ - '/usr/share/keyrings' => 'OpenZiti keyrings directory', - '/usr/share/keyrings/openziti.gpg' => 'OpenZiti GPG key file', - '/etc/apt/sources.list.d' => 'APT sources directory', - '/etc/apt/sources.list.d/openziti-release.list' => 'OpenZiti repository file', - '/tmp' => 'Temporary directory', - '/var/log' => 'Log directory' - ]; - - foreach ($paths as $path => $description) { - $expectedType = (substr($path, -1) === '/' || is_dir($path)) ? 'directory' : 'file'; - $results['files'][$path] = checkPath($path, $description, $expectedType); - } - - // Generate recommendations - $results['recommendations'] = generateRecommendations($results); - - return $results; -} - -/** - * Generate recommendations based on check results - */ -function generateRecommendations($results) { - $recommendations = []; - - // Check if running as www-data - if ($results['environment']['user'] === 'www-data') { - $recommendations[] = [ - 'type' => 'info', - 'message' => 'Running as www-data user (web server context)', - 'action' => 'This is expected for web-based enrollment' - ]; - } - - // Check sudo access - if (!$results['permissions']['sudo_test']['success']) { - $recommendations[] = [ - 'type' => 'error', - 'message' => 'Sudo access not working', - 'action' => 'Run: sudo ./fix-permissions.sh or ensure www-data has proper sudo permissions' - ]; - } - - // Check required commands - $requiredCommands = ['curl', 'gpg', 'sudo', 'systemctl']; - foreach ($requiredCommands as $cmd) { - if (!$results['commands'][$cmd]['success']) { - $recommendations[] = [ - 'type' => 'error', - 'message' => "Required command '$cmd' not found", - 'action' => "Install $cmd: sudo apt-get update && sudo apt-get install -y $cmd" - ]; - } - } - - // Check network connectivity - if (!$results['network']['https_test']['success']) { - $recommendations[] = [ - 'type' => 'error', - 'message' => 'HTTPS connectivity to OpenZiti failed', - 'action' => 'Check firewall settings and internet connectivity' - ]; - } - - // Check if GPG key already exists - if ($results['files']['/usr/share/keyrings/openziti.gpg']['exists']) { - $size = $results['files']['/usr/share/keyrings/openziti.gpg']['size']; - if ($size > 0) { - $recommendations[] = [ - 'type' => 'success', - 'message' => "OpenZiti GPG key already exists ($size bytes)", - 'action' => 'GPG key installation should be skipped automatically' - ]; - } else { - $recommendations[] = [ - 'type' => 'warning', - 'message' => 'OpenZiti GPG key file exists but is empty', - 'action' => 'Remove the empty file: sudo rm /usr/share/keyrings/openziti.gpg' - ]; - } - } - - // Check keyrings directory - if (!$results['files']['/usr/share/keyrings']['exists']) { - $recommendations[] = [ - 'type' => 'warning', - 'message' => 'Keyrings directory does not exist', - 'action' => 'Will be created automatically during enrollment' - ]; - } - - return $recommendations; -} - -/** - * Output results in HTML format - */ -function outputHTML($results) { - ?> - - -
- - -Purpose: Verify system readiness for ZitiNexus Router enrollment
-Time:
- - -| - | - |
| Command | Status | Details |
|---|---|---|
| - | - - | -- - - - - - | -
| Path | Status | Size | Permissions | Description |
|---|---|---|---|---|
| - | - - | -0 ? number_format($info['size']) . ' bytes' : '-'; ?> | -- | - |
sudo ./fix-permissions.sh/var/www/ziti-enrollment/logs/ if enrollment fails