DatabaseBackend.php 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
  5. * SPDX-License-Identifier: AGPL-3.0-or-later
  6. */
  7. namespace OC\Security\Bruteforce\Backend;
  8. use OCP\IDBConnection;
  9. class DatabaseBackend implements IBackend {
  10. private const TABLE_NAME = 'bruteforce_attempts';
  11. public function __construct(
  12. private IDBConnection $db,
  13. ) {
  14. }
  15. /**
  16. * {@inheritDoc}
  17. */
  18. public function getAttempts(
  19. string $ipSubnet,
  20. int $maxAgeTimestamp,
  21. ?string $action = null,
  22. ?array $metadata = null,
  23. ): int {
  24. $query = $this->db->getQueryBuilder();
  25. $query->select($query->func()->count('*', 'attempts'))
  26. ->from(self::TABLE_NAME)
  27. ->where($query->expr()->gt('occurred', $query->createNamedParameter($maxAgeTimestamp)))
  28. ->andWhere($query->expr()->eq('subnet', $query->createNamedParameter($ipSubnet)));
  29. if ($action !== null) {
  30. $query->andWhere($query->expr()->eq('action', $query->createNamedParameter($action)));
  31. if ($metadata !== null) {
  32. $query->andWhere($query->expr()->eq('metadata', $query->createNamedParameter(json_encode($metadata))));
  33. }
  34. }
  35. $result = $query->executeQuery();
  36. $row = $result->fetch();
  37. $result->closeCursor();
  38. return (int)$row['attempts'];
  39. }
  40. /**
  41. * {@inheritDoc}
  42. */
  43. public function resetAttempts(
  44. string $ipSubnet,
  45. ?string $action = null,
  46. ?array $metadata = null,
  47. ): void {
  48. $query = $this->db->getQueryBuilder();
  49. $query->delete(self::TABLE_NAME)
  50. ->where($query->expr()->eq('subnet', $query->createNamedParameter($ipSubnet)));
  51. if ($action !== null) {
  52. $query->andWhere($query->expr()->eq('action', $query->createNamedParameter($action)));
  53. if ($metadata !== null) {
  54. $query->andWhere($query->expr()->eq('metadata', $query->createNamedParameter(json_encode($metadata))));
  55. }
  56. }
  57. $query->executeStatement();
  58. }
  59. /**
  60. * {@inheritDoc}
  61. */
  62. public function registerAttempt(
  63. string $ip,
  64. string $ipSubnet,
  65. int $timestamp,
  66. string $action,
  67. array $metadata = [],
  68. ): void {
  69. $values = [
  70. 'ip' => $ip,
  71. 'subnet' => $ipSubnet,
  72. 'action' => $action,
  73. 'metadata' => json_encode($metadata),
  74. 'occurred' => $timestamp,
  75. ];
  76. $qb = $this->db->getQueryBuilder();
  77. $qb->insert(self::TABLE_NAME);
  78. foreach ($values as $column => $value) {
  79. $qb->setValue($column, $qb->createNamedParameter($value));
  80. }
  81. $qb->executeStatement();
  82. }
  83. }