Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php

namespace EE\Migration;

use EE;

/**
* Removes the site credentials that older backups wrote to the local copies of their metadata.
*
* Remote copies are not changed; restore no longer reads credentials from metadata, so old backups still restore.
*/
class StripBackupMetadataCredentials extends Base {

const SECRET_KEYS = [ 'db_password', 'db_root_password', 'app_admin_password', 'site_auth_password' ];

public function up() {

if ( ! is_dir( EE_BACKUP_DIR ) ) {
return;
}

$files = array_merge(
glob( EE_BACKUP_DIR . '/*.metadata.json' ) ?: [],
glob( EE_BACKUP_DIR . '/*/metadata.json' ) ?: []
);

foreach ( $files as $file ) {
if ( is_link( $file ) || ! is_file( $file ) ) {
continue;
}

$data = json_decode( (string) file_get_contents( $file ), true );
if ( ! is_array( $data ) || ! array_intersect_key( $data, array_flip( self::SECRET_KEYS ) ) ) {
continue;
}

foreach ( self::SECRET_KEYS as $key ) {
unset( $data[ $key ] );
}

// A half-written file would make restore refuse the backup, so it is replaced only when complete.
$tmp = $file . '.ee-tmp';
$json = json_encode( $data, JSON_PRETTY_PRINT );
if ( false === $json || strlen( $json ) !== file_put_contents( $tmp, $json ) || ! chmod( $tmp, fileperms( $file ) & 0777 ) || ! rename( $tmp, $file ) ) {
@unlink( $tmp );
EE::warning( "Could not remove the credentials from $file." );
continue;
}
EE::debug( "Removed the credentials from $file." );
}
}

/**
* Removed credentials are not restored.
*/
public function down() {
}
}
17 changes: 11 additions & 6 deletions src/helper/Site_Backup_Restore.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ class Site_Backup_Restore {
const RCLONE_MIN_VERSION_MT_WRITE_BUFFER = '1.63.0'; // --multi-thread-write-buffer-size (rclone v1.63.0)
const RCLONE_MIN_VERSION_MT_CHUNK_SIZE = '1.64.0'; // --multi-thread-chunk-size (rclone v1.64.0)

const METADATA_SECRET_KEYS = [ 'db_password', 'db_root_password', 'app_admin_password', 'site_auth_password' ];

private $fs;
public $site_data;
private $rclone_config_path;
Expand Down Expand Up @@ -80,9 +82,6 @@ public function backup( $args, $assoc_args = [] ) {

// Handle --dash-auth flag for EasyDash integration
if ( $dash_auth ) {
// Debug: Log the raw dash_auth value received
EE::debug( 'Received --dash-auth value: ' . $dash_auth );

// Parse backup-id:backup-verification-token format
$auth_parts = explode( ':', $dash_auth, 2 );
if ( count( $auth_parts ) !== 2 || empty( $auth_parts[0] ) || empty( $auth_parts[1] ) ) {
Expand All @@ -101,10 +100,13 @@ public function backup( $args, $assoc_args = [] ) {
$this->dash_backup_id = $auth_parts[0];
$this->dash_verify_token = $auth_parts[1];
$this->dash_api_url = $ed_api_url;
// The token also goes into the logged callback payloads.
if ( method_exists( 'EE', 'obfuscate' ) ) {
EE::obfuscate( [ $dash_auth, $this->dash_verify_token ] );
}

// Debug: Log parsed values
EE::debug( 'Parsed backup_id: ' . $this->dash_backup_id );
EE::debug( 'Parsed verify_token: ' . $this->dash_verify_token );
EE::debug( 'API URL: ' . $this->dash_api_url );

// Register shutdown handler to send failure callback if backup doesn't complete
Expand Down Expand Up @@ -434,6 +436,10 @@ function ( $theme ) {
$remote_path = $this->get_remote_path();
$backup_data['remote_path'] = explode( ':', $remote_path )[1];
$backup_data = array_merge( $this->site_data, $backup_data );
// Credentials stay out of the backup: restore uses the current site's, and the metadata is also kept unencrypted on the remote and in EE_BACKUP_DIR.
foreach ( self::METADATA_SECRET_KEYS as $key ) {
unset( $backup_data[ $key ] );
}

$backup_data_file = $backup_dir . '/metadata.json';
$metadata_copy = EE_BACKUP_DIR . '/' . $this->site_data['site_url'] . '.metadata.json';
Expand Down Expand Up @@ -1704,7 +1710,6 @@ private function send_dash_success_callback( $ed_api_url, $backup_id, $verify_to

// Debug: Log the values being used for callback
EE::debug( 'Sending success callback with backup_id: ' . $backup_id );
EE::debug( 'Sending success callback with verify_token: ' . $verify_token );

// Build metadata for the API call - always include all fields
$metadata = [
Expand All @@ -1727,7 +1732,7 @@ private function send_dash_success_callback( $ed_api_url, $backup_id, $verify_to
'metadata' => $metadata,
];

EE::debug( 'Payload being sent: ' . json_encode( $payload ) );
EE::debug( 'Payload being sent: ' . json_encode( array_merge( $payload, [ 'verify' => '******' ] ) ) );

return $this->send_dash_request( $endpoint, $payload );
}
Expand Down
Loading