refactor: store config as .bak, rebuild on restore
Generic: Repo Health / Access control (push) Successful in 1s
Generic: Repo Health / Site Health (push) Has been skipped
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 3s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Generic: Repo Health / Access control (pull_request) Successful in 1s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 5s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 6s
Universal: Auto Version Bump / Version Bump (push) Successful in 8s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 6s
Universal: PR Check / Validate PR (pull_request) Failing after 18s
Generic: Repo Health / Scripts governance (push) Has been cancelled
Generic: Repo Health / Repository health (push) Has been cancelled
Generic: Repo Health / Report Issues (push) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Access control (push) Successful in 1s
Generic: Repo Health / Site Health (push) Has been skipped
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 3s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Generic: Repo Health / Access control (pull_request) Successful in 1s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 5s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 6s
Universal: Auto Version Bump / Version Bump (push) Successful in 8s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 6s
Universal: PR Check / Validate PR (pull_request) Failing after 18s
Generic: Repo Health / Scripts governance (push) Has been cancelled
Generic: Repo Health / Repository health (push) Has been cancelled
Generic: Repo Health / Report Issues (push) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
Instead of storing a sanitized configuration.php in the archive, save it as configuration.php.bak with credentials stripped. No configuration.php exists in the archive — it's rebuilt from the .bak template + user-provided credentials during restore. Backup side: - configuration.php stored as configuration.php.bak (sanitized) - No configuration.php in the archive (prevents accidental use) MokoRestore side: - Reads .bak as base template (preserves non-sensitive settings: debug, cache, SEF, editor, timezone, etc.) - Replaces all sanitized fields with user input - Clears proxy/Redis/TLS placeholders to empty strings - Deletes .bak after successful rebuild - Falls back to configuration.php for legacy backups FileRestorer: - Added configuration.php.bak to skip list
This commit is contained in:
@@ -166,13 +166,13 @@ class BackupEngine
|
||||
continue;
|
||||
}
|
||||
|
||||
// Sanitize configuration.php — replace credentials with
|
||||
// placeholders so backups are safe to store or transfer.
|
||||
// MokoRestore prompts for these values during restore.
|
||||
// Store configuration.php as .bak with credentials stripped.
|
||||
// The restore process rebuilds a fresh configuration.php
|
||||
// from user input + non-sensitive values from the .bak.
|
||||
if ($relativePath === 'configuration.php') {
|
||||
$sanitized = self::sanitizeConfiguration($fullPath);
|
||||
$archiver->addFromString($relativePath, $sanitized);
|
||||
$this->log('configuration.php sanitized (credentials replaced with placeholders)');
|
||||
$archiver->addFromString('configuration.php.bak', $sanitized);
|
||||
$this->log('configuration.php saved as .bak (credentials stripped)');
|
||||
} else {
|
||||
$archiver->addFile($fullPath, $relativePath);
|
||||
}
|
||||
|
||||
@@ -22,10 +22,11 @@ class FileRestorer
|
||||
|
||||
/**
|
||||
* Files that should never be overwritten during restore.
|
||||
* configuration.php is handled separately by the RestoreEngine.
|
||||
* configuration.php is rebuilt from .bak + user input by RestoreEngine.
|
||||
*/
|
||||
private const SKIP_FILES = [
|
||||
'configuration.php',
|
||||
'configuration.php.bak',
|
||||
'.htaccess',
|
||||
'web.config',
|
||||
];
|
||||
|
||||
@@ -258,10 +258,14 @@ function actionExtract(array $data): array
|
||||
$count = $zip->numFiles;
|
||||
$zip->close();
|
||||
|
||||
// Try to read existing configuration.php for pre-filling.
|
||||
// Sanitized backups contain [SANITIZED:field] placeholders — skip those.
|
||||
// Pre-fill from configuration.php.bak (sanitized backup) or
|
||||
// configuration.php (legacy/unsanitized backup). Skip [SANITIZED:] values.
|
||||
$existingConfig = [];
|
||||
$configFile = RESTORE_DIR . '/configuration.php';
|
||||
$configFile = RESTORE_DIR . '/configuration.php.bak';
|
||||
|
||||
if (!is_file($configFile)) {
|
||||
$configFile = RESTORE_DIR . '/configuration.php';
|
||||
}
|
||||
|
||||
if (is_file($configFile)) {
|
||||
$content = file_get_contents($configFile);
|
||||
@@ -278,7 +282,6 @@ function actionExtract(array $data): array
|
||||
|
||||
foreach ($fieldMap as $phpField => $configKey) {
|
||||
if (preg_match('/\$' . preg_quote($phpField, '/') . '\s*=\s*\'([^\']*)\'/', $content, $m)) {
|
||||
// Skip sanitized placeholder values
|
||||
if (strpos($m[1], '[SANITIZED:') === false) {
|
||||
$existingConfig[$configKey] = $m[1];
|
||||
}
|
||||
@@ -396,12 +399,18 @@ function actionConfig(array $data): array
|
||||
$tmpPath = RESTORE_DIR . '/tmp';
|
||||
$logPath = RESTORE_DIR . '/administrator/logs';
|
||||
|
||||
$configFile = RESTORE_DIR . '/configuration.php';
|
||||
$configPath = RESTORE_DIR . '/configuration.php';
|
||||
$bakPath = RESTORE_DIR . '/configuration.php.bak';
|
||||
|
||||
if (is_file($configFile)) {
|
||||
// Update existing configuration.php
|
||||
$config = file_get_contents($configFile);
|
||||
// Use .bak as the base template (preserves non-sensitive settings like
|
||||
// debug, cache, SEF, editor, etc.). Fall back to existing config
|
||||
// for legacy/unsanitized backups, or build from scratch if neither exists.
|
||||
$basePath = is_file($bakPath) ? $bakPath : (is_file($configPath) ? $configPath : null);
|
||||
|
||||
if ($basePath !== null) {
|
||||
$config = file_get_contents($basePath);
|
||||
|
||||
// Replace all credential and server-specific fields with user input
|
||||
$replacements = [
|
||||
'/\$host\s*=\s*\'[^\']*\'/' => "\$host = '{$host}'",
|
||||
'/\$db\s*=\s*\'[^\']*\'/' => "\$db = '{$dbName}'",
|
||||
@@ -418,24 +427,32 @@ function actionConfig(array $data): array
|
||||
$replacements['/\$live_site\s*=\s*\'[^\']*\'/'] = "\$live_site = '{$livesite}'";
|
||||
}
|
||||
|
||||
// Replace SMTP credentials (only if provided — leave existing values if blank)
|
||||
if ($smtpHost !== '') {
|
||||
$replacements['/\$smtphost\s*=\s*\'[^\']*\'/'] = "\$smtphost = '{$smtpHost}'";
|
||||
}
|
||||
if ($smtpUser !== '') {
|
||||
$replacements['/\$smtpuser\s*=\s*\'[^\']*\'/'] = "\$smtpuser = '" . addcslashes($smtpUser, "'\\") . "'";
|
||||
}
|
||||
if ($smtpPass !== '') {
|
||||
$replacements['/\$smtppass\s*=\s*\'[^\']*\'/'] = "\$smtppass = '" . addcslashes($smtpPass, "'\\") . "'";
|
||||
}
|
||||
// SMTP — always replace (clears sanitized placeholders even if blank)
|
||||
$replacements['/\$smtphost\s*=\s*\'[^\']*\'/'] = "\$smtphost = '" . addcslashes($smtpHost, "'\\") . "'";
|
||||
$replacements['/\$smtpuser\s*=\s*\'[^\']*\'/'] = "\$smtpuser = '" . addcslashes($smtpUser, "'\\") . "'";
|
||||
$replacements['/\$smtppass\s*=\s*\'[^\']*\'/'] = "\$smtppass = '" . addcslashes($smtpPass, "'\\") . "'";
|
||||
|
||||
// Clear remaining sanitized placeholders (proxy, Redis, DB TLS)
|
||||
$replacements['/\$proxy_user\s*=\s*\'[^\']*\'/'] = "\$proxy_user = ''";
|
||||
$replacements['/\$proxy_pass\s*=\s*\'[^\']*\'/'] = "\$proxy_pass = ''";
|
||||
$replacements['/\$redis_server_auth\s*=\s*\'[^\']*\'/'] = "\$redis_server_auth = ''";
|
||||
$replacements['/\$session_redis_server_auth\s*=\s*\'[^\']*\'/'] = "\$session_redis_server_auth = ''";
|
||||
$replacements['/\$dbsslkey\s*=\s*\'[^\']*\'/'] = "\$dbsslkey = ''";
|
||||
$replacements['/\$dbsslcert\s*=\s*\'[^\']*\'/'] = "\$dbsslcert = ''";
|
||||
$replacements['/\$dbsslca\s*=\s*\'[^\']*\'/'] = "\$dbsslca = ''";
|
||||
|
||||
foreach ($replacements as $pattern => $replacement) {
|
||||
$config = preg_replace($pattern, $replacement, $config);
|
||||
}
|
||||
|
||||
file_put_contents($configFile, $config);
|
||||
file_put_contents($configPath, $config);
|
||||
|
||||
return ['success' => true, 'message' => 'configuration.php updated with new settings and fresh secret'];
|
||||
// Remove .bak after successful rebuild
|
||||
if (is_file($bakPath)) {
|
||||
@unlink($bakPath);
|
||||
}
|
||||
|
||||
return ['success' => true, 'message' => 'Joomla configuration rebuilt with fresh credentials and secret'];
|
||||
}
|
||||
|
||||
// Create new configuration.php from scratch
|
||||
|
||||
@@ -281,10 +281,10 @@ class SteppedBackupEngine
|
||||
continue;
|
||||
}
|
||||
|
||||
// Sanitize Joomla config — replace credentials with placeholders
|
||||
// Store config as .bak with credentials stripped — restore rebuilds it
|
||||
if (basename($relativePath) === 'configuration.php' && dirname($relativePath) === '.') {
|
||||
$sanitized = BackupEngine::sanitizeConfiguration($fullPath);
|
||||
$zip->addFromString($relativePath, $sanitized);
|
||||
$zip->addFromString('configuration.php.bak', $sanitized);
|
||||
} else {
|
||||
$zip->addFile($fullPath, $relativePath);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user