From 3a6bb1c7838d4d4d5f886d920b47980cc0eb2166 Mon Sep 17 00:00:00 2001 From: Jonathan Miller Date: Tue, 30 Jun 2026 12:50:02 -0500 Subject: [PATCH 1/6] fix: remote upload prefix mismatch and restore security file visibility Remote uploaders (SFTP, FTP, S3, Google Drive) expect type-prefixed property names (sftp_host, ftp_port, etc.) but createUploaderFromParams passes unprefixed keys from the remotes table params JSON. Add prefix mapping in createUploaderFromParams to bridge the naming gap. Rename .mokorestore-security.php to mokorestore-security.php (no leading dot) so the file is visible in file managers and not blocked by web server dotfile rules. Also clean it up in actionCleanup. Closes #13 Claude-Session: https://claude.ai/code/session_01MbEjBtsSjPuTWhqqrMS2wG --- .../com_mokosuitebackup/src/Engine/BackupEngine.php | 11 ++++++++++- .../com_mokosuitebackup/src/Engine/MokoRestore.php | 12 ++++++------ .../src/Engine/SteppedBackupEngine.php | 11 ++++++++++- 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/source/packages/com_mokosuitebackup/src/Engine/BackupEngine.php b/source/packages/com_mokosuitebackup/src/Engine/BackupEngine.php index 5eb994c..aaf8a56 100644 --- a/source/packages/com_mokosuitebackup/src/Engine/BackupEngine.php +++ b/source/packages/com_mokosuitebackup/src/Engine/BackupEngine.php @@ -547,7 +547,16 @@ class BackupEngine */ private function createUploaderFromParams(string $type, array $params): RemoteUploaderInterface { - $fake = (object) $params; + $prefixMap = ['ftp' => 'ftp_', 'sftp' => 'sftp_', 's3' => 's3_', 'google_drive' => 'gdrive_']; + $prefix = $prefixMap[$type] ?? ''; + + $prefixed = []; + + foreach ($params as $key => $value) { + $prefixed[$prefix . $key] = $value; + } + + $fake = (object) $prefixed; return match ($type) { 'ftp' => new FtpUploader($fake), diff --git a/source/packages/com_mokosuitebackup/src/Engine/MokoRestore.php b/source/packages/com_mokosuitebackup/src/Engine/MokoRestore.php index 78c4b2a..a66dd33 100644 --- a/source/packages/com_mokosuitebackup/src/Engine/MokoRestore.php +++ b/source/packages/com_mokosuitebackup/src/Engine/MokoRestore.php @@ -358,7 +358,7 @@ $token = $_SESSION['restore_token']; // Write a security file to the web root with a random code. // The user must read the code from the file and enter it in the browser // to prove they have filesystem access before any restore actions are allowed. -$securityFile = RESTORE_DIR . '/.mokorestore-security.php'; +$securityFile = RESTORE_DIR . '/mokorestore-security.php'; $securityCode = $_SESSION['security_code'] ?? ''; if (empty($securityCode)) { @@ -395,7 +395,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST[' echo json_encode(['success' => true, 'message' => 'Security verified']); } else { - echo json_encode(['success' => false, 'message' => 'Incorrect security code. Check the file: .mokorestore-security.php']); + echo json_encode(['success' => false, 'message' => 'Incorrect security code. Check the file: mokorestore-security.php']); } exit; @@ -414,7 +414,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) { } if (!$securityVerified) { - echo json_encode(['success' => false, 'message' => 'Security verification required. Enter the code from .mokorestore-security.php']); + echo json_encode(['success' => false, 'message' => 'Security verification required. Enter the code from mokorestore-security.php']); exit; } @@ -1397,7 +1397,7 @@ function actionCleanup(): array { $removed = []; - foreach (['database.sql', 'site-backup.zip'] as $file) { + foreach (['database.sql', 'site-backup.zip', 'mokorestore-security.php'] as $file) { $path = RESTORE_DIR . '/' . $file; if (is_file($path) && @unlink($path)) { @@ -1570,14 +1570,14 @@ body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'Helvetica N

Security Verification

-

To prevent unauthorized access, enter the security code from the file .mokorestore-security.php in your site root.

+

To prevent unauthorized access, enter the security code from the file mokorestore-security.php in your site root.

🔒 How to find the code
  1. Connect to your server via FTP, SSH, or file manager
  2. -
  3. Open .mokorestore-security.php in the site root directory
  4. +
  5. Open mokorestore-security.php in the site root directory
  6. Copy the 8-character code and enter it below
