fix: security + data-integrity fixes (P0/P1) #211
@@ -60,7 +60,7 @@ Joomla **package** with four sub-extensions:
|
||||
- **Workflow directory**: `.mokogitea/` (not `.gitea/` or `.github/`)
|
||||
- **Minification**: handled at build time (CI)
|
||||
- **Wiki**: documentation lives in the Gitea wiki, not `docs/` files
|
||||
- **Standards**: [MokoStandards](https://git.mokoconsulting.tech/MokoConsulting/mokoplatform/wiki/Home)
|
||||
- **Standards**: [MokoStandards](https://git.mokoconsulting.tech/MokoConsulting/mokocli/wiki/Home)
|
||||
|
||||
## Coding Standards
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
# FILE INFORMATION
|
||||
# DEFGROUP: Gitea.Workflow
|
||||
# INGROUP: mokocli.Automation
|
||||
# VERSION: 01.00.00
|
||||
# VERSION: 02.56.07
|
||||
# BRIEF: Auto-create feature branch when an issue is opened
|
||||
|
||||
name: "Universal: Issue Branch"
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ DEFGROUP: Template-Joomla
|
||||
INGROUP: Template-Joomla.Documentation
|
||||
REPO: https://git.mokoconsulting.tech/MokoConsulting/Template-Joomla
|
||||
PATH: /SECURITY.md
|
||||
VERSION: 02.56.05
|
||||
VERSION: 02.56.07
|
||||
BRIEF: Security vulnerability reporting and handling policy
|
||||
-->
|
||||
|
||||
|
||||
Submodule source/packages/MokoSuiteClient updated: 464b5da929...2273690f94
@@ -24,7 +24,6 @@ class JsonapiView extends BaseApiView
|
||||
'origin',
|
||||
'backup_type',
|
||||
'archivename',
|
||||
'absolute_path',
|
||||
'total_size',
|
||||
'db_size',
|
||||
'files_count',
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
-->
|
||||
<extension type="component" method="upgrade">
|
||||
<name>Component - MokoSuiteBackup</name>
|
||||
<version>02.56.05</version>
|
||||
<version>02.56.07</version>
|
||||
<creationDate>2026-06-02</creationDate>
|
||||
<author>Moko Consulting</author>
|
||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
DROP TABLE IF EXISTS `#__mokosuitebackup_remotes`;
|
||||
DROP TABLE IF EXISTS `#__mokosuitebackup_records`;
|
||||
DROP TABLE IF EXISTS `#__mokosuitebackup_snapshots`;
|
||||
DROP TABLE IF EXISTS `#__mokosuitebackup_profiles`;
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
/* 02.56.07 — no schema changes */
|
||||
@@ -1201,6 +1201,7 @@ class AjaxController extends BaseController
|
||||
private function maskSecrets(array $config, string $type): array
|
||||
{
|
||||
$secrets = [
|
||||
'ftp' => ['password'],
|
||||
'sftp' => ['password', 'passphrase', 'key_data'],
|
||||
's3' => ['secret_key'],
|
||||
'google_drive' => ['client_secret', 'refresh_token'],
|
||||
@@ -1223,6 +1224,7 @@ class AjaxController extends BaseController
|
||||
private function mergeExistingSecrets(int $id, array $config, string $type): array
|
||||
{
|
||||
$secrets = [
|
||||
'ftp' => ['password'],
|
||||
'sftp' => ['password', 'passphrase', 'key_data'],
|
||||
's3' => ['secret_key'],
|
||||
'google_drive' => ['client_secret', 'refresh_token'],
|
||||
|
||||
@@ -326,7 +326,7 @@ class DatabaseDumper
|
||||
}
|
||||
|
||||
$createSql = str_replace('`' . $prefix, '`#__', $createRow[1]);
|
||||
fwrite($fp, 'DROP TABLE IF EXISTS `' . $abstractName . "`;\\n");
|
||||
fwrite($fp, 'DROP TABLE IF EXISTS `' . $abstractName . "`;\n");
|
||||
fwrite($fp, $createSql . ";\n\n");
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,13 @@ use Joomla\CMS\Factory;
|
||||
|
||||
class DatabaseImporter
|
||||
{
|
||||
/**
|
||||
* Non-fatal per-statement errors collected during the last import().
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
private array $errors = [];
|
||||
|
||||
/**
|
||||
* Import a SQL dump file into the database.
|
||||
*
|
||||
@@ -31,6 +38,8 @@ class DatabaseImporter
|
||||
*/
|
||||
public function import(string $sqlFile): int
|
||||
{
|
||||
$this->errors = [];
|
||||
|
||||
if (!is_file($sqlFile) || !is_readable($sqlFile)) {
|
||||
throw new \RuntimeException('SQL file not readable: ' . $sqlFile);
|
||||
}
|
||||
@@ -97,8 +106,10 @@ class DatabaseImporter
|
||||
} catch (\Exception $e) {
|
||||
// Log but don't abort — some statements may fail on
|
||||
// different MySQL versions (e.g. charset differences)
|
||||
// but the overall restore should continue.
|
||||
// but the overall restore should continue. Errors are
|
||||
// collected so the caller can surface a warning status.
|
||||
error_log('MokoSuiteBackup SQL import warning: ' . $e->getMessage());
|
||||
$this->errors[] = $e->getMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -115,6 +126,7 @@ class DatabaseImporter
|
||||
$statementsExecuted++;
|
||||
} catch (\Exception $e) {
|
||||
error_log('MokoSuiteBackup SQL import warning (final): ' . $e->getMessage());
|
||||
$this->errors[] = $e->getMessage();
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
@@ -123,4 +135,24 @@ class DatabaseImporter
|
||||
|
||||
return $statementsExecuted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Non-fatal errors from the last import(), if any. A non-empty result
|
||||
* means the restore completed with problems and should be treated as a
|
||||
* warning rather than a clean success.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function getErrors(): array
|
||||
{
|
||||
return $this->errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the last import() had any non-fatal statement errors.
|
||||
*/
|
||||
public function hasErrors(): bool
|
||||
{
|
||||
return $this->errors !== [];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,7 +207,7 @@ class SftpUploader implements RemoteUploaderInterface
|
||||
*/
|
||||
private function buildScpCommand(string $localPath, string $remoteTarget, ?string $keyFile): string
|
||||
{
|
||||
$parts = ['scp', '-o', 'StrictHostKeyChecking=no', '-o', 'BatchMode=yes'];
|
||||
$parts = ['scp', '-o', 'StrictHostKeyChecking=accept-new', '-o', 'BatchMode=yes'];
|
||||
|
||||
if ($this->port !== 22) {
|
||||
$parts[] = '-P';
|
||||
@@ -235,7 +235,7 @@ class SftpUploader implements RemoteUploaderInterface
|
||||
*/
|
||||
private function buildSshCommand(string $remoteCmd, ?string $keyFile): string
|
||||
{
|
||||
$parts = ['ssh', '-o', 'StrictHostKeyChecking=no', '-o', 'BatchMode=yes'];
|
||||
$parts = ['ssh', '-o', 'StrictHostKeyChecking=accept-new', '-o', 'BatchMode=yes'];
|
||||
|
||||
if ($this->port !== 22) {
|
||||
$parts[] = '-p';
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
-->
|
||||
<extension type="module" client="administrator" method="upgrade">
|
||||
<name>Module - MokoSuiteBackup - cPanel</name>
|
||||
<version>02.56.05</version>
|
||||
<version>02.56.07</version>
|
||||
<creationDate>2026-06-23</creationDate>
|
||||
<author>Moko Consulting</author>
|
||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
-->
|
||||
<extension type="plugin" group="actionlog" method="upgrade">
|
||||
<name>Action Log - MokoSuiteBackup</name>
|
||||
<version>02.56.05</version>
|
||||
<version>02.56.07</version>
|
||||
<creationDate>2026-06-04</creationDate>
|
||||
<author>Moko Consulting</author>
|
||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
-->
|
||||
<extension type="plugin" group="console" method="upgrade">
|
||||
<name>Console - MokoSuiteBackup</name>
|
||||
<version>02.56.05</version>
|
||||
<version>02.56.07</version>
|
||||
<creationDate>2026-06-04</creationDate>
|
||||
<author>Moko Consulting</author>
|
||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||
|
||||
@@ -227,11 +227,11 @@ class SnapshotCommand extends AbstractCommand
|
||||
}
|
||||
|
||||
// Delete the snapshot file if it exists
|
||||
if (!empty($record->file_path) && is_file($record->file_path)) {
|
||||
if (!@unlink($record->file_path)) {
|
||||
$io->warning('Could not delete snapshot file: ' . $record->file_path);
|
||||
if (!empty($record->data_file) && is_file($record->data_file)) {
|
||||
if (!@unlink($record->data_file)) {
|
||||
$io->warning('Could not delete snapshot file: ' . $record->data_file);
|
||||
} else {
|
||||
$io->text('Deleted file: ' . $record->file_path);
|
||||
$io->text('Deleted file: ' . $record->data_file);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
-->
|
||||
<extension type="plugin" group="content" method="upgrade">
|
||||
<name>Content - MokoSuiteBackup</name>
|
||||
<version>02.56.05</version>
|
||||
<version>02.56.07</version>
|
||||
<creationDate>2026-06-04</creationDate>
|
||||
<author>Moko Consulting</author>
|
||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||
@@ -59,7 +59,7 @@
|
||||
type="sql"
|
||||
label="PLG_CONTENT_MOKOJOOMBACKUP_FIELD_PROFILE"
|
||||
description="PLG_CONTENT_MOKOJOOMBACKUP_FIELD_PROFILE_DESC"
|
||||
query="SELECT id AS value, title AS text FROM #__mokosuitebackup_profiles WHERE published = 1 ORDER BY ordering ASC"
|
||||
query="SELECT id AS value, title AS text FROM #__mokosuitebackup_profiles WHERE published = 1 ORDER BY id ASC"
|
||||
default="1"
|
||||
>
|
||||
<option value="1">Default Backup Profile</option>
|
||||
|
||||
+3
-13
@@ -24,9 +24,11 @@ final class MokoSuiteBackupContent extends CMSPlugin implements SubscriberInterf
|
||||
|
||||
public static function getSubscribedEvents(): array
|
||||
{
|
||||
// Pre-update backups are owned by plg_system_mokosuitebackup, which also
|
||||
// subscribes to onExtensionBeforeUpdate. Only pre-install is handled here
|
||||
// to avoid running the backup twice on a single extension update.
|
||||
return [
|
||||
'onExtensionBeforeInstall' => 'onExtensionBeforeInstall',
|
||||
'onExtensionBeforeUpdate' => 'onExtensionBeforeUpdate',
|
||||
];
|
||||
}
|
||||
|
||||
@@ -42,18 +44,6 @@ final class MokoSuiteBackupContent extends CMSPlugin implements SubscriberInterf
|
||||
$this->triggerAutoBackup('Pre-install backup');
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger a backup before an extension is updated.
|
||||
*/
|
||||
public function onExtensionBeforeUpdate(Event $event): void
|
||||
{
|
||||
if (!(int) $this->params->get('backup_before_update', 1)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->triggerAutoBackup('Pre-update backup');
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a backup using the configured profile.
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<extension type="plugin" group="quickicon" method="upgrade">
|
||||
<name>Quick Icon - MokoSuiteBackup</name>
|
||||
<version>02.56.05</version>
|
||||
<version>02.56.07</version>
|
||||
<creationDate>2026-06-02</creationDate>
|
||||
<author>Moko Consulting</author>
|
||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
-->
|
||||
<extension type="plugin" group="system" method="upgrade">
|
||||
<name>System - MokoSuiteBackup</name>
|
||||
<version>02.56.05</version>
|
||||
<version>02.56.07</version>
|
||||
<creationDate>2026-06-02</creationDate>
|
||||
<author>Moko Consulting</author>
|
||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
type="sql"
|
||||
label="PLG_TASK_MOKOJOOMBACKUP_FIELD_PROFILE"
|
||||
description="PLG_TASK_MOKOJOOMBACKUP_FIELD_PROFILE_DESC"
|
||||
query="SELECT id AS value, title AS text FROM #__mokosuitebackup_profiles WHERE published = 1 ORDER BY ordering ASC"
|
||||
query="SELECT id AS value, title AS text FROM #__mokosuitebackup_profiles WHERE published = 1 ORDER BY id ASC"
|
||||
default="1"
|
||||
required="true"
|
||||
>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
-->
|
||||
<extension type="plugin" group="task" method="upgrade">
|
||||
<name>Task - MokoSuiteBackup</name>
|
||||
<version>02.56.05</version>
|
||||
<version>02.56.07</version>
|
||||
<creationDate>2026-06-02</creationDate>
|
||||
<author>Moko Consulting</author>
|
||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
-->
|
||||
<extension type="plugin" group="webservices" method="upgrade">
|
||||
<name>Web Services - MokoSuiteBackup</name>
|
||||
<version>02.56.05</version>
|
||||
<version>02.56.07</version>
|
||||
<creationDate>2026-06-02</creationDate>
|
||||
<author>Moko Consulting</author>
|
||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<extension type="package" method="upgrade">
|
||||
<name>Package - MokoSuiteBackup</name>
|
||||
<packagename>mokosuitebackup</packagename>
|
||||
<version>02.56.05</version>
|
||||
<version>02.56.07</version>
|
||||
<creationDate>2026-06-02</creationDate>
|
||||
<author>Moko Consulting</author>
|
||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||
|
||||
Reference in New Issue
Block a user