Skip to content

Redo chat parsing and validation#24

Merged
creesch merged 4 commits intoTildes-MC:mainfrom
danthedaniel:parsing-validating
Dec 19, 2024
Merged

Redo chat parsing and validation#24
creesch merged 4 commits intoTildes-MC:mainfrom
danthedaniel:parsing-validating

Conversation

@danthedaniel
Copy link
Copy Markdown
Member

@danthedaniel danthedaniel commented Dec 19, 2024

Fixes #20

  • Components are rendered to DOM elements (eliminates hand-rolled escaping)
  • Structures are validated up-front instead of throughout the code (including depth checks)
  • I also fixed some incorrect types from chat.mjs where I thought we stored parsed messages

@danthedaniel
Copy link
Copy Markdown
Member Author

@creesch the structure from prismarine-chat is out-of-date. The value field is deprecated. Perhaps only used by old Minecraft versions?

// that automatically pauses when tab is inactive
if (timestamp - lastUpdate >= updateInterval) {
const elements = document.getElementsByClassName('minecraft-obfuscated');
const elements = document.getElementsByClassName('mc-obfuscated');
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I threw in this random change because the different class name format was upsetting me.

* }} HoverEventContents
* @typedef {Object} ShowEntityHoverEvent
* @property {'show_entity'} action - Displays entity information
* @property {{ type: string, id: unknown, name?: string }} contents - The entity data to show
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left id as unknown. It seems it should be a UUID string, but it's coming through as an array of 4 numbers (which could make sense if the 4 numbers are 1:1 with a UUID at 32 bits each). So perhaps we're doing a different serialization than the Wiki expects.

Copy link
Copy Markdown
Collaborator

@creesch creesch Dec 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh btw

So perhaps we're doing a different serialization than the Wiki expects.

We are using native serialization, its also possible the wiki is incorrect. There is also differences between bedrock and java. Which wiki have you been looking at?

div.innerHTML = parseMinecraftText(json);

/** @type {unknown} */
const json = JSON.parse(rawJson);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like this would fail. While the variable is called rawJSON it is already parsed and an object when received through websockets.

Trying to parse a js object as JSON again will throw a syntax error.

@creesch
Copy link
Copy Markdown
Collaborator

creesch commented Dec 19, 2024

@creesch the structure from prismarine-chat is out-of-date. The value field is deprecated. Perhaps only used by old Minecraft versions?

That is entirely possible as they support multiple version of minecraft, if we are sure it is no longer used by newer versions of minecraft we can leave that field out I am not planning on figuring out support for older versions of minecraft.

I'll have a proper look a bit later, on the face of it it seems fairly solid. Some things that do jump out:

  • Are we sure that for titles it is enough to rely on the browser to sanitize what we put in there? I feel like I have seen some stuff about attribute injection in the past.
  • One potential bug in initial json handling.
  • Error handling feels like it might be too strict in some cases but I want to test it first before I comment on that.

@creesch
Copy link
Copy Markdown
Collaborator

creesch commented Dec 19, 2024

Little bit of work todo

image

