zitinexus-router-script/UI/pre-enrollment-check.php

400 lines
17 KiB
PHP

<?php
/**
* Pre-Enrollment Check Script
* Verifies system readiness before attempting router enrollment
*/
require_once 'includes/config.php';
// Set content type for web access
if (php_sapi_name() !== 'cli') {
header('Content-Type: text/html; charset=UTF-8');
}
/**
* Execute command and return detailed result
*/
function checkCommand($command, $description) {
$startTime = microtime(true);
$output = '';
$returnCode = 0;
exec($command . ' 2>&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) {
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Pre-Enrollment System Check</title>
<style>
body { font-family: monospace; margin: 20px; background: #f5f5f5; }
.container { max-width: 1200px; margin: 0 auto; background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
.section { margin: 20px 0; padding: 15px; border: 1px solid #ddd; border-radius: 5px; }
.section h3 { margin-top: 0; color: #333; border-bottom: 2px solid #007bff; padding-bottom: 5px; }
.success { background-color: #d4edda; border-color: #c3e6cb; color: #155724; }
.warning { background-color: #fff3cd; border-color: #ffeaa7; color: #856404; }
.error { background-color: #f8d7da; border-color: #f5c6cb; color: #721c24; }
.info { background-color: #d1ecf1; border-color: #bee5eb; color: #0c5460; }
.command { background: #f8f9fa; padding: 10px; border-left: 4px solid #007bff; margin: 10px 0; font-family: 'Courier New', monospace; }
.output { background: #2d3748; color: #e2e8f0; padding: 10px; border-radius: 4px; margin: 10px 0; white-space: pre-wrap; font-family: 'Courier New', monospace; }
table { width: 100%; border-collapse: collapse; margin: 10px 0; }
th, td { padding: 8px; text-align: left; border-bottom: 1px solid #ddd; }
th { background-color: #f2f2f2; }
.status-ok { color: #28a745; font-weight: bold; }
.status-fail { color: #dc3545; font-weight: bold; }
.status-warn { color: #ffc107; font-weight: bold; }
</style>
</head>
<body>
<div class="container">
<h1>🔍 Pre-Enrollment System Check</h1>
<p><strong>Purpose:</strong> Verify system readiness for ZitiNexus Router enrollment</p>
<p><strong>Time:</strong> <?php echo $results['timestamp']; ?></p>
<!-- Environment Information -->
<div class="section info">
<h3>📋 Environment Information</h3>
<table>
<?php foreach ($results['environment'] as $key => $value): ?>
<tr>
<td><?php echo ucwords(str_replace('_', ' ', $key)); ?></td>
<td><?php echo htmlspecialchars($value); ?></td>
</tr>
<?php endforeach; ?>
</table>
</div>
<!-- Command Availability -->
<div class="section">
<h3>🔧 Command Availability</h3>
<table>
<tr><th>Command</th><th>Status</th><th>Details</th></tr>
<?php foreach ($results['commands'] as $name => $result): ?>
<?php if (strpos($name, '_version') !== false) continue; ?>
<tr>
<td><?php echo htmlspecialchars($name); ?></td>
<td class="<?php echo $result['success'] ? 'status-ok' : 'status-fail'; ?>">
<?php echo $result['success'] ? '✅ Available' : '❌ Not Found'; ?>
</td>
<td>
<?php if ($result['success'] && isset($results['commands'][$name . '_version'])): ?>
<?php echo htmlspecialchars(trim(explode("\n", $results['commands'][$name . '_version']['output'])[0])); ?>
<?php else: ?>
<?php echo htmlspecialchars($result['output']); ?>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
</table>
</div>
<!-- Permissions Check -->
<div class="section">
<h3>🔐 Permissions Check</h3>
<?php foreach ($results['permissions'] as $name => $result): ?>
<div class="command"><?php echo htmlspecialchars($result['command']); ?></div>
<div class="<?php echo $result['success'] ? 'success' : 'error'; ?>">
<strong>Status:</strong> <?php echo $result['success'] ? '✅ SUCCESS' : '❌ FAILED'; ?><br>
<strong>Return Code:</strong> <?php echo $result['returnCode']; ?><br>
<strong>Duration:</strong> <?php echo $result['duration']; ?>
</div>
<?php if (!empty($result['output'])): ?>
<div class="output"><?php echo htmlspecialchars($result['output']); ?></div>
<?php endif; ?>
<?php endforeach; ?>
</div>
<!-- Network Connectivity -->
<div class="section">
<h3>🌐 Network Connectivity</h3>
<?php foreach ($results['network'] as $name => $result): ?>
<div class="command"><?php echo htmlspecialchars($result['command']); ?></div>
<div class="<?php echo $result['success'] ? 'success' : 'warning'; ?>">
<strong>Status:</strong> <?php echo $result['success'] ? '✅ SUCCESS' : '⚠️ FAILED'; ?><br>
<strong>Return Code:</strong> <?php echo $result['returnCode']; ?><br>
<strong>Duration:</strong> <?php echo $result['duration']; ?>
</div>
<?php if (!empty($result['output'])): ?>
<div class="output"><?php echo htmlspecialchars(substr($result['output'], 0, 500)) . (strlen($result['output']) > 500 ? '...' : ''); ?></div>
<?php endif; ?>
<?php endforeach; ?>
</div>
<!-- File System Status -->
<div class="section">
<h3>📁 File System Status</h3>
<table>
<tr><th>Path</th><th>Status</th><th>Size</th><th>Permissions</th><th>Description</th></tr>
<?php foreach ($results['files'] as $path => $info): ?>
<tr>
<td><?php echo htmlspecialchars($path); ?></td>
<td class="<?php echo $info['exists'] ? 'status-ok' : 'status-warn'; ?>">
<?php echo $info['exists'] ? '✅ Exists' : '⚠️ Missing'; ?>
</td>
<td><?php echo $info['size'] > 0 ? number_format($info['size']) . ' bytes' : '-'; ?></td>
<td><?php echo $info['permissions'] ?: '-'; ?></td>
<td><?php echo htmlspecialchars($info['description']); ?></td>
</tr>
<?php endforeach; ?>
</table>
</div>
<!-- Recommendations -->
<div class="section">
<h3>💡 Recommendations</h3>
<?php if (empty($results['recommendations'])): ?>
<div class="success">
<strong>✅ System appears ready for enrollment!</strong><br>
No critical issues detected.
</div>
<?php else: ?>
<?php foreach ($results['recommendations'] as $rec): ?>
<div class="<?php echo $rec['type']; ?>">
<strong><?php echo ucfirst($rec['type']); ?>:</strong> <?php echo htmlspecialchars($rec['message']); ?><br>
<strong>Action:</strong> <?php echo htmlspecialchars($rec['action']); ?>
</div>
<?php endforeach; ?>
<?php endif; ?>
</div>
<!-- Next Steps -->
<div class="section info">
<h3>🚀 Next Steps</h3>
<ol>
<li><strong>Address any errors or warnings</strong> shown in the recommendations above</li>
<li><strong>Run fix-permissions.sh</strong> if sudo access is not working: <code>sudo ./fix-permissions.sh</code></li>
<li><strong>Try the enrollment process</strong> once all critical issues are resolved</li>
<li><strong>Check the logs</strong> in <code>/var/www/ziti-enrollment/logs/</code> if enrollment fails</li>
</ol>
</div>
</div>
</body>
</html>
<?php
}
// Run the checks and output results
$results = runPreEnrollmentChecks();
if (php_sapi_name() === 'cli') {
// CLI output
echo "Pre-Enrollment System Check\n";
echo "===========================\n\n";
echo "Environment: " . $results['environment']['php_sapi'] . " (PHP " . $results['environment']['php_version'] . ")\n";
echo "User: " . $results['environment']['user'] . " (UID: " . $results['environment']['uid'] . ")\n\n";
echo "Recommendations:\n";
foreach ($results['recommendations'] as $rec) {
echo "- [{$rec['type']}] {$rec['message']}\n";
echo " Action: {$rec['action']}\n\n";
}
} else {
// Web output
outputHTML($results);
}
?>