I have a text format that has the token_filter enabled.
I want to use the [site:url] token as the href of a link, added via the standard core ckeditor link dialog.
On output the first time, the link is correct. But when re-editing the node, the token will be silently truncated to url] and saved into the database.
I would not expect a token in a url to be silently broken and saved into the database.
To reproduce:
- Instantiate a simplytest.me instance with token_filter module.
- Edit the basic html text format, enabling token replacement.
- Move the token replacement filter before "Limit allowed HTML tags and correct faulty HTML".
- Create a basic page node.
- Select basic html format for the text field.
- Add a link to the text field using the editor link button, with
[site:url] as the link href.
- Also add the same token to the text for checking.
- Save the node.
- Inspect the output. The link href is replaced by the site url. The token in the text is replaced by the site url.
- Edit the node again. Just add some text and save, don't touch the link.
- Inspect the output. The link href has been truncated to
url]. The token in the text is replaced by the site url.
- Edit the node again. Double click the link to check it. The token has been saved in its truncated state.
Comments
Comment #2
johnpitcairn commentedComment #3
johnpitcairn commentedMoving to editor module. Line 84 of \Drupal\editor\EditorXssFilter\Standard.php:
$output = static::filter($html, $blacklisted_tags);This is where the token is getting mangled on input.
Comment #4
johnpitcairn commentedIt all boils down to
UrlHelper::filterBadProtocol()being run on the link href at ckeditor load. In the absence of a full URL, everything up to the colon in the token is interpreted as a protocol.This means you cannot reliably use a token as the path component of a link via ckeditor. The same token in the query component of the link is fine.
If you precede the token with a slash, the token is not truncated, but that will result in an invalid URL when the token is replaced by either a Drupal path (itself beginning with /) or by a full URL.
Comment #5
johnpitcairn commentedComment #6
wim leersThis is one of so many cases of
UrlHelper::filterBadProtocol()getting in the way. There's nothing thateditor.modulecan do to help here.I'm assuming this is when you also use https://www.drupal.org/project/token_filter?
What would help is test coverage.
Comment #7
johnpitcairn commentedThanks
I'm not using token_filter module, I have a custom module that supplies its own token and filter. The filter runs before the "limit tags" filter, but that doesn't help, if the token is not replaced and left as-is it still will get mangled. I think this can be tested without any filter, since the problem occurs when the token is not replaced.
Comment #9
k-l commentedSolved same issue by creating custom EditorXssFilter which extended \Drupal\editor\EditorXssFilter\Standard.php and just implements attributes() method. Which is identical to attributes method in \Drupal\Component\Utility\Xss.php only adjusted to set $skip_protocol_filtering = TRUE; when href contains token. Then using hook_editor_xss_filter_alter() custom filter class is set for selected text format.
When displaying text, tokens needs to be replaced before 'Correct faulty and chopped off HTML' filter kicks in.
Comment #18
larowlanThanks for reporting this issue. We rely on issue reports like this one to resolve bugs and improve Drupal core.
As part of the Bug Smash Initiative, we are triaging issues that are marked "Postponed (maintainer needs more info)". This issue was marked "Postponed (maintainer needs more info)" 5 years ago however it appears that the status was not reset.
Regardless I think the fix here is for you to run the token filter before the limit/fix HTML one.
Is there a reason this isn't possible? Perhaps that your filter uses tags that shouldn't ordinarily be allowed?
Is this still an issue?
Comment #19
johnpitcairn commentedThanks @larowlan - it's been a while since I've looked at this. I've reproduced the issue in a clean simplytest.me install.
Running the token filter before limit/correct html does not resolve the problem if a link url contains a token. On subsequent editing, that token will be silently truncated and saved to the database.
I have updated the title and issue summary steps to reproduce to reflect the real problem, which is
UrlHelper::stripBadProtocol()as per #6.Comment #20
johnpitcairn commentedComment #21
johnpitcairn commentedBumping to major as user input is irrevocably altered.
Comment #22
larowlanCan you provide an example URL here
Is the token url encoded?
At that point it aught to be
Comment #23
larowlane.g. I assume your use case here is something like
/foo/bar/get-token?token=[foo:bar]but at that point it should be encoded to%5Bfoo%3Abar%5Dor does that not matter because filterBadProtocol decodes it anyway?
Perhaps a good starting point is to add a failing case to
\Drupal\Tests\Component\Utility\UrlHelperTest::providerTestFilterBadProtocolso we're all talking about the same thingComment #24
johnpitcairn commentedSimplest case is
<a href="[site:url]">This will break</a>, as per the issue summary.That seems a not unreasonable use case for something somebody might want to do using the editor link button and a token.
I'll try to find some time to add a failing test.
Comment #25
larowlanI'm sorry, I still don't understand the problem.
If your example is
<a href="[site:url]">This will break</a>and your token filter runs before the HTML validation, doesn't it get transformed to<a href="https://somesite.com">This will break</a>before the HTML validation?I must be missing something
Comment #26
johnpitcairn commentedYes, the first time after saving.
But if you edit the node again, without touching the link at all, the token still gets run through the protocol check when ckeditor loads or something, and the link href gets saved in that broken state.
Comment #27
larowlan#2944173: CKEditor mangles tokens in URLs, due to bug in Xss::attributes() is a duplicate and has a patch so closing this one
Comment #28
johnpitcairn commentedThanks @larowlan, I agree this is a duplicate.