From 3094053537eb1371a39b13b6d1b9b0d32bfa0c8d Mon Sep 17 00:00:00 2001 From: Altamash Shaikh Date: Thu, 12 Feb 2026 18:16:16 +0530 Subject: [PATCH 1/8] Added validation rule for apiMethod parameter in getTreemapData API call, #AS-494 --- API.php | 6 ++++++ CHANGELOG.md | 3 +++ plugin.json | 5 +---- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/API.php b/API.php index 496141c..bacd35f 100644 --- a/API.php +++ b/API.php @@ -52,6 +52,12 @@ public function getTreemapData( if (!Request::isCurrentApiRequestTheRootApiRequest()) { return []; } + list($apiName, $apiAction) = explode('.', $apiMethod); + $disAllowedApiActions = ['getBulkRequest']; + // Block id API action does not start with get + if (!in_array($apiAction, $disAllowedApiActions)|| stripos($apiAction, 'get') !== 0) { + throw new \Exception('Invalid API method'); + } if ( $period == 'range' diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d4dda7..72af7eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ ## Changelog +# 5.0.5 - 2026-02-16 +- Added validation rules for ApiAction + # 5.0.4 - 2025-07-07 - Textual changes diff --git a/plugin.json b/plugin.json index 7cfe493..6b94cf1 100644 --- a/plugin.json +++ b/plugin.json @@ -1,10 +1,7 @@ { "name": "TreemapVisualization", "version": "5.0.4", - "description": "Visualise any report in Matomo as a Treemap. Click on the Treemap icon in each report to load the visualisation.", - "keywords": ["treemap", "graph", "visualization", "infovis", "jit"], - "license": "GPL v3+", - "homepage": "https://matomo.org", + "description": "Visualis5tps://matomo.org", "require": { "matomo": ">=5.0.0-b1,<6.0.0-b1" }, From 30b630e31d1a7bc17580abbf37b73e4447ae8469 Mon Sep 17 00:00:00 2001 From: Altamash Shaikh Date: Thu, 12 Feb 2026 18:20:53 +0530 Subject: [PATCH 2/8] Adds translation --- API.php | 3 ++- lang/en.json | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/API.php b/API.php index bacd35f..572c51d 100644 --- a/API.php +++ b/API.php @@ -15,6 +15,7 @@ use Piwik\DataTable; use Piwik\Metrics; use Piwik\Period\Range; +use Piwik\Piwik; use Piwik\Plugins\TreemapVisualization\Visualizations\Treemap; /** @@ -56,7 +57,7 @@ public function getTreemapData( $disAllowedApiActions = ['getBulkRequest']; // Block id API action does not start with get if (!in_array($apiAction, $disAllowedApiActions)|| stripos($apiAction, 'get') !== 0) { - throw new \Exception('Invalid API method'); + throw new \Exception(Piwik::translate('TreemapVisualization_InvalidApiMethodException')); } if ( diff --git a/lang/en.json b/lang/en.json index 631a455..e4bd7ee 100644 --- a/lang/en.json +++ b/lang/en.json @@ -1,6 +1,7 @@ { "TreemapVisualization": { "PluginDescription": "Visualise any report in Matomo as a Treemap. Click on the Treemap icon in each report to load the visualisation.", - "Treemap": "Treemap" + "Treemap": "Treemap", + "InvalidApiMethodException": "Invalid API method." } } \ No newline at end of file From 53f4234331f3ffd09cbda18bbd58d47c34ac95ed Mon Sep 17 00:00:00 2001 From: Altamash Shaikh Date: Thu, 12 Feb 2026 18:24:03 +0530 Subject: [PATCH 3/8] Fixes PHPCS --- API.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/API.php b/API.php index 572c51d..43baab5 100644 --- a/API.php +++ b/API.php @@ -56,7 +56,7 @@ public function getTreemapData( list($apiName, $apiAction) = explode('.', $apiMethod); $disAllowedApiActions = ['getBulkRequest']; // Block id API action does not start with get - if (!in_array($apiAction, $disAllowedApiActions)|| stripos($apiAction, 'get') !== 0) { + if (!in_array($apiAction, $disAllowedApiActions) || stripos($apiAction, 'get') !== 0) { throw new \Exception(Piwik::translate('TreemapVisualization_InvalidApiMethodException')); } From 9c42f220eaf2b91e15860d2ed0cdcd9deb1cb57b Mon Sep 17 00:00:00 2001 From: Altamash Shaikh Date: Thu, 12 Feb 2026 21:39:13 +0530 Subject: [PATCH 4/8] Fixes plugin.json --- API.php | 2 +- plugin.json | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/API.php b/API.php index 43baab5..4458329 100644 --- a/API.php +++ b/API.php @@ -55,7 +55,7 @@ public function getTreemapData( } list($apiName, $apiAction) = explode('.', $apiMethod); $disAllowedApiActions = ['getBulkRequest']; - // Block id API action does not start with get + // Block if API action does not start with get if (!in_array($apiAction, $disAllowedApiActions) || stripos($apiAction, 'get') !== 0) { throw new \Exception(Piwik::translate('TreemapVisualization_InvalidApiMethodException')); } diff --git a/plugin.json b/plugin.json index 6b94cf1..7cfe493 100644 --- a/plugin.json +++ b/plugin.json @@ -1,7 +1,10 @@ { "name": "TreemapVisualization", "version": "5.0.4", - "description": "Visualis5tps://matomo.org", + "description": "Visualise any report in Matomo as a Treemap. Click on the Treemap icon in each report to load the visualisation.", + "keywords": ["treemap", "graph", "visualization", "infovis", "jit"], + "license": "GPL v3+", + "homepage": "https://matomo.org", "require": { "matomo": ">=5.0.0-b1,<6.0.0-b1" }, From d9d42925c0ab9db96d26d348be74f96d952f2228 Mon Sep 17 00:00:00 2001 From: Altamash Shaikh Date: Thu, 12 Feb 2026 21:39:55 +0530 Subject: [PATCH 5/8] Version update --- plugin.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin.json b/plugin.json index 7cfe493..ed87f26 100644 --- a/plugin.json +++ b/plugin.json @@ -1,6 +1,6 @@ { "name": "TreemapVisualization", - "version": "5.0.4", + "version": "5.0.5", "description": "Visualise any report in Matomo as a Treemap. Click on the Treemap icon in each report to load the visualisation.", "keywords": ["treemap", "graph", "visualization", "infovis", "jit"], "license": "GPL v3+", From c0a07476b110b82c964d2beffa451d164268f2c0 Mon Sep 17 00:00:00 2001 From: Altamash Shaikh Date: Fri, 13 Feb 2026 07:33:18 +0530 Subject: [PATCH 6/8] Applied PR feedback --- API.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/API.php b/API.php index 4458329..02dd3df 100644 --- a/API.php +++ b/API.php @@ -13,6 +13,7 @@ use Piwik\API\Request; use Piwik\Common; use Piwik\DataTable; +use Piwik\Http\BadRequestException; use Piwik\Metrics; use Piwik\Period\Range; use Piwik\Piwik; @@ -53,11 +54,11 @@ public function getTreemapData( if (!Request::isCurrentApiRequestTheRootApiRequest()) { return []; } - list($apiName, $apiAction) = explode('.', $apiMethod); + list($module, $method) = explode('.', $apiMethod); $disAllowedApiActions = ['getBulkRequest']; // Block if API action does not start with get - if (!in_array($apiAction, $disAllowedApiActions) || stripos($apiAction, 'get') !== 0) { - throw new \Exception(Piwik::translate('TreemapVisualization_InvalidApiMethodException')); + if (in_array($method, $disAllowedApiActions) || stripos($method, 'get') !== 0) { + throw new BadRequestException(Piwik::translate('TreemapVisualization_InvalidApiMethodException')); } if ( From 19b180b3a8d687a9f91d0df3e2fda3d9636a9bdc Mon Sep 17 00:00:00 2001 From: Altamash Shaikh Date: Fri, 13 Feb 2026 07:54:12 +0530 Subject: [PATCH 7/8] Take care of null values for in_array and stripos --- API.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/API.php b/API.php index 02dd3df..a06fe74 100644 --- a/API.php +++ b/API.php @@ -57,7 +57,7 @@ public function getTreemapData( list($module, $method) = explode('.', $apiMethod); $disAllowedApiActions = ['getBulkRequest']; // Block if API action does not start with get - if (in_array($method, $disAllowedApiActions) || stripos($method, 'get') !== 0) { + if (!$method || in_array(strtolower($method), $disAllowedApiActions) || stripos($method, 'get') !== 0) { throw new BadRequestException(Piwik::translate('TreemapVisualization_InvalidApiMethodException')); } From 716d32534ec1a1bdda73c40680b1b16cb64fafc7 Mon Sep 17 00:00:00 2001 From: Altamash Shaikh Date: Fri, 13 Feb 2026 08:37:14 +0530 Subject: [PATCH 8/8] Adds test --- API.php | 4 +- tests/Integration/ApiTest.php | 78 +++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 tests/Integration/ApiTest.php diff --git a/API.php b/API.php index a06fe74..24da02f 100644 --- a/API.php +++ b/API.php @@ -51,13 +51,13 @@ public function getTreemapData( $availableHeight = false, $show_evolution_values = false ) { - if (!Request::isCurrentApiRequestTheRootApiRequest()) { + if (!Request::isCurrentApiRequestTheRootApiRequest() && !defined('PIWIK_TEST_MODE')) { return []; } list($module, $method) = explode('.', $apiMethod); $disAllowedApiActions = ['getBulkRequest']; // Block if API action does not start with get - if (!$method || in_array(strtolower($method), $disAllowedApiActions) || stripos($method, 'get') !== 0) { + if (!$method || in_array($method, $disAllowedApiActions) || stripos($method, 'get') !== 0) { throw new BadRequestException(Piwik::translate('TreemapVisualization_InvalidApiMethodException')); } diff --git a/tests/Integration/ApiTest.php b/tests/Integration/ApiTest.php new file mode 100644 index 0000000..0641c09 --- /dev/null +++ b/tests/Integration/ApiTest.php @@ -0,0 +1,78 @@ +api = API::getInstance(); + } + + /** + * @dataProvider validMethod + */ + public function testGetTreemapDataAllowsValidApiMethod($method): void + { + $result = $this->api->getTreemapData( + $method, + 'nb_visits', + 'day', + '2025-02-03' + ); + + $this->assertIsArray($result); + } + + /** + * @dataProvider inValidMethod + */ + public function testGetTreemapDataRejectsInvalidApiMethod($method): void + { + $this->expectException(BadRequestException::class); + $this->api->getTreemapData( + $method, + 'nb_visits', + 'day', + '2025-02-03' + ); + } + + public function validMethod() + { + return [ + ['API.getMatomoVersion'], + ['API.getPhpVersion'], + ]; + } + + public function inValidMethod() + { + return [ + ['API.getBulkRequest'], + ['UsersManager.deleteUser'], + ]; + } +}