diff --git a/CHANGELOG.md b/CHANGELOG.md index 65151ed..1d451d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,17 @@ All notable changes to **Tiger Core** (`webtigers/tiger-core`). Format follows ## [Unreleased] +## [1.32.0] — 2026-10-21 + +### Changed +- **TIGER-335 migration (batch 1 of the per-module sweep)** — replaced the deprecated resource-level + `_isAdmin()` guards with privilege-scoped `_isAllowed('')` in five admin-only modules: + **identity** (TIGER-356), **matomo** (TIGER-355), **schedule** (TIGER-351), **backup** (TIGER-349), + **ally** (TIGER-350). Behavior-preserving (each service is granted to `admin` at the resource, so the + wildcard grant covers every method privilege); the in-method guard stays as defense-in-depth for any + in-process caller, now expressed without a role comparer. The deprecated comparers are removed in a + later release once every module is migrated (TIGER-358). + ## [1.31.0] — 2026-10-21 ### Added diff --git a/library/Tiger/Version.php b/library/Tiger/Version.php index db8fcd9..0f826a7 100644 --- a/library/Tiger/Version.php +++ b/library/Tiger/Version.php @@ -9,5 +9,5 @@ class Tiger_Version { /** Current Tiger Core version. Keep in lockstep with the git tag cut for a release. */ - const VERSION = '1.31.0'; + const VERSION = '1.32.0'; } diff --git a/modules/ally/services/Scan.php b/modules/ally/services/Scan.php index 18f2df0..76e5f55 100644 --- a/modules/ally/services/Scan.php +++ b/modules/ally/services/Scan.php @@ -22,7 +22,7 @@ class Ally_Service_Scan extends Tiger_Service_Service */ public function scan(array $params): void { - if (!$this->_isAdmin()) { $this->_error('core.api.error.not_allowed'); return; } + if (!$this->_isAllowed('scan')) { $this->_error('core.api.error.not_allowed'); return; } $html = (string) ($params['html'] ?? ''); $pageId = trim((string) ($params['page_id'] ?? '')); @@ -63,7 +63,7 @@ public function scan(array $params): void */ public function scanModule(array $params): void { - if (!$this->_isAdmin()) { $this->_error('core.api.error.not_allowed'); return; } + if (!$this->_isAllowed('scanModule')) { $this->_error('core.api.error.not_allowed'); return; } $mod = preg_replace('/[^a-zA-Z0-9_-]/', '', (string) ($params['module'] ?? '')); if ($mod === '' || !defined('MODULES_PATH')) { $this->_error('ally.scan.module_not_found'); return; } @@ -106,7 +106,7 @@ public function scanModule(array $params): void */ public function pages(array $params): void { - if (!$this->_isAdmin()) { $this->_error('core.api.error.not_allowed'); return; } + if (!$this->_isAllowed('pages')) { $this->_error('core.api.error.not_allowed'); return; } $this->_success(['pages' => $this->_pageList()], 'core.api.success'); } @@ -118,7 +118,7 @@ public function pages(array $params): void */ public function scanAll(array $params): void { - if (!$this->_isAdmin()) { $this->_error('core.api.error.not_allowed'); return; } + if (!$this->_isAllowed('scanAll')) { $this->_error('core.api.error.not_allowed'); return; } $renderer = new Tiger_Cms_Renderer(); $results = []; diff --git a/modules/backup/services/Backup.php b/modules/backup/services/Backup.php index 13d1c9e..b5c0c85 100644 --- a/modules/backup/services/Backup.php +++ b/modules/backup/services/Backup.php @@ -21,7 +21,7 @@ class Backup_Service_Backup extends Tiger_Service_Service */ public function run(array $params): void { - if (!$this->_isAdmin()) { $this->_error('core.api.error.not_allowed'); return; } + if (!$this->_isAllowed('run')) { $this->_error('core.api.error.not_allowed'); return; } $components = $this->_components($params); if (!$components) { $this->_error('backup.bad_component', ['field' => 'components']); return; } @@ -53,7 +53,7 @@ public function run(array $params): void */ public function remove(array $params): void { - if (!$this->_isAdmin()) { $this->_error('core.api.error.not_allowed'); return; } + if (!$this->_isAllowed('remove')) { $this->_error('core.api.error.not_allowed'); return; } $id = (string) ($params['backup_id'] ?? ''); if ($id === '' || !(new Tiger_Model_Backup())->findById($id)) { $this->_error('backup.not_found'); return; } Tiger_Backup::delete($id); @@ -68,7 +68,7 @@ public function remove(array $params): void */ public function restore(array $params): void { - if (!$this->_isAdmin()) { $this->_error('core.api.error.not_allowed'); return; } + if (!$this->_isAllowed('restore')) { $this->_error('core.api.error.not_allowed'); return; } if ((string) ($params['confirm'] ?? '') !== 'RESTORE') { $this->_error('backup.restore.confirm', ['field' => 'confirm']); return; } $model = new Tiger_Model_Backup(); @@ -103,7 +103,7 @@ public function restore(array $params): void */ public function saveSettings(array $params): void { - if (!$this->_isAdmin()) { $this->_error('core.api.error.not_allowed'); return; } + if (!$this->_isAllowed('saveSettings')) { $this->_error('core.api.error.not_allowed'); return; } $components = $this->_components($params); $disk = $this->_disk($params['disk'] ?? 'local'); diff --git a/modules/identity/services/Identity.php b/modules/identity/services/Identity.php index 253afc2..ab57f2b 100644 --- a/modules/identity/services/Identity.php +++ b/modules/identity/services/Identity.php @@ -43,7 +43,7 @@ class Identity_Service_Identity extends Tiger_Service_Service */ public function save(array $params): void { - if (!$this->_isAdmin()) { + if (!$this->_isAllowed('save')) { $this->_error('core.api.error.not_allowed'); return; } diff --git a/modules/matomo/services/Matomo.php b/modules/matomo/services/Matomo.php index 9b71b67..2823990 100644 --- a/modules/matomo/services/Matomo.php +++ b/modules/matomo/services/Matomo.php @@ -20,7 +20,7 @@ class Matomo_Service_Matomo extends Tiger_Service_Service */ public function save(array $params): void { - if (!$this->_isAdmin()) { + if (!$this->_isAllowed('save')) { $this->_error('core.api.error.not_allowed'); return; } diff --git a/modules/schedule/services/Schedule.php b/modules/schedule/services/Schedule.php index 3bdfd5f..7870588 100644 --- a/modules/schedule/services/Schedule.php +++ b/modules/schedule/services/Schedule.php @@ -21,7 +21,7 @@ class Schedule_Service_Schedule extends Tiger_Service_Service */ public function jobs(array $params): void { - if (!$this->_isAdmin()) { $this->_error('core.api.error.not_allowed'); return; } + if (!$this->_isAllowed('jobs')) { $this->_error('core.api.error.not_allowed'); return; } $latest = (new Tiger_Model_ScheduleRun())->latestPerJob(); $now = time(); @@ -65,7 +65,7 @@ public function jobs(array $params): void */ public function setSchedule(array $params): void { - if (!$this->_isAdmin()) { $this->_error('core.api.error.not_allowed'); return; } + if (!$this->_isAllowed('setSchedule')) { $this->_error('core.api.error.not_allowed'); return; } $key = preg_replace('/[^a-zA-Z0-9._-]/', '', (string) ($params['key'] ?? '')); if ($key === '' || !Tiger_Schedule::get($key)) { $this->_error('schedule.unknown_job'); return; } @@ -96,7 +96,7 @@ public function setSchedule(array $params): void */ public function runNow(array $params): void { - if (!$this->_isAdmin()) { $this->_error('core.api.error.not_allowed'); return; } + if (!$this->_isAllowed('runNow')) { $this->_error('core.api.error.not_allowed'); return; } $key = preg_replace('/[^a-zA-Z0-9._-]/', '', (string) ($params['key'] ?? '')); if ($key === '' || !Tiger_Schedule::get($key)) { $this->_error('schedule.unknown_job'); return; } $r = Tiger_Schedule::runNow($key);