Skip to content

Commit cdc0db1

Browse files
Fix fingerprinting vulnerability
Fixes Wurst-Imperium#1226
1 parent d3fa1ba commit cdc0db1

File tree

2 files changed

+68
-0
lines changed

2 files changed

+68
-0
lines changed
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/*
2+
* Copyright (c) 2014-2025 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 java.nio.file.Path;
11+
import java.util.UUID;
12+
13+
import org.spongepowered.asm.mixin.Final;
14+
import org.spongepowered.asm.mixin.Mixin;
15+
import org.spongepowered.asm.mixin.Shadow;
16+
import org.spongepowered.asm.mixin.injection.At;
17+
18+
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
19+
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
20+
21+
import net.minecraft.client.session.Session;
22+
import net.minecraft.util.Downloader;
23+
import net.minecraft.util.Uuids;
24+
import net.wurstclient.WurstClient;
25+
26+
@Mixin(Downloader.class)
27+
public abstract class DownloaderMixin implements AutoCloseable
28+
{
29+
@Shadow
30+
@Final
31+
private Path directory;
32+
33+
/**
34+
* Patches a fingerprinting vulnerability by creating a separate cache
35+
* folder for each Minecraft account.
36+
*
37+
* <p>
38+
* This mixin targets the <code>entries.forEach()</code> lambda in
39+
* <code>download(Config, Map)</code>.
40+
*
41+
* @see https://github.com/Wurst-Imperium/Wurst7/issues/1226
42+
*/
43+
@WrapOperation(at = @At(value = "INVOKE",
44+
target = "Ljava/nio/file/Path;resolve(Ljava/lang/String;)Ljava/nio/file/Path;",
45+
ordinal = 0,
46+
remap = false), method = "method_55485")
47+
private Path wrapResolve(Path instance, String filename,
48+
Operation<Path> original)
49+
{
50+
Path result = original.call(instance, filename);
51+
52+
// If the path has already been modified by another mod (likely trying
53+
// to patch the same exploit), don't modify it further.
54+
if(result == null || !result.getParent().equals(directory))
55+
return result;
56+
57+
// "getUuidOrNull" seems to be an outdated Yarn name, as Minecraft
58+
// 1.21.10 treats this like a non-null method. Just in case, we manually
59+
// fallback to the offline UUID if it ever does return null.
60+
Session session = WurstClient.MC.getSession();
61+
UUID uuid = session.getUuidOrNull();
62+
if(uuid == null)
63+
uuid = Uuids.getOfflinePlayerUuid(session.getUsername());
64+
65+
return original.call(instance.resolve(uuid.toString()), filename);
66+
}
67+
}

src/main/resources/wurst.mixins.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
"DimensionOrBossFogModifierMixin",
3232
"DirectConnectScreenMixin",
3333
"DisconnectedScreenMixin",
34+
"DownloaderMixin",
3435
"EntityMixin",
3536
"EntityRendererMixin",
3637
"FluidRendererMixin",

0 commit comments

Comments
 (0)