Skip to content

Commit 7e42d27

Browse files
committed
Improve PublicSuffix validation in the Domain object
1 parent 8489bd2 commit 7e42d27

File tree

4 files changed

+63
-78
lines changed

4 files changed

+63
-78
lines changed

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
"require": {
3737
"php": ">=7.0",
3838
"ext-intl": "*",
39-
"psr/simple-cache": "^1"
39+
"psr/simple-cache": "^1.0.1"
4040
},
4141
"require-dev": {
4242
"composer/composer": "^1.6",

phpstan.src.neon

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,2 @@
11
includes:
2-
- vendor/phpstan/phpstan-strict-rules/rules.neon
3-
parameters:
4-
ignoreErrors:
5-
- '#has invalid typehint type Psr\\SimpleCache\\DateInterval#'
6-
reportUnmatchedIgnoredErrors: false
2+
- vendor/phpstan/phpstan-strict-rules/rules.neon

src/Domain.php

Lines changed: 26 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -73,44 +73,47 @@ public static function __set_state(array $properties): self
7373
public function __construct(string $domain = null, PublicSuffix $publicSuffix = null)
7474
{
7575
list($this->domain, $this->labels) = $this->setDomain($domain);
76-
$this->publicSuffix = $this->setPublicSuffix($publicSuffix);
77-
$this->assertValidState();
76+
$this->publicSuffix = $this->setPublicSuffix($publicSuffix ?? new PublicSuffix());
7877
$this->registrableDomain = $this->setRegistrableDomain();
7978
$this->subDomain = $this->setSubDomain();
8079
}
8180

8281
/**
8382
* Sets the public suffix domain part.
8483
*
85-
* @param PublicSuffix|null $publicSuffix
84+
* @param PublicSuffix $publicSuffix
85+
*
86+
* @throws Exception If the domain can not contain a public suffix
87+
* @throws Exception If the domain value is the same as the public suffix value
88+
* @throws Exception If the domain can not be match with the public suffix
8689
*
8790
* @return PublicSuffix
8891
*/
89-
private function setPublicSuffix(PublicSuffix $publicSuffix = null): PublicSuffix
92+
private function setPublicSuffix(PublicSuffix $publicSuffix): PublicSuffix
9093
{
91-
if (null === $publicSuffix
92-
|| null === $this->domain
93-
|| false === strpos($this->domain, '.')
94-
|| count($this->labels) === count($publicSuffix)
95-
) {
94+
if (null === $publicSuffix->getContent()) {
9695
return new PublicSuffix();
9796
}
9897

99-
return $publicSuffix;
100-
}
98+
if (null === $this->domain || false === strpos($this->domain, '.')) {
99+
throw new Exception(sprintf('The domain `%s` can not contain a public suffix', $this->domain));
100+
}
101101

102-
/**
103-
* assert the domain internal state is valid
104-
*
105-
* @throws Exception if the public suffix does not match the domain
106-
*/
107-
protected function assertValidState()
108-
{
109-
foreach ($this->publicSuffix as $offset => $label) {
110-
if ($label !== $this->labels[$offset]) {
111-
throw new Exception(sprintf('The public suffix `%s` is invalid for the domain `%s`', $this->publicSuffix->getContent(), $this->domain));
112-
}
102+
static $pattern = '/[^\x20-\x7f]/';
103+
if (preg_match($pattern, $this->domain)) {
104+
$publicSuffix = $publicSuffix->toUnicode();
105+
}
106+
107+
$publicSuffixContent = $publicSuffix->getContent();
108+
if ($this->domain === $publicSuffixContent) {
109+
throw new Exception(sprintf('The public suffix `%s` can not be equal to the domain name `%s`', $publicSuffixContent, $this->domain));
110+
}
111+
112+
if ('.'.$publicSuffixContent !== substr($this->domain, - strlen($publicSuffixContent) - 1)) {
113+
throw new Exception(sprintf('The public suffix `%s` can not be assign to the domain name `%s`', $publicSuffixContent, $this->domain));
113114
}
115+
116+
return $publicSuffix;
114117
}
115118

116119
/**
@@ -350,9 +353,6 @@ public function toUnicode()
350353
*
351354
* @param PublicSuffix $publicSuffix
352355
*
353-
* @throws Exception if the domain can not contain a public suffix
354-
* @throws Exception if the public suffix can not be assign to the domain name
355-
*
356356
* @return self
357357
*/
358358
public function withPublicSuffix(PublicSuffix $publicSuffix): self
@@ -361,31 +361,8 @@ public function withPublicSuffix(PublicSuffix $publicSuffix): self
361361
return $this;
362362
}
363363

364-
if (null === $publicSuffix->getContent()) {
365-
$clone = clone $this;
366-
$clone->publicSuffix = $publicSuffix;
367-
$clone->registrableDomain = $clone->setRegistrableDomain();
368-
$clone->subDomain = $clone->setSubDomain();
369-
370-
return $clone;
371-
}
372-
373-
if (null === $this->domain || false === strpos($this->domain, '.')) {
374-
throw new Exception(sprintf('The domain `%s` can not contain a public suffix', $this->domain));
375-
}
376-
377-
static $pattern = '/[^\x20-\x7f]/';
378-
if (preg_match($pattern, $this->domain)) {
379-
$publicSuffix = $publicSuffix->toUnicode();
380-
}
381-
382-
$publicSuffixContent = $publicSuffix->getContent();
383-
if ($this->domain === $publicSuffixContent || '.'.$publicSuffixContent !== substr($this->domain, - strlen($publicSuffixContent) - 1)) {
384-
throw new Exception(sprintf('the public suffix `%s` can not be assign to the domain name `%s`', $publicSuffixContent, $this->domain));
385-
}
386-
387364
$clone = clone $this;
388-
$clone->publicSuffix = $publicSuffix;
365+
$clone->publicSuffix = $clone->setPublicSuffix($publicSuffix);
389366
$clone->registrableDomain = $clone->setRegistrableDomain();
390367
$clone->subDomain = $clone->setSubDomain();
391368

tests/DomainTest.php

Lines changed: 35 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -16,46 +16,56 @@
1616
class DomainTest extends TestCase
1717
{
1818
/**
19-
* @dataProvider invalidRegistrableDomainProvider
20-
*
21-
* @param string|null $domain
22-
* @param string|null $publicSuffix
23-
*
2419
* @covers ::__construct
2520
* @covers ::setPublicSuffix
2621
* @covers ::setRegistrableDomain
2722
* @covers ::setSubDomain
28-
* @covers ::assertValidState
2923
* @covers ::getPublicSuffix
3024
* @covers ::getRegistrableDomain
3125
* @covers ::getSubDomain
3226
*/
33-
public function testRegistrableDomainIsNullWithFoundDomain($domain, $publicSuffix)
27+
public function testRegistrableDomainIsNullWithFoundDomain()
3428
{
35-
$domain = new Domain($domain, new PublicSuffix($publicSuffix));
29+
$domain = new Domain('faketld', null);
3630
$this->assertNull($domain->getPublicSuffix());
3731
$this->assertNull($domain->getRegistrableDomain());
3832
$this->assertNull($domain->getSubDomain());
3933
}
4034

41-
public function invalidRegistrableDomainProvider()
42-
{
43-
return [
44-
'domain and suffix are the same' => ['co.uk', 'co.uk'],
45-
'domain has no labels' => ['faketld', 'faketld'],
46-
'public suffix is null' => ['faketld', null],
47-
'domain is null' => [null, 'faketld'],
48-
];
49-
}
50-
5135
/**
5236
* @covers ::__construct
53-
* @covers ::assertValidState
37+
* @covers ::setPublicSuffix
38+
*
39+
* @dataProvider provideWrongConstructor
40+
* @param mixed $domain
41+
* @param mixed $publicSuffix
5442
*/
55-
public function testConstructorThrowsExceptionOnMisMatchPublicSuffixDomain()
43+
public function testConstructorThrowsExceptionOnMisMatchPublicSuffixDomain($domain, $publicSuffix)
5644
{
5745
$this->expectException(Exception::class);
58-
new Domain('www.ulb.ac.be', new PublicSuffix('com'));
46+
new Domain($domain, new PublicSuffix($publicSuffix));
47+
}
48+
49+
public function provideWrongConstructor()
50+
{
51+
return [
52+
'public suffix mismatch' => [
53+
'domain' => 'www.ulb.ac.be',
54+
'publicSuffix' => 'com',
55+
],
56+
'domain and public suffix are the same' => [
57+
'domain' => 'co.uk',
58+
'publicSuffix' => 'co.uk',
59+
],
60+
'domain has no labels' => [
61+
'domain' => 'localhost',
62+
'publicSuffix' => 'localhost',
63+
],
64+
'domain is null' => [
65+
'domain' => null,
66+
'publicSuffix' => 'com',
67+
],
68+
];
5969
}
6070

6171
/**
@@ -159,7 +169,6 @@ public function testOffsets()
159169
*
160170
* @covers ::setDomain
161171
* @covers ::setPublicSuffix
162-
* @covers ::assertValidState
163172
* @covers ::setRegistrableDomain
164173
* @covers ::setSubDomain
165174
* @covers ::getDomain
@@ -259,7 +268,6 @@ public function toUnicodeProvider()
259268
*
260269
* @covers ::setDomain
261270
* @covers ::setPublicSuffix
262-
* @covers ::assertValidState
263271
* @covers ::setRegistrableDomain
264272
* @covers ::setSubDomain
265273
* @covers ::getDomain
@@ -414,6 +422,10 @@ public function withPublicSuffixFailsProvider()
414422
'domain' => $domain,
415423
'public suffix' => new PublicSuffix('c.be'),
416424
],
425+
'mismatch idn public suffix' => [
426+
'domain' => new Domain('www.食狮.公司.cn'),
427+
'public suffix' => new PublicSuffix('cn.公司'),
428+
],
417429
];
418430
}
419431

0 commit comments

Comments
 (0)