TYPO3  7.6
BulkUpdateTask.php
Go to the documentation of this file.
1 <?php
2 namespace TYPO3\CMS\Saltedpasswords\Task;
3 
4 /*
5  * This file is part of the TYPO3 CMS project.
6  *
7  * It is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License, either version 2
9  * of the License, or any later version.
10  *
11  * For the full copyright and license information, please read the
12  * LICENSE.txt file that was distributed with this source code.
13  *
14  * The TYPO3 project - inspiring people to share!
15  */
16 
21 {
25  protected $canDeactivateSelf = true;
26 
35  protected $numberOfRecords = 250;
36 
40  protected $userRecordPointer = array();
41 
45  public function __construct()
46  {
47  parent::__construct();
48  $this->userRecordPointer = array(
49  'FE' => 0,
50  'BE' => 0
51  );
52  }
53 
59  public function execute()
60  {
61  $processedAllRecords = true;
62  // For frontend and backend
63  foreach ($this->userRecordPointer as $mode => $pointer) {
64  // If saltedpasswords is active for frontend / backend
65  if (\TYPO3\CMS\Saltedpasswords\Utility\SaltedPasswordsUtility::isUsageEnabled($mode)) {
66  $usersToUpdate = $this->findUsersToUpdate($mode);
67  $numberOfRows = count($usersToUpdate);
68  if ($numberOfRows > 0) {
69  $processedAllRecords = false;
70  $this->activateSelf();
71  $this->incrementUserRecordPointer($mode, $numberOfRows);
72  $this->convertPasswords($mode, $usersToUpdate);
73  }
74  }
75  }
76  if ($processedAllRecords) {
77  // Reset the user record pointer
78  $this->userRecordPointer = array(
79  'FE' => 0,
80  'BE' => 0
81  );
82  // Determine if task should disable itself
83  if ($this->canDeactivateSelf) {
84  $this->deactivateSelf();
85  }
86  }
87  // Use save() of parent class \TYPO3\CMS\Scheduler\Task\AbstractTask to persist changed task variables
88  $this->save();
89  return true;
90  }
91 
97  public function getAdditionalInformation()
98  {
99  $information = $GLOBALS['LANG']->sL('LLL:EXT:saltedpasswords/Resources/Private/Language/locallang.xlf:ext.saltedpasswords.tasks.bulkupdate.label.additionalinformation.deactivateself') . $this->getCanDeactivateSelf() . '; ' . $GLOBALS['LANG']->sL('LLL:EXT:saltedpasswords/Resources/Private/Language/locallang.xlf:ext.saltedpasswords.tasks.bulkupdate.label.additionalinformation.numberofrecords') . $this->getNumberOfRecords();
100  return $information;
101  }
102 
109  protected function findUsersToUpdate($mode)
110  {
111  $usersToUpdate = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('uid, password', strtolower($mode) . '_users', '1 = 1', '', 'uid ASC', $this->userRecordPointer[$mode] . ', ' . $this->numberOfRecords);
112  return $usersToUpdate;
113  }
114 
122  protected function convertPasswords($mode, array $users)
123  {
124  $updateUsers = array();
125  foreach ($users as $user) {
126  // If a password is already a salted hash it must not be updated
127  if ($this->isSaltedHash($user['password'])) {
128  continue;
129  }
130  $updateUsers[] = $user;
131  }
132  if (!empty($updateUsers)) {
133  $this->updatePasswords($mode, $updateUsers);
134  }
135  }
136 
144  protected function updatePasswords($mode, array $users)
145  {
147  $saltedpasswordsInstance = \TYPO3\CMS\Saltedpasswords\Salt\SaltFactory::getSaltingInstance(null, $mode);
148  foreach ($users as $user) {
149  $newPassword = $saltedpasswordsInstance->getHashedPassword($user['password']);
150  // If a given password is a md5 hash (usually default be_users without saltedpasswords activated),
151  // result of getHashedPassword() is a salted hashed md5 hash.
152  // We prefix those with 'M', saltedpasswords will then update this password
153  // to a usual salted hash upon first login of the user.
154  if ($this->isMd5Password($user['password'])) {
155  $newPassword = 'M' . $newPassword;
156  }
157  // Persist updated password
158  $GLOBALS['TYPO3_DB']->exec_UPDATEquery(strtolower($mode) . '_users', 'uid = ' . $user['uid'], array(
159  'password' => $newPassword
160  ));
161  }
162  }
163 
175  protected function isSaltedHash($password)
176  {
177  $isSaltedHash = false;
178  if (strlen($password) > 2 && (\TYPO3\CMS\Core\Utility\GeneralUtility::isFirstPartOfStr($password, 'C$') || \TYPO3\CMS\Core\Utility\GeneralUtility::isFirstPartOfStr($password, 'M$'))) {
179  // Cut off M or C and test if we have a salted hash
180  $isSaltedHash = \TYPO3\CMS\Saltedpasswords\Salt\SaltFactory::determineSaltingHashingMethod(substr($password, 1));
181  }
182  // Test if given password is already a usual salted hash
183  if (!$isSaltedHash) {
184  $isSaltedHash = \TYPO3\CMS\Saltedpasswords\Salt\SaltFactory::determineSaltingHashingMethod($password);
185  }
186  return $isSaltedHash;
187  }
188 
195  protected function isMd5Password($password)
196  {
197  return (bool)preg_match('/[0-9abcdef]{32,32}/i', $password);
198  }
199 
207  protected function incrementUserRecordPointer($mode, $number)
208  {
209  $this->userRecordPointer[$mode] += $number;
210  }
211 
218  protected function activateSelf()
219  {
220  $this->setDisabled(false);
221  }
222 
229  protected function deactivateSelf()
230  {
231  $this->setDisabled(true);
232  }
233 
241  {
242  $this->canDeactivateSelf = $canDeactivateSelf;
243  }
244 
250  public function getCanDeactivateSelf()
251  {
253  }
254 
262  {
263  $this->numberOfRecords = $numberOfRecords;
264  }
265 
271  public function getNumberOfRecords()
272  {
273  return $this->numberOfRecords;
274  }
275 }