diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..12adab7 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "source/packages/MokoSuiteClient"] + path = source/packages/MokoSuiteClient + url = https://git.mokoconsulting.tech/MokoConsulting/MokoSuiteClient.git diff --git a/.mokogitea/workflows/issue-branch.yml b/.mokogitea/workflows/issue-branch.yml index 117dfa0..03793d5 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.43.22 +# VERSION: 01.43.26 # BRIEF: Auto-create feature branch when an issue is opened name: "Universal: Issue Branch" diff --git a/README.md b/README.md index edf4659..b949bbb 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ Full-site backup and restore for Joomla — database, files, and configuration. | Field | Value | |---|---| | **Package** | `pkg_mokosuitebackup` | -| **Type** | Joomla Package (8 sub-extensions) | +| **Type** | Joomla Package (9 sub-extensions + MokoSuiteClient) | | **Joomla** | 6.x+ | | **PHP** | 8.1+ | | **License** | GPL-3.0-or-later | @@ -30,7 +30,8 @@ Full-site backup and restore for Joomla — database, files, and configuration. - Scheduled snapshot task via com_scheduler ### Remote Storage -- SFTP with SSH key file authentication (key stored base64-encoded in database) +- Multi-remote — upload to multiple destinations per profile simultaneously +- SFTP with SSH key file auth + remote directory browser - Amazon S3 and S3-compatible (DigitalOcean Spaces, Wasabi, MinIO) - Google Drive with OAuth2 and resumable uploads - Graceful degradation — local backup preserved if upload fails @@ -66,6 +67,10 @@ Full-site backup and restore for Joomla — database, files, and configuration. - Snapshots: create, list, restore, delete, download - Profile credentials masked in API responses +### Bundled: MokoSuiteClient +- Full MokoSuiteClient package installed automatically alongside MokoSuiteBackup +- Provides admin dashboard, security firewall, tenant management, and developer tools + ## Installation 1. Download from [Releases](https://git.mokoconsulting.tech/MokoConsulting/MokoSuiteBackup/releases) diff --git a/source/packages/MokoSuiteClient b/source/packages/MokoSuiteClient new file mode 160000 index 0000000..9df6bea --- /dev/null +++ b/source/packages/MokoSuiteClient @@ -0,0 +1 @@ +Subproject commit 9df6bea4b7480b2e443898ad84a279070ba4a7f6 diff --git a/source/packages/com_mokosuitebackup/mokosuitebackup.xml b/source/packages/com_mokosuitebackup/mokosuitebackup.xml index d5aa305..91fcf6a 100644 --- a/source/packages/com_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/com_mokosuitebackup/mokosuitebackup.xml @@ -7,8 +7,7 @@ --> MokoSuiteBackup - 01.43.22 - 01.43.22 + 01.43.26 2026-06-02 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/com_mokosuitebackup/sql/install.mysql.sql b/source/packages/com_mokosuitebackup/sql/install.mysql.sql index 8767c04..76be0f7 100644 --- a/source/packages/com_mokosuitebackup/sql/install.mysql.sql +++ b/source/packages/com_mokosuitebackup/sql/install.mysql.sql @@ -40,6 +40,7 @@ CREATE TABLE IF NOT EXISTS `#__mokosuitebackup_profiles` ( `remote_keep_local` TINYINT(1) NOT NULL DEFAULT 1 COMMENT 'Keep local copy after upload', `encryption_password` VARCHAR(255) NOT NULL DEFAULT '' COMMENT 'AES-256 archive encryption password (blank = no encryption)', `include_mokorestore` VARCHAR(20) NOT NULL DEFAULT '0' COMMENT 'MokoRestore mode: 0=none, 1=wrapped, standalone', + `restore_script_name` VARCHAR(100) NOT NULL DEFAULT 'restore.php' COMMENT 'Custom restore script filename', `sanitize_passwords` TINYINT(1) NOT NULL DEFAULT 0 COMMENT 'Replace user password hashes with invalid value', `preserve_super_admin` TINYINT(1) NOT NULL DEFAULT 1 COMMENT 'Keep super admin password when sanitizing', `sanitize_emails` TINYINT(1) NOT NULL DEFAULT 0 COMMENT 'Replace user emails with dummy values', @@ -113,14 +114,13 @@ CREATE TABLE IF NOT EXISTS `#__mokosuitebackup_remotes` ( `title` VARCHAR(255) NOT NULL DEFAULT '', `type` VARCHAR(20) NOT NULL DEFAULT 'sftp' COMMENT 'sftp, s3, google_drive', `enabled` TINYINT(1) NOT NULL DEFAULT 1, - `keep_local` TINYINT(1) NOT NULL DEFAULT 1 COMMENT 'Keep local copy after upload', - `config` MEDIUMTEXT NOT NULL COMMENT 'JSON — type-specific settings', + `params` MEDIUMTEXT COMMENT 'JSON: type-specific settings', `ordering` INT(11) NOT NULL DEFAULT 0, `created` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00', `modified` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00', PRIMARY KEY (`id`), KEY `idx_profile` (`profile_id`), - KEY `idx_enabled` (`enabled`) + KEY `idx_enabled` (`profile_id`, `enabled`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- Insert default backup profile (IGNORE prevents duplicate key error on update) diff --git a/source/packages/com_mokosuitebackup/sql/updates/mysql/01.43.22.sql b/source/packages/com_mokosuitebackup/sql/updates/mysql/01.43.22.sql index fcb8aac..01f1e95 100644 --- a/source/packages/com_mokosuitebackup/sql/updates/mysql/01.43.22.sql +++ b/source/packages/com_mokosuitebackup/sql/updates/mysql/01.43.22.sql @@ -1 +1,5 @@ -/* 01.43.22 — no schema changes */ +-- 01.43.22 — Add restore_script_name to profiles, align remotes schema + +ALTER TABLE `#__mokosuitebackup_profiles` + ADD COLUMN `restore_script_name` VARCHAR(100) NOT NULL DEFAULT 'restore.php' COMMENT 'Custom restore script filename' + AFTER `include_mokorestore`; diff --git a/source/packages/com_mokosuitebackup/sql/updates/mysql/01.43.23.sql b/source/packages/com_mokosuitebackup/sql/updates/mysql/01.43.23.sql new file mode 100644 index 0000000..08a0685 --- /dev/null +++ b/source/packages/com_mokosuitebackup/sql/updates/mysql/01.43.23.sql @@ -0,0 +1 @@ +/* 01.43.23 — no schema changes */ diff --git a/source/packages/com_mokosuitebackup/sql/updates/mysql/01.43.24.sql b/source/packages/com_mokosuitebackup/sql/updates/mysql/01.43.24.sql new file mode 100644 index 0000000..64643df --- /dev/null +++ b/source/packages/com_mokosuitebackup/sql/updates/mysql/01.43.24.sql @@ -0,0 +1 @@ +/* 01.43.24 — no schema changes */ diff --git a/source/packages/com_mokosuitebackup/sql/updates/mysql/01.43.25.sql b/source/packages/com_mokosuitebackup/sql/updates/mysql/01.43.25.sql new file mode 100644 index 0000000..6ae1419 --- /dev/null +++ b/source/packages/com_mokosuitebackup/sql/updates/mysql/01.43.25.sql @@ -0,0 +1 @@ +/* 01.43.25 — no schema changes */ diff --git a/source/packages/com_mokosuitebackup/sql/updates/mysql/01.43.26.sql b/source/packages/com_mokosuitebackup/sql/updates/mysql/01.43.26.sql new file mode 100644 index 0000000..6c94f71 --- /dev/null +++ b/source/packages/com_mokosuitebackup/sql/updates/mysql/01.43.26.sql @@ -0,0 +1 @@ +/* 01.43.26 — no schema changes */ diff --git a/source/packages/com_mokosuitebackup/src/Controller/AjaxController.php b/source/packages/com_mokosuitebackup/src/Controller/AjaxController.php index 41c861a..159af3b 100644 --- a/source/packages/com_mokosuitebackup/src/Controller/AjaxController.php +++ b/source/packages/com_mokosuitebackup/src/Controller/AjaxController.php @@ -924,11 +924,11 @@ class AjaxController extends BaseController return; } - // Decode JSON config and mask secrets + // Decode JSON params and mask secrets $items = []; foreach ($rows as $row) { - $config = json_decode($row->config, true) ?: []; + $config = json_decode($row->params, true) ?: []; // Mask sensitive fields so they never leave the server in list views $masked = $this->maskSecrets($config, $row->type); @@ -939,8 +939,7 @@ class AjaxController extends BaseController 'title' => $row->title, 'type' => $row->type, 'enabled' => (int) $row->enabled, - 'keep_local' => (int) $row->keep_local, - 'config' => $masked, + 'params' => $masked, 'ordering' => (int) $row->ordering, ]; } @@ -971,7 +970,6 @@ class AjaxController extends BaseController $title = trim($this->input->getString('remote_title', '')); $type = $this->input->getCmd('remote_type', 'sftp'); $enabled = $this->input->getInt('remote_enabled', 1); - $keepLocal = $this->input->getInt('remote_keep_local', 1); $configRaw = $this->input->getString('remote_config', '{}'); if (!$profileId) { @@ -1019,9 +1017,7 @@ class AjaxController extends BaseController $table->title = $title; $table->type = $type; $table->enabled = $enabled ? 1 : 0; - $table->keep_local = $keepLocal ? 1 : 0; - $table->config = json_encode($config); - + $table->params = json_encode($config); if (!$table->check() || !$table->store()) { $this->sendJson(['error' => true, 'message' => $table->getError() ?: 'Save failed']); @@ -1190,7 +1186,7 @@ class AjaxController extends BaseController try { $db = Factory::getDbo(); $query = $db->getQuery(true) - ->select($db->quoteName('config')) + ->select($db->quoteName('params')) ->from($db->quoteName('#__mokosuitebackup_remotes')) ->where($db->quoteName('id') . ' = ' . $id); $db->setQuery($query); diff --git a/source/packages/com_mokosuitebackup/src/Engine/SteppedBackupEngine.php b/source/packages/com_mokosuitebackup/src/Engine/SteppedBackupEngine.php index 0901d09..9e18d04 100644 --- a/source/packages/com_mokosuitebackup/src/Engine/SteppedBackupEngine.php +++ b/source/packages/com_mokosuitebackup/src/Engine/SteppedBackupEngine.php @@ -394,8 +394,14 @@ class SteppedBackupEngine $restoreScriptName = MokoRestore::sanitizeScriptName($restoreScriptName); $restoreDir = dirname($session->archivePath); $session->restoreScriptPath = $restoreDir . '/' . $restoreScriptName; - MokoRestore::generateStandalone($session->restoreScriptPath); - $session->log('Standalone ' . $restoreScriptName . ' generated'); + + try { + MokoRestore::generateStandalone($session->restoreScriptPath); + $session->log('Standalone ' . $restoreScriptName . ' generated'); + } catch (\Throwable $e) { + $session->log('MokoRestore error: ' . $e->getMessage() . ' in ' . $e->getFile() . ':' . $e->getLine()); + $session->log('Stack trace: ' . $e->getTraceAsString()); + } } // Update record diff --git a/source/packages/com_mokosuitebackup/src/Model/DashboardModel.php b/source/packages/com_mokosuitebackup/src/Model/DashboardModel.php index b378f0a..ae85d6e 100644 --- a/source/packages/com_mokosuitebackup/src/Model/DashboardModel.php +++ b/source/packages/com_mokosuitebackup/src/Model/DashboardModel.php @@ -294,7 +294,7 @@ class DashboardModel extends BaseDatabaseModel ->select($db->quoteName(['id', 'title', 'backup_type'])) ->from($db->quoteName('#__mokosuitebackup_profiles')) ->where($db->quoteName('published') . ' = 1') - ->order($db->quoteName('ordering') . ' ASC'); + ->order($db->quoteName('id') . ' ASC'); $db->setQuery($query); return $db->loadObjectList() ?: []; diff --git a/source/packages/mod_mokosuitebackup_cpanel/mod_mokosuitebackup_cpanel.xml b/source/packages/mod_mokosuitebackup_cpanel/mod_mokosuitebackup_cpanel.xml index f2901d1..dfd2640 100644 --- a/source/packages/mod_mokosuitebackup_cpanel/mod_mokosuitebackup_cpanel.xml +++ b/source/packages/mod_mokosuitebackup_cpanel/mod_mokosuitebackup_cpanel.xml @@ -8,8 +8,7 @@ --> mod_mokosuitebackup_cpanel - 01.43.22 - 01.43.22 + 01.43.26 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 0639249..b4b7bee 100644 --- a/source/packages/plg_actionlog_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_actionlog_mokosuitebackup/mokosuitebackup.xml @@ -7,8 +7,7 @@ --> Action Log - MokoSuiteBackup - 01.43.22 - 01.43.22 + 01.43.26 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 21de5de..0afd5c5 100644 --- a/source/packages/plg_console_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_console_mokosuitebackup/mokosuitebackup.xml @@ -7,8 +7,7 @@ --> Console - MokoSuiteBackup - 01.43.22 - 01.43.22 + 01.43.26 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 8527f39..3fae853 100644 --- a/source/packages/plg_content_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_content_mokosuitebackup/mokosuitebackup.xml @@ -7,8 +7,7 @@ --> Content - MokoSuiteBackup - 01.43.22 - 01.43.22 + 01.43.26 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 c16823b..6a54105 100644 --- a/source/packages/plg_quickicon_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_quickicon_mokosuitebackup/mokosuitebackup.xml @@ -1,8 +1,7 @@ Quick Icon - MokoSuiteBackup - 01.43.22 - 01.43.22 + 01.43.26 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 c1d1cdb..f8593ce 100644 --- a/source/packages/plg_system_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_system_mokosuitebackup/mokosuitebackup.xml @@ -7,8 +7,7 @@ --> System - MokoSuiteBackup - 01.43.22 - 01.43.22 + 01.43.26 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 f5babc9..7771324 100644 --- a/source/packages/plg_task_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_task_mokosuitebackup/mokosuitebackup.xml @@ -7,8 +7,7 @@ --> Task - MokoSuiteBackup - 01.43.22 - 01.43.22 + 01.43.26 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 15a07a4..de00043 100644 --- a/source/packages/plg_webservices_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_webservices_mokosuitebackup/mokosuitebackup.xml @@ -7,8 +7,7 @@ --> Web Services - MokoSuiteBackup - 01.43.22 - 01.43.22 + 01.43.26 2026-06-02 Moko Consulting hello@mokoconsulting.tech diff --git a/source/pkg_mokosuitebackup.xml b/source/pkg_mokosuitebackup.xml index ae02e44..60e0c63 100644 --- a/source/pkg_mokosuitebackup.xml +++ b/source/pkg_mokosuitebackup.xml @@ -8,8 +8,7 @@ Package - MokoSuiteBackup mokosuitebackup - 01.43.22 - 01.43.22 + 01.43.26 2026-06-02 Moko Consulting hello@mokoconsulting.tech @@ -30,6 +29,7 @@ plg_content_mokosuitebackup.zip plg_actionlog_mokosuitebackup.zip mod_mokosuitebackup_cpanel.zip + MokoSuiteClient.zip