diff --git a/.mokogitea/workflows/issue-branch.yml b/.mokogitea/workflows/issue-branch.yml index c58ebd05..934a65ce 100644 --- a/.mokogitea/workflows/issue-branch.yml +++ b/.mokogitea/workflows/issue-branch.yml @@ -5,7 +5,7 @@ # FILE INFORMATION # DEFGROUP: MokoGitea.Workflow # INGROUP: mokocli.Automation -# VERSION: 02.58.35 +# VERSION: 02.58.36 # BRIEF: Auto-create feature branch when an issue is opened name: "Universal: Issue Branch" diff --git a/SECURITY.md b/SECURITY.md index 345d2cb3..73a6d6e9 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.58.35 +VERSION: 02.58.36 BRIEF: Security vulnerability reporting and handling policy --> diff --git a/source/packages/com_mokosuitebackup/mokosuitebackup.xml b/source/packages/com_mokosuitebackup/mokosuitebackup.xml index 187ea632..61d533d3 100644 --- a/source/packages/com_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/com_mokosuitebackup/mokosuitebackup.xml @@ -17,7 +17,7 @@ display label there. --> MokoSuiteBackup - 02.58.35 + 02.58.36 2026-06-02 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/com_mokosuitebackup/sql/updates/mysql/02.58.36.sql b/source/packages/com_mokosuitebackup/sql/updates/mysql/02.58.36.sql new file mode 100644 index 00000000..bd262657 --- /dev/null +++ b/source/packages/com_mokosuitebackup/sql/updates/mysql/02.58.36.sql @@ -0,0 +1 @@ +/* 02.58.36 — no schema changes */ diff --git a/source/packages/com_mokosuitebackup/src/Engine/SnapshotRestoreEngine.php b/source/packages/com_mokosuitebackup/src/Engine/SnapshotRestoreEngine.php index 9e32577a..3b59ccf0 100644 --- a/source/packages/com_mokosuitebackup/src/Engine/SnapshotRestoreEngine.php +++ b/source/packages/com_mokosuitebackup/src/Engine/SnapshotRestoreEngine.php @@ -125,11 +125,23 @@ class SnapshotRestoreEngine $prefix = $db->getPrefix(); $totalRows = 0; - try { - $db->transactionStart(); + // Build list of tables to restore based on selected types + $tablesToRestore = $this->getTablesToRestore($restoreTypes); - // Build list of tables to restore based on selected types - $tablesToRestore = $this->getTablesToRestore($restoreTypes); + /* Duplicate mode inserts brand-new records through Joomla's Table API, + whose Nested tables (categories, tags) issue LOCK TABLES — which + implicitly COMMITS any open transaction in MySQL/InnoDB. Wrapping it + in transactionStart()/Rollback() would be a false atomicity promise: + the first category/tag store would commit and defeat the rollback. + Duplicate mode is therefore best-effort and per-item defensive (a bad + item is skipped and logged, never fatal) rather than all-or-nothing. + The raw-DB modes (replace/create/merge) remain fully transactional. */ + $useTransaction = ($mode !== 'duplicate'); + + try { + if ($useTransaction) { + $db->transactionStart(); + } if ($mode === 'duplicate') { $totalRows = $this->restoreDuplicate($data, $restoreTypes); @@ -156,7 +168,9 @@ class SnapshotRestoreEngine } } - $db->transactionCommit(); + if ($useTransaction) { + $db->transactionCommit(); + } $this->log('Restore complete: ' . $totalRows . ' total rows'); @@ -188,11 +202,15 @@ class SnapshotRestoreEngine 'log' => implode("\n", $this->log), ]; } catch (\Throwable $e) { - try { - $db->transactionRollback(); - $this->log('Transaction rolled back'); - } catch (\Exception $rollbackEx) { - $this->log('Rollback failed: ' . $rollbackEx->getMessage()); + if ($useTransaction) { + try { + $db->transactionRollback(); + $this->log('Transaction rolled back'); + } catch (\Exception $rollbackEx) { + $this->log('Rollback failed: ' . $rollbackEx->getMessage()); + } + } else { + $this->log('Duplicate mode is not transactional; records already inserted are left in place.'); } $this->log('FATAL: ' . $e->getMessage()); diff --git a/source/packages/com_mokosuitebackup/tmpl/runbackup/default.php b/source/packages/com_mokosuitebackup/tmpl/runbackup/default.php index 5e148445..5f408e55 100644 --- a/source/packages/com_mokosuitebackup/tmpl/runbackup/default.php +++ b/source/packages/com_mokosuitebackup/tmpl/runbackup/default.php @@ -34,6 +34,14 @@ if ($this->returnUrl !== '') { $decoded = base64_decode($this->returnUrl, true); $raw = ($decoded !== false && $decoded !== '') ? $decoded : $this->returnUrl; + /* Reject any backslash or control char outright: legitimate Joomla admin + return URLs never contain them, and a browser normalises a leading "/\" + to "//", turning a would-be root-relative path into a protocol-relative + open redirect (e.g. "/\evil.com" → "//evil.com"). */ + if (preg_match('/[\x00-\x1f\x7f\\\\]/', $raw)) { + $raw = ''; + } + $isAbsoluteHttp = (bool) preg_match('#^https?://#i', $raw); $isRootRelative = isset($raw[0]) && $raw[0] === '/' && (!isset($raw[1]) || $raw[1] !== '/'); diff --git a/source/packages/mod_mokosuitebackup_cpanel/mod_mokosuitebackup_cpanel.xml b/source/packages/mod_mokosuitebackup_cpanel/mod_mokosuitebackup_cpanel.xml index 4f635e5c..e9756fec 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 @@ --> Module - MokoSuiteBackup - cPanel - 02.58.35 + 02.58.36 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 3bc177fb..dd9ca3e9 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.58.35 + 02.58.36 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 45e20e18..951da50a 100644 --- a/source/packages/plg_console_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_console_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> Console - MokoSuiteBackup - 02.58.35 + 02.58.36 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 578c792f..3d0f5112 100644 --- a/source/packages/plg_content_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_content_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> Content - MokoSuiteBackup - 02.58.35 + 02.58.36 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 53de7146..3ee21949 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.58.35 + 02.58.36 2026-06-02 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_system_mokosuitebackup/media/js/installer-backup.js b/source/packages/plg_system_mokosuitebackup/media/js/installer-backup.js index 6f80f850..477df90e 100644 --- a/source/packages/plg_system_mokosuitebackup/media/js/installer-backup.js +++ b/source/packages/plg_system_mokosuitebackup/media/js/installer-backup.js @@ -70,6 +70,22 @@ return; } + var ret = window.location.href; + ret += (ret.indexOf('?') === -1 ? '?' : '&') + 'msb_resume=1'; + + /* Build the redirect BEFORE we swallow the click. btoa() throws on + non-Latin1 input (e.g. a UTF-8 filter value in the query string), so + encode as UTF-8 first; if it still fails, bail WITHOUT preventing the + click so Joomla's own update/uninstall proceeds normally. */ + var target; + try { + target = cfg.runbackupUrl + + '&profile_id=' + encodeURIComponent(cfg.profileId) + + '&returnurl=' + encodeURIComponent(btoa(unescape(encodeURIComponent(ret)))); + } catch (x) { + return; + } + e.preventDefault(); e.stopImmediatePropagation(); @@ -77,12 +93,7 @@ sessionStorage.setItem(STORAGE_KEY, JSON.stringify({ task: task, cids: cids })); } catch (x) {} - var ret = window.location.href; - ret += (ret.indexOf('?') === -1 ? '?' : '&') + 'msb_resume=1'; - - window.location.href = cfg.runbackupUrl - + '&profile_id=' + encodeURIComponent(cfg.profileId) - + '&returnurl=' + encodeURIComponent(btoa(ret)); + window.location.href = target; }, true); /* On return from the backup screen: restore the selection and re-fire. */ diff --git a/source/packages/plg_system_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_system_mokosuitebackup/mokosuitebackup.xml index fb2f9f37..53e6e4fa 100644 --- a/source/packages/plg_system_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_system_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> System - MokoSuiteBackup - 02.58.35 + 02.58.36 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 46dd12db..670652f3 100644 --- a/source/packages/plg_task_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_task_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> Task - MokoSuiteBackup - 02.58.35 + 02.58.36 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 8cdaf10f..86609f71 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.58.35 + 02.58.36 2026-06-02 Moko Consulting hello@mokoconsulting.tech diff --git a/source/pkg_mokosuitebackup.xml b/source/pkg_mokosuitebackup.xml index 9690b40c..b175f745 100644 --- a/source/pkg_mokosuitebackup.xml +++ b/source/pkg_mokosuitebackup.xml @@ -8,7 +8,7 @@ Package - MokoSuiteBackup mokosuitebackup - 02.58.35 + 02.58.36 2026-06-02 Moko Consulting hello@mokoconsulting.tech