diff --git a/source/packages/com_mokosuitebackup/src/Engine/SteppedBackupEngine.php b/source/packages/com_mokosuitebackup/src/Engine/SteppedBackupEngine.php index 9e18d04..a9dbb08 100644 --- a/source/packages/com_mokosuitebackup/src/Engine/SteppedBackupEngine.php +++ b/source/packages/com_mokosuitebackup/src/Engine/SteppedBackupEngine.php @@ -889,7 +889,16 @@ class SteppedBackupEngine */ private function createUploaderFromParams(string $type, array $params): RemoteUploaderInterface { - $fake = (object) $params; + $prefixMap = ['ftp' => 'ftp_', 'sftp' => 'sftp_', 's3' => 's3_', 'google_drive' => 'gdrive_']; + $prefix = $prefixMap[$type] ?? ''; + + $prefixed = []; + + foreach ($params as $key => $value) { + $prefixed[$prefix . $key] = $value; + } + + $fake = (object) $prefixed; return match ($type) { 'ftp' => new FtpUploader($fake), From f2f424a5653abb4345ba86fedfd3ce43503651d1 Mon Sep 17 00:00:00 2001 From: "gitea-actions[bot]" Date: Tue, 30 Jun 2026 17:50:30 +0000 Subject: [PATCH 2/6] chore(version): pre-release bump to 02.52.16-dev [skip ci] --- .mokogitea/workflows/issue-branch.yml | 2 +- SECURITY.md | 2 +- source/packages/MokoSuiteClient | 2 +- source/packages/com_mokosuitebackup/mokosuitebackup.xml | 2 +- .../packages/com_mokosuitebackup/sql/updates/mysql/02.52.16.sql | 1 + .../mod_mokosuitebackup_cpanel/mod_mokosuitebackup_cpanel.xml | 2 +- .../packages/plg_actionlog_mokosuitebackup/mokosuitebackup.xml | 2 +- source/packages/plg_console_mokosuitebackup/mokosuitebackup.xml | 2 +- source/packages/plg_content_mokosuitebackup/mokosuitebackup.xml | 2 +- .../packages/plg_quickicon_mokosuitebackup/mokosuitebackup.xml | 2 +- source/packages/plg_system_mokosuitebackup/mokosuitebackup.xml | 2 +- source/packages/plg_task_mokosuitebackup/mokosuitebackup.xml | 2 +- .../plg_webservices_mokosuitebackup/mokosuitebackup.xml | 2 +- source/pkg_mokosuitebackup.xml | 2 +- 14 files changed, 14 insertions(+), 13 deletions(-) create mode 100644 source/packages/com_mokosuitebackup/sql/updates/mysql/02.52.16.sql diff --git a/.mokogitea/workflows/issue-branch.yml b/.mokogitea/workflows/issue-branch.yml index 11958bd..0567b3c 100644 --- a/.mokogitea/workflows/issue-branch.yml +++ b/.mokogitea/workflows/issue-branch.yml @@ -5,7 +5,7 @@ # FILE INFORMATION # DEFGROUP: Gitea.Workflow # INGROUP: mokocli.Automation -# VERSION: 01.00.00 +# VERSION: 02.52.16 # BRIEF: Auto-create feature branch when an issue is opened name: "Universal: Issue Branch" diff --git a/SECURITY.md b/SECURITY.md index 2286acd..c488295 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -23,7 +23,7 @@ DEFGROUP: Template-Joomla INGROUP: Template-Joomla.Documentation REPO: https://git.mokoconsulting.tech/MokoConsulting/Template-Joomla PATH: /SECURITY.md -VERSION: 01.45.00 +VERSION: 02.52.16 BRIEF: Security vulnerability reporting and handling policy --> diff --git a/source/packages/MokoSuiteClient b/source/packages/MokoSuiteClient index 9df6bea..0a9125e 160000 --- a/source/packages/MokoSuiteClient +++ b/source/packages/MokoSuiteClient @@ -1 +1 @@ -Subproject commit 9df6bea4b7480b2e443898ad84a279070ba4a7f6 +Subproject commit 0a9125e51956a084941abccdf2de8ddd064777e8 diff --git a/source/packages/com_mokosuitebackup/mokosuitebackup.xml b/source/packages/com_mokosuitebackup/mokosuitebackup.xml index 1bba702..f481e8d 100644 --- a/source/packages/com_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/com_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> MokoSuiteBackup - 01.45.00 + 02.52.16 2026-06-02 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/com_mokosuitebackup/sql/updates/mysql/02.52.16.sql b/source/packages/com_mokosuitebackup/sql/updates/mysql/02.52.16.sql new file mode 100644 index 0000000..cd9e5d7 --- /dev/null +++ b/source/packages/com_mokosuitebackup/sql/updates/mysql/02.52.16.sql @@ -0,0 +1 @@ +/* 02.52.16 — no schema changes */ diff --git a/source/packages/mod_mokosuitebackup_cpanel/mod_mokosuitebackup_cpanel.xml b/source/packages/mod_mokosuitebackup_cpanel/mod_mokosuitebackup_cpanel.xml index e6eb337..1f4465b 100644 --- a/source/packages/mod_mokosuitebackup_cpanel/mod_mokosuitebackup_cpanel.xml +++ b/source/packages/mod_mokosuitebackup_cpanel/mod_mokosuitebackup_cpanel.xml @@ -8,7 +8,7 @@ --> mod_mokosuitebackup_cpanel - 01.45.00 + 02.52.16 2026-06-23 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_actionlog_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_actionlog_mokosuitebackup/mokosuitebackup.xml index 22bb14b..b7b8892 100644 --- a/source/packages/plg_actionlog_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_actionlog_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> Action Log - MokoSuiteBackup - 01.45.00 + 02.52.16 2026-06-04 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_console_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_console_mokosuitebackup/mokosuitebackup.xml index 5b1fe35..449d6cb 100644 --- a/source/packages/plg_console_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_console_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> Console - MokoSuiteBackup - 01.45.00 + 02.52.16 2026-06-04 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_content_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_content_mokosuitebackup/mokosuitebackup.xml index 44f4a47..5dc9251 100644 --- a/source/packages/plg_content_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_content_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> Content - MokoSuiteBackup - 01.45.00 + 02.52.16 2026-06-04 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_quickicon_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_quickicon_mokosuitebackup/mokosuitebackup.xml index 345b8bd..eae02d4 100644 --- a/source/packages/plg_quickicon_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_quickicon_mokosuitebackup/mokosuitebackup.xml @@ -1,7 +1,7 @@ Quick Icon - MokoSuiteBackup - 01.45.00 + 02.52.16 2026-06-02 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_system_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_system_mokosuitebackup/mokosuitebackup.xml index 9d0f954..41c491d 100644 --- a/source/packages/plg_system_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_system_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> System - MokoSuiteBackup - 01.45.00 + 02.52.16 2026-06-02 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_task_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_task_mokosuitebackup/mokosuitebackup.xml index d9a104f..065010a 100644 --- a/source/packages/plg_task_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_task_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> Task - MokoSuiteBackup - 01.45.00 + 02.52.16 2026-06-02 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_webservices_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_webservices_mokosuitebackup/mokosuitebackup.xml index cb64b0d..850b06f 100644 --- a/source/packages/plg_webservices_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_webservices_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> Web Services - MokoSuiteBackup - 01.45.00 + 02.52.16 2026-06-02 Moko Consulting hello@mokoconsulting.tech diff --git a/source/pkg_mokosuitebackup.xml b/source/pkg_mokosuitebackup.xml index a88829b..510a1d2 100644 --- a/source/pkg_mokosuitebackup.xml +++ b/source/pkg_mokosuitebackup.xml @@ -8,7 +8,7 @@ Package - MokoSuiteBackup mokosuitebackup - 01.45.00 + 02.52.16 2026-06-02 Moko Consulting hello@mokoconsulting.tech From 20ce945e73de66559975bab8f876d1ead1a6a4b2 Mon Sep 17 00:00:00 2001 From: Jonathan Miller Date: Tue, 30 Jun 2026 12:53:03 -0500 Subject: [PATCH 3/6] fix: recreate security file if missing while verification is pending The security file was only written inside the code-generation block (first page load). If the file was deleted or failed to write, it was never recreated because the session already held the code. Now file writing is a separate check that runs whenever verification is pending and the file is missing. Claude-Session: https://claude.ai/code/session_01MbEjBtsSjPuTWhqqrMS2wG --- .../packages/com_mokosuitebackup/src/Engine/MokoRestore.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/source/packages/com_mokosuitebackup/src/Engine/MokoRestore.php b/source/packages/com_mokosuitebackup/src/Engine/MokoRestore.php index a66dd33..0079a1f 100644 --- a/source/packages/com_mokosuitebackup/src/Engine/MokoRestore.php +++ b/source/packages/com_mokosuitebackup/src/Engine/MokoRestore.php @@ -365,8 +365,10 @@ if (empty($securityCode)) { $securityCode = strtoupper(substr(bin2hex(random_bytes(4)), 0, 8)); $_SESSION['security_code'] = $securityCode; $_SESSION['security_verified'] = false; +} - // Write security file with the code +// Write (or recreate) the security file whenever verification is still pending +if (empty($_SESSION['security_verified']) && !is_file($securityFile)) { $securityContent = "\n" . "MokoRestore Security Verification\n" . "==================================\n" @@ -374,7 +376,6 @@ if (empty($securityCode)) { . "Enter this code in the MokoRestore browser interface to proceed.\n" . "This file will be deleted automatically after verification.\n"; if (file_put_contents($securityFile, $securityContent) === false) { - // Cannot write security file — skip verification to avoid locking user out $_SESSION['security_verified'] = true; error_log('MokoRestore: Cannot write security file — verification skipped (check directory permissions)'); } From 236609341f4b83b3795986ab6ca83e1156ea22df Mon Sep 17 00:00:00 2001 From: "gitea-actions[bot]" Date: Tue, 30 Jun 2026 17:53:59 +0000 Subject: [PATCH 4/6] chore(version): pre-release bump to 02.52.17-dev [skip ci] --- .mokogitea/workflows/issue-branch.yml | 2 +- SECURITY.md | 2 +- source/packages/com_mokosuitebackup/mokosuitebackup.xml | 2 +- .../packages/com_mokosuitebackup/sql/updates/mysql/02.52.17.sql | 1 + .../mod_mokosuitebackup_cpanel/mod_mokosuitebackup_cpanel.xml | 2 +- .../packages/plg_actionlog_mokosuitebackup/mokosuitebackup.xml | 2 +- source/packages/plg_console_mokosuitebackup/mokosuitebackup.xml | 2 +- source/packages/plg_content_mokosuitebackup/mokosuitebackup.xml | 2 +- .../packages/plg_quickicon_mokosuitebackup/mokosuitebackup.xml | 2 +- source/packages/plg_system_mokosuitebackup/mokosuitebackup.xml | 2 +- source/packages/plg_task_mokosuitebackup/mokosuitebackup.xml | 2 +- .../plg_webservices_mokosuitebackup/mokosuitebackup.xml | 2 +- source/pkg_mokosuitebackup.xml | 2 +- 13 files changed, 13 insertions(+), 12 deletions(-) create mode 100644 source/packages/com_mokosuitebackup/sql/updates/mysql/02.52.17.sql diff --git a/.mokogitea/workflows/issue-branch.yml b/.mokogitea/workflows/issue-branch.yml index 0567b3c..6245055 100644 --- a/.mokogitea/workflows/issue-branch.yml +++ b/.mokogitea/workflows/issue-branch.yml @@ -5,7 +5,7 @@ # FILE INFORMATION # DEFGROUP: Gitea.Workflow # INGROUP: mokocli.Automation -# VERSION: 02.52.16 +# VERSION: 02.52.17 # BRIEF: Auto-create feature branch when an issue is opened name: "Universal: Issue Branch" diff --git a/SECURITY.md b/SECURITY.md index c488295..7a7da29 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -23,7 +23,7 @@ DEFGROUP: Template-Joomla INGROUP: Template-Joomla.Documentation REPO: https://git.mokoconsulting.tech/MokoConsulting/Template-Joomla PATH: /SECURITY.md -VERSION: 02.52.16 +VERSION: 02.52.17 BRIEF: Security vulnerability reporting and handling policy --> diff --git a/source/packages/com_mokosuitebackup/mokosuitebackup.xml b/source/packages/com_mokosuitebackup/mokosuitebackup.xml index f481e8d..b96f870 100644 --- a/source/packages/com_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/com_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> MokoSuiteBackup - 02.52.16 + 02.52.17 2026-06-02 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/com_mokosuitebackup/sql/updates/mysql/02.52.17.sql b/source/packages/com_mokosuitebackup/sql/updates/mysql/02.52.17.sql new file mode 100644 index 0000000..bd657ea --- /dev/null +++ b/source/packages/com_mokosuitebackup/sql/updates/mysql/02.52.17.sql @@ -0,0 +1 @@ +/* 02.52.17 — no schema changes */ diff --git a/source/packages/mod_mokosuitebackup_cpanel/mod_mokosuitebackup_cpanel.xml b/source/packages/mod_mokosuitebackup_cpanel/mod_mokosuitebackup_cpanel.xml index 1f4465b..624746b 100644 --- a/source/packages/mod_mokosuitebackup_cpanel/mod_mokosuitebackup_cpanel.xml +++ b/source/packages/mod_mokosuitebackup_cpanel/mod_mokosuitebackup_cpanel.xml @@ -8,7 +8,7 @@ --> mod_mokosuitebackup_cpanel - 02.52.16 + 02.52.17 2026-06-23 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_actionlog_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_actionlog_mokosuitebackup/mokosuitebackup.xml index b7b8892..bb6b2e4 100644 --- a/source/packages/plg_actionlog_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_actionlog_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> Action Log - MokoSuiteBackup - 02.52.16 + 02.52.17 2026-06-04 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_console_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_console_mokosuitebackup/mokosuitebackup.xml index 449d6cb..a77f40c 100644 --- a/source/packages/plg_console_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_console_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> Console - MokoSuiteBackup - 02.52.16 + 02.52.17 2026-06-04 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_content_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_content_mokosuitebackup/mokosuitebackup.xml index 5dc9251..21e7829 100644 --- a/source/packages/plg_content_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_content_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> Content - MokoSuiteBackup - 02.52.16 + 02.52.17 2026-06-04 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_quickicon_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_quickicon_mokosuitebackup/mokosuitebackup.xml index eae02d4..11e4151 100644 --- a/source/packages/plg_quickicon_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_quickicon_mokosuitebackup/mokosuitebackup.xml @@ -1,7 +1,7 @@ Quick Icon - MokoSuiteBackup - 02.52.16 + 02.52.17 2026-06-02 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_system_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_system_mokosuitebackup/mokosuitebackup.xml index 41c491d..d386a41 100644 --- a/source/packages/plg_system_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_system_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> System - MokoSuiteBackup - 02.52.16 + 02.52.17 2026-06-02 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_task_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_task_mokosuitebackup/mokosuitebackup.xml index 065010a..c97e6c6 100644 --- a/source/packages/plg_task_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_task_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> Task - MokoSuiteBackup - 02.52.16 + 02.52.17 2026-06-02 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_webservices_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_webservices_mokosuitebackup/mokosuitebackup.xml index 850b06f..d3add2e 100644 --- a/source/packages/plg_webservices_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_webservices_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> Web Services - MokoSuiteBackup - 02.52.16 + 02.52.17 2026-06-02 Moko Consulting hello@mokoconsulting.tech diff --git a/source/pkg_mokosuitebackup.xml b/source/pkg_mokosuitebackup.xml index 510a1d2..8848c3b 100644 --- a/source/pkg_mokosuitebackup.xml +++ b/source/pkg_mokosuitebackup.xml @@ -8,7 +8,7 @@ Package - MokoSuiteBackup mokosuitebackup - 02.52.16 + 02.52.17 2026-06-02 Moko Consulting hello@mokoconsulting.tech From 4093267984f1067a5e8e205c9297894c07a111c9 Mon Sep 17 00:00:00 2001 From: Jonathan Miller Date: Tue, 30 Jun 2026 12:58:53 -0500 Subject: [PATCH 5/6] fix: add verbose error_log throughout restore script Every action handler now logs entry, key parameters, outcomes, and failures to PHP error_log. Security file creation logs directory permissions, PHP user, and the specific error when file_put_contents fails. Database import logs SQL file size, statement counts, and individual errors. Cleanup logs each file removal success/failure. Claude-Session: https://claude.ai/code/session_01MbEjBtsSjPuTWhqqrMS2wG --- .../src/Engine/MokoRestore.php | 66 +++++++++++++++++-- 1 file changed, 61 insertions(+), 5 deletions(-) diff --git a/source/packages/com_mokosuitebackup/src/Engine/MokoRestore.php b/source/packages/com_mokosuitebackup/src/Engine/MokoRestore.php index 0079a1f..eb6ea0a 100644 --- a/source/packages/com_mokosuitebackup/src/Engine/MokoRestore.php +++ b/source/packages/com_mokosuitebackup/src/Engine/MokoRestore.php @@ -346,6 +346,9 @@ define('MOKOJOOMBACKUP_RESTORE', 1); define('RESTORE_DIR', __DIR__); define('BACKUP_FILE', RESTORE_DIR . '/site-backup.zip'); +error_log('MokoRestore: Script loaded — RESTORE_DIR=' . RESTORE_DIR); +error_log('MokoRestore: PHP ' . PHP_VERSION . ', SAPI=' . php_sapi_name() . ', memory_limit=' . ini_get('memory_limit')); + session_start(); if (empty($_SESSION['restore_token'])) { @@ -369,15 +372,26 @@ if (empty($securityCode)) { // Write (or recreate) the security file whenever verification is still pending if (empty($_SESSION['security_verified']) && !is_file($securityFile)) { + error_log('MokoRestore: Writing security file: ' . $securityFile); + error_log('MokoRestore: Target directory: ' . RESTORE_DIR . ' (writable: ' . (is_writable(RESTORE_DIR) ? 'yes' : 'NO') . ')'); + $securityContent = "\n" . "MokoRestore Security Verification\n" . "==================================\n" . "Code: " . $securityCode . "\n" . "Enter this code in the MokoRestore browser interface to proceed.\n" . "This file will be deleted automatically after verification.\n"; - if (file_put_contents($securityFile, $securityContent) === false) { + + $written = @file_put_contents($securityFile, $securityContent); + + if ($written === false) { + $err = error_get_last(); + error_log('MokoRestore: FAILED to write security file — ' . ($err['message'] ?? 'unknown error')); + error_log('MokoRestore: Directory permissions: ' . decoct(@fileperms(RESTORE_DIR) & 0777) . ', owner: ' . @fileowner(RESTORE_DIR) . ', PHP user: ' . (function_exists('posix_getuid') ? posix_getuid() : 'n/a')); + error_log('MokoRestore: Security verification SKIPPED — user will not be challenged'); $_SESSION['security_verified'] = true; - error_log('MokoRestore: Cannot write security file — verification skipped (check directory permissions)'); + } else { + error_log('MokoRestore: Security file created (' . $written . ' bytes)'); } } @@ -388,14 +402,16 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST[' if ($inputCode === $securityCode) { $_SESSION['security_verified'] = true; + error_log('MokoRestore: Security code VERIFIED'); - // Delete the security file if (is_file($securityFile)) { @unlink($securityFile); + error_log('MokoRestore: Security file deleted'); } echo json_encode(['success' => true, 'message' => 'Security verified']); } else { + error_log('MokoRestore: Security code REJECTED (input=' . $inputCode . ')'); echo json_encode(['success' => false, 'message' => 'Incorrect security code. Check the file: mokorestore-security.php']); } @@ -425,9 +441,12 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) { @ignore_user_abort(true); try { + error_log('MokoRestore: Action dispatched — ' . $_POST['action']); $result = handleAction($_POST['action'], $_POST); + error_log('MokoRestore: Action ' . $_POST['action'] . ' completed — ' . ($result['success'] ? 'OK' : 'FAIL: ' . ($result['message'] ?? ''))); echo json_encode($result); } catch (Throwable $e) { + error_log('MokoRestore: Action ' . $_POST['action'] . ' EXCEPTION — ' . $e->getMessage()); echo json_encode(['success' => false, 'message' => $e->getMessage()]); } @@ -552,10 +571,14 @@ function actionPreflight(): array function actionExtract(array $data): array { + error_log('MokoRestore: Extract — target=' . BACKUP_FILE . ', exists=' . (file_exists(BACKUP_FILE) ? 'yes' : 'no')); + if (!file_exists(BACKUP_FILE)) { throw new RuntimeException('Backup file not found: site-backup.zip'); } + error_log('MokoRestore: Extract — archive size=' . number_format(filesize(BACKUP_FILE) / 1048576, 2) . ' MB'); + $zip = new ZipArchive(); if ($zip->open(BACKUP_FILE) !== true) { @@ -592,6 +615,8 @@ function actionExtract(array $data): array $count = $zip->numFiles; $zip->close(); + error_log('MokoRestore: Extract — ' . $count . ' files extracted to ' . RESTORE_DIR); + // Pre-fill from configuration.php.bak (sanitized backup) or // configuration.php (legacy/unsanitized backup). Skip [SANITIZED:] values. $existingConfig = []; @@ -720,6 +745,8 @@ function actionDatabase(array $data): array $user = $data['db_user'] ?? ''; $pass = $data['db_pass'] ?? ''; + error_log('MokoRestore: Database import — host=' . $host . ', db=' . $name . ', user=' . $user); + if (empty($name) || empty($user)) { throw new RuntimeException('Database name and user are required'); } @@ -727,9 +754,12 @@ function actionDatabase(array $data): array $sqlFile = RESTORE_DIR . '/database.sql'; if (!is_file($sqlFile)) { + error_log('MokoRestore: Database import — no database.sql found, skipping'); return ['success' => true, 'message' => 'No database.sql found — skipped', 'statements' => 0, 'errors' => 0]; } + error_log('MokoRestore: Database import — SQL file size=' . number_format(filesize($sqlFile) / 1048576, 2) . ' MB'); + $pdo = new PDO( "mysql:host={$host};dbname={$name};charset=utf8mb4", $user, @@ -836,6 +866,14 @@ function actionDatabase(array $data): array $msg .= " ({$errors} warnings)"; } + error_log('MokoRestore: Database import — ' . $msg); + + if (!empty($errorList)) { + foreach ($errorList as $i => $err) { + error_log('MokoRestore: DB error ' . ($i + 1) . ': ' . $err); + } + } + return [ 'success' => ($statements > 0 || $errors === 0), 'message' => $msg, @@ -848,6 +886,7 @@ function actionDatabase(array $data): array function actionConfig(array $data): array { + error_log('MokoRestore: Config rebuild started'); $host = $data['db_host'] ?? 'localhost'; $dbName = $data['db_name'] ?? ''; $dbUser = $data['db_user'] ?? ''; @@ -868,6 +907,7 @@ function actionConfig(array $data): array // 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); + error_log('MokoRestore: Config — base template: ' . ($basePath ?? 'none (building from scratch)')); if ($basePath !== null) { $config = file_get_contents($basePath); @@ -920,9 +960,12 @@ function actionConfig(array $data): array } if (file_put_contents($configPath, $config) === false) { + error_log('MokoRestore: Config — FAILED to write ' . $configPath); return ['success' => false, 'message' => 'Failed to write Joomla config file — check directory permissions']; } + error_log('MokoRestore: Config — written to ' . $configPath . ' (' . filesize($configPath) . ' bytes)'); + // Remove .bak after successful rebuild if (is_file($bakPath)) { @unlink($bakPath); @@ -1176,6 +1219,8 @@ function actionResetAdmin(array $data): array $userId = (int) ($data['admin_id'] ?? 0); $password = $data['new_password'] ?? ''; + error_log('MokoRestore: Admin password reset — user_id=' . $userId); + if ($userId < 1 || strlen($password) < 8) { throw new RuntimeException('Select an admin and enter a password (8+ characters)'); } @@ -1189,6 +1234,7 @@ function actionResetAdmin(array $data): array throw new RuntimeException('User not found or password unchanged'); } + error_log('MokoRestore: Admin password reset — success'); return ['success' => true, 'message' => 'Admin password updated successfully']; } @@ -1198,6 +1244,7 @@ function actionPostRestore(array $data): array $prefix = getValidatedPrefix($data); $tasks = json_decode($data['tasks'] ?? '[]', true) ?: []; $results = []; + error_log('MokoRestore: Post-restore — ' . count($tasks) . ' task(s): ' . implode(', ', $tasks)); foreach ($tasks as $task) { try { @@ -1320,6 +1367,7 @@ function actionProvision(array $data): array $prefix = getValidatedPrefix($data); $tasks = json_decode($data['tasks'] ?? '[]', true) ?: []; $results = []; + error_log('MokoRestore: Provisioning — ' . count($tasks) . ' task(s): ' . implode(', ', $tasks)); foreach ($tasks as $task) { try { @@ -1396,16 +1444,24 @@ function actionProvision(array $data): array function actionCleanup(): array { + error_log('MokoRestore: Cleanup started'); $removed = []; foreach (['database.sql', 'site-backup.zip', 'mokorestore-security.php'] as $file) { $path = RESTORE_DIR . '/' . $file; - if (is_file($path) && @unlink($path)) { - $removed[] = $file; + if (is_file($path)) { + if (@unlink($path)) { + $removed[] = $file; + error_log('MokoRestore: Cleanup — removed ' . $file); + } else { + error_log('MokoRestore: Cleanup — FAILED to remove ' . $file); + } } } + error_log('MokoRestore: Cleanup complete — removed ' . count($removed) . ' file(s)'); + return [ 'success' => true, 'message' => 'Removed: ' . (empty($removed) ? '(none)' : implode(', ', $removed)) From 3d9c48f40fd99f7282a5221691428f933e818428 Mon Sep 17 00:00:00 2001 From: "gitea-actions[bot]" Date: Tue, 30 Jun 2026 18:00:27 +0000 Subject: [PATCH 6/6] chore(version): pre-release bump to 02.52.18-dev [skip ci] --- .mokogitea/workflows/issue-branch.yml | 2 +- SECURITY.md | 2 +- source/packages/com_mokosuitebackup/mokosuitebackup.xml | 2 +- .../packages/com_mokosuitebackup/sql/updates/mysql/02.52.18.sql | 1 + .../mod_mokosuitebackup_cpanel/mod_mokosuitebackup_cpanel.xml | 2 +- .../packages/plg_actionlog_mokosuitebackup/mokosuitebackup.xml | 2 +- source/packages/plg_console_mokosuitebackup/mokosuitebackup.xml | 2 +- source/packages/plg_content_mokosuitebackup/mokosuitebackup.xml | 2 +- .../packages/plg_quickicon_mokosuitebackup/mokosuitebackup.xml | 2 +- source/packages/plg_system_mokosuitebackup/mokosuitebackup.xml | 2 +- source/packages/plg_task_mokosuitebackup/mokosuitebackup.xml | 2 +- .../plg_webservices_mokosuitebackup/mokosuitebackup.xml | 2 +- source/pkg_mokosuitebackup.xml | 2 +- 13 files changed, 13 insertions(+), 12 deletions(-) create mode 100644 source/packages/com_mokosuitebackup/sql/updates/mysql/02.52.18.sql diff --git a/.mokogitea/workflows/issue-branch.yml b/.mokogitea/workflows/issue-branch.yml index 6245055..136d61e 100644 --- a/.mokogitea/workflows/issue-branch.yml +++ b/.mokogitea/workflows/issue-branch.yml @@ -5,7 +5,7 @@ # FILE INFORMATION # DEFGROUP: Gitea.Workflow # INGROUP: mokocli.Automation -# VERSION: 02.52.17 +# VERSION: 02.52.18 # BRIEF: Auto-create feature branch when an issue is opened name: "Universal: Issue Branch" diff --git a/SECURITY.md b/SECURITY.md index 7a7da29..5dfd6f1 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -23,7 +23,7 @@ DEFGROUP: Template-Joomla INGROUP: Template-Joomla.Documentation REPO: https://git.mokoconsulting.tech/MokoConsulting/Template-Joomla PATH: /SECURITY.md -VERSION: 02.52.17 +VERSION: 02.52.18 BRIEF: Security vulnerability reporting and handling policy --> diff --git a/source/packages/com_mokosuitebackup/mokosuitebackup.xml b/source/packages/com_mokosuitebackup/mokosuitebackup.xml index b96f870..916c79c 100644 --- a/source/packages/com_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/com_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> MokoSuiteBackup - 02.52.17 + 02.52.18 2026-06-02 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/com_mokosuitebackup/sql/updates/mysql/02.52.18.sql b/source/packages/com_mokosuitebackup/sql/updates/mysql/02.52.18.sql new file mode 100644 index 0000000..27c00ce --- /dev/null +++ b/source/packages/com_mokosuitebackup/sql/updates/mysql/02.52.18.sql @@ -0,0 +1 @@ +/* 02.52.18 — no schema changes */ diff --git a/source/packages/mod_mokosuitebackup_cpanel/mod_mokosuitebackup_cpanel.xml b/source/packages/mod_mokosuitebackup_cpanel/mod_mokosuitebackup_cpanel.xml index 624746b..8c6c5ba 100644 --- a/source/packages/mod_mokosuitebackup_cpanel/mod_mokosuitebackup_cpanel.xml +++ b/source/packages/mod_mokosuitebackup_cpanel/mod_mokosuitebackup_cpanel.xml @@ -8,7 +8,7 @@ --> mod_mokosuitebackup_cpanel - 02.52.17 + 02.52.18 2026-06-23 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_actionlog_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_actionlog_mokosuitebackup/mokosuitebackup.xml index bb6b2e4..14db151 100644 --- a/source/packages/plg_actionlog_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_actionlog_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> Action Log - MokoSuiteBackup - 02.52.17 + 02.52.18 2026-06-04 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_console_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_console_mokosuitebackup/mokosuitebackup.xml index a77f40c..1fdeb74 100644 --- a/source/packages/plg_console_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_console_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> Console - MokoSuiteBackup - 02.52.17 + 02.52.18 2026-06-04 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_content_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_content_mokosuitebackup/mokosuitebackup.xml index 21e7829..0c325b4 100644 --- a/source/packages/plg_content_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_content_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> Content - MokoSuiteBackup - 02.52.17 + 02.52.18 2026-06-04 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_quickicon_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_quickicon_mokosuitebackup/mokosuitebackup.xml index 11e4151..d00530b 100644 --- a/source/packages/plg_quickicon_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_quickicon_mokosuitebackup/mokosuitebackup.xml @@ -1,7 +1,7 @@ Quick Icon - MokoSuiteBackup - 02.52.17 + 02.52.18 2026-06-02 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_system_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_system_mokosuitebackup/mokosuitebackup.xml index d386a41..7ad71bf 100644 --- a/source/packages/plg_system_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_system_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> System - MokoSuiteBackup - 02.52.17 + 02.52.18 2026-06-02 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_task_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_task_mokosuitebackup/mokosuitebackup.xml index c97e6c6..0a4e874 100644 --- a/source/packages/plg_task_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_task_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> Task - MokoSuiteBackup - 02.52.17 + 02.52.18 2026-06-02 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_webservices_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_webservices_mokosuitebackup/mokosuitebackup.xml index d3add2e..acd32a2 100644 --- a/source/packages/plg_webservices_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_webservices_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> Web Services - MokoSuiteBackup - 02.52.17 + 02.52.18 2026-06-02 Moko Consulting hello@mokoconsulting.tech diff --git a/source/pkg_mokosuitebackup.xml b/source/pkg_mokosuitebackup.xml index 8848c3b..aa7a8ae 100644 --- a/source/pkg_mokosuitebackup.xml +++ b/source/pkg_mokosuitebackup.xml @@ -8,7 +8,7 @@ Package - MokoSuiteBackup mokosuitebackup - 02.52.17 + 02.52.18 2026-06-02 Moko Consulting hello@mokoconsulting.tech