Skip to content

Refactor user agent validator - #145

Merged
arhimede merged 7 commits into
laminas:3.0.xfrom
SergiuBota1:refactor-user-agent-validator
Aug 7, 2025
Merged

Refactor user agent validator#145
arhimede merged 7 commits into
laminas:3.0.xfrom
SergiuBota1:refactor-user-agent-validator

Conversation

@SergiuBota1

Copy link
Copy Markdown
Contributor
Q A
BC Break yes
New Feature yes
RFC no

Description

Pull request based on #133
I closed the previous pull request #136 and opened this one to keep it clean (and a failed rebase). Based on what was discussed I replaced the use of the super-global variable with an object populated from outside.

Do we want the properties in the object to be mutable?
Based on @gsteel comment should we no longer allow $data to be null?

Comment thread src/Validator/EnvironmentValueObject.php Outdated
Comment thread src/Validator/HttpUserAgent.php Outdated
Comment thread src/Validator/EnvironmentValueObject.php Outdated
Comment thread src/Validator/EnvironmentValueObject.php Outdated
@SergiuBota1

Copy link
Copy Markdown
Contributor Author

Uploaded an initial commit removing the getData() method - it was used and in ValidatorChain.php. Removing will require updating the other validators as well.
I'm aware of the failing test but i have questions related to this use case

Should the data still be attached to the storage metadata going forward?

