TokenStorage.php 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. <?php
  2. /**
  3. * @package Grav\Plugin\Login
  4. *
  5. * @copyright Copyright (C) 2014 - 2021 RocketTheme, LLC. All rights reserved.
  6. * @license MIT License; see LICENSE file for details.
  7. */
  8. namespace Grav\Plugin\Login\RememberMe;
  9. use Grav\Common\File\CompiledYamlFile;
  10. use Grav\Common\Filesystem\Folder;
  11. use Grav\Common\Grav;
  12. use Birke\Rememberme\Storage\StorageInterface;
  13. /**
  14. * Token Storage wrapper
  15. *
  16. * Used for storing the credential/token/persistentToken triplets.
  17. */
  18. class TokenStorage implements StorageInterface
  19. {
  20. /** @var string */
  21. protected $path;
  22. /** @var int */
  23. protected $timeout;
  24. /**
  25. * Constructor
  26. *
  27. * @param string $path Path to storage directory
  28. * @param int $timeout
  29. * @throws \InvalidArgumentException
  30. */
  31. public function __construct($path = 'user-data://rememberme', $timeout = 604800)
  32. {
  33. $this->path = Grav::instance()['locator']->findResource($path, true, true);
  34. $this->timeout = $timeout;
  35. }
  36. /**
  37. * Return Tri-state value constant
  38. *
  39. * @param mixed $credential Unique credential (user id, email address, user name)
  40. * @param string $token One-Time Token
  41. * @param string $persistentToken Persistent Token
  42. *
  43. * @return int
  44. */
  45. public function findTriplet($credential, $token, $persistentToken)
  46. {
  47. // Hash the tokens, because they can contain a salt and can be accessed in the file system
  48. $persistentToken = sha1($persistentToken);
  49. $token = sha1($token);
  50. $file = $this->getFile($credential);
  51. $tokens = (array)$file->content();
  52. if (!isset($tokens[$persistentToken]) || $tokens[$persistentToken] < time() + $this->timeout) {
  53. return self::TRIPLET_NOT_FOUND;
  54. }
  55. $stored = key($tokens[$persistentToken]);
  56. if ($stored !== $token) {
  57. return self::TRIPLET_INVALID;
  58. }
  59. return self::TRIPLET_FOUND;
  60. }
  61. /**
  62. * Store the new token for the credential and the persistent token. Create a new storage entry, if the combination
  63. * of credential and persistent token does not exist.
  64. *
  65. * @param mixed $credential
  66. * @param string $token
  67. * @param string $persistentToken
  68. * @param int $expire Timestamp when this triplet will expire (0 = no expiry)
  69. */
  70. public function storeTriplet($credential, $token, $persistentToken, $expire = null)
  71. {
  72. // Hash the tokens, because they can contain a salt and can be accessed in the file system
  73. $persistentToken = sha1($persistentToken);
  74. $token = sha1($token);
  75. $file = $this->getFile($credential);
  76. $tokens = (array)$file->content();
  77. // Update token
  78. $tokens[$persistentToken] = [$token => time()];
  79. $file->save($tokens);
  80. }
  81. /**
  82. * Replace current token after successful authentication
  83. *
  84. * @param mixed $credential
  85. * @param string $token
  86. * @param string $persistentToken
  87. * @param int $expire
  88. */
  89. public function replaceTriplet($credential, $token, $persistentToken, $expire = null)
  90. {
  91. $this->storeTriplet($credential, $token, $persistentToken, $expire);
  92. }
  93. /**
  94. * Remove one triplet of the user from the store
  95. *
  96. * @param mixed $credential
  97. * @param string $persistentToken
  98. */
  99. public function cleanTriplet($credential, $persistentToken)
  100. {
  101. // Hash the tokens, because they can contain a salt and can be accessed in the file system
  102. $persistentToken = sha1($persistentToken);
  103. $file = $this->getFile($credential);
  104. if (!$file->exists()) {
  105. return;
  106. }
  107. $tokens = (array)$file->content();
  108. if (isset($tokens[$persistentToken])) {
  109. // Delete token from storage
  110. unset($tokens[$persistentToken]);
  111. if ($tokens) {
  112. $file->save($tokens);
  113. } else {
  114. $file->delete();
  115. }
  116. }
  117. }
  118. /**
  119. * Remove all triplets of a user, effectively logging him out on all
  120. * machines
  121. *
  122. * @param mixed $credential
  123. */
  124. public function cleanAllTriplets($credential)
  125. {
  126. $file = $this->getFile($credential);
  127. if ($file->exists()) {
  128. $file->delete();
  129. }
  130. }
  131. /**
  132. * Helper method to clear RememberMe cache
  133. */
  134. public function clearCache()
  135. {
  136. if (is_dir($this->path)) {
  137. Folder::delete($this->path, false);
  138. }
  139. }
  140. /**
  141. * @param string $credential
  142. * @return CompiledYamlFile
  143. */
  144. protected function getFile($credential)
  145. {
  146. return CompiledYamlFile::instance($this->path . '/' . sha1($credential) . '.yaml');
  147. }
  148. }