XOOPS  2.6.0
RememberMe.php
Go to the documentation of this file.
1 <?php
2 /*
3  You may not change or alter any portion of this comment or credits
4  of supporting developers from this source code or any supporting source code
5  which is considered copyrighted (c) material of the original comment or credit authors.
6 
7  This program is distributed in the hope that it will be useful,
8  but WITHOUT ANY WARRANTY; without even the implied warranty of
9  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10 */
11 
12 namespace Xoops\Core\Session;
13 
17 
57 {
58 
62  protected $userTokens = array();
63 
67  protected $userId = 0;
68 
72  protected $xoops = null;
73 
77  protected $now = 0;
78 
82  public function __construct()
83  {
84  $this->xoops = \Xoops::getInstance();
85  $this->now = time();
86  }
87 
88 
94  public function recall()
95  {
96  $this->now = time();
97  $cookieData = $this->readUserCookie();
98  if (false === $cookieData) {
99  return false; // no or invalid cookie
100  }
101  list($userId, $series, $token) = $cookieData;
102  $this->readUserTokens($userId);
103  if ($this->hasSeriesToken($series, $token)) {
104  $values = $this->getSeriesToken($series, $token);
105  // debounce concurrent requests
106  if (isset($values['next_token'])) {
107  // this token was already replaced, use replacement to update cookie
108  $nextToken = $values['next_token'];
109  } else {
110  // issue a new token for this series
111  $nextToken = $this->getNewToken();
112  // expire old token, and forward to the new one
113  $values = array('expires_at' => $this->now + 10, 'next_token' => $nextToken);
114  $this->setSeriesToken($series, $token, $values);
115  // register the new token
116  $values = array('expires_at' => $this->now + 2592000);
117  $this->setSeriesToken($series, $nextToken, $values);
118  }
119  $cookieData = array($userId, $series, $nextToken);
120  $this->writeUserCookie($cookieData);
121  $return = $userId;
122  } else {
123  // cookie is not valid
124  if ($this->hasSeries($series)) {
125  // We have a valid series, but an invalid token.
126  // Highly possible token was comprimised. Invalidate all saved tokens;
127  $this->clearUserTokens();
128  }
129  $this->clearUserCookie();
130  $return = false;
131  }
132  $this->writeUserTokens($userId);
133  return $return;
134  }
135 
143  public function forget()
144  {
145  $this->now = time();
146  $cookieData = $this->readUserCookie();
147  if (false !== $cookieData) {
148  list($userId, $series, $token) = $cookieData;
149  $this->readUserTokens($userId);
150  $this->unsetSeries($series);
151  $this->writeUserTokens($userId);
152  }
153  $this->clearUserCookie();
154  }
155 
165  public function invalidateAllForUser($userId)
166  {
167  $this->readUserTokens($userId);
168  $this->clearUserTokens();
169  $this->writeUserTokens($userId);
170  }
171 
179  protected function hasSeries($series)
180  {
181  return isset($this->userTokens[$series]);
182  }
183 
191  protected function unsetSeries($series)
192  {
193  unset($this->userTokens[$series]);
194  }
195 
204  protected function hasSeriesToken($series, $token)
205  {
206  return isset($this->userTokens[$series][$token]);
207  }
208 
217  protected function getSeriesToken($series, $token)
218  {
219  if (isset($this->userTokens[$series][$token])) {
220  return $this->userTokens[$series][$token];
221  }
222  return false;
223  }
224 
234  protected function setSeriesToken($series, $token, $values)
235  {
236  $this->userTokens[$series][$token] = $values;
237  }
238 
247  protected function unsetSeriesToken($series, $token)
248  {
249  unset($this->userTokens[$series][$token]);
250  }
251 
259  protected function readUserTokens($userId)
260  {
261  $key = "user/{$userId}/usercookie";
262  $this->userTokens = $this->xoops->cache()->read($key);
263  if (false === $this->userTokens) {
264  $this->clearUserTokens();
265  }
266  $this->removeExpiredTokens();
267  }
268 
276  protected function writeUserTokens($userId)
277  {
278  $key = "user/{$userId}/usercookie";
279  $this->xoops->cache()->write($key, $this->userTokens, 2592000);
280  }
281 
287  protected function removeExpiredTokens()
288  {
289  $now = $this->now;
291  foreach ($userTokens as $series => $tokens) {
292  foreach ($tokens as $token => $values) {
293  if (isset($values['expires_at']) && $values['expires_at'] < $now) {
294  $this->unsetSeriesToken($series, $token);
295  }
296  }
297  }
299  foreach ($userTokens as $series => $tokens) {
300  if (empty($tokens)) {
301  $this->unsetSeries($series);
302  }
303  }
304  }
305 
310  protected function clearUserTokens()
311  {
312  $this->userTokens = array();
313  }
314 
320  protected function getNewSeries()
321  {
322  return Random::generateKey();
323  }
324 
330  protected function getNewToken()
331  {
333  }
334 
342  public function createUserCookie($userId)
343  {
344  $this->readUserTokens($userId);
345  $this->now = time();
346  $series = $this->getNewSeries();
347  $token = $this->getNewToken();
348  $cookieData = array($userId, $series, $token);
349  $this->setSeriesToken($series, $token, array('expires_at' => $this->now + 2592000));
350  $this->writeUserCookie($cookieData);
351  $this->writeUserTokens($userId);
352  }
353 
359  protected function clearUserCookie()
360  {
361  $this->writeUserCookie('', -3600);
362  }
363 
370  protected function readUserCookie()
371  {
372  $usercookie = $this->xoops->getConfig('usercookie');
373  if (empty($usercookie)) {
374  return false; // remember me is not configured
375  }
376 
377  $usercookie = $this->xoops->getConfig('usercookie');
378  $notFound = 'Nosuchcookie';
379  $cookieData = Request::getString($usercookie, $notFound, 'COOKIE');
380  if ($cookieData !== $notFound) {
381  $temp = explode('-', $cookieData);
382  if (count($temp) == 3) {
383  $temp[0] = (integer) $temp[0];
384  return $temp;
385  }
386  $this->clearUserCookie(); // clean up garbage cookie
387  }
388  return false;
389  }
390 
399  protected function writeUserCookie($cookieData, $expire = 2592000)
400  {
401  $usercookie = $this->xoops->getConfig('usercookie');
402  if (empty($usercookie)) {
403  return; // remember me is not configured
404  }
405  if (is_array($cookieData)) {
406  $cookieData = implode('-', $cookieData);
407  }
408  $httpRequest = HttpRequest::getInstance();
409  $path = \XoopsBaseConfig::get('cookie-path');
410  $domain = \XoopsBaseConfig::get('cookie-domain');
411  $secure = $httpRequest->is('ssl');
412  setcookie($usercookie, $cookieData, $this->now + $expire, $path, $domain, $secure, true);
413  }
414 }
unsetSeriesToken($series, $token)
Definition: RememberMe.php:247
$path
Definition: execute.php:31
static getInstance()
Definition: Xoops.php:160
static generateOneTimeToken($hash= 'sha512', $bytes=64)
Definition: Random.php:41
hasSeriesToken($series, $token)
Definition: RememberMe.php:204
setSeriesToken($series, $token, $values)
Definition: RememberMe.php:234
writeUserCookie($cookieData, $expire=2592000)
Definition: RememberMe.php:399
static generateKey($hash= 'sha512', $bytes=128)
Definition: Random.php:60
static get($name)
static getString($name, $default= '', $hash= 'default', $mask=0)
Definition: Request.php:244
getSeriesToken($series, $token)
Definition: RememberMe.php:217