@SergiuBota1
SergiuBota1 requested a review from gsteel May 20, 2025 09:06
Comment thread src/Validator/HttpUserAgent.php
Comment thread test/Validator/IdTest.php Outdated
Comment thread src/ValidatorChain.php Outdated
@SergiuBota1
SergiuBota1 force-pushed the refactor-user-agent-validator branch from e59a027 to ecaea56 Compare June 2, 2025 08:52
@SergiuBota1
SergiuBota1 requested a review from gsteel June 2, 2025 08:57
Comment thread src/Validator/HttpUserAgent.php Outdated
@arhimede
arhimede requested a review from gsteel June 9, 2025 09:12
Comment thread src/SessionManager.php Outdated
Comment on lines +191 to +196
if ($data !== null) {
/** @var Environment $currentEnvironment */
$currentEnvironment = unserialize($data);
} else {
$currentEnvironment = Environment::fromGlobals($_SERVER);
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This block should just be replaced with $currentEnvironment = Environment::fromGlobals($_SERVER);

We are initialising new validators and we should only care what the environment is right now, not any kind of stale or already serialised data

Comment thread src/Validator/Environment.php Outdated
Comment on lines +40 to +37
public static function getServerOption(string $name, ?array $superglobal = null): mixed
{
if ($superglobal === null) {
$superglobal = $_SERVER;
}

return $superglobal[$name] ?? null;
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this method here?

I cannot see any use case for this. This value object should be a wrapper around common environment related/request variables so that we have a predictable API for retrieving the data, therefore any/all data retrieval should be via public properties.

Comment thread src/Validator/Environment.php Outdated
Comment on lines +31 to +33
if ($remoteAddr === null || (isset($options['use_proxy']) && $options['use_proxy'])) {
$remoteAddr = RemoteAddr::getIpAddress($options, $remoteAddr);
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Accessing static methods on a validator here is the wrong thing to do - you are making this value object dependent on the validator - RemoteAddr needs the X-ForwardedFor, maybe X-ForwardedProto or whatever - these should be made public properties and simply copied from the given array.

Suggested change
if ($remoteAddr === null || (isset($options['use_proxy']) && $options['use_proxy'])) {
$remoteAddr = RemoteAddr::getIpAddress($options, $remoteAddr);
}
$forwardedFor = isset($server['X_FORWARDED_FOR']) && is_string($server['X_FORWARDED_FOR'])
? $server['X_FORWARDED_FOR']
: null;

The $options argument should also be dropped

Comment thread src/ValidatorChain.php Outdated
Comment on lines +23 to +35
$validators = $storage->getMetadata('_VALID');
$environment = (string) $storage->getMetadata('environment');
if ($validators) {
/**
* @var class-string<ValidatorInterface> $validator
*/
foreach ($validators as $validator => $data) {
$this->attachValidator('session.validate', [new $validator($data), 'isValid'], 1);
$currentEnvironment = $data instanceof Environment ? $data : Environment::fromGlobals($_SERVER);
$this->attachValidator(
'session.validate',
[new $validator(unserialize($environment), $currentEnvironment), 'isValid'],
1
);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct me if I am wrong, but it looks to me like all of this work is already done in SessionManager. Why repeat it?

Comment thread src/ValidatorChain.php
@@ -69,11 +81,9 @@ private function attachValidator($event, $callback, $priority)
array_unshift($callback, $test);
}
if ($context instanceof ValidatorInterface) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because the validator chain is specific to this lib, why not change this method signature to attachValidator(Event $event, ValidatorInterface $validator, int $priority) for better type inference? (Possibly better in another patch)

Comment thread src/ValidatorChain.php Outdated
$data = $context->getData();
$name = $context->getName();
$this->getStorage()->setMetadata('_VALID', [$name => $data]);
$this->getStorage()->setMetadata('_VALID', [$name => serialize($context->current)]);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you check - does setMetadata merge or replace data? If it's a replace operation (which its name suggests) then there could only ever be 1 validator in a re-constituted chain.

I don't really understand why the validators are persisted to metadata at all, as they are constructed inside SessionManager from a list of configuration items right?

Comment thread src/Validator/Id.php Outdated
public function getData(): ?string
{
return $this->id;
return (bool) preg_match($pattern, $this->initial->sessionId);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Surely you'd want to validate the "current" session id?

@SergiuBota1

Copy link
Copy Markdown
Contributor Author

Based on this comment i've change de flow to only allow attaching validators via config file, the benefit of this is allowing to drop the unused $data in the attach method of ValidatorChain. Also removed test cases using that function.

I don't really understand why the validators are persisted to metadata at all, as they are constructed inside SessionManager from a list of configuration items right?

However the old version allowed users to manually attach validators in other places during the request, if i understand correctly this should no longer be the case, correct?

@arhimede
arhimede requested a review from gsteel June 19, 2025 09:48
@arhimede

Copy link
Copy Markdown
Member

@alexmerlin Can you too review this one ? We are a bit behind with this package

@alexmerlin

Copy link
Copy Markdown
Member

@SergiuBota1 Let's keep things straightforward and allow adding validators only via the configs.
If one would like to add a new validator at runtime (less likely to be needed), they should create a new instance of the validator chain.

Signed-off-by: bota <Bota@dotkernel.com>
Signed-off-by: bota <Bota@dotkernel.com>
Signed-off-by: bota <Bota@dotkernel.com>
Signed-off-by: bota <Bota@dotkernel.com>
Signed-off-by: bota <Bota@dotkernel.com>
Signed-off-by: bota <Bota@dotkernel.com>
Signed-off-by: bota <Bota@dotkernel.com>
@Jurj-Bogdan
Jurj-Bogdan force-pushed the refactor-user-agent-validator branch from 65542d5 to b16cc9f Compare July 31, 2025 14:14
@Jurj-Bogdan

Copy link
Copy Markdown
Contributor

@SergiuBota1 Let's keep things straightforward and allow adding validators only via the configs.

Unless I'm mistaken this seems to be the case in the current version of this PR
For now i've only updated the branch to match current 3.0.x

@arhimede

arhimede commented Aug 6, 2025

Copy link
Copy Markdown
Member

@gsteel I am about to merge this PR , we are quite late with this :-)

@arhimede

arhimede commented Aug 7, 2025

Copy link
Copy Markdown
Member

@SergiuBota1 LGTM

@arhimede
arhimede merged commit 7e9cb7f into laminas:3.0.x Aug 7, 2025
13 of 14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants