From fc90f774bc4c6bcbd484f78bbc8fe7e45b22cca7 Mon Sep 17 00:00:00 2001 From: zml Date: Mon, 19 Jul 2021 16:11:06 -0700 Subject: [PATCH] Fix book title and author being improperly serialized as components (#6190) They are kept as plain strings Additional validation has been added to prevent invalid books from being sent to the client. --- patches/server/Adventure.patch | 38 +++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/patches/server/Adventure.patch b/patches/server/Adventure.patch index ba9fc4c42f..0e8a62c3e3 100644 --- a/patches/server/Adventure.patch +++ b/patches/server/Adventure.patch @@ -531,6 +531,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.BossEvent; +import net.minecraft.world.item.ItemStack; ++import net.minecraft.world.item.WrittenBookItem; +import org.bukkit.ChatColor; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; @@ -682,6 +683,18 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return net.minecraft.network.chat.Component.Serializer.toJson(component); + } + ++ public static String asPlain(final Component component, final Locale locale) { ++ return PLAIN.serialize( ++ GlobalTranslator.render( ++ component, ++ // play it safe ++ locale != null ++ ? locale ++ : Locale.US ++ ) ++ ); ++ } ++ + // thank you for being worse than wet socks, Bukkit + public static String superHackyLegacyRepresentationOfComponent(final Component component, final String string) { + return LEGACY_SECTION_UXRC.serialize(component) + ChatColor.getLastColors(string); @@ -770,16 +783,31 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + public static ItemStack asItemStack(final Book book, final Locale locale) { + final ItemStack item = new ItemStack(net.minecraft.world.item.Items.WRITTEN_BOOK, 1); + final CompoundTag tag = item.getOrCreateTag(); -+ tag.putString("title", asJsonString(book.title(), locale)); -+ tag.putString("author", asJsonString(book.author(), locale)); ++ tag.putString(WrittenBookItem.TAG_TITLE, validateField(asPlain(book.title(), locale), WrittenBookItem.TITLE_MAX_LENGTH, WrittenBookItem.TAG_TITLE)); ++ tag.putString(WrittenBookItem.TAG_AUTHOR, asPlain(book.author(), locale)); + final ListTag pages = new ListTag(); -+ for (final Component page : book.pages()) { -+ pages.add(StringTag.valueOf(asJsonString(page, locale))); ++ if (book.pages().size() > WrittenBookItem.MAX_PAGES) { ++ throw new IllegalArgumentException("Book provided had " + book.pages().size() + " pages, but is only allowed a maximum of " + WrittenBookItem.MAX_PAGES); + } -+ tag.put("pages", pages); ++ for (final Component page : book.pages()) { ++ pages.add(StringTag.valueOf(validateField(asJsonString(page, locale), WrittenBookItem.PAGE_LENGTH, "page"))); ++ } ++ tag.put(WrittenBookItem.TAG_PAGES, pages); + return item; + } + ++ private static String validateField(final String content, final int length, final String name) { ++ if (content == null) { ++ return content; ++ } ++ ++ final int actual = content.length(); ++ if (actual > length) { ++ throw new IllegalArgumentException("Field '" + name + "' has a maximum length of " + length + " but was passed '" + content + "', which was " + actual + " characters long."); ++ } ++ return content; ++ } ++ + // Sounds + + public static SoundSource asVanilla(final Sound.Source source) {