Skip to content

Mark external links as unsafe #81

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 19, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions src/Renderers/SpanNodeRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ public function link(?string $url, string $title, array $attributes = []): strin
$this->urlChecker->checkUrl($url);
}

if (!$this->isSafeUrl($url)) {
$attributes['rel'] = 'external noopener noreferrer';
$attributes['target'] = '_blank';
}

return $this->templateRenderer->render(
'link.html.twig',
[
Expand Down Expand Up @@ -80,4 +85,20 @@ private function isExternalUrl($url): bool
{
return u($url)->containsAny('://');
}

/*
* If the URL is considered safe, it's opened in the same browser tab;
* otherwise it's opened in a new tab and with some strict security options.
*/
private function isSafeUrl(string $url): bool
{
// The following are considered Symfony URLs:
// * https://symfony.com/[...]
// * https://[...].symfony.com/ (e.g. insight.symfony.com, etc.)
// * https://symfony.wip/[...] (used for internal/local development)
$isSymfonyUrl = preg_match('{^http(s)?://(.*\.)?symfony.(com|wip)}', $url);
$isRelativeUrl = !str_starts_with($url, 'http://') && !str_starts_with($url, 'https://');

return $isSymfonyUrl || $isRelativeUrl;
}
}
6 changes: 3 additions & 3 deletions tests/fixtures/expected/blocks/references/php-class.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
<head>
<meta charset="utf-8" />


</head>

<body>
<p><a href="https://secure.php.net/manual/en/class.arrayaccess.php" class="reference external" title="ArrayAccess">ArrayAccess</a></p>
<p><a href="https://secure.php.net/manual/en/class.arrayaccess.php" class="reference external" title="ArrayAccess" rel="external noopener noreferrer" target="_blank">ArrayAccess</a></p>

</body>
</html>
</html>
6 changes: 3 additions & 3 deletions tests/fixtures/expected/blocks/references/php-function.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
<head>
<meta charset="utf-8" />


</head>

<body>
<p><a href="https://secure.php.net/manual/en/function.trigger-error.php" class="reference external" title="trigger_error">trigger_error</a></p>
<p><a href="https://secure.php.net/manual/en/function.trigger-error.php" class="reference external" title="trigger_error" rel="external noopener noreferrer" target="_blank">trigger_error</a></p>

</body>
</html>
</html>
6 changes: 3 additions & 3 deletions tests/fixtures/expected/blocks/references/php-method.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
<head>
<meta charset="utf-8" />


</head>

<body>
<p><a href="https://secure.php.net/manual/en/locale.getdefault.php" class="reference external" title="Locale">Locale::getDefault()</a></p>
<p><a href="https://secure.php.net/manual/en/locale.getdefault.php" class="reference external" title="Locale" rel="external noopener noreferrer" target="_blank">Locale::getDefault()</a></p>

</body>
</html>
</html>
14 changes: 7 additions & 7 deletions tests/fixtures/expected/main/datetime.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<head>
<meta charset="utf-8" />


</head>

<body>
Expand All @@ -12,7 +12,7 @@ <h1 id="datetimetype-field"><a class="headerlink" href="#datetimetype-field" tit
<p>This field type allows the user to modify data that represents a specific
date and time (e.g. <code translate="no" class="notranslate">1984-06-05 12:15:30</code>).</p>
<table>

<tbody>
<tr>
<td>Underlying Data Type</td>
Expand Down Expand Up @@ -67,8 +67,8 @@ <h3 id="the-date-format-option"><a class="headerlink" href="#the-date-format-opt
</p><p>This is a little tip about something! We an also talk about specific
methods: <a href="https://api.symfony.com/4.0/Symfony/Component/BrowserKit/Client.html#method_doRequest" class="reference external" title="Symfony\Component\BrowserKit\Client::doRequest()">doRequest()</a>.
Or a namespace: <a href="https://api.symfony.com/4.0/Symfony/Component/Validator/Constraints.html" class="reference external" title="Symfony\Component\Validator\Constraints">Constraints</a>.
Or a PHP function: <a href="https://secure.php.net/manual/en/function.parse-ini-file.php" class="reference external" title="parse_ini_file">parse_ini_file</a>.
Or a PHP method! <a href="https://secure.php.net/manual/en/locale.getdefault.php" class="reference external" title="Locale">Locale::getDefault()</a>.</p>
Or a PHP function: <a href="https://secure.php.net/manual/en/function.parse-ini-file.php" class="reference external" title="parse_ini_file" rel="external noopener noreferrer" target="_blank">parse_ini_file</a>.
Or a PHP method! <a href="https://secure.php.net/manual/en/locale.getdefault.php" class="reference external" title="Locale" rel="external noopener noreferrer" target="_blank">Locale::getDefault()</a>.</p>
</div>
</div>
<div class="section">
Expand Down Expand Up @@ -129,7 +129,7 @@ <h3 id="format"><a class="headerlink" href="#format" title="Permalink to this he
<p><strong>type</strong>: <code translate="no" class="notranslate">string</code><strong>default</strong>: <code translate="no" class="notranslate">Symfony<wbr>\Component<wbr>\Form<wbr>\Extension<wbr>\Core<wbr>\Type<wbr>\DateTimeType::HTML5_FORMAT</code></p>
<p>If the <code translate="no" class="notranslate">widget</code> option is set to <code translate="no" class="notranslate">single_text</code>, this option specifies
the format of the input, i.e. how Symfony will interpret the given input
as a datetime string. See <a href="http://userguide.icu-project.org/formatparse/datetime#TOC-Date-Time-Format-Syntax" class="reference external">Date/Time Format Syntax</a>.</p>
as a datetime string. See <a href="http://userguide.icu-project.org/formatparse/datetime#TOC-Date-Time-Format-Syntax" class="reference external" rel="external noopener noreferrer" target="_blank">Date/Time Format Syntax</a>.</p>
<div class="admonition-wrapper"><div class="admonition admonition-sidebar"><p class="sidebar-title">Everyone loves sidebars</p><p>But do they really? They also get in the way!</p>
</div></div>
<div class="admonition admonition-caution ">
Expand Down Expand Up @@ -294,7 +294,7 @@ <h2 id="field-variables"><a class="headerlink" href="#field-variables" title="Pe
<th>Usage</th>
</tr>
</thead>

<tbody>
<tr>
<td>widget</td>
Expand All @@ -313,7 +313,7 @@ <h2 id="field-variables"><a class="headerlink" href="#field-variables" title="Pe
<div class="section">
<h2 id="url-checker-errors"><a class="headerlink" href="#url-checker-errors" title="Permalink to this headline">Url checker errors</a></h2>
<p>This is a <a href="https://symfony.com/404" class="reference external">404 error</a>.
And here is an invalid url <a href="http://invalid-url" class="reference external">invalid-url</a>.</p>
And here is an invalid url <a href="http://invalid-url" class="reference external" rel="external noopener noreferrer" target="_blank">invalid-url</a>.</p>
</div>

</body>
Expand Down