‪TYPO3CMS  ‪main
NoncePool.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
19 
24 {
28  protected const ‪DEFAULT_SIZE = 5;
29 
33  protected const ‪DEFAULT_EXPIRATION = 900;
34 
38  protected array ‪$options;
39 
43  protected array ‪$items;
44 
48  protected array ‪$changeItems = [];
49 
53  public function ‪__construct(array $nonces = [], array ‪$options = [])
54  {
55  $this->options = [
56  'size' => max(1, (int)(‪$options['size'] ?? self::DEFAULT_SIZE)),
57  'expiration' => max(0, (int)(‪$options['expiration'] ?? self::DEFAULT_EXPIRATION)),
58  ];
59 
60  foreach ($nonces as $name => $value) {
61  if ($value !== null && !$value instanceof ‪Nonce) {
62  throw new \LogicException(sprintf('Invalid valid for nonce "%s"', $name), 1664195013);
63  }
64  }
65  // filter valid items
66  $this->items = array_filter(
67  $nonces,
68  fn(?‪Nonce $item, string $name) => $item !== null
69  && $this->isValidNonceName($item, $name)
70  && $this->‪isNonceUpToDate($item),
71  ARRAY_FILTER_USE_BOTH
72  );
73  // items that were not valid -> to be revoked
74  $invalidItems = array_diff_key($nonces, $this->items);
75  $this->changeItems = array_fill_keys(array_keys($invalidItems), null);
76  }
77 
78  public function ‪findSigningSecret(string $name): ?‪Nonce
79  {
80  return $this->items[$name] ?? null;
81  }
82 
83  public function ‪provideSigningSecret(): ‪Nonce
84  {
85  ‪$items = array_filter($this->changeItems);
86  $nonce = reset(‪$items);
87  if (!$nonce instanceof ‪Nonce) {
88  $nonce = ‪Nonce::create();
89  $this->‪emit($nonce);
90  }
91  return $nonce;
92  }
93 
94  public function ‪merge(self $other): self
95  {
96  $this->items = array_merge($this->items, $other->items);
97  $this->changeItems = array_merge($this->changeItems, $other->changeItems);
98  return $this;
99  }
100 
101  public function ‪purge(): self
102  {
103  $size = $this->options['size'];
104  ‪$items = array_filter($this->items);
105  if (count(‪$items) <= $size) {
106  return $this;
107  }
108  uasort(‪$items, static fn(‪Nonce $a, ‪Nonce $b) => $b->time <=> $a->time);
109  $exceedingItems = array_splice(‪$items, $size, null, []);
110  foreach ($exceedingItems as $name => $_) {
111  $this->changeItems[$name] = null;
112  }
113  return $this;
114  }
115 
116  public function ‪emit(‪Nonce $nonce): self
117  {
118  $this->changeItems[$nonce->‪getSigningIdentifier()->name] = $nonce;
119  return $this;
120  }
121 
122  public function ‪revoke(‪Nonce $nonce): self
123  {
124  $this->‪revokeSigningSecret($nonce->‪getSigningIdentifier()->name);
125  return $this;
126  }
127 
128  public function ‪revokeSigningSecret(string $name): void
129  {
130  if (isset($this->items[$name])) {
131  $this->changeItems[$name] = null;
132  }
133  }
134 
138  public function getEmittableNonces(): array
139  {
140  return array_filter($this->changeItems);
141  }
142 
146  public function getRevocableNames(): array
147  {
148  return array_keys(
149  array_diff_key($this->changeItems, $this->getEmittableNonces())
150  );
151  }
152 
153  protected function isValidNonceName(Nonce $nonce, $name): bool
154  {
155  return $nonce->getSigningIdentifier()->name === $name;
156  }
157 
158  protected function ‪isNonceUpToDate(‪Nonce $nonce): bool
159  {
160  if ($this->options['expiration'] <= 0) {
161  return true;
162  }
163  $now = new \DateTimeImmutable();
164  $interval = new \DateInterval(sprintf('PT%dS', $this->options['expiration']));
165  return $nonce->time->add($interval) > $now;
166  }
167 }
‪TYPO3\CMS\Core\Security\Nonce\getSigningIdentifier
‪getSigningIdentifier()
Definition: Nonce.php:72
‪TYPO3\CMS\Core\Security\NoncePool\provideSigningSecret
‪provideSigningSecret()
Definition: NoncePool.php:83
‪TYPO3\CMS\Core\Security\NoncePool\DEFAULT_SIZE
‪const DEFAULT_SIZE
Definition: NoncePool.php:28
‪TYPO3\CMS\Core\Security\NoncePool\__construct
‪__construct(array $nonces=[], array $options=[])
Definition: NoncePool.php:53
‪TYPO3\CMS\Core\Security\NoncePool\$options
‪array $options
Definition: NoncePool.php:38
‪TYPO3\CMS\Core\Security\NoncePool\purge
‪purge()
Definition: NoncePool.php:101
‪TYPO3\CMS\Core\Security\NoncePool\revoke
‪revoke(Nonce $nonce)
Definition: NoncePool.php:122
‪TYPO3\CMS\Core\Security\NoncePool\DEFAULT_EXPIRATION
‪const DEFAULT_EXPIRATION
Definition: NoncePool.php:33
‪TYPO3\CMS\Core\Security\NoncePool\$items
‪array $items
Definition: NoncePool.php:43
‪TYPO3\CMS\Core\Security\Nonce\create
‪static create(int $length=self::MIN_BYTES)
Definition: Nonce.php:37
‪TYPO3\CMS\Core\Security\NoncePool
Definition: NoncePool.php:24
‪TYPO3\CMS\Core\Security\NoncePool\merge
‪merge(self $other)
Definition: NoncePool.php:94
‪TYPO3\CMS\Core\Security\NoncePool\$changeItems
‪array $changeItems
Definition: NoncePool.php:48
‪TYPO3\CMS\Core\Security\NoncePool\revokeSigningSecret
‪revokeSigningSecret(string $name)
Definition: NoncePool.php:128
‪TYPO3\CMS\Core\Security\Nonce
Definition: Nonce.php:29
‪TYPO3\CMS\Core\Security\SigningProviderInterface
Definition: SigningProviderInterface.php:24
‪TYPO3\CMS\Core\Security\NoncePool\emit
‪emit(Nonce $nonce)
Definition: NoncePool.php:116
‪TYPO3\CMS\Core\Security\NoncePool\isNonceUpToDate
‪isNonceUpToDate(Nonce $nonce)
Definition: NoncePool.php:158
‪TYPO3\CMS\Core\Security\NoncePool\findSigningSecret
‪findSigningSecret(string $name)
Definition: NoncePool.php:78
‪TYPO3\CMS\Core\Security
Definition: BlockSerializationTrait.php:18