Skip to content
This repository was archived by the owner on May 23, 2024. It is now read-only.

Commit 5d02dcb

Browse files
authored
Merge pull request #59 from olegatro/relative-links
add allow_relative_links setting
2 parents 10adad2 + f4e7747 commit 5d02dcb

10 files changed

Lines changed: 129 additions & 11 deletions

File tree

docs/1-getting-started.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,11 @@ $sanitizer = HtmlSanitizer\Sanitizer::create([
9393
* If true, mailto links will be accepted.
9494
*/
9595
'allow_mailto' => false,
96+
97+
/*
98+
* If true, relative links will be accepted.
99+
*/
100+
'allow_relative_links' => false,
96101
],
97102

98103
'img' => [
@@ -111,6 +116,11 @@ $sanitizer = HtmlSanitizer\Sanitizer::create([
111116
* If true, images data-uri URLs will be accepted.
112117
*/
113118
'allow_data_uri' => false,
119+
120+
/*
121+
* If true, relative links will be accepted.
122+
*/
123+
'allow_relative_links' => false,
114124
],
115125

116126
'iframe' => [
@@ -124,6 +134,11 @@ $sanitizer = HtmlSanitizer\Sanitizer::create([
124134
* 'allowed_hosts' => ['trusted1.com', 'google.com'],
125135
*/
126136
'allowed_hosts' => null,
137+
138+
/*
139+
* If true, relative links will be accepted.
140+
*/
141+
'allow_relative_links' => false,
127142
],
128143
],
129144
]);

src/Extension/Basic/NodeVisitor/ANodeVisitor.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ public function __construct(array $config = [])
4141
$this->config['allowed_schemes'],
4242
$this->config['allowed_hosts'],
4343
$this->config['allow_mailto'],
44+
$this->config['allow_relative_links'],
4445
$this->config['force_https']
4546
);
4647
}
@@ -61,6 +62,7 @@ public function getDefaultConfiguration(): array
6162
'allowed_schemes' => ['http', 'https'],
6263
'allowed_hosts' => null,
6364
'allow_mailto' => true,
65+
'allow_relative_links' => false,
6466
'force_https' => false,
6567
'rel' => null,
6668
];

src/Extension/Basic/Sanitizer/AHrefSanitizer.php

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,15 @@ class AHrefSanitizer
2323
private $allowedSchemes;
2424
private $allowedHosts;
2525
private $allowMailTo;
26+
private $allowRelativeLinks;
2627
private $forceHttps;
2728

28-
public function __construct(array $allowedSchemes, ?array $allowedHosts, bool $allowMailTo, bool $forceHttps)
29+
public function __construct(array $allowedSchemes, ?array $allowedHosts, bool $allowMailTo, bool $allowRelativeLinks, bool $forceHttps)
2930
{
3031
$this->allowedSchemes = $allowedSchemes;
3132
$this->allowedHosts = $allowedHosts;
3233
$this->allowMailTo = $allowMailTo;
34+
$this->allowRelativeLinks = $allowRelativeLinks;
3335
$this->forceHttps = $forceHttps;
3436
}
3537

@@ -46,6 +48,14 @@ public function sanitize(?string $input): ?string
4648
}
4749
}
4850

51+
if ($this->allowRelativeLinks) {
52+
$allowedSchemes[] = null;
53+
54+
if (\is_array($this->allowedHosts)) {
55+
$allowedHosts[] = null;
56+
}
57+
}
58+
4959
if (!$sanitized = $this->sanitizeUrl($input, $allowedSchemes, $allowedHosts, $this->forceHttps)) {
5060
return null;
5161
}

src/Extension/Iframe/NodeVisitor/IframeNodeVisitor.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ public function __construct(array $config = [])
4040
$this->sanitizer = new IframeSrcSanitizer(
4141
$this->config['allowed_schemes'],
4242
$this->config['allowed_hosts'],
43+
$this->config['allow_relative_links'],
4344
$this->config['force_https']
4445
);
4546
}
@@ -64,6 +65,7 @@ public function getDefaultConfiguration(): array
6465
return [
6566
'allowed_schemes' => ['http', 'https'],
6667
'allowed_hosts' => null,
68+
'allow_relative_links' => false,
6769
'force_https' => false,
6870
];
6971
}

src/Extension/Iframe/Sanitizer/IframeSrcSanitizer.php

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,30 @@ class IframeSrcSanitizer
2222

2323
private $allowedSchemes;
2424
private $allowedHosts;
25+
private $allowRelativeLinks;
2526
private $forceHttps;
2627

27-
public function __construct(array $allowedSchemes, ?array $allowedHosts, bool $forceHttps)
28+
public function __construct(array $allowedSchemes, ?array $allowedHosts, bool $allowRelativeLinks, bool $forceHttps)
2829
{
2930
$this->allowedSchemes = $allowedSchemes;
3031
$this->allowedHosts = $allowedHosts;
32+
$this->allowRelativeLinks = $allowRelativeLinks;
3133
$this->forceHttps = $forceHttps;
3234
}
3335

