RetroAchievements / RAWeb

RetroAchievements.org Platform

Home Page:https://retroachievements.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Errors displaying achievements tooltips with quotes in forum posts

Mindhral opened this issue · comments

Describe the bug
Forum posts with achievements links ([ach] tags) provoke javascript warnings and errors in the browser console, and the tooltip doesn't display, when the game title or the achievement title contains single quotes.

To Reproduce
Steps to reproduce the behavior:

  1. Go to Achievement of the Week 2023 topic for example
  2. Open the browser console: it's full of warnings and errors
  3. Hover on a link such as "Masked Jungle Warrior": the tooltip doesn't display and a bunch of other errors appears in the console (because of the quote in the game title (it's "Majora's Mask")
  4. Hover on a link such as "Warhawk's Rooftop": same result because of the quote in achievement's title

Expected behavior
Tooltips on all achievements, no JS errors.

Screenshots
While hovering over the link:
image

Example of warning:

Alpine Expression Error: missing ) after argument list

Expression: "tooltipComponent($el, { staticHtmlContent: useCard('achievement', '55510', '', '<div class=\'tooltip-body flex items-start gap-2 p-2\' style=\'max-width: 400px\'><img src=\'https://media.retroachievements.org/Badge/119641.png\' width=\'64\' height=\'64\' /><div><div><b>Witch's Brew</b></div><div class=\'mb-1\'>Obtain a bottle from the Old Hag.</div><div>2 Points</div><div><i>Legend of Zelda, The: Majora's Mask</i></div></div></div>') })"

 <span class="inline" x-data="tooltipComponent($el, { …></div></div></div>') })" @mouseover="showTooltip($event)" @mouseleave="hideTooltip" @mousemove="trackMouseMovement($event)">
app-ee02857a.js:1:4982

HTML code of the corresponding element:

<span class='inline'     x-data="tooltipComponent($el, { staticHtmlContent: useCard('achievement', '55529', '', '&lt;div class=\'tooltip-body flex items-start gap-2 p-2\' style=\'max-width: 400px\'&gt;&lt;img src=\'https://media.retroachievements.org/Badge/119652.png\' width=\'64\' height=\'64\' /&gt;&lt;div&gt;&lt;div&gt;&lt;b&gt;Masked Jungle Warrior&lt;/b&gt;&lt;/div&gt;&lt;div class=\'mb-1\'&gt;Obtain Odolwa\'s Remains.&lt;/div&gt;&lt;div&gt;5 Points&lt;/div&gt;&lt;div&gt;&lt;i&gt;Legend of Zelda, The: Majora&#039;s Mask&lt;/i&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;') })"
    @mouseover="showTooltip($event)"
    @mouseleave="hideTooltip"
    @mousemove="trackMouseMovement($event)"><a class='inline-block' href='[https://retroachievements.org/achievement/55529](view-source:https://retroachievements.org/achievement/55529)'><img loading='lazy' decoding='async' width='24' height='24' src='[https://media.retroachievements.org/Badge/119652.png](view-source:https://media.retroachievements.org/Badge/119652.png)' alt='Masked Jungle Warrior' class='badgeimg'> Masked Jungle Warrior (5)</a></span>

Desktop (please complete the following information):

  • OS: Windows 10
  • Browser Firefox 120.0

Additional context

The description seems to be correctly escaped.
I believe that in

$title = str_replace("\n", '', Blade::render('<x-achievement.title :rawTitle="$rawTitle" />', [
'rawTitle' => $data['AchievementTitle'] ?? $data['Title'] ?? '',
]));
$description = $data['AchievementDesc'] ?? $data['Description'] ?? null;
$achPoints = $data['Points'] ?? null;
$badgeName = $data['BadgeName'] ?? null;
$unlock = $data['Unlock'] ?? null;
$badgeImgSrc = $iconUrl ?? media_asset("Badge/{$badgeName}.png");
$gameTitle = str_replace("\n", '', Blade::render('<x-game-title :rawTitle="$rawTitle" />', ['rawTitle' => $data['GameTitle'] ?? '']));
$tooltip = "<div class='tooltip-body flex items-start gap-2 p-2' style='max-width: 400px'>";
$tooltip .= "<img src='$badgeImgSrc' width='64' height='64' />";
$tooltip .= "<div>";
$tooltip .= "<div><b>$title</b></div>";
$tooltip .= "<div class='mb-1'>$description</div>";
if ($achPoints) {
$tooltip .= "<div>$achPoints " . __res('point', (int) $achPoints) . "</div>";
}
if ($gameTitle) {
$tooltip .= "<div><i>" . trim($gameTitle) . "</i></div>";
}

the blades renders HTML entities for quotes, so that
function tooltipEscape(string $input): string
{
// the Tip() function expected single quotes to be escaped, and other html reserved
// characters to be converted to entities.
$input = htmlentities($input, ENT_COMPAT | ENT_HTML401);
// ENT_COMPAT will not convert single quotes. do so ourself.
$input = str_replace("'", "\'", $input);
return str_replace("\n", "<br/>", $input);
}

doesn't escape them.

It seems that the game title is now correctly escaped (thanks to #2086), but the achievement title still isn't?
Example: [ach=224088] (Beta Dodongo Cavern's)