Skip to content

Commit a6b885e

Browse files
Merge branch 'Wurst-Imperium:master' into murder-mystery
2 parents 612a1f3 + 86f3ae8 commit a6b885e

13 files changed

+232
-38
lines changed

gradle.properties

+3-3
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@ org.gradle.parallel=true
77
# https://www.curseforge.com/minecraft/mc-mods/fabric-api
88
minecraft_version=1.20.4
99
yarn_mappings=1.20.4+build.3
10-
loader_version=0.15.6
10+
loader_version=0.15.7
1111

1212
#Fabric api
13-
fabric_version=0.95.4+1.20.4
13+
fabric_version=0.96.4+1.20.4
1414

1515
# Mod Properties
16-
mod_version = v7.41-MC1.20.4
16+
mod_version = v7.41.1-MC1.20.4
1717
maven_group = net.wurstclient
1818
archives_base_name = Wurst-Client
1919

src/main/java/net/wurstclient/WurstClient.java

+16-4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import java.nio.file.Files;
1212
import java.nio.file.Path;
1313
import java.util.ArrayList;
14+
import java.util.IllegalFormatException;
1415
import java.util.stream.Collectors;
1516
import java.util.stream.Stream;
1617

@@ -57,7 +58,7 @@ public enum WurstClient
5758
public static MinecraftClient MC;
5859
public static IMinecraftClient IMC;
5960

60-
public static final String VERSION = "7.41";
61+
public static final String VERSION = "7.41.1";
6162
public static final String MC_VERSION = "1.20.4";
6263

6364
private WurstAnalytics analytics;
@@ -175,18 +176,29 @@ private Path createWurstFolder()
175176
return wurstFolder;
176177
}
177178

178-
public String translate(String key)
179+
public String translate(String key, Object... args)
179180
{
180181
if(otfs.translationsOtf.getForceEnglish().isChecked())
181-
return ILanguageManager.getEnglish().get(key);
182+
{
183+
String string = ILanguageManager.getEnglish().get(key);
182184

185+
try
186+
{
187+
return String.format(string, args);
188+
189+
}catch(IllegalFormatException e)
190+
{
191+
return key;
192+
}
193+
}
194+
183195
// This extra check is necessary because I18n.translate() doesn't
184196
// always return the key when the translation is missing. If the key
185197
// contains a '%', it will return "Format Error: key" instead.
186198
if(!I18n.hasTranslation(key))
187199
return key;
188200

189-
return I18n.translate(key);
201+
return I18n.translate(key, args);
190202
}
191203

192204
public WurstAnalytics getAnalytics()

src/main/java/net/wurstclient/altmanager/screens/AltManagerScreen.java

