diff --git a/CHANGELOG.md b/CHANGELOG.md index fdd55d1..b24058b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Release Notes for Activity Log +## 1.2.0 - 2023-03-17 +### Added +- Add advanced payload filtering + ## 1.1.5 - 2023-03-17 ### Fixed - IP Query: Search for string contains rather than exact match diff --git a/README.md b/README.md index 319f754..7e7ec20 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,27 @@ Click the "+" sign on the left-hand side of each row to expand a child row conta ![craft4 test_adminos_activity-log_site=default (4)](https://user-images.githubusercontent.com/1510460/175233957-eeb453c1-8b18-448e-af7a-c476f3ac9cb5.png) +### Payload Filtering + +The plugin automatically replaces the CSRF Token and any payload key which contains the word "password" with a "[filtered]" mask. +You can add additional keys to be filtered in two ways: +a.General: Add it to the `filterPayloadKeys` on the setting file: +```php + 'filterPayloadKeys'=>[ + 'cvv','long_number' + ] +``` +b. Specific: If you only want to filter a certain key from specific requests you can use the `filterPayloadCallbacks` array instead, e.g: +```php + 'filterPayloadCallbacks'=> [ + function(\craft\web\Request $request) { + if (str_contains($request->getUrl(),'add-credit-card')) { + return 'cvv'; + } + + return false; + } +``` ### Pruning Data You can prune (delete) data before that last X days using the following console command: diff --git a/src/models/Settings.php b/src/models/Settings.php index aa8039a..da3b0e2 100644 --- a/src/models/Settings.php +++ b/src/models/Settings.php @@ -13,6 +13,9 @@ class Settings extends Model public bool $recordOnlyActions = false; public ?\Closure $requestFilter = null; + public array $filterPayloadKeys = []; + public array $filterPayloadCallbacks = []; + public function rules() : array { return [ diff --git a/src/services/RecordRequest.php b/src/services/RecordRequest.php index 9c475e5..92f5078 100644 --- a/src/services/RecordRequest.php +++ b/src/services/RecordRequest.php @@ -8,6 +8,7 @@ use Craft; use craft\web\Request; use craft\web\Response; +use matfish\ActivityLog\Plugin; use yii\base\Event; use matfish\ActivityLog\records\ActivityLog as ActivityLogRecord; use matfish\ActivityLog\models\ActivityLog as ActivityLogModel; @@ -107,23 +108,36 @@ protected function getPayload(): string|null|false $payload = $this->request->getBodyParams(); if ($payload) { - if (isset($payload['CRAFT_CSRF_TOKEN'])) { - $payload['CRAFT_CSRF_TOKEN'] = '[filtered]'; - } - - $passwordKeys = []; + $filterableKeys = $this->getFilterableKeys($payload); foreach (array_keys($payload) as $key) { - if (str_contains($key, 'password')) { - $passwordKeys[] = $key; + if (in_array($key, $filterableKeys, true)) { + $payload[$key] = '[filtered]'; } } + } - foreach ($passwordKeys as $key) { - $payload[$key] = '[filtered]'; + return $payload ? json_encode($payload, JSON_THROW_ON_ERROR) : null; + } + + private function getFilterableKeys($payload): array + { + $settings = Plugin::getInstance()->getSettings(); + $keys = array_merge(['CRAFT_CSRF_TOKEN'], $settings->filterPayloadKeys); + + foreach ($settings->filterPayloadCallbacks as $callback) { + if ($key = $callback($this->request)) { + $keys[] = $key; } } - return $payload ? json_encode($payload, JSON_THROW_ON_ERROR) : null; + foreach (array_keys($payload) as $key) { + if (str_contains($key, 'password')) { + $keys[] = $key; + } + } + + return $keys; + } } \ No newline at end of file