Limiter.php 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * @copyright Copyright (c) 2017 Lukas Reschke <lukas@statuscode.ch>
  5. *
  6. * @author Lukas Reschke <lukas@statuscode.ch>
  7. *
  8. * @license GNU AGPL version 3 or any later version
  9. *
  10. * This program is free software: you can redistribute it and/or modify
  11. * it under the terms of the GNU Affero General Public License as
  12. * published by the Free Software Foundation, either version 3 of the
  13. * License, or (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU Affero General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU Affero General Public License
  21. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  22. *
  23. */
  24. namespace OC\Security\RateLimiting;
  25. use OC\Security\Normalizer\IpAddress;
  26. use OC\Security\RateLimiting\Backend\IBackend;
  27. use OC\Security\RateLimiting\Exception\RateLimitExceededException;
  28. use OCP\AppFramework\Utility\ITimeFactory;
  29. use OCP\IRequest;
  30. use OCP\IUser;
  31. use OCP\IUserSession;
  32. class Limiter {
  33. /** @var IBackend */
  34. private $backend;
  35. /** @var ITimeFactory */
  36. private $timeFactory;
  37. /**
  38. * @param IUserSession $userSession
  39. * @param IRequest $request
  40. * @param ITimeFactory $timeFactory
  41. * @param IBackend $backend
  42. */
  43. public function __construct(IUserSession $userSession,
  44. IRequest $request,
  45. ITimeFactory $timeFactory,
  46. IBackend $backend) {
  47. $this->backend = $backend;
  48. $this->timeFactory = $timeFactory;
  49. }
  50. /**
  51. * @param string $methodIdentifier
  52. * @param string $userIdentifier
  53. * @param int $period
  54. * @param int $limit
  55. * @throws RateLimitExceededException
  56. */
  57. private function register(string $methodIdentifier,
  58. string $userIdentifier,
  59. int $period,
  60. int $limit) {
  61. $existingAttempts = $this->backend->getAttempts($methodIdentifier, $userIdentifier, $period);
  62. if ($existingAttempts >= $limit) {
  63. throw new RateLimitExceededException();
  64. }
  65. $this->backend->registerAttempt($methodIdentifier, $userIdentifier, $this->timeFactory->getTime());
  66. }
  67. /**
  68. * Registers attempt for an anonymous request
  69. *
  70. * @param string $identifier
  71. * @param int $anonLimit
  72. * @param int $anonPeriod
  73. * @param string $ip
  74. * @throws RateLimitExceededException
  75. */
  76. public function registerAnonRequest(string $identifier,
  77. int $anonLimit,
  78. int $anonPeriod,
  79. string $ip) {
  80. $ipSubnet = (new IpAddress($ip))->getSubnet();
  81. $anonHashIdentifier = hash('sha512', 'anon::' . $identifier . $ipSubnet);
  82. $this->register($identifier, $anonHashIdentifier, $anonPeriod, $anonLimit);
  83. }
  84. /**
  85. * Registers attempt for an authenticated request
  86. *
  87. * @param string $identifier
  88. * @param int $userLimit
  89. * @param int $userPeriod
  90. * @param IUser $user
  91. * @throws RateLimitExceededException
  92. */
  93. public function registerUserRequest(string $identifier,
  94. int $userLimit,
  95. int $userPeriod,
  96. IUser $user) {
  97. $userHashIdentifier = hash('sha512', 'user::' . $identifier . $user->getUID());
  98. $this->register($identifier, $userHashIdentifier, $userPeriod, $userLimit);
  99. }
  100. }