Skip to content

Commit d968f3d

Browse files
Bernhard Schmittmficzel
authored andcommitted
Adjust Neos.Flow Session subcontext
1 parent ed984c0 commit d968f3d

10 files changed

+123
-34
lines changed

Neos.Flow/Classes/Session/Aspect/LazyLoadingAspect.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ class LazyLoadingAspect
2929
#[Flow\Inject]
3030
protected ?LoggerInterface $logger = null;
3131

32+
/**
33+
* @var array<string,object>
34+
*/
3235
protected array $sessionOriginalInstances = [];
3336

3437
public function __construct(

Neos.Flow/Classes/Session/Aspect/SessionObjectMethodsPointcutFilter.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public function injectObjectManager(CompileTimeObjectManager $objectManager): vo
3737
* Checks if the specified class and method matches against the filter
3838
*
3939
* @param string $className Name of the class to check against
40-
* @param string $methodName Name of the method to check against
40+
* @param ?string $methodName Name of the method to check against
4141
* @param string $methodDeclaringClassName Name of the class the method was originally declared in
4242
* @param mixed $pointcutQueryIdentifier Some identifier for this query - must at least differ from a previous identifier. Used for circular reference detection.
4343
* @return bool true if the class / method match, otherwise false
@@ -79,7 +79,7 @@ public function hasRuntimeEvaluationsDefinition(): bool
7979
/**
8080
* Returns runtime evaluations for a previously matched pointcut
8181
*
82-
* @return array Runtime evaluations
82+
* @return array<mixed> Runtime evaluations
8383
*/
8484
public function getRuntimeEvaluationsDefinition(): array
8585
{

Neos.Flow/Classes/Session/CookieEnabledInterface.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,8 @@ interface CookieEnabledInterface extends SessionInterface
1818
{
1919
public function getSessionCookie(): Cookie;
2020

21+
/**
22+
* @param array<string> $tags
23+
*/
2124
public static function createFromCookieAndSessionInformation(Cookie $sessionCookie, string $storageIdentifier, int $lastActivityTimestamp, array $tags = []): SessionInterface|CookieEnabledInterface;
2225
}

Neos.Flow/Classes/Session/Data/SessionKeyValueStore.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ public function store(StorageIdentifier $storageIdentifier, string $key, mixed $
7272
{
7373
$entryIdentifier = $this->createEntryIdentifier($storageIdentifier, $key);
7474
$serializedValue = ($this->useIgBinary === true) ? igbinary_serialize($value) : serialize($value);
75+
if (is_null($serializedValue)) {
76+
throw new \Exception('Failed to serialize value', 1743874462);
77+
}
7578
$valueHash = md5($serializedValue);
7679
$debounceHash = $this->writeDebounceHashes[$storageIdentifier->value][$key] ?? null;
7780
if ($debounceHash !== null && $debounceHash === $valueHash) {
@@ -90,7 +93,7 @@ public function remove(StorageIdentifier $storageIdentifier): int
9093
return $this->cache->flushByTag($storageIdentifier->value);
9194
}
9295

93-
private function createEntryIdentifier(StorageIdentifier $storageIdentifier, $key): string
96+
private function createEntryIdentifier(StorageIdentifier $storageIdentifier, string $key): string
9497
{
9598
return $storageIdentifier->value . md5($key);
9699
}

Neos.Flow/Classes/Session/Data/SessionMetaDataStore.php

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,15 @@ public function retrieve(SessionIdentifier $sessionIdentifier): ?SessionMetaData
8282
}
8383

8484
if (is_array($metaDataFromCache)) {
85+
if (!is_string($metaDataFromCache['storageIdentifier'] ?? null)) {
86+
throw new \Exception('Missing storageIdentifier', 1743874214);
87+
}
88+
if (!is_int($metaDataFromCache['lastActivityTimestamp'])) {
89+
throw new \Exception('Missing lastActivityTimestamp', 1743874236);
90+
}
91+
if (!is_array($metaDataFromCache['tags'])) {
92+
throw new \Exception('Missing tags', 1743874272);
93+
}
8594
$metaDataFromCache = SessionMetaData::createFromSessionIdentifierStringAndOldArrayCacheFormat($sessionIdentifier->value, $metaDataFromCache);
8695
$this->writeDebounceCache[$metaDataFromCache->sessionIdentifier->value] = $metaDataFromCache;
8796
return $metaDataFromCache;
@@ -104,6 +113,15 @@ public function retrieveByTag(string $tag): \Generator
104113
$this->writeDebounceCache[$sessionIdentifier] = $sessionMetaData;
105114
yield $sessionIdentifier => $sessionMetaData;
106115
} elseif (is_array($sessionMetaData)) {
116+
if (!is_string($sessionMetaData['storageIdentifier'] ?? null)) {
117+
throw new \Exception('Missing storageIdentifier', 1743874214);
118+
}
119+
if (!is_int($sessionMetaData['lastActivityTimestamp'])) {
120+
throw new \Exception('Missing lastActivityTimestamp', 1743874236);
121+
}
122+
if (!is_array($sessionMetaData['tags'])) {
123+
throw new \Exception('Missing tags', 1743874272);
124+
}
107125
$sessionMetaData = SessionMetaData::createFromSessionIdentifierStringAndOldArrayCacheFormat($sessionIdentifier, $sessionMetaData);
108126
$this->writeDebounceCache[$sessionIdentifier] = $sessionMetaData;
109127
yield $sessionIdentifier => $sessionMetaData;
@@ -125,7 +143,19 @@ public function retrieveAll(): \Generator
125143
$this->writeDebounceCache[$sessionIdentifier] = $sessionMetaData;
126144
yield $sessionIdentifier => $sessionMetaData;
127145
} elseif (is_array($sessionMetaData)) {
128-
$sessionMetaData = SessionMetaData::createFromSessionIdentifierStringAndOldArrayCacheFormat($sessionIdentifier, $sessionMetaData);
146+
if (!is_string($sessionMetaData['storageIdentifier'] ?? null)) {
147+
throw new \Exception('Missing storageIdentifier', 1743874214);
148+
}
149+
if (!is_int($sessionMetaData['lastActivityTimestamp'])) {
150+
throw new \Exception('Missing lastActivityTimestamp', 1743874236);
151+
}
152+
if (!is_array($sessionMetaData['tags'])) {
153+
throw new \Exception('Missing tags', 1743874272);
154+
}
155+
$sessionMetaData = SessionMetaData::createFromSessionIdentifierStringAndOldArrayCacheFormat(
156+
$sessionIdentifier,
157+
$sessionMetaData
158+
);
129159
$this->writeDebounceCache[$sessionIdentifier] = $sessionMetaData;
130160
yield $sessionIdentifier => $sessionMetaData;
131161
}

Neos.Flow/Classes/Session/Session.php

Lines changed: 62 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ class Session implements CookieEnabledInterface
7171
protected ?string $sessionCookieSameSite = null;
7272
protected ?Cookie $sessionCookie = null;
7373
protected int $inactivityTimeout;
74+
/**
75+
* @var array<string>
76+
*/
7477
protected array $tags = [];
7578
protected int $now = 0;
7679
protected ?SessionMetaData $sessionMetaData = null;
@@ -91,7 +94,10 @@ public static function create(): self
9194
return new static();
9295
}
9396

94-
public static function createRemote(string $sessionIdentifier, string $storageIdentifier, ?int $lastActivityTimestamp = null, array $tags = []): self
97+
/**
98+
* @param array<string> $tags
99+
*/
100+
public static function createRemote(string $sessionIdentifier, string $storageIdentifier, int $lastActivityTimestamp, array $tags = []): self
95101
{
96102
$session = new static();
97103
$session->sessionMetaData = new SessionMetaData(
@@ -114,6 +120,9 @@ public static function createRemoteFromSessionMetaData(SessionMetaData $sessionM
114120
return $session;
115121
}
116122

123+
/**
124+
* @param array<string> $tags
125+
*/
117126
public static function createFromCookieAndSessionInformation(Cookie $sessionCookie, string $storageIdentifier, int $lastActivityTimestamp, array $tags = []): SessionInterface|CookieEnabledInterface
118127
{
119128
$session = new static();
@@ -127,6 +136,9 @@ public static function createFromCookieAndSessionInformation(Cookie $sessionCook
127136
return $session;
128137
}
129138

139+
/**
140+
* @param array<string,mixed> $settings
141+
*/
130142
public function injectSettings(array $settings): void
131143
{
132144
$this->sessionCookieName = $settings['session']['name'];
@@ -141,6 +153,9 @@ public function injectSettings(array $settings): void
141153

142154
public function getSessionCookie(): Cookie
143155
{
156+
if (!$this->sessionCookie) {
157+
throw new \Exception('Missing session cookie');
158+
}
144159
return $this->sessionCookie;
145160
}
146161

@@ -172,6 +187,9 @@ public function start(): void
172187
{
173188
if ($this->started === false) {
174189
$this->sessionMetaData = SessionMetaData::createWithTimestamp($this->now);
190+
if (!$this->sessionCookiePath) {
191+
throw new \Exception('Cannot start a session without a path');
192+
}
175193
$this->sessionCookie = new Cookie($this->sessionCookieName, $this->sessionMetaData->sessionIdentifier->value, 0, $this->sessionCookieLifetime, $this->sessionCookieDomain, $this->sessionCookiePath, $this->sessionCookieSecure, $this->sessionCookieHttpOnly, $this->sessionCookieSameSite);
176194
$this->started = true;
177195

@@ -221,6 +239,9 @@ public function canBeResumed(): bool
221239
public function resume(): ?int
222240
{
223241
if ($this->started === false && $this->canBeResumed()) {
242+
if (!$this->sessionMetaData) {
243+
throw new \Exception('Cannot resume a session without metadata');
244+
}
224245
$this->started = true;
225246

226247
$sessionObjects = $this->sessionKeyValueStore->retrieve($this->sessionMetaData->storageIdentifier, self::FLOW_OBJECT_STORAGE_KEY);
@@ -256,7 +277,7 @@ public function resume(): ?int
256277
*/
257278
public function getId(): string
258279
{
259-
if ($this->started !== true) {
280+
if ($this->started !== true || !$this->sessionMetaData) {
260281
throw new Exception\SessionNotStartedException('Tried to retrieve the session identifier, but the session has not been started yet.)', 1351171517);
261282
}
262283
return $this->sessionMetaData->sessionIdentifier->value;
@@ -276,6 +297,12 @@ public function renewId(): string
276297
if ($this->started !== true) {
277298
throw new Exception\SessionNotStartedException('Tried to renew the session identifier, but the session has not been started yet.', 1351182429);
278299
}
300+
if (!$this->sessionMetaData) {
301+
throw new \Exception('Missing session metadata');
302+
}
303+
if (!$this->sessionCookie) {
304+
throw new \Exception('Missing session cookie');
305+
}
279306
if ($this->remote === true) {
280307
throw new Exception\OperationNotSupportedException(sprintf('Tried to renew the session identifier on a remote session (%s).', $this->sessionMetaData->sessionIdentifier->value), 1354034230);
281308
}
@@ -284,6 +311,12 @@ public function renewId(): string
284311
$this->sessionMetaData = $this->sessionMetaData->withNewSessionIdentifier();
285312
$this->writeSessionMetaDataCacheEntry();
286313

314+
if (!$this->sessionMetaData) {
315+
throw new \Exception('Missing session metadata');
316+
}
317+
if (!$this->sessionCookie) {
318+
throw new \Exception('Missing session cookie');
319+
}
287320
$this->sessionCookie->setValue($this->sessionMetaData->sessionIdentifier->value);
288321
return $this->sessionMetaData->sessionIdentifier->value;
289322
}
@@ -297,7 +330,7 @@ public function renewId(): string
297330
*/
298331
public function getData(string $key): mixed
299332
{
300-
if ($this->started !== true) {
333+
if ($this->started !== true || !$this->sessionMetaData) {
301334
throw new Exception\SessionNotStartedException('Tried to get session data, but the session has not been started yet.', 1351162255);
302335
}
303336
return $this->sessionKeyValueStore->retrieve($this->sessionMetaData->storageIdentifier, $key);
@@ -312,7 +345,7 @@ public function getData(string $key): mixed
312345
*/
313346
public function hasKey(string $key): bool
314347
{
315-
if ($this->started !== true) {
348+
if ($this->started !== true || !$this->sessionMetaData) {
316349
throw new Exception\SessionNotStartedException('Tried to check a session data entry, but the session has not been started yet.', 1352488661);
317350
}
318351
return $this->sessionKeyValueStore->has($this->sessionMetaData->storageIdentifier, $key);
@@ -332,7 +365,7 @@ public function hasKey(string $key): bool
332365
*/
333366
public function putData(string $key, mixed $data): void
334367
{
335-
if ($this->started !== true) {
368+
if ($this->started !== true || !$this->sessionMetaData) {
336369
throw new Exception\SessionNotStartedException('Tried to create a session data entry, but the session has not been started yet.', 1351162259);
337370
}
338371
if (is_resource($data)) {
@@ -354,7 +387,7 @@ public function putData(string $key, mixed $data): void
354387
*/
355388
public function getLastActivityTimestamp(): int
356389
{
357-
if ($this->started !== true) {
390+
if ($this->started !== true || !$this->sessionMetaData) {
358391
throw new Exception\SessionNotStartedException('Tried to retrieve the last activity timestamp of a session which has not been started yet.', 1354290378);
359392
}
360393
return $this->sessionMetaData->lastActivityTimestamp;
@@ -378,9 +411,9 @@ public function addTag(string $tag): void
378411
throw new Exception\SessionNotStartedException('Tried to tag a session which has not been started yet.', 1355143533);
379412
}
380413
if (!$this->sessionMetaDataStore->isValidSessionTag($tag)) {
381-
throw new \InvalidArgumentException(sprintf('The tag used for tagging session %s contained invalid characters. Make sure it matches this regular expression: "%s"', $this->sessionMetaData->sessionIdentifier->value, FrontendInterface::PATTERN_TAG));
414+
throw new \InvalidArgumentException(sprintf('The tag used for tagging session %s contained invalid characters. Make sure it matches this regular expression: "%s"', $this->sessionMetaData?->sessionIdentifier->value ?: '', FrontendInterface::PATTERN_TAG));
382415
}
383-
$this->sessionMetaData = $this->sessionMetaData->withAddedTag($tag);
416+
$this->sessionMetaData = $this->sessionMetaData?->withAddedTag($tag);
384417
}
385418

386419
/**
@@ -396,14 +429,14 @@ public function removeTag(string $tag): void
396429
if ($this->started !== true) {
397430
throw new Exception\SessionNotStartedException('Tried to tag a session which has not been started yet.', 1355150140);
398431
}
399-
$this->sessionMetaData = $this->sessionMetaData->withRemovedTag($tag);
432+
$this->sessionMetaData = $this->sessionMetaData?->withRemovedTag($tag);
400433
}
401434

402435

403436
/**
404437
* Returns the tags this session has been tagged with.
405438
*
406-
* @return array The tags or an empty array if there aren't any
439+
* @return array<string> The tags or an empty array if there aren't any
407440
* @throws Exception\SessionNotStartedException
408441
* @api
409442
*/
@@ -412,7 +445,7 @@ public function getTags(): array
412445
if ($this->started !== true) {
413446
throw new Exception\SessionNotStartedException('Tried to retrieve tags from a session which has not been started yet.', 1355141501);
414447
}
415-
return $this->sessionMetaData->tags;
448+
return $this->sessionMetaData?->tags ?: [];
416449
}
417450

418451
/**
@@ -428,7 +461,7 @@ public function touch(): void
428461

429462
// Only makes sense for remote sessions because the currently active session
430463
// will be updated on shutdown anyway:
431-
if ($this->remote === true) {
464+
if ($this->remote === true && $this->sessionMetaData) {
432465
$this->sessionMetaData = $this->sessionMetaData->withLastActivityTimestamp($this->now);
433466
$this->writeSessionMetaDataCacheEntry();
434467
}
@@ -461,12 +494,14 @@ public function destroy(?string $reason = null): void
461494
}
462495

463496
if ($this->remote !== true) {
464-
$this->sessionCookie->expire();
497+
$this->sessionCookie?->expire();
465498
}
466499

467-
$this->sessionMetaDataStore->remove($this->sessionMetaData);
468-
$this->sessionKeyValueStore->remove($this->sessionMetaData->storageIdentifier);
469-
$this->sessionMetaData = null;
500+
if ($this->sessionMetaData) {
501+
$this->sessionMetaDataStore->remove($this->sessionMetaData);
502+
$this->sessionKeyValueStore->remove($this->sessionMetaData->storageIdentifier);
503+
$this->sessionMetaData = null;
504+
}
470505
$this->started = false;
471506
}
472507

@@ -482,8 +517,12 @@ public function destroy(?string $reason = null): void
482517
public function shutdownObject(): void
483518
{
484519
if ($this->started === true && $this->remote === false) {
485-
if ($this->sessionMetaDataStore->has($this->sessionMetaData->sessionIdentifier)) {
486-
$this->sessionKeyValueStore->store($this->sessionMetaData->storageIdentifier, self::FLOW_OBJECT_STORAGE_KEY, $this->objectManager->getSessionInstances() ?? []);
520+
if ($this->sessionMetaData && $this->sessionMetaDataStore->has($this->sessionMetaData->sessionIdentifier)) {
521+
$this->sessionKeyValueStore->store(
522+
$this->sessionMetaData->storageIdentifier,
523+
self::FLOW_OBJECT_STORAGE_KEY,
524+
$this->objectManager->getSessionInstances()
525+
);
487526
$this->writeSessionMetaDataCacheEntry();
488527
}
489528
$this->started = false;
@@ -497,11 +536,11 @@ public function shutdownObject(): void
497536
*/
498537
protected function autoExpire(): bool
499538
{
500-
$lastActivitySecondsAgo = $this->now - $this->sessionMetaData->lastActivityTimestamp;
539+
$lastActivitySecondsAgo = $this->now - ($this->sessionMetaData?->lastActivityTimestamp ?: 0);
501540
$expired = false;
502541
if ($this->inactivityTimeout !== 0 && $lastActivitySecondsAgo > $this->inactivityTimeout) {
503542
$this->started = true;
504-
$this->destroy(sprintf('Session %s was inactive for %s seconds, more than the configured timeout of %s seconds.', $this->sessionMetaData->sessionIdentifier->value, $lastActivitySecondsAgo, $this->inactivityTimeout));
543+
$this->destroy(sprintf('Session %s was inactive for %s seconds, more than the configured timeout of %s seconds.', $this->sessionMetaData?->sessionIdentifier->value ?: '', $lastActivitySecondsAgo, $this->inactivityTimeout));
505544
$expired = true;
506545
}
507546
return $expired;
@@ -521,6 +560,8 @@ protected function autoExpire(): bool
521560
*/
522561
protected function writeSessionMetaDataCacheEntry(): void
523562
{
524-
$this->sessionMetaDataStore->store($this->sessionMetaData);
563+
if ($this->sessionMetaData) {
564+
$this->sessionMetaDataStore->store($this->sessionMetaData);
565+
}
525566
}
526567
}

Neos.Flow/Classes/Session/SessionInterface.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ public function removeTag(string $tag): void;
107107
/**
108108
* Returns the tags this session has been tagged with.
109109
*
110-
* @return array The tags or an empty array if there aren't any
110+
* @return array<string> The tags or an empty array if there aren't any
111111
* @throws Exception\SessionNotStartedException
112112
* @api
113113
*/

0 commit comments

Comments
 (0)