fix(shell): normalizar IPv4 de peers no Windows
Evita IP IPv6-mapeado com zone id no campo de destino ao abrir conversa pela lista. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
8fe9bee453
commit
e0624403b2
10 files changed
+131
-47
No files matched your search
@@ -1,6 +1,8 @@
|
||||
package pitiupi.models;
|
||||
|
||||
import java.net.InetAddress;
|
||||
|
||||
import pitiupi.presentation.shell.PeerIpv4;
|
||||
/**
|
||||
* Representa um usuário identificado na rede e as informações necessárias
|
||||
* para acompanhar sua presença através de mensagens de heartbeat.
|
||||
@@ -68,6 +70,6 @@ public class User {
|
||||
if (isBroadcastTarget() || address == null) {
|
||||
return userName;
|
||||
}
|
||||
return userName + " (" + address.getHostAddress() + ")";
|
||||
return userName + " (" + PeerIpv4.fromInetAddress(address) + ")";
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,6 @@ package pitiupi.presentation.shell;
|
||||
|
||||
import pitiupi.control.ConnectionManager;
|
||||
|
||||
import java.net.InetAddress;
|
||||
|
||||
/**
|
||||
* Identifica mensagens e atividade originadas neste host (eco de rede).
|
||||
*/
|
||||
@@ -28,7 +26,7 @@ public final class LocalUserIdentity {
|
||||
|
||||
private static String canonicalIpv4(String ip) {
|
||||
try {
|
||||
return InetAddress.getByName(ip.trim()).getHostAddress();
|
||||
return PeerIpv4.normalize(ip);
|
||||
} catch (Exception ex) {
|
||||
return ip.trim();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
package pitiupi.presentation.shell;
|
||||
|
||||
import java.net.Inet4Address;
|
||||
import java.net.Inet6Address;
|
||||
import java.net.InetAddress;
|
||||
|
||||
/**
|
||||
* IPv4 legível para peers (UDP/TCP/chat). No Windows, {@link InetAddress#getHostAddress()}
|
||||
* pode devolver forma IPv6 mapeada ({@code 0:0:...:ffff:a9fe:f8c4}) ou sufixo de zona ({@code %7}).
|
||||
*/
|
||||
public final class PeerIpv4 {
|
||||
|
||||
private PeerIpv4() {
|
||||
}
|
||||
|
||||
public static String fromInetAddress(InetAddress address) {
|
||||
if (address == null) {
|
||||
return "";
|
||||
}
|
||||
if (address instanceof Inet4Address) {
|
||||
return address.getHostAddress();
|
||||
}
|
||||
if (address instanceof Inet6Address inet6 && inet6.isIPv4CompatibleAddress()) {
|
||||
byte[] raw = address.getAddress();
|
||||
if (raw.length == 16) {
|
||||
return ipv4FromBytes(raw, 12);
|
||||
}
|
||||
}
|
||||
byte[] raw = address.getAddress();
|
||||
if (raw.length == 16 && isIpv4Mapped(raw)) {
|
||||
return ipv4FromBytes(raw, 12);
|
||||
}
|
||||
return stripZoneId(address.getHostAddress());
|
||||
}
|
||||
|
||||
public static String normalize(String text) {
|
||||
if (text == null || text.isBlank()) {
|
||||
return "";
|
||||
}
|
||||
String trimmed = stripZoneId(text.trim());
|
||||
try {
|
||||
return fromInetAddress(InetAddress.getByName(trimmed));
|
||||
} catch (Exception ex) {
|
||||
return trimmed;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isIpv4Mapped(byte[] raw) {
|
||||
return raw[0] == 0 && raw[1] == 0 && raw[2] == 0 && raw[3] == 0
|
||||
&& raw[4] == 0 && raw[5] == 0 && raw[6] == 0 && raw[7] == 0
|
||||
&& raw[8] == 0 && raw[9] == 0 && raw[10] == (byte) 0xff && raw[11] == (byte) 0xff;
|
||||
}
|
||||
|
||||
private static String ipv4FromBytes(byte[] raw, int offset) {
|
||||
return (raw[offset] & 0xff) + "." + (raw[offset + 1] & 0xff) + "."
|
||||
+ (raw[offset + 2] & 0xff) + "." + (raw[offset + 3] & 0xff);
|
||||
}
|
||||
|
||||
private static String stripZoneId(String host) {
|
||||
if (host == null) {
|
||||
return "";
|
||||
}
|
||||
int zone = host.indexOf('%');
|
||||
return zone >= 0 ? host.substring(0, zone) : host;
|
||||
}
|
||||
}
|
||||
@@ -95,11 +95,14 @@ public final class PluginRoutingPanel extends JPanel {
|
||||
|
||||
public void bindPeerSession(String ip, String displayName, String receiveScopeHtml) {
|
||||
everyoneInRoom = false;
|
||||
if (ip != null) {
|
||||
String normalized = PeerIpv4.normalize(ip != null ? ip : "");
|
||||
if (!normalized.isEmpty()) {
|
||||
ipField.setText(normalized);
|
||||
} else if (ip != null) {
|
||||
ipField.setText(ip);
|
||||
}
|
||||
String who = displayName != null && !displayName.isBlank() ? displayName : ip;
|
||||
sessionBanner.setText(SessionPeerLabels.sessionBannerHtml(who, ip));
|
||||
String who = displayName != null && !displayName.isBlank() ? displayName : normalized;
|
||||
sessionBanner.setText(SessionPeerLabels.sessionBannerHtml(who, normalized.isEmpty() ? ip : normalized));
|
||||
setReceiveScopeHint(receiveScopeHtml);
|
||||
applyRoutingState();
|
||||
}
|
||||
|
||||
@@ -3,8 +3,6 @@ package pitiupi.presentation.shell;
|
||||
import pitiupi.application.presence.UserPeerView;
|
||||
import pitiupi.control.ConnectionManager;
|
||||
|
||||
import java.net.InetAddress;
|
||||
|
||||
/**
|
||||
* Nomes amigáveis para abas e banner de sessão com peers.
|
||||
*/
|
||||
@@ -17,7 +15,7 @@ public final class SessionPeerLabels {
|
||||
if (ip == null || ip.isBlank()) {
|
||||
return hintName != null && !hintName.isBlank() ? hintName : "";
|
||||
}
|
||||
String trimmedIp = ip.trim();
|
||||
String trimmedIp = PeerIpv4.normalize(ip);
|
||||
if (hintName != null && !hintName.isBlank() && !hintName.trim().equals(trimmedIp)) {
|
||||
return hintName.trim();
|
||||
}
|
||||
@@ -28,7 +26,7 @@ public final class SessionPeerLabels {
|
||||
if (view.isSelf() && isLocalIp(trimmedIp)) {
|
||||
return selfLabel(connectionManager);
|
||||
}
|
||||
if (view.getInetAddress().map(InetAddress::getHostAddress).orElse("").equals(trimmedIp)) {
|
||||
if (view.getInetAddress().map(PeerIpv4::fromInetAddress).orElse("").equals(trimmedIp)) {
|
||||
String name = view.getDisplayName();
|
||||
if (name != null && !name.isBlank() && !name.equals(trimmedIp)) {
|
||||
return name;
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package pitiupi.presentation.shell;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.net.InetAddress;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
class PeerIpv4Test {
|
||||
|
||||
@Test
|
||||
void mapsIpv4MappedIpv6ToDottedDecimal() throws Exception {
|
||||
InetAddress mapped = InetAddress.getByName("0:0:0:0:0:ffff:a9fe:f8c4");
|
||||
assertEquals("169.254.248.196", PeerIpv4.fromInetAddress(mapped));
|
||||
}
|
||||
|
||||
@Test
|
||||
void stripsZoneIdFromString() {
|
||||
assertEquals("169.254.248.196", PeerIpv4.normalize("0:0:0:0:0:ffff:a9fe:f8c4%7"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void keepsPlainIpv4() throws Exception {
|
||||
InetAddress v4 = InetAddress.getByName("169.254.165.248");
|
||||
assertEquals("169.254.165.248", PeerIpv4.fromInetAddress(v4));
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@ import pitiupi.chat.net.LegacyMpChatMessage;
|
||||
import pitiupi.control.ConnectionManager;
|
||||
import pitiupi.models.User;
|
||||
import pitiupi.presentation.shell.LocalNetworkInfo;
|
||||
import pitiupi.presentation.shell.PeerIpv4;
|
||||
import pitiupi.presentation.shell.LocalUserIdentity;
|
||||
import pitiupi.presentation.shell.PeerDraftPanel;
|
||||
import pitiupi.presentation.shell.PluginRoutingPanel;
|
||||
@@ -245,14 +246,7 @@ public class ChatPanel extends JPanel implements PrivateChatUiSink {
|
||||
}
|
||||
|
||||
private static String canonicalPeerIp(String ip) {
|
||||
if (ip == null || ip.isBlank()) {
|
||||
return "";
|
||||
}
|
||||
try {
|
||||
return InetAddress.getByName(ip.trim()).getHostAddress();
|
||||
} catch (Exception ex) {
|
||||
return ip.trim();
|
||||
}
|
||||
return PeerIpv4.normalize(ip);
|
||||
}
|
||||
|
||||
private void selectRoomSession() {
|
||||
@@ -275,7 +269,7 @@ public class ChatPanel extends JPanel implements PrivateChatUiSink {
|
||||
return;
|
||||
}
|
||||
peer.getInetAddress().ifPresent(addr ->
|
||||
openPeerTab(addr.getHostAddress(), peer.getDisplayName()));
|
||||
openPeerTab(PeerIpv4.fromInetAddress(addr), peer.getDisplayName()));
|
||||
}
|
||||
|
||||
public void enablePrivateTcpForPeer(UserPeerView peer) {
|
||||
@@ -415,7 +409,7 @@ public class ChatPanel extends JPanel implements PrivateChatUiSink {
|
||||
if (privateChatController != null) {
|
||||
privateChatController.openChat(user);
|
||||
}
|
||||
appendSystemLine(privateKey(user.getAddress().getHostAddress()),
|
||||
appendSystemLine(privateKey(PeerIpv4.fromInetAddress(user.getAddress())),
|
||||
"Canal TCP privado conectando… envie de novo em instantes.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import pitiupi.control.ConnectionManager;
|
||||
import pitiupi.models.User;
|
||||
import pitiupi.net.tcp.TcpConnection;
|
||||
import pitiupi.presentation.shell.LocalNetworkInfo;
|
||||
import pitiupi.presentation.shell.PeerIpv4;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
@@ -29,14 +30,14 @@ public class PrivateChatController {
|
||||
}
|
||||
|
||||
private static String addressKey(TcpConnection connection) {
|
||||
return connection.getAddress().getHostAddress();
|
||||
return PeerIpv4.fromInetAddress(connection.getAddress());
|
||||
}
|
||||
|
||||
public void openChat(User user) {
|
||||
if (user == null || user.getAddress() == null) {
|
||||
return;
|
||||
}
|
||||
String address = user.getAddress().getHostAddress();
|
||||
String address = PeerIpv4.fromInetAddress(user.getAddress());
|
||||
if (connections.containsKey(address)) {
|
||||
if (uiSink != null) {
|
||||
uiSink.onPrivateChannelReady(address);
|
||||
@@ -77,7 +78,7 @@ public class PrivateChatController {
|
||||
if (user == null || user.getAddress() == null || text == null || text.isBlank()) {
|
||||
return false;
|
||||
}
|
||||
String address = user.getAddress().getHostAddress();
|
||||
String address = PeerIpv4.fromInetAddress(user.getAddress());
|
||||
TcpConnection connection = connections.get(address);
|
||||
if (connection == null) {
|
||||
return false;
|
||||
@@ -104,6 +105,6 @@ public class PrivateChatController {
|
||||
if (user == null || user.getAddress() == null) {
|
||||
return false;
|
||||
}
|
||||
return connections.containsKey(user.getAddress().getHostAddress());
|
||||
return connections.containsKey(PeerIpv4.fromInetAddress(user.getAddress()));
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ import pitiupi.chat.net.ChatMessage;
|
||||
import pitiupi.chat.net.LegacyMpChatMessage;
|
||||
import pitiupi.control.ConnectionManager;
|
||||
import pitiupi.presentation.shell.LocalUserIdentity;
|
||||
import pitiupi.presentation.shell.PeerIpv4;
|
||||
import pitiupi.control.GuiManager;
|
||||
import pitiupi.models.Messages.Message;
|
||||
import pitiupi.models.Plugin;
|
||||
@@ -138,17 +139,17 @@ public class ChatPlugin extends Plugin implements PrivateChatHost {
|
||||
if (ip == null || ip.isBlank() || connectionManager == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
InetAddress address = InetAddress.getByName(ip);
|
||||
for (UserPeerView view : connectionManager.getPresenceService().listPeerViews()) {
|
||||
if (view.isSelf()) {
|
||||
continue;
|
||||
}
|
||||
if (view.getInetAddress().isPresent() && view.getInetAddress().get().equals(address)) {
|
||||
return view.getInstanceId();
|
||||
}
|
||||
String needle = PeerIpv4.normalize(ip);
|
||||
if (needle.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
for (UserPeerView view : connectionManager.getPresenceService().listPeerViews()) {
|
||||
if (view.isSelf()) {
|
||||
continue;
|
||||
}
|
||||
if (view.getInetAddress().map(PeerIpv4::fromInetAddress).orElse("").equals(needle)) {
|
||||
return view.getInstanceId();
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -166,7 +167,7 @@ public class ChatPlugin extends Plugin implements PrivateChatHost {
|
||||
return true;
|
||||
}
|
||||
privateChatController.receiveMessage(connection, legacy);
|
||||
String instanceId = peerInstanceIdForActivity(connection.getAddress().getHostAddress());
|
||||
String instanceId = peerInstanceIdForActivity(PeerIpv4.fromInetAddress(connection.getAddress()));
|
||||
if (instanceId != null) {
|
||||
connectionManager.getPeerActivityInbox().record(instanceId, getIdentifier(), "chat.private.tcp");
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import pitiupi.application.messaging.TransportMode;
|
||||
import pitiupi.application.presence.UserPeerView;
|
||||
import pitiupi.control.ConnectionManager;
|
||||
import pitiupi.presentation.shell.PeerDraftPanel;
|
||||
import pitiupi.presentation.shell.PeerIpv4;
|
||||
import pitiupi.presentation.shell.PluginRoutingPanel;
|
||||
import pitiupi.presentation.shell.PluginSessionKeys;
|
||||
import pitiupi.presentation.shell.PluginSessionWorkspace;
|
||||
@@ -350,14 +351,7 @@ public class ScreenCastPanel extends JPanel {
|
||||
}
|
||||
|
||||
private static String canonicalPeerIp(String ip) {
|
||||
if (ip == null || ip.isBlank()) {
|
||||
return "";
|
||||
}
|
||||
try {
|
||||
return InetAddress.getByName(ip.trim()).getHostAddress();
|
||||
} catch (Exception ex) {
|
||||
return ip.trim();
|
||||
}
|
||||
return PeerIpv4.normalize(ip);
|
||||
}
|
||||
|
||||
public void focusMulticastSharing() {
|
||||
@@ -375,7 +369,7 @@ public class ScreenCastPanel extends JPanel {
|
||||
return;
|
||||
}
|
||||
peer.getInetAddress().ifPresent(addr -> {
|
||||
String ip = addr.getHostAddress();
|
||||
String ip = PeerIpv4.fromInetAddress(addr);
|
||||
openPeerTab(ip, peer.getDisplayName());
|
||||
String key = PluginSessionKeys.peer(canonicalPeerIp(ip));
|
||||
sharingByTabKey.put(key, true);
|
||||
@@ -389,7 +383,7 @@ public class ScreenCastPanel extends JPanel {
|
||||
if (peer == null || peer.isBroadcastTarget() || peer.isSelf()) {
|
||||
return;
|
||||
}
|
||||
peer.getInetAddress().ifPresent(addr -> openPeerTab(addr.getHostAddress(), peer.getDisplayName()));
|
||||
peer.getInetAddress().ifPresent(addr -> openPeerTab(PeerIpv4.fromInetAddress(addr), peer.getDisplayName()));
|
||||
}
|
||||
|
||||
private void ensureTodosTab() {
|
||||
@@ -534,7 +528,7 @@ public class ScreenCastPanel extends JPanel {
|
||||
continue;
|
||||
}
|
||||
if (senderName != null && senderName.equals(view.getDisplayName())) {
|
||||
view.getInetAddress().ifPresent(addr -> peerIpsByViewKey.put(viewKey, addr.getHostAddress()));
|
||||
view.getInetAddress().ifPresent(addr -> peerIpsByViewKey.put(viewKey, PeerIpv4.fromInetAddress(addr)));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user