3436
public function sanitize(?string $input): ?string
3537
{
36-
return $this->sanitizeUrl($input, $this->allowedSchemes, $this->allowedHosts, $this->forceHttps);
38+
$allowedSchemes = $this->allowedSchemes;
39+
$allowedHosts = $this->allowedHosts;
40+
41+
if ($this->allowRelativeLinks) {
42+
$allowedSchemes[] = null;
43+
44+
if (\is_array($this->allowedHosts)) {
45+
$allowedHosts[] = null;
46+
}
47+
}
48+
49+
return $this->sanitizeUrl($input, $allowedSchemes, $allowedHosts, $this->forceHttps);
3750
}
3851
}

src/Extension/Image/NodeVisitor/ImgNodeVisitor.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ public function __construct(array $config = [])
4141
$this->config['allowed_schemes'],
4242
$this->config['allowed_hosts'],
4343
$this->config['allow_data_uri'],
44+
$this->config['allow_relative_links'],
4445
$this->config['force_https']
4546
);
4647
}
@@ -61,6 +62,7 @@ public function getDefaultConfiguration(): array
6162
'allowed_schemes' => ['http', 'https'],
6263
'allowed_hosts' => null,
6364
'allow_data_uri' => false,
65+
'allow_relative_links' => false,
6466
'force_https' => false,
6567
];
6668
}

src/Extension/Image/Sanitizer/ImgSrcSanitizer.php

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,15 @@ class ImgSrcSanitizer
2323
private $allowedSchemes;
2424
private $allowedHosts;
2525
private $allowDataUri;
26+
private $allowRelativeLinks;
2627
private $forceHttps;
2728

28-
public function __construct(array $allowedSchemes, ?array $allowedHosts, bool $allowDataUri, bool $forceHttps)
29+
public function __construct(array $allowedSchemes, ?array $allowedHosts, bool $allowDataUri, bool $allowRelativeLinks, bool $forceHttps)
2930
{
3031
$this->allowedSchemes = $allowedSchemes;
3132
$this->allowedHosts = $allowedHosts;
3233
$this->allowDataUri = $allowDataUri;
34+
$this->allowRelativeLinks = $allowRelativeLinks;
3335
$this->forceHttps = $forceHttps;
3436
}
3537

@@ -38,13 +40,20 @@ public function sanitize(?string $input): ?string
3840
$allowedSchemes = $this->allowedSchemes;
3941
$allowedHosts = $this->allowedHosts;
4042

41-
if ($this->allowDataUri) {
43+
if ($this->allowDataUri && !$this->allowRelativeLinks) {
4244
$allowedSchemes[] = 'data';
4345
if (null !== $allowedHosts) {
4446
$allowedHosts[] = null;
4547
}
4648
}
4749

50+
if ($this->allowRelativeLinks) {
51+
$allowedSchemes[] = null;
52+
if (null !== $allowedHosts) {
53+
$allowedHosts[] = null;
54+
}
55+
}
56+
4857
if (!$sanitized = $this->sanitizeUrl($input, $allowedSchemes, $allowedHosts, $this->forceHttps)) {
4958
return null;
5059
}

tests/Sanitizer/AHrefSanitizerTest.php

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ public function provideUrls()
2323
'allowedSchemes' => ['http', 'https'],
2424
'allowedHosts' => null,
2525
'allowMailTo' => false,
26+
'allowRelativeLinks' => false,
2627
'forceHttps' => false,
2728
'input' => 'https://trusted.com/link.php',
2829
'output' => 'https://trusted.com/link.php',
@@ -32,6 +33,7 @@ public function provideUrls()
3233
'allowedSchemes' => ['http', 'https'],
3334
'allowedHosts' => ['trusted.com'],
3435
'allowMailTo' => false,
36+
'allowRelativeLinks' => false,
3537
'forceHttps' => false,
3638
'input' => 'https://trusted.com/link.php',
3739
'output' => 'https://trusted.com/link.php',
@@ -41,6 +43,7 @@ public function provideUrls()
4143
'allowedSchemes' => ['http', 'https'],
4244
'allowedHosts' => ['trusted.com'],
4345
'allowMailTo' => false,
46+
'allowRelativeLinks' => false,
4447
'forceHttps' => false,
4548
'input' => 'https://untrusted.com/link.php',
4649
'output' => null,
@@ -50,6 +53,7 @@ public function provideUrls()
5053
'allowedSchemes' => ['http', 'https'],
5154
'allowedHosts' => null,
5255
'allowMailTo' => false,
56+
'allowRelativeLinks' => false,
5357
'forceHttps' => false,
5458
'input' => '/link.php',
5559
'output' => null,
@@ -59,16 +63,28 @@ public function provideUrls()
5963
'allowedSchemes' => ['http', 'https'],
6064
'allowedHosts' => null,
6165
'allowMailTo' => true,
66+
'allowRelativeLinks' => false,
6267
'forceHttps' => false,
6368
'input' => '/link.php',
6469
'output' => null,
6570
];
6671

