[FEATURE] Add scheduler task to anonymize IP addresses of tables 23/56923/9
authorGeorg Ringer <georg.ringer@gmail.com>
Thu, 19 Apr 2018 11:36:03 +0000 (13:36 +0200)
committerMathias Brodala <mbrodala@pagemachine.de>
Mon, 14 May 2018 09:09:26 +0000 (11:09 +0200)
IP anonymizing improves the privacy of users and required as part of
the GDPR.

Resolves: #84781
Releases: master, 8.7, 7.6
Change-Id: Idd938136bed8f29e86b5e3e541c9fb8c9afd48ff
Reviewed-on: https://review.typo3.org/56923
Reviewed-by: Markus Klein <markus.klein@typo3.org>
Tested-by: Markus Klein <markus.klein@typo3.org>
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Mathias Brodala <mbrodala@pagemachine.de>
Tested-by: Mathias Brodala <mbrodala@pagemachine.de>
typo3/sysext/core/Documentation/Changelog/7.6.x/Feature-84781-AddedSchedulerTaskToAnonymizeIPAddressesOfTables.rst [new file with mode: 0644]
typo3/sysext/core/Documentation/Changelog/8.7.x/Feature-84781-AddedSchedulerTaskToAnonymizeIPAddressesOfTables.rst [new file with mode: 0644]
typo3/sysext/indexed_search/ext_localconf.php
typo3/sysext/scheduler/Classes/Task/IpAnonymizationAdditionalFieldProvider.php [new file with mode: 0644]
typo3/sysext/scheduler/Classes/Task/IpAnonymizationTask.php [new file with mode: 0644]
typo3/sysext/scheduler/Resources/Private/Language/locallang.xlf
typo3/sysext/scheduler/ext_localconf.php

diff --git a/typo3/sysext/core/Documentation/Changelog/7.6.x/Feature-84781-AddedSchedulerTaskToAnonymizeIPAddressesOfTables.rst b/typo3/sysext/core/Documentation/Changelog/7.6.x/Feature-84781-AddedSchedulerTaskToAnonymizeIPAddressesOfTables.rst
new file mode 100644 (file)
index 0000000..e77b6a9
--- /dev/null
@@ -0,0 +1,38 @@
+.. include:: ../../Includes.txt
+
+==========================================================================
+Feature: #84781 - Added scheduler task to anonymize IP addresses of tables
+==========================================================================
+
+See :issue:`84781`
+
+Description
+===========
+
+A new scheduler task has been added which makes it possible to anonymize IP addresses stored in database tables.
+
+The task *Anonymize IP addresses in database tables* is configured in the :file:`ext_localconf.php`.
+
+.. code-block:: php
+
+    $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][\TYPO3\CMS\Scheduler\Task\IpAnonymizationTask::class]['options']['tables']['<tableName>'] = [
+        'dateField' => '<dateFieldName>',
+        'ipField' => '<ipFieldName>'
+    ];
+
+After the base configuration the table is available in the scheduler task with the following configuration options:
+
+- Table
+- Minimum age an entry must have to be anonymized
+- IP mask level
+
+
+Impact
+======
+
+The following tables are available by default:
+
+- index_stat_search
+- sys_log
+
+.. index:: CLI, ext:scheduler
\ No newline at end of file
diff --git a/typo3/sysext/core/Documentation/Changelog/8.7.x/Feature-84781-AddedSchedulerTaskToAnonymizeIPAddressesOfTables.rst b/typo3/sysext/core/Documentation/Changelog/8.7.x/Feature-84781-AddedSchedulerTaskToAnonymizeIPAddressesOfTables.rst
new file mode 100644 (file)
index 0000000..e77b6a9
--- /dev/null
@@ -0,0 +1,38 @@
+.. include:: ../../Includes.txt
+
+==========================================================================
+Feature: #84781 - Added scheduler task to anonymize IP addresses of tables
+==========================================================================
+
+See :issue:`84781`
+
+Description
+===========
+
+A new scheduler task has been added which makes it possible to anonymize IP addresses stored in database tables.
+
+The task *Anonymize IP addresses in database tables* is configured in the :file:`ext_localconf.php`.
+
+.. code-block:: php
+
+    $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][\TYPO3\CMS\Scheduler\Task\IpAnonymizationTask::class]['options']['tables']['<tableName>'] = [
+        'dateField' => '<dateFieldName>',
+        'ipField' => '<ipFieldName>'
+    ];
+
+After the base configuration the table is available in the scheduler task with the following configuration options:
+
+- Table
+- Minimum age an entry must have to be anonymized
+- IP mask level
+
+
+Impact
+======
+
+The following tables are available by default:
+
+- index_stat_search
+- sys_log
+
+.. index:: CLI, ext:scheduler
\ No newline at end of file
index bb86e92..9111b87 100644 (file)
@@ -101,3 +101,10 @@ if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][\TYPO3
         'expirePeriod' => 90
     ];
 }