+9-7
Original file line numberDiff line numberDiff line change
@@ -86,14 +86,15 @@ public AltManagerScreen(Screen prevScreen, AltManager altManager)
8686
public void init()
8787
{
8888
listGui = new ListGui(client, this, altManager.getList());
89+
WurstClient wurst = WurstClient.INSTANCE;
8990

9091
Exception folderException = altManager.getFolderException();
9192
if(folderException != null && shouldAsk)
9293
{
93-
Text title =
94-
Text.translatable("gui.wurst.altmanager.folder_error.title");
95-
Text message = Text.translatable(
96-
"gui.wurst.altmanager.folder_error.message", folderException);
94+
Text title = Text.literal(
95+
wurst.translate("gui.wurst.altmanager.folder_error.title"));
96+
Text message = Text.literal(wurst.translate(
97+
"gui.wurst.altmanager.folder_error.message", folderException));
9798
Text buttonText = Text.translatable("gui.done");
9899

99100
// This just sets shouldAsk to false and closes the message.
@@ -105,9 +106,10 @@ public void init()
105106

106107
}else if(altManager.getList().isEmpty() && shouldAsk)
107108
{
108-
Text title = Text.translatable("gui.wurst.altmanager.empty.title");
109-
Text message =
110-
Text.translatable("gui.wurst.altmanager.empty.message");
109+
Text title = Text
110+
.literal(wurst.translate("gui.wurst.altmanager.empty.title"));
111+
Text message = Text
112+
.literal(wurst.translate("gui.wurst.altmanager.empty.message"));
111113
BooleanConsumer callback = this::confirmGenerate;
112114

113115
ConfirmScreen screen = new ConfirmScreen(callback, title, message);

src/main/java/net/wurstclient/mixin/ClientPlayNetworkHandlerMixin.java

+6-5
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ private ClientPlayNetworkHandlerMixin(WurstClient wurst,
4646
public void onOnServerMetadata(ServerMetadataS2CPacket packet,
4747
CallbackInfo ci)
4848
{
49-
if(!WurstClient.INSTANCE.isEnabled())
49+
WurstClient wurst = WurstClient.INSTANCE;
50+
if(!wurst.isEnabled())
5051
return;
5152

5253
// Remove Mojang's dishonest warning toast on safe servers
@@ -58,10 +59,10 @@ public void onOnServerMetadata(ServerMetadataS2CPacket packet,
5859
}
5960

6061
// Add an honest warning toast on unsafe servers
61-
MutableText title = Text.literal(ChatUtils.WURST_PREFIX).append(
62-
Text.translatable("toast.wurst.nochatreports.unsafe_server.title"));
63-
MutableText message = Text
64-
.translatable("toast.wurst.nochatreports.unsafe_server.message");
62+
MutableText title = Text.literal(ChatUtils.WURST_PREFIX
63+
+ wurst.translate("toast.wurst.nochatreports.unsafe_server.title"));
64+
MutableText message = Text.literal(
65+
wurst.translate("toast.wurst.nochatreports.unsafe_server.message"));
6566

6667
SystemToast systemToast = SystemToast.create(client,
6768
SystemToast.Type.UNSECURE_SERVER_WARNING, title, message);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Copyright (c) 2014-2024 Wurst-Imperium and contributors.
3+
*
4+
* This source code is subject to the terms of the GNU General Public
5+
* License, version 3. If a copy of the GPL was not distributed with this
6+
* file, You can obtain one at: https://www.gnu.org/licenses/gpl-3.0.txt
7+
*/
8+
package net.wurstclient.mixin;
9+
10+
import org.spongepowered.asm.mixin.Mixin;
11+
import org.spongepowered.asm.mixin.injection.At;
12+
13+
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
14+
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
15+
16+
import net.minecraft.client.MinecraftClient;
17+
import net.minecraft.client.gui.screen.option.ControlsListWidget;
18+
import net.minecraft.client.gui.widget.ElementListWidget;
19+
import net.minecraft.client.gui.widget.EntryListWidget;
20+
import net.minecraft.text.Text;
21+
import net.minecraft.text.TranslatableTextContent;
22+
import net.wurstclient.WurstClient;
23+
24+
@Mixin(ControlsListWidget.class)
25+
public abstract class ControlsListWidgetMixin
26+
extends ElementListWidget<ControlsListWidget.Entry>
27+
{
28+
public ControlsListWidgetMixin(WurstClient wurst, MinecraftClient client,
29+
int width, int height, int y, int itemHeight)
30+
{
31+
super(client, width, height, y, itemHeight);
32+
}
33+
34+
/**
35+
* Prevents Wurst's zoom keybind from being added to the controls list.
36+
*/
37+
@WrapOperation(at = @At(value = "INVOKE",
38+
target = "Lnet/minecraft/client/gui/screen/option/ControlsListWidget;addEntry(Lnet/minecraft/client/gui/widget/EntryListWidget$Entry;)I",
39+
ordinal = 1),
40+
method = "<init>(Lnet/minecraft/client/gui/screen/option/KeybindsScreen;Lnet/minecraft/client/MinecraftClient;)V")
41+
private int dontAddZoomEntry(ControlsListWidget instance,
42+
EntryListWidget.Entry<?> entry, Operation<Integer> original)
43+
{
44+
if(!(entry instanceof ControlsListWidget.KeyBindingEntry kbEntry))
45+
return original.call(instance, entry);
46+
47+
Text name = kbEntry.bindingName;
48+
if(name == null || !(name
49+
.getContent() instanceof TranslatableTextContent trContent))
50+
return original.call(instance, entry);
51+
52+
if(!"key.wurst.zoom".equals(trContent.getKey()))
53+
return original.call(instance, entry);
54+
55+
return 0;
56+
}
57+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* Copyright (c) 2014-2024 Wurst-Imperium and contributors.
3+
*
4+
* This source code is subject to the terms of the GNU General Public
5+
* License, version 3. If a copy of the GPL was not distributed with this
6+
* file, You can obtain one at: https://www.gnu.org/licenses/gpl-3.0.txt
7+
*/
8+
package net.wurstclient.mixin;
9+
10+
import org.spongepowered.asm.mixin.Final;
11+
import org.spongepowered.asm.mixin.Mixin;
12+
import org.spongepowered.asm.mixin.Shadow;
13+
import org.spongepowered.asm.mixin.injection.At;
14+
import org.spongepowered.asm.mixin.injection.Inject;
15+
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
16+
17+
import net.minecraft.text.KeybindTextContent;
18+
import net.minecraft.text.Text;
19+
import net.minecraft.text.TextContent;
20+
21+
@Mixin(KeybindTextContent.class)
22+
public abstract class KeybindTextContentMixin implements TextContent
23+
{
24+
@Shadow
25+
@Final
26+
private String key;
27+
28+
/**
29+
* Ensures that any chat messages, written books, signs, etc. cannot resolve
30+
* Wurst-related keybinds.
31+
*
32+
* <p>
33+
* Fixes at least one security vulnerability affecting Minecraft 1.20 and
34+
* later versions, where the server can detect the presence of Wurst by
35+
* abusing Minecraft's sign editing feature. When a player edits a sign, any
36+
* translated text and keybind text components on that sign are resolved by
37+
* the client and sent back to the server as plain text. This allows the
38+
* server to detect the presence of non-vanilla keybinds, such as Wurst's
39+
* zoom keybind.
40+
*
41+
* <p>
42+
* It is likely that similar vulnerabilities exist or will exist in other
43+
* parts of the game, such as chat messages and written books. Mojang has a
44+
* long history of failing to properly secure their text component system
45+
* (see BookHack, OP-Sign, BookDupe). Therefore it's best to cut off this
46+
* entire attack vector at the source.
47+
*/
48+
@Inject(at = @At("RETURN"),
49+
method = "getTranslated()Lnet/minecraft/text/Text;",
50+
cancellable = true)
51+
private void onGetTranslated(CallbackInfoReturnable<Text> cir)
52+
{
53+
if(key != null && key.contains("wurst"))
54+
cir.setReturnValue(Text.literal(key));
55+
}
56+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/*
2+
* Copyright (c) 2014-2024 Wurst-Imperium and contributors.
3+
*
4+
* This source code is subject to the terms of the GNU General Public
5+
* License, version 3. If a copy of the GPL was not distributed with this
6+
* file, You can obtain one at: https://www.gnu.org/licenses/gpl-3.0.txt
7+
*/
8+
package net.wurstclient.mixin;
9+
10+
import org.spongepowered.asm.mixin.Mixin;
11+
import org.spongepowered.asm.mixin.injection.At;
12+
13+
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
14+
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
15+
16+
import net.minecraft.text.TextContent;
17+
import net.minecraft.text.TranslatableTextContent;
18+
import net.minecraft.util.Language;
19+
20+
@Mixin(TranslatableTextContent.class)
21+
public abstract class TranslatableTextContentMixin implements TextContent
22+
{
23+
/**
24+
* Ensures that any chat messages, written books, signs, etc. cannot resolve
25+
* Wurst-related translation keys.
26+
*
27+
* <p>
28+
* Fixes at least one security vulnerability affecting Minecraft 1.20 and
29+
* later versions, where the server can detect the presence of Wurst by
30+
* abusing Minecraft's sign editing feature. When a player edits a sign, any
31+
* translated text and keybind text components on that sign are resolved by
32+
* the client and sent back to the server as plain text. This allows the
33+
* server to detect the presence of non-vanilla translation keys.
34+
*
35+
* <p>
36+
* It is likely that similar vulnerabilities exist or will exist in other
37+
* parts of the game, such as chat messages and written books. Mojang has a
38+
* long history of failing to properly secure their text component system
39+
* (see BookHack, OP-Sign, BookDupe). Therefore it's best to cut off this
40+
* entire attack vector at the source.
41+
*/
42+
@WrapOperation(at = @At(value = "INVOKE",
43+
target = "Lnet/minecraft/util/Language;get(Ljava/lang/String;)Ljava/lang/String;",
44+
ordinal = 0), method = "updateTranslations()V")
45+
private String translate(Language instance, String key,
46+
Operation<String> original)
47+
{
48+
if(key != null && key.contains("wurst"))
49+
return key;
50+
51+
return original.call(instance, key);
52+
}
53+
54+
/**
55+
* Same as above, but for translatable text components with a fallback.
56+
*/
57+
@WrapOperation(at = @At(value = "INVOKE",
58+
target = "Lnet/minecraft/util/Language;get(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
59+
ordinal = 0), method = "updateTranslations()V")
60+
private String translateWithFallback(Language instance, String key,
61+
String fallback, Operation<String> original)
62+
{
63+
if(key != null && key.contains("wurst"))
64+
return fallback;
65+
66+
return original.call(instance, key, fallback);
67+
}
68+
}

src/main/java/net/wurstclient/nochatreports/ForcedChatReportsScreen.java

+5-4
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,13 @@ public final class ForcedChatReportsScreen extends Screen
4747

4848
public ForcedChatReportsScreen(Screen prevScreen)
4949
{
50-
super(Text.literal(ChatUtils.WURST_PREFIX).append(
51-
Text.translatable("gui.wurst.nochatreports.unsafe_server.title")));
50+
super(Text.literal(ChatUtils.WURST_PREFIX)
51+
.append(Text.literal(WurstClient.INSTANCE
52+
.translate("gui.wurst.nochatreports.unsafe_server.title"))));
5253
this.prevScreen = prevScreen;
5354

54-
reason =
55-
Text.translatable("gui.wurst.nochatreports.unsafe_server.message");
55+
reason = Text.literal(WurstClient.INSTANCE
56+
.translate("gui.wurst.nochatreports.unsafe_server.message"));
5657

5758
NoChatReportsOtf ncr = WurstClient.INSTANCE.getOtfs().noChatReportsOtf;
5859
sigButtonMsg = () -> WurstClient.INSTANCE

src/main/java/net/wurstclient/nochatreports/NcrModRequiredScreen.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,12 @@ public final class NcrModRequiredScreen extends Screen
4343

4444
public NcrModRequiredScreen(Screen prevScreen)
4545
{
46-
super(Text.literal(ChatUtils.WURST_PREFIX).append(
47-
Text.translatable("gui.wurst.nochatreports.ncr_mod_server.title")));
46+
super(Text.literal(ChatUtils.WURST_PREFIX + WurstClient.INSTANCE
47+
.translate("gui.wurst.nochatreports.ncr_mod_server.title")));
4848
this.prevScreen = prevScreen;
4949

50-
reason =
51-
Text.translatable("gui.wurst.nochatreports.ncr_mod_server.message");
50+
reason = Text.literal(WurstClient.INSTANCE
51+
.translate("gui.wurst.nochatreports.ncr_mod_server.message"));
5252

5353
OtfList otfs = WurstClient.INSTANCE.getOtfs();
5454

src/main/java/net/wurstclient/other_features/NoChatReportsOtf.java

+4-6
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
import net.wurstclient.Category;
2121
import net.wurstclient.DontBlock;
2222
import net.wurstclient.SearchTags;
23-
import net.wurstclient.WurstClient;
2423
import net.wurstclient.events.UpdateListener;
2524
import net.wurstclient.other_feature.OtherFeature;
2625
import net.wurstclient.settings.CheckboxSetting;
@@ -81,15 +80,15 @@ private void onLoginStart(ClientLoginNetworkHandler handler,
8180
public MessageIndicator modifyIndicator(Text message,
8281
MessageSignatureData signature, MessageIndicator indicator)
8382
{
84-
if(!WurstClient.INSTANCE.isEnabled() || MC.isInSingleplayer())
83+
if(!WURST.isEnabled() || MC.isInSingleplayer())
8584
return indicator;
8685

8786
if(indicator != null || signature == null)
8887
return indicator;
8988

9089
return new MessageIndicator(0xE84F58, Icon.CHAT_MODIFIED,
91-
Text.literal(ChatUtils.WURST_PREFIX + "\u00a7cReportable\u00a7r - ")
92-
.append(Text.translatable(
90+
Text.literal(ChatUtils.WURST_PREFIX + "\u00a7cReportable\u00a7r - "
91+
+ WURST.translate(
9392
"description.wurst.nochatreports.message_is_reportable")),
9493
"Reportable");
9594
}
@@ -102,8 +101,7 @@ public boolean isEnabled()
102101

103102
public boolean isActive()
104103
{
105-
return isEnabled() && WurstClient.INSTANCE.isEnabled()
106-
&& !MC.isInSingleplayer();
104+
return isEnabled() && WURST.isEnabled() && !MC.isInSingleplayer();
107105
}
108106

109107
@Override

src/main/java/net/wurstclient/serverfinder/WurstServerPinger.java

-5
Original file line numberDiff line numberDiff line change
@@ -69,11 +69,6 @@ public boolean isWorking()
6969
return !failed;
7070
}
7171

72-
public boolean isOtherVersion()
73-
{
74-
return server.protocolVersion != 47;
75-
}
76-
7772
public String getServerIP()
7873
{
7974
return server.address;

0 commit comments

Comments
 (0)