P3-11 review fixes : direction guard + warn on priority out-of-range
HIGH RISK-001 : ModNetwork.reg() helper n enforce pas NetworkDirection, guard défensif ajouté dans handleOnClient (reject non-S→C + WARN). Fix systémique du helper tracé en backlog séparé. LOW SMELL-001 + SMELL-002 : priority() fallback silencieux + idx<0 dead après masking. WARN log ajouté sur out-of-range. Condition nettoyée.
This commit is contained in:
@@ -45,9 +45,15 @@ public record PacketPlayRigAnim(
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Layer.Priority priority() {
|
public Layer.Priority priority() {
|
||||||
// Guard out-of-range si un peer malveillant envoie un byte invalide
|
// Guard out-of-range si un peer malveillant envoie un byte invalide.
|
||||||
|
// Note : priorityOrdinal & 0xFF donne unsigned [0,255] donc idx < 0 est
|
||||||
|
// impossible ici — seul le bound haut est à tester (SMELL-002).
|
||||||
int idx = priorityOrdinal & 0xFF;
|
int idx = priorityOrdinal & 0xFF;
|
||||||
if (idx < 0 || idx >= PRIORITY_COUNT) {
|
if (idx >= PRIORITY_COUNT) {
|
||||||
|
TiedUpRigConstants.LOGGER.warn(
|
||||||
|
"[PacketPlayRigAnim] priority ordinal out of range ({}), falling back to LOWEST. Possible protocol mismatch.",
|
||||||
|
idx
|
||||||
|
);
|
||||||
return Layer.Priority.LOWEST; // fallback safe
|
return Layer.Priority.LOWEST; // fallback safe
|
||||||
}
|
}
|
||||||
return Layer.Priority.values()[idx];
|
return Layer.Priority.values()[idx];
|
||||||
@@ -73,13 +79,28 @@ public record PacketPlayRigAnim(
|
|||||||
* patch, playAnimation) viendra en P3-12.
|
* patch, playAnimation) viendra en P3-12.
|
||||||
*/
|
*/
|
||||||
public static void handleOnClient(PacketPlayRigAnim pkt, Supplier<NetworkEvent.Context> ctx) {
|
public static void handleOnClient(PacketPlayRigAnim pkt, Supplier<NetworkEvent.Context> ctx) {
|
||||||
ctx.get().enqueueWork(() -> {
|
NetworkEvent.Context context = ctx.get();
|
||||||
|
|
||||||
|
// Direction guard : ce packet est S→C uniquement. ModNetwork.reg() helper
|
||||||
|
// n'enforce pas NetworkDirection, donc un client malveillant pourrait
|
||||||
|
// spoofer ce packet vers le serveur. Guard défensif (voir P3-11 review
|
||||||
|
// RISK-001 — fix systémique du helper reg() tracé en backlog séparé).
|
||||||
|
if (context.getDirection() != net.minecraftforge.network.NetworkDirection.PLAY_TO_CLIENT) {
|
||||||
|
TiedUpRigConstants.LOGGER.warn(
|
||||||
|
"[PacketPlayRigAnim] rejected non-S→C packet direction: {} (possible spoofing attempt)",
|
||||||
|
context.getDirection()
|
||||||
|
);
|
||||||
|
context.setPacketHandled(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
context.enqueueWork(() -> {
|
||||||
TiedUpRigConstants.LOGGER.debug(
|
TiedUpRigConstants.LOGGER.debug(
|
||||||
"[PacketPlayRigAnim] received (stub P3-11): entityId={}, animId={}, transition={}s, priority={}",
|
"[PacketPlayRigAnim] received (stub P3-11): entityId={}, animId={}, transition={}s, priority={}",
|
||||||
pkt.entityId, pkt.animId, pkt.transitionTime, pkt.priority()
|
pkt.entityId, pkt.animId, pkt.transitionTime, pkt.priority()
|
||||||
);
|
);
|
||||||
// TODO P3-12 : resolve entity + patch + animator.playAnimation
|
// TODO P3-12 : resolve entity + patch + animator.playAnimation
|
||||||
});
|
});
|
||||||
ctx.get().setPacketHandled(true);
|
context.setPacketHandled(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,10 +6,19 @@ package com.tiedup.remake.rig.network;
|
|||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.never;
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import io.netty.buffer.Unpooled;
|
import io.netty.buffer.Unpooled;
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraftforge.network.NetworkDirection;
|
||||||
|
import net.minecraftforge.network.NetworkEvent;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
@@ -137,6 +146,36 @@ class PacketPlayRigAnimTest {
|
|||||||
assertEquals("deep/path/with_underscores", decoded.animId().getPath());
|
assertEquals("deep/path/with_underscores", decoded.animId().getPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Direction guard (RISK-001) : handleOnClient doit rejeter les packets
|
||||||
|
* reçus avec direction PLAY_TO_SERVER (spoofing client malveillant).
|
||||||
|
* On mock NetworkEvent.Context + son Supplier, on stub getDirection() et
|
||||||
|
* on vérifie que enqueueWork() n'est PAS appelé + setPacketHandled(true)
|
||||||
|
* est appelé.
|
||||||
|
*
|
||||||
|
* <p>Note : on n'exécute pas la branche PLAY_TO_CLIENT ici car enqueueWork
|
||||||
|
* invoque LogicalSidedProvider.WORKQUEUE qui NPE sans bootstrap MC —
|
||||||
|
* testable uniquement en runClient/gameday.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
void handleOnClient_rejectsServerBoundDirection() {
|
||||||
|
ResourceLocation anim = ResourceLocation.fromNamespaceAndPath("tiedup", "test");
|
||||||
|
PacketPlayRigAnim pkt = PacketPlayRigAnim.of(42, anim, 0.15F, Layer.Priority.MIDDLE);
|
||||||
|
|
||||||
|
NetworkEvent.Context context = mock(NetworkEvent.Context.class);
|
||||||
|
when(context.getDirection()).thenReturn(NetworkDirection.PLAY_TO_SERVER);
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
Supplier<NetworkEvent.Context> ctxSupplier = mock(Supplier.class);
|
||||||
|
when(ctxSupplier.get()).thenReturn(context);
|
||||||
|
|
||||||
|
PacketPlayRigAnim.handleOnClient(pkt, ctxSupplier);
|
||||||
|
|
||||||
|
// Guard doit short-circuit : setPacketHandled(true) appelé, enqueueWork jamais.
|
||||||
|
verify(context, times(1)).setPacketHandled(true);
|
||||||
|
verify(context, never()).enqueueWork(org.mockito.ArgumentMatchers.any());
|
||||||
|
}
|
||||||
|
|
||||||
/** Sanity check : deux packets distincts ne sont pas equal. */
|
/** Sanity check : deux packets distincts ne sont pas equal. */
|
||||||
@Test
|
@Test
|
||||||
void records_notEqual_whenDifferent() {
|
void records_notEqual_whenDifferent() {
|
||||||
|
|||||||
Reference in New Issue
Block a user