{"translate":"chat.type.text","with":[{"text":"creesch","hoverEvent":{"contents":{"type":"minecraft:player","id":[2097578677,-1517796232,-2140994661,-1953866359],"name":"creesch"},"action":"show_entity"},"insertion":"creesch","clickEvent":{"action":"suggest_command","value":"/tell creesch "}},"test"]}
chat.mjs:79 Invalid component: Component is not an object at .with.1
displayMessage @ chat.mjs:79
chat.mjs:68 {"translate":"chat.type.text","with":[{"text":"creesch","hoverEvent":{"contents":{"type":"minecraft:player","id":[2097578677,-1517796232,-2140994661,-1953866359],"name":"creesch"},"action":"show_entity"},"insertion":"creesch","clickEvent":{"action":"suggest_command","value":"/tell creesch "}},"cool"]}
chat.mjs:79 Invalid component: Component is not an object at .with.1
displayMessage @ chat.mjs:79
chat.mjs:68 {"translate":"chat.type.text","with":[{"text":"creesch","hoverEvent":{"contents":{"type":"minecraft:player","id":[2097578677,-1517796232,-2140994661,-1953866359],"name":"creesch"},"action":"show_entity"},"insertion":"creesch","clickEvent":{"action":"suggest_command","value":"/tell creesch "}},"works"]}
chat.mjs:79 Invalid component: Component is not an object at .with.1
displayMessage @ chat.mjs:79
chat.mjs:68 {"translate":"chat.type.text","with":[{"text":"creesch","hoverEvent":{"contents":{"type":"minecraft:player","id":[2097578677,-1517796232,-2140994661,-1953866359],"name":"creesch"},"action":"show_entity"},"insertion":"creesch","clickEvent":{"action":"suggest_command","value":"/tell creesch "}},"like it should"]}
chat.mjs:79 Invalid component: Component is not an object at .with.1
displayMessage @ chat.mjs:79
chat.mjs:68 {"translate":"chat.type.text","with":[{"text":"creesch","hoverEvent":{"contents":{"type":"minecraft:player","id":[2097578677,-1517796232,-2140994661,-1953866359],"name":"creesch"},"action":"show_entity"},"insertion":"creesch","clickEvent":{"action":"suggest_command","value":"/tell creesch "}},"awesome! "]}
chat.mjs:79 Invalid component: Component is not an object at .with.1
displayMessage @ chat.mjs:79
chat.mjs:107 Connected to server
chat.mjs:68 {"translate":"chat.type.text","with":[{"text":"creesch","hoverEvent":{"contents":{"type":"minecraft:player","id":[2097578677,-1517796232,-2140994661,-1953866359],"name":"creesch"},"action":"show_entity"},"insertion":"creesch","clickEvent":{"action":"suggest_command","value":"/tell creesch "}},"does this come through?"]}
chat.mjs:79 Invalid component: Component is not an object at .with.1

It looks like value is still in use even in 1.21.1.

@creesch
Copy link
Copy Markdown
Collaborator

creesch commented Dec 19, 2024

Also going to be a bit real, I like code to be actually tested before a PR is made. Or have the PR marked as a draft if you haven't been able to test it.

@danthedaniel
Copy link
Copy Markdown
Member Author

That's fair. I did test the PR. I did not see any errors when I tested. I do not have a good understanding of what cases to run through.

@creesch
Copy link
Copy Markdown
Collaborator

creesch commented Dec 19, 2024

That's fair. I did test the PR. I did not see any errors when I tested

Interesting, I just realized that this only happens in a game I am running locally. I did open it up to LAN so it acts as a server and the same still happens there.

I do not have a good understanding of what cases to run through.

At the very least the messages from above ;)

I have also been using https://mcstacker.net/1.21.php to create /tellraw commands to test various formatting.

@creesch
Copy link
Copy Markdown
Collaborator

creesch commented Dec 19, 2024

So it looks like that in Minecraft's chat format, the elements in the with array can actually be a string. Same as you handle extra

@danthedaniel
Copy link
Copy Markdown
Member Author

danthedaniel commented Dec 19, 2024

Are we sure that for titles it is enough to rely on the browser to sanitize what we put in there? I feel like I have seen some stuff about attribute injection in the past.

I think that's an issue if:

  1. We are doing string interpolation for building HTML elements - at which point an attacker could terminate the attribute's string and inject a <script> tag.
  2. We put raw HTML into the title attribute and read it back later. We might do this at some point for more rich hover information, but that's currently not the case.

@creesch
Copy link
Copy Markdown
Collaborator

creesch commented Dec 19, 2024

Alright, did some testing and seems to work as expected now.

@creesch creesch merged commit 0da96ce into Tildes-MC:main Dec 19, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Reorganize parsing/validation/escaping code

2 participants