+
+if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][\TYPO3\CMS\Scheduler\Task\IpAnonymizationTask::class]['options']['tables'])) {
+    $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][\TYPO3\CMS\Scheduler\Task\IpAnonymizationTask::class]['options']['tables']['index_stat_search'] = [
+        'dateField' => 'tstamp',
+        'ipField' => 'IP'
+    ];
+}
diff --git a/typo3/sysext/scheduler/Classes/Task/IpAnonymizationAdditionalFieldProvider.php b/typo3/sysext/scheduler/Classes/Task/IpAnonymizationAdditionalFieldProvider.php
new file mode 100644 (file)
index 0000000..c11a74c
--- /dev/null
@@ -0,0 +1,248 @@
+<?php
+
+namespace TYPO3\CMS\Scheduler\Task;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Lang\LanguageService;
+use TYPO3\CMS\Scheduler\AdditionalFieldProviderInterface;
+
+/**
+ * Additional BE fields for ip address anonymization task.
+ */
+class IpAnonymizationAdditionalFieldProvider implements AdditionalFieldProviderInterface
+{
+    /**
+     * @var array Default number of days by table
+     */
+    protected $defaultNumberOfDays = [];
+
+    /**
+     * Add additional fields
+     *
+     * @param array $taskInfo Reference to the array containing the info used in the add/edit form
+     * @param AbstractTask|null $task When editing, reference to the current task. NULL when adding.
+     * @param \TYPO3\CMS\Scheduler\Controller\SchedulerModuleController $parentObject Reference to the calling object (Scheduler's BE module)
+     * @return array Array containing all the information pertaining to the additional fields
+     */
+    public function getAdditionalFields(array &$taskInfo, $task, \TYPO3\CMS\Scheduler\Controller\SchedulerModuleController $parentObject)
+    {
+        $additionalFields = [];
+        $additionalFields['task_ipAnonymization_table'] = $this->getTableAdditionalField($taskInfo, $task, $parentObject);
+        $additionalFields['task_ipAnonymization_numberOfDays'] = $this->getNumberOfDaysAdditionalField($taskInfo, $task, $parentObject);
+        $additionalFields['task_ipAnonymization_mask'] = $this->getMaskAdditionalField($taskInfo, $task, $parentObject);
+        return $additionalFields;
+    }
+
+    /**
+     * Add a select field of available tables.
+     *
+     * @param array $taskInfo Reference to the array containing the info used in the add/edit form
+     * @param AbstractTask|IpAnonymizationTask|null $task When editing, reference to the current task. NULL when adding.
+     * @param \TYPO3\CMS\Scheduler\Controller\SchedulerModuleController $parentObject Reference to the calling object (Scheduler's BE module)
+     * @return array Array containing all the information pertaining to the additional fields
+     */
+    protected function getTableAdditionalField(array &$taskInfo, $task, \TYPO3\CMS\Scheduler\Controller\SchedulerModuleController $parentObject)
+    {
+        $tableConfiguration = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][IpAnonymizationTask::class]['options']['tables'];
+        $options = [];
+        // Add an empty option on top if an existing task is configured
+        // with a table that can not be found in configuration anymore
+        if ($parentObject->CMD === 'edit' && !array_key_exists($task->table, $tableConfiguration)) {
+            $options[] = '<option value="" selected="selected"></option>';
+        }
+        foreach ($tableConfiguration as $tableName => $configuration) {
+            if ($parentObject->CMD === 'add' && empty($options)) {
+                // Select first table by default if adding a new task
+                $options[] = '<option value="' . $tableName . '" selected="selected">' . $tableName . '</option>';
+            } elseif ($task->table === $tableName) {
+                // Select currently selected table
+                $options[] = '<option value="' . $tableName . '" selected="selected">' . $tableName . '</option>';
+            } else {
+                $options[] = '<option value="' . $tableName . '">' . $tableName . '</option>';
+            }
+        }
+        $fieldName = 'tx_scheduler[scheduler_ipAnonymization_table]';
+        $fieldId = 'task_ipAnonymization_table';
+        $fieldHtml = [];
+        // Add table drop down html
+        $fieldHtml[] = '<select class="form-control" name="' . $fieldName . '" id="' . $fieldId . '">' . implode(LF, $options) . '</select>';
+        // Add js array for default 'number of days' values
+        $fieldHtml[] = '<script type="text/javascript">/*<![CDATA[*/<!--';
+        $fieldHtml[] = 'var defaultNumberOfDays = ' . json_encode($this->defaultNumberOfDays) . ';';
+        $fieldHtml[] = '// -->/*]]>*/</script>';
+        $fieldConfiguration = [
+            'code' => implode(LF, $fieldHtml),
+            'label' => 'LLL:EXT:scheduler/Resources/Private/Language/locallang.xlf:label.ipAnonymization.table',
+            'cshKey' => '_MOD_system_txschedulerM1',
+            'cshLabel' => $fieldId
+        ];
+        return $fieldConfiguration;
+    }
+
+    /**
+     * Add an input field to get the number of days.
+     *
+     * @param array $taskInfo Reference to the array containing the info used in the add/edit form
+     * @param AbstractTask|IpAnonymizationTask|null $task When editing, reference to the current task. NULL when adding.
+     * @param \TYPO3\CMS\Scheduler\Controller\SchedulerModuleController $parentObject Reference to the calling object (Scheduler's BE module)
+     * @return array Array containing all the information pertaining to the additional fields
+     */
+    protected function getNumberOfDaysAdditionalField(array &$taskInfo, $task, \TYPO3\CMS\Scheduler\Controller\SchedulerModuleController $parentObject)
+    {
+        $fieldId = 'scheduler_ipAnonymization_numberOfDays';
+        // Initialize selected fields
+        $disabled = '';
+        if (empty($taskInfo[$fieldId])) {
+            if ($parentObject->CMD === 'add') {
+                // In case of new task, set to 180 days
+                $taskInfo[$fieldId] = 180;
+            } elseif ($parentObject->CMD === 'edit') {
+                // In case of editing the task, set to currently selected value
+                $taskInfo[$fieldId] = $task->numberOfDays;
+                if ($task->numberOfDays === 0 && !isset($this->defaultNumberOfDays[$task->table])) {
+                    $disabled = ' disabled="disabled"';
+                }
+            }
+        }
+        $fieldName = 'tx_scheduler[' . $fieldId . ']';
+        $fieldHtml = '<input class="form-control" type="text" ' . 'name="' . $fieldName . '" ' . 'id="' . $fieldId . '" ' . $disabled . 'value="' . (int)$taskInfo['scheduler_ipAnonymization_numberOfDays'] . '" ' . 'size="4">';
+        $fieldConfiguration = [
+            'code' => $fieldHtml,
+            'label' => 'LLL:EXT:scheduler/Resources/Private/Language/locallang.xlf:label.ipAnonymization.numberOfDays',
+            'cshKey' => '_MOD_system_txschedulerM1',
+            'cshLabel' => $fieldId
+        ];
+        return $fieldConfiguration;
+    }
+
+    /**
+     * Add an input field to get the mask.
+     *
+     * @param array $taskInfo Reference to the array containing the info used in the add/edit form
+     * @param AbstractTask|IpAnonymizationTask|null $task When editing, reference to the current task. NULL when adding.
+     * @param \TYPO3\CMS\Scheduler\Controller\SchedulerModuleController $parentObject Reference to the calling object (Scheduler's BE module)
+     * @return array Array containing all the information pertaining to the additional fields
+     */
+    protected function getMaskAdditionalField(array &$taskInfo, $task, \TYPO3\CMS\Scheduler\Controller\SchedulerModuleController $parentObject)
+    {
+        $fieldId = 'scheduler_ipAnonymization_mask';
+        // Initialize selected fields
+        if (empty($taskInfo[$fieldId])) {
+            if ($parentObject->CMD === 'add') {
+                // In case of new task, set to 180 days
+                $taskInfo[$fieldId] = 2;
+            } elseif ($parentObject->CMD === 'edit') {
+                // In case of editing the task, set to currently selected value
+                $taskInfo[$fieldId] = $task->mask;
+            }
+        }
+        $fieldName = 'tx_scheduler[' . $fieldId . ']';
+
+        $fieldHtml = '';
+        foreach ([1, 2] as $mask) {
+            $selected = (int)$taskInfo[$fieldId] === $mask ? ' selected' : '';
+            $fieldHtml .= '<option value="' . $mask . '"' . $selected . '>'
+                . htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:scheduler/Resources/Private/Language/locallang.xlf:label.ipAnonymization.mask.' . $mask))
+                . '</option>';
+        }
+
+        $fieldHtml = '<select class="form-control" name="' . $fieldName . '" ' . 'id="' . $fieldId . '">' . $fieldHtml . '</select>';
+
+        $fieldConfiguration = [
+            'code' => $fieldHtml,
+            'label' => 'LLL:EXT:scheduler/Resources/Private/Language/locallang.xlf:label.ipAnonymization.mask',
+            'cshKey' => '_MOD_system_txschedulerM1',
+            'cshLabel' => $fieldId
+        ];
+        return $fieldConfiguration;
+    }
+
+    /**
+     * Validate additional fields
+     *
+     * @param array $submittedData Reference to the array containing the data submitted by the user
+     * @param \TYPO3\CMS\Scheduler\Controller\SchedulerModuleController $parentObject Reference to the calling object (Scheduler's BE module)
+     * @return bool True if validation was ok (or selected class is not relevant), false otherwise
+     */
+    public function validateAdditionalFields(array &$submittedData, \TYPO3\CMS\Scheduler\Controller\SchedulerModuleController $parentObject)
+    {
+        $validData = $this->validateTableAdditionalField($submittedData, $parentObject);
+        $validData &= $this->validateNumberOfDaysAdditionalField($submittedData, $parentObject);
+        return $validData;
+    }
+
+    /**
+     * Checks given table for existence in configuration array
+     *
+     * @param array $submittedData Reference to the array containing the data submitted by the user
+     * @param \TYPO3\CMS\Scheduler\Controller\SchedulerModuleController $parentObject Reference to the calling object (Scheduler's BE module)
+     * @return bool True if table exists in configuration, false otherwise
+     */
+    public function validateTableAdditionalField(array &$submittedData, \TYPO3\CMS\Scheduler\Controller\SchedulerModuleController $parentObject)
+    {
+        $validData = false;
+        $tableConfiguration = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][IpAnonymizationTask::class]['options']['tables'];
+        if (!isset($submittedData['scheduler_ipAnonymization_table'])) {
+            $validData = true;
+        } elseif (array_key_exists($submittedData['scheduler_ipAnonymization_table'], $tableConfiguration)) {
+            $validData = true;
+        }
+        return $validData;
+    }
+
+    /**
+     * Checks if given number of days is a positive integer
+     *
+     * @param array $submittedData Reference to the array containing the data submitted by the user
+     * @param \TYPO3\CMS\Scheduler\Controller\SchedulerModuleController $parentObject Reference to the calling object (Scheduler's BE module)
+     * @return bool True if validation was ok (or selected class is not relevant), false otherwise
+     */
+    public function validateNumberOfDaysAdditionalField(array &$submittedData, \TYPO3\CMS\Scheduler\Controller\SchedulerModuleController $parentObject)
+    {
+        $validData = false;
+        if (!isset($submittedData['scheduler_ipAnonymization_numberOfDays'])) {
+            $validData = true;
+        } elseif ((int)$submittedData['scheduler_ipAnonymization_numberOfDays'] >= 0) {
+            $validData = true;
+        } else {
+            // Issue error message
+            $parentObject->addMessage($this->getLanguageService()->sL('LLL:EXT:scheduler/Resources/Private/Language/locallang.xlf:msg.invalidNumberOfDays'), \TYPO3\CMS\Core\Messaging\FlashMessage::ERROR);
+        }
+        return $validData;
+    }
+
+    /**
+     * Save additional field in task
+     *
+     * @param array $submittedData Contains data submitted by the user
+     * @param \TYPO3\CMS\Scheduler\Task\AbstractTask $task Reference to the current task object
+     */
+    public function saveAdditionalFields(array $submittedData, \TYPO3\CMS\Scheduler\Task\AbstractTask $task)
+    {
+        $task->table = $submittedData['scheduler_ipAnonymization_table'];
+        $task->mask = $submittedData['scheduler_ipAnonymization_mask'];
+        $task->numberOfDays = (int)$submittedData['scheduler_ipAnonymization_numberOfDays'];
+    }
+
+    /**
+     * Returns an instance of LanguageService
+     *
+     * @return LanguageService
+     */
+    protected function getLanguageService(): LanguageService
+    {
+        return $GLOBALS['LANG'];
+    }
+}
diff --git a/typo3/sysext/scheduler/Classes/Task/IpAnonymizationTask.php b/typo3/sysext/scheduler/Classes/Task/IpAnonymizationTask.php
new file mode 100644 (file)
index 0000000..3ad530d
--- /dev/null
@@ -0,0 +1,142 @@
+<?php
+
+namespace TYPO3\CMS\Scheduler\Task;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Database\ConnectionPool;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Core\Utility\IpAnonymizationUtility;
+
+/**
+ * Anonymize IP addresses in records
+ *
+ * This task anonymizes IP addresses in tables older than the given number of days.
+ *
+ * Available tables must be registered in
+ * $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][\TYPO3\CMS\Scheduler\Task\IpAnonymizationTask::class]['options']['tables']
+ * See ext_localconf.php of scheduler extension for an example
+ */
+class IpAnonymizationTask extends AbstractTask
+{
+
+    /**
+     * @var int Number of days
+     */
+    public $numberOfDays = 180;
+
+    /**
+     * @var int mask level see \TYPO3\CMS\Core\Utility\IpAnonymizationUtility::anonymizeIp
+     */
+    public $mask = 2;
+
+    /**
+     * @var string Table to clean up
+     */
+    public $table = '';
+
+    /**
+     * Execute garbage collection, called by scheduler.
+     *
+     * @throws \RuntimeException If configured table was not cleaned up
+     * @return bool TRUE if task run was successful
+     */
+    public function execute()
+    {
+        $configuration = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][self::class]['options']['tables'][$this->table] ?? [];
+        if (empty($configuration)) {
+            throw new \RuntimeException(self::class . ' misconfiguration: ' . $this->table . ' does not exist in configuration', 1524502548);
+        }
+        $this->handleTable($this->table, $configuration);
+        return true;
+    }
+
+    /**
+     * Execute clean up of a specific table
+     *
+     * @throws \RuntimeException If table configuration is broken
+     * @param string $table The table to handle
+     * @param array $configuration Clean up configuration
+     * @return bool TRUE if cleanup was successful
+     */
+    protected function handleTable($table, array $configuration)
+    {
+        $connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable($table);
+        $queryBuilder = $connection->createQueryBuilder();
+        $queryBuilder->getRestrictions()->removeAll();
+
+        if (empty($configuration['dateField'])) {
+            throw new \RuntimeException(self::class . ' misconfiguration: "dateField" must be defined for table ' . $table, 1524502549);
+        }
+        if (empty($configuration['ipField'])) {
+            throw new \RuntimeException(self::class . ' misconfiguration: "ipField" must be defined for table ' . $table, 1524502666);
+        }
+        $deleteTimestamp = strtotime('-' . $this->numberOfDays . 'days');
+        if ($deleteTimestamp === false) {
+            throw new \RuntimeException(self::class . ' misconfiguration: number of days could not be calculated for table ' . $table, 1524526354);
+        }
+        try {
+            $result = $queryBuilder
+                ->select('uid', $configuration['ipField'])
+                ->where(
+                    $queryBuilder->expr()->lt(
+                        $configuration['dateField'],
+                        $queryBuilder->createNamedParameter($deleteTimestamp, \PDO::PARAM_INT)
+                    ),
+                    $queryBuilder->expr()->neq(
+                        $configuration['ipField'],
+                        $queryBuilder->createNamedParameter('', \PDO::PARAM_STR)
+                    ),
+                    $queryBuilder->expr()->isNotNull($configuration['ipField']),
+                    $queryBuilder->expr()->notLike(
+                        $configuration['ipField'],
+                        $queryBuilder->createNamedParameter('%.0.0', \PDO::PARAM_STR)
+                    ),
+                    $queryBuilder->expr()->notLike(
+                        $configuration['ipField'],
+                        $queryBuilder->createNamedParameter('%::', \PDO::PARAM_STR)
+                    )
+                )
+                ->from($table)
+                ->execute();
+
+            while ($row = $result->fetch()) {
+                $ip = (string)$row[$configuration['ipField']];
+
+                $connection->update(
+                    $table,
+                    [
+                        $configuration['ipField'] => IpAnonymizationUtility::anonymizeIp($ip, $this->mask)
+                    ],
+                    [
+                        'uid' => $row['uid']
+                    ]
+                );
+            }
+        } catch (\Exception $e) {
+            throw new \RuntimeException(self::class . ' failed for table ' . $this->table . ' with error: ' . $e->getMessage(), 1524502550);
+        }
+        return true;
+    }
+
+    /**
+     * This method returns the selected table as additional information
+     *
+     * @return string Information to display
+     */
+    public function getAdditionalInformation()
+    {
+        return sprintf($GLOBALS['LANG']->sL('LLL:EXT:scheduler/Resources/Private/Language/locallang.xlf:label.ipAnonymization.additionalInformationTable'), $this->table, $this->numberOfDays);
+    }
+}
index 73c278f..e32a6e8 100644 (file)
                        <trans-unit id="optimizeDatabaseTable.description">
                                <source>This task executes "OPTIMIZE TABLE" statements on the selected database tables. This helps to reduce storage space and improve I/O efficiency. Warning! Tables will be locked during the optimization process.</source>
                        </trans-unit>
