Files
MokoSuiteBackup/source/packages/com_mokosuitebackup/src/Model/BackupsModel.php
T
Jonathan Miller 3328d7cf19
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Blocked by required conditions
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Blocked by required conditions
Joomla: Extension CI / PHPStan Analysis (pull_request) Blocked by required conditions
Joomla: Extension CI / Build RC Pre-Release (pull_request) Blocked by required conditions
Universal: PR Check / Build RC Package (pull_request) Blocked by required conditions
Universal: PR Check / Report Issues (pull_request) Blocked by required conditions
Generic: Repo Health / Scripts governance (pull_request) Blocked by required conditions
Generic: Repo Health / Repository health (pull_request) Blocked by required conditions
Generic: Repo Health / Report Issues (pull_request) Blocked by required conditions
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 25s
Universal: Build & Release / Promote to RC (pull_request) Successful in 28s
Universal: Build & Release / Build & Release Pipeline (pull_request) Has been skipped
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 4s
Universal: PR Check / Branch Policy (pull_request) Failing after 1s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 7s
Universal: PR Check / Secret Scan (pull_request) Successful in 5s
Universal: PR Check / Validate PR (pull_request) Failing after 4s
Generic: Repo Health / Access control (pull_request) Successful in 1s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 11s
feat: backup type filter + path traversal protection (#68, #72)
#68: Add backup type filter dropdown to backups list view
- filter_backups.xml: full/database/files/differential options
- BackupsModel: backup_type filter in getListQuery()
- Language string: COM_MOKOJOOMBACKUP_FILTER_TYPE_ALL

#72: Path traversal protection in RestoreEngine and MokoRestore
- RestoreEngine::extractArchive(): validate ZIP entries before extractTo()
- RestoreEngine::extractTarGz(): validate PharData entries before extractTo()
- MokoRestore standalone script: same validation in generated PHP code
- Rejects entries containing ../ or starting with / or \

Closes #68, closes #72
2026-06-21 18:50:07 -05:00

91 lines
2.4 KiB
PHP

<?php
/**
* @package MokoSuiteBackup
* @subpackage com_mokosuitebackup
* @author Moko Consulting <hello@mokoconsulting.tech>
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
* @license GNU General Public License version 3 or later; see LICENSE
*/
namespace Joomla\Component\MokoSuiteBackup\Administrator\Model;
defined('_JEXEC') or die;
use Joomla\CMS\MVC\Model\ListModel;
use Joomla\Database\QueryInterface;
class BackupsModel extends ListModel
{
public function __construct($config = [])
{
if (empty($config['filter_fields'])) {
$config['filter_fields'] = [
'id', 'a.id',
'profile_id', 'a.profile_id',
'status', 'a.status',
'origin', 'a.origin',
'backup_type', 'a.backup_type',
'total_size', 'a.total_size',
'backupstart', 'a.backupstart',
'backupend', 'a.backupend',
];
}
parent::__construct($config);
}
protected function getListQuery(): QueryInterface
{
$db = $this->getDatabase();
$query = $db->getQuery(true);
$query->select('a.*')
->from($db->quoteName('#__mokosuitebackup_records', 'a'));
// Join profile title
$query->select($db->quoteName('p.title', 'profile_title'))
->join('LEFT', $db->quoteName('#__mokosuitebackup_profiles', 'p') . ' ON p.id = a.profile_id');
// Filter by status
$status = $this->getState('filter.status');
if (!empty($status)) {
$query->where($db->quoteName('a.status') . ' = ' . $db->quote($status));
}
// Filter by profile
$profileId = $this->getState('filter.profile_id');
if (is_numeric($profileId)) {
$query->where($db->quoteName('a.profile_id') . ' = ' . (int) $profileId);
}
// Filter by backup type
$backupType = $this->getState('filter.backup_type');
if (!empty($backupType)) {
$query->where($db->quoteName('a.backup_type') . ' = ' . $db->quote($backupType));
}
// Filter by search
$search = $this->getState('filter.search');
if (!empty($search)) {
$search = $db->quote('%' . $db->escape(trim($search), true) . '%');
$query->where('(' . $db->quoteName('a.description') . ' LIKE ' . $search . ')');
}
$orderCol = $this->state->get('list.ordering', 'a.backupstart');
$orderDir = $this->state->get('list.direction', 'DESC');
$query->order($db->escape($orderCol) . ' ' . $db->escape($orderDir));
return $query;
}
protected function populateState($ordering = 'a.backupstart', $direction = 'DESC'): void
{
parent::populateState($ordering, $direction);
}
}