UserTrait.php 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. <?php
  2. /**
  3. * @package Grav\Common\User
  4. *
  5. * @copyright Copyright (C) 2015 - 2019 Trilby Media, LLC. All rights reserved.
  6. * @license MIT License; see LICENSE file for details.
  7. */
  8. namespace Grav\Common\User\Traits;
  9. use Grav\Common\Grav;
  10. use Grav\Common\Page\Medium\ImageMedium;
  11. use Grav\Common\User\Authentication;
  12. use Grav\Common\Utils;
  13. trait UserTrait
  14. {
  15. /**
  16. * Authenticate user.
  17. *
  18. * If user password needs to be updated, new information will be saved.
  19. *
  20. * @param string $password Plaintext password.
  21. * @return bool
  22. */
  23. public function authenticate(string $password): bool
  24. {
  25. $hash = $this->get('hashed_password');
  26. $isHashed = null !== $hash;
  27. if (!$isHashed) {
  28. // If there is no hashed password, fake verify with default hash.
  29. $hash = Grav::instance()['config']->get('system.security.default_hash');
  30. }
  31. // Always execute verify() to protect us from timing attacks, but make the test to fail if hashed password wasn't set.
  32. $result = Authentication::verify($password, $hash) && $isHashed;
  33. $plaintext_password = $this->get('password');
  34. if (null !== $plaintext_password) {
  35. // Plain-text password is still stored, check if it matches.
  36. if ($password !== $plaintext_password) {
  37. return false;
  38. }
  39. // Force hash update to get rid of plaintext password.
  40. $result = 2;
  41. }
  42. if ($result === 2) {
  43. // Password needs to be updated, save the user.
  44. $this->set('password', $password);
  45. $this->undef('hashed_password');
  46. $this->save();
  47. }
  48. return (bool)$result;
  49. }
  50. /**
  51. * Checks user authorization to the action.
  52. *
  53. * @param string $action
  54. * @param string|null $scope
  55. * @return bool
  56. */
  57. public function authorize(string $action, string $scope = null): bool
  58. {
  59. if (!$this->get('authenticated')) {
  60. return false;
  61. }
  62. if ($this->get('state', 'enabled') !== 'enabled') {
  63. return false;
  64. }
  65. if (null !== $scope) {
  66. $action = $scope . '.' . $action;
  67. }
  68. $config = Grav::instance()['config'];
  69. $authorized = false;
  70. //Check group access level
  71. $groups = (array)$this->get('groups');
  72. foreach ($groups as $group) {
  73. $permission = $config->get("groups.{$group}.access.{$action}");
  74. $authorized = Utils::isPositive($permission);
  75. if ($authorized === true) {
  76. break;
  77. }
  78. }
  79. //Check user access level
  80. $access = $this->get('access');
  81. if ($access && Utils::getDotNotation($access, $action) !== null) {
  82. $permission = $this->get("access.{$action}");
  83. $authorized = Utils::isPositive($permission);
  84. }
  85. return $authorized;
  86. }
  87. /**
  88. * Return media object for the User's avatar.
  89. *
  90. * Note: if there's no local avatar image for the user, you should call getAvatarUrl() to get the external avatar URL.
  91. *
  92. * @return ImageMedium|null
  93. */
  94. public function getAvatarImage(): ?ImageMedium
  95. {
  96. $avatars = $this->get('avatar');
  97. if (\is_array($avatars) && $avatars) {
  98. $avatar = array_shift($avatars);
  99. $media = $this->getMedia();
  100. $name = $avatar['name'] ?? null;
  101. $image = $name ? $media[$name] : null;
  102. if ($image instanceof ImageMedium) {
  103. return $image;
  104. }
  105. }
  106. return null;
  107. }
  108. /**
  109. * Return the User's avatar URL
  110. *
  111. * @return string
  112. */
  113. public function getAvatarUrl(): string
  114. {
  115. // Try to locate avatar image.
  116. $avatar = $this->getAvatarImage();
  117. if ($avatar) {
  118. return $avatar->url();
  119. }
  120. // Try if avatar is a sting (URL).
  121. $avatar = $this->get('avatar');
  122. if (\is_string($avatar)) {
  123. return $avatar;
  124. }
  125. // Try looking for provider.
  126. $provider = $this->get('provider');
  127. $provider_options = $this->get($provider);
  128. if (\is_array($provider_options)) {
  129. if (isset($provider_options['avatar_url']) && \is_string($provider_options['avatar_url'])) {
  130. return $provider_options['avatar_url'];
  131. }
  132. if (isset($provider_options['avatar']) && \is_string($provider_options['avatar'])) {
  133. return $provider_options['avatar'];
  134. }
  135. }
  136. $email = $this->get('email');
  137. // By default fall back to gravatar image.
  138. return $email ? 'https://www.gravatar.com/avatar/' . md5(strtolower(trim($email))) : '';
  139. }
  140. abstract public function get($name, $default = null, $separator = null);
  141. abstract public function set($name, $value, $separator = null);
  142. abstract public function undef($name, $separator = null);
  143. abstract public function save();
  144. }