+                       <trans-unit id="ipAnonymization.name">
+                               <source>Anonymize IP addresses in database tables</source>
+                       </trans-unit>
+                       <trans-unit id="ipAnonymization.description">
+                               <source>This task anonymizes the IP addresses to enforce the privacy of the persisted data.</source>
+                       </trans-unit>
+                       <trans-unit id="label.ipAnonymization.table">
+                               <source>Table to anoymize</source>
+                       </trans-unit>
+                       <trans-unit id="label.ipAnonymization.additionalInformationTable">
+                               <source>Table: %s after %s days</source>
+                       </trans-unit>
+                       <trans-unit id="label.ipAnonymization.additionalInformationAllTables">
+                               <source>All tables</source>
+                       </trans-unit>
+                       <trans-unit id="label.ipAnonymization.numberOfDays">
+                               <source>Handle entries older than given number of days</source>
+                       </trans-unit>
+                       <trans-unit id="label.ipAnonymization.mask">
+                               <source>Mask level</source>
+                       </trans-unit>
+                       <trans-unit id="label.ipAnonymization.mask.1">
+                               <source>Last byte for IPv4 / Interface ID for IPv6</source>
+                       </trans-unit>
+                       <trans-unit id="label.ipAnonymization.mask.2">
+                               <source>Last 2 bytes for IPv4 / Interface &amp; SLA ID for IPv6</source>
+                       </trans-unit>
                </body>
        </file>
 </xliff>
index 6f74803..7aa8a7f 100644 (file)
@@ -100,6 +100,28 @@ if (!is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][\T
     ];
 }
 
+// Save any previous option array for ip anonymization task
+// to temporary variable so it can be pre-populated by other
+// extensions and LocalConfiguration/AdditionalConfiguration
+$ipAnonymizeCollectionTaskOptions = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][\TYPO3\CMS\Scheduler\Task\IpAnonymizationTask::class]['options'] ?? [];
+$ipAnonymizeCollectionTaskOptions['tables'] = $ipAnonymizeCollectionTaskOptions['tables'] ?? [];
+// Add ip anonymization task
+$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][\TYPO3\CMS\Scheduler\Task\IpAnonymizationTask::class] = [
+    'extension' => 'scheduler',
+    'title' => 'LLL:EXT:scheduler/Resources/Private/Language/locallang.xlf:ipAnonymization.name',
+    'description' => 'LLL:EXT:scheduler/Resources/Private/Language/locallang.xlf:tableGarbageCollection.description',
+    'additionalFields' => \TYPO3\CMS\Scheduler\Task\IpAnonymizationAdditionalFieldProvider::class,
+    'options' => $ipAnonymizeCollectionTaskOptions
+];
+unset($ipAnonymizeCollectionTaskOptions);
+
+if (!is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][\TYPO3\CMS\Scheduler\Task\IpAnonymizationTask::class]['options']['tables']['sys_log'] ?? false)) {
+    $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][\TYPO3\CMS\Scheduler\Task\IpAnonymizationTask::class]['options']['tables']['sys_log'] = [
+        'dateField' => 'tstamp',
+        'ipField' => 'IP'
+    ];
+}
+
 // Add task for optimizing database tables
 $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][\TYPO3\CMS\Scheduler\Task\OptimizeDatabaseTableTask::class] = [
     'extension' => 'scheduler',