package org.openautonomousconnection.webclient; import dev.unlegitdqrk.unlegitlibrary.event.Listener; import dev.unlegitdqrk.unlegitlibrary.network.system.client.events.packets.C_PacketReadEvent; import lombok.Getter; import org.openautonomousconnection.oacswing.component.OACOptionPane; import org.openautonomousconnection.protocol.packets.v1_0_1.beta.web.WebPacket; import org.openautonomousconnection.protocol.packets.v1_0_1.beta.web.impl.navigate.WebNavigateAckPacket; import org.openautonomousconnection.protocol.packets.v1_0_1.beta.web.impl.resource.WebResourceResponsePacket; import org.openautonomousconnection.protocol.side.client.ProtocolClient; import org.openautonomousconnection.protocol.side.client.ProtocolWebClient; import org.openautonomousconnection.protocol.side.client.events.ConnectedToProtocolINSServerEvent; import org.openautonomousconnection.protocol.urlhandler.v1_0_1.beta.LibClientImpl_v1_0_1_B; import org.openautonomousconnection.protocol.urlhandler.v1_0_1.beta.web.WebFlagInspector; import org.openautonomousconnection.protocol.urlhandler.v1_0_1.beta.web.WebRequestContextProvider; import org.openautonomousconnection.protocol.versions.v1_0_1.beta.WebPacketHeader; import org.openautonomousconnection.webclient.ui.BrowserTab; import java.awt.*; import java.io.ByteArrayOutputStream; import java.net.URL; import java.nio.charset.StandardCharsets; import java.util.Map; import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicBoolean; /** * WebClient Protocol implementation (v1.0.1). * *
Implements full stream assembly with strict correlation via: * requestId + tabId + pageId + frameId.
*/ public final class ClientImpl extends ProtocolWebClient { private static final long MAX_STREAM_BYTES = 64L * 1024L * 1024L; // 64MB safety cap private static final int MAX_CONCURRENT_STREAMS = 256; @Getter private final LibImpl libImpl = new LibImpl(); private final AtomicBoolean serverConnectionInitialized = new AtomicBoolean(false); private final Component dialogParent; private final Runnable onServerReady; public ClientImpl(Component dialogParent, Runnable onServerReady) { this.dialogParent = dialogParent; this.onServerReady = Objects.requireNonNull(onServerReady); } @Override public boolean trustINS(String caFingerprint) { Object[] options = {"Continue", "Cancel"}; return OACOptionPane.showOptionDialog( dialogParent, "Fingerprint: " + caFingerprint + "\nContinue?", "INS Connection", OACOptionPane.YES_NO_OPTION, OACOptionPane.INFORMATION_MESSAGE, null, options, options[0] ) == 0; } @Override public boolean trustNewINSFingerprint(String oldCAFingerprint, String newCAFingerprint) { Object[] options = {"Continue", "Cancel"}; return OACOptionPane.showOptionDialog( dialogParent, "Saved: " + oldCAFingerprint + "\nNew: " + newCAFingerprint + "\nContinue?", "INS Connection", OACOptionPane.YES_NO_OPTION, OACOptionPane.INFORMATION_MESSAGE, null, options, options[0] ) == 0; } @Listener public void onConnected(ConnectedToProtocolINSServerEvent event) { try { if (serverConnectionInitialized.compareAndSet(false, true)) { buildServerConnection(null, getProtocolBridge().getProtocolValues().ssl); onServerReady.run(); } } catch (Exception e) { serverConnectionInitialized.set(false); throw new RuntimeException(e); } } private record StreamKey(long requestId, long tabId, long pageId, long frameId) { StreamKey(WebPacketHeader h) { this(h.getRequestId(), h.getTabId(), h.getPageId(), h.getFrameId()); } } private static final class StreamState { private final int statusCode; private final String contentType; private final Map