72+
yield [
73+
'allowedSchemes' => ['http', 'https'],
74+
'allowedHosts' => null,
75+
'allowMailTo' => true,
76+
'allowRelativeLinks' => true,
77+
'forceHttps' => false,
78+
'input' => '/link.php',
79+
'output' => '/link.php',
80+
];
81+
6782
// Force HTTPS
6883
yield [
6984
'allowedSchemes' => ['http', 'https'],
7085
'allowedHosts' => ['trusted.com'],
7186
'allowMailTo' => false,
87+
'allowRelativeLinks' => false,
7288
'forceHttps' => true,
7389
'input' => 'http://trusted.com/link.php',
7490
'output' => 'https://trusted.com/link.php',
@@ -79,6 +95,7 @@ public function provideUrls()
7995
'allowedSchemes' => ['http', 'https'],
8096
'allowedHosts' => null,
8197
'allowMailTo' => true,
98+
'allowRelativeLinks' => false,
8299
'forceHttps' => false,
83100
'input' => 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7',
84101
'output' => null,
@@ -88,6 +105,7 @@ public function provideUrls()
88105
'allowedSchemes' => ['http', 'https'],
89106
'allowedHosts' => null,
90107
'allowMailTo' => true,
108+
'allowRelativeLinks' => false,
91109
'forceHttps' => true,
92110
'input' => 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7',
93111
'output' => null,
@@ -98,6 +116,7 @@ public function provideUrls()
98116
'allowedSchemes' => ['http', 'https'],
99117
'allowedHosts' => null,
100118
'allowMailTo' => false,
119+
'allowRelativeLinks' => false,
101120
'forceHttps' => false,
102121
'input' => 'mailto:test@gmail.com',
103122
'output' => null,
@@ -107,6 +126,7 @@ public function provideUrls()
107126
'allowedSchemes' => ['http', 'https'],
108127
'allowedHosts' => null,
109128
'allowMailTo' => true,
129+
'allowRelativeLinks' => false,
110130
'forceHttps' => false,
111131
'input' => 'mailto:test@gmail.com',
112132
'output' => 'mailto:test@gmail.com',
@@ -116,6 +136,7 @@ public function provideUrls()
116136
'allowedSchemes' => ['http', 'https'],
117137
'allowedHosts' => ['trusted.com'],
118138
'allowMailTo' => true,
139+
'allowRelativeLinks' => false,
119140
'forceHttps' => false,
120141
'input' => 'mailto:test@gmail.com',
121142
'output' => 'mailto:test@gmail.com',
@@ -125,6 +146,7 @@ public function provideUrls()
125146
'allowedSchemes' => ['http', 'https'],
126147
'allowedHosts' => ['trusted.com'],
127148
'allowMailTo' => true,
149+
'allowRelativeLinks' => false,
128150
'forceHttps' => true,
129151
'input' => 'mailto:test@gmail.com',
130152
'output' => 'mailto:test@gmail.com',
@@ -134,6 +156,7 @@ public function provideUrls()
134156
'allowedSchemes' => ['http', 'https'],
135157
'allowedHosts' => null,
136158
'allowMailTo' => true,
159+
'allowRelativeLinks' => false,
137160
'forceHttps' => false,
138161
'input' => 'mailto:invalid',
139162
'output' => null,
@@ -143,6 +166,7 @@ public function provideUrls()
143166
'allowedSchemes' => ['http', 'https'],
144167
'allowedHosts' => null,
145168
'allowMailTo' => true,
169+
'allowRelativeLinks' => false,
146170
'forceHttps' => false,
147171
'input' => 'mailto:',
148172
'output' => null,
@@ -152,6 +176,7 @@ public function provideUrls()
152176
'allowedSchemes' => ['https'],
153177
'allowedHosts' => null,
154178
'allowMailTo' => true,
179+
'allowRelativeLinks' => false,
155180
'forceHttps' => false,
156181
'input' => 'http://trusted.com/link.php',
157182
'output' => null,
@@ -161,8 +186,8 @@ public function provideUrls()
161186
/**
162187
* @dataProvider provideUrls
163188
*/
164-
public function testSanitize($allowedSchemes, $allowedHosts, $allowMailTo, $forceHttps, $input, $expected)
189+
public function testSanitize($allowedSchemes, $allowedHosts, $allowMailTo, $allowRelativeLinks, $forceHttps, $input, $expected)
165190
{
166-
$this->assertSame($expected, (new AHrefSanitizer($allowedSchemes, $allowedHosts, $allowMailTo, $forceHttps))->sanitize($input));
191+
$this->assertSame($expected, (new AHrefSanitizer($allowedSchemes, $allowedHosts, $allowMailTo, $allowRelativeLinks, $forceHttps))->sanitize($input));
167192
}
168193
}

0 commit comments

Comments
 (0)