1+ package me .ayunami2000 .ayunViaProxyEagUtils ;
2+
3+ import com .google .common .primitives .Ints ;
4+ import io .netty .buffer .ByteBuf ;
5+ import io .netty .buffer .ByteBufUtil ;
6+ import io .netty .buffer .Unpooled ;
7+ import io .netty .channel .*;
8+ import io .netty .handler .codec .MessageToMessageCodec ;
9+ import io .netty .handler .codec .http .websocketx .*;
10+ import net .raphimc .netminecraft .constants .MCPackets ;
11+ import net .raphimc .netminecraft .netty .connection .NetClient ;
12+ import net .raphimc .netminecraft .packet .PacketTypes ;
13+ import net .raphimc .vialegacy .protocols .release .protocol1_6_1to1_5_2 .ClientboundPackets1_5_2 ;
14+ import net .raphimc .vialegacy .protocols .release .protocol1_6_1to1_5_2 .ServerboundPackets1_5_2 ;
15+ import net .raphimc .vialegacy .protocols .release .protocol1_7_2_5to1_6_4 .types .Types1_6_4 ;
16+ import net .raphimc .vialoader .util .VersionEnum ;
17+ import net .raphimc .viaproxy .proxy .session .ProxyConnection ;
18+ import net .raphimc .viaproxy .proxy .util .ExceptionUtil ;
19+
20+ import java .io .IOException ;
21+ import java .nio .charset .StandardCharsets ;
22+ import java .util .*;
23+
24+ public class EaglerServerHandler extends MessageToMessageCodec <BinaryWebSocketFrame , ByteBuf > {
25+ private final VersionEnum version ;
26+ private final String password ;
27+ private final NetClient proxyConnection ;
28+ private final Map <UUID , String > uuidStringMap = new HashMap <>();
29+ private final List <UUID > skinsBeingFetched = new ArrayList <>();
30+ private ByteBuf serverBoundPartialPacket = Unpooled .EMPTY_BUFFER ;
31+ private ByteBuf clientBoundPartialPacket = Unpooled .EMPTY_BUFFER ;
32+ public EaglerServerHandler (NetClient proxyConnection , String password ) {
33+ this .version = proxyConnection instanceof ProxyConnection ? ((ProxyConnection ) proxyConnection ).getServerVersion () : VersionEnum .r1_5_2 ;
34+ this .password = password ;
35+ this .proxyConnection = proxyConnection ;
36+ }
37+
38+ @ Override
39+ public void exceptionCaught (ChannelHandlerContext ctx , Throwable cause ) {
40+ ExceptionUtil .handleNettyException (ctx , cause , null );
41+ }
42+
43+ private int handshakeState = 0 ;
44+
45+ @ Override
46+ public void encode (ChannelHandlerContext ctx , ByteBuf in , List <Object > out ) {
47+ if (version .isNewerThan (VersionEnum .r1_6_4 )) {
48+ if (handshakeState == 0 ) {
49+ handshakeState = 1 ;
50+ if (((ProxyConnection ) proxyConnection ).getGameProfile () == null ) {
51+ out .add (Unpooled .EMPTY_BUFFER );
52+ ctx .close ();
53+ return ;
54+ }
55+ ConnectionHandshake .attemptHandshake (out , ctx .channel (), (ProxyConnection ) proxyConnection , password );
56+ if (out .isEmpty ()) {
57+ out .add (Unpooled .EMPTY_BUFFER );
58+ }
59+ } else if (handshakeState < 4 ) {
60+ out .add (Unpooled .EMPTY_BUFFER );
61+ } else {
62+ out .add (new BinaryWebSocketFrame (in .retain ()));
63+ }
64+ } else {
65+ ByteBuf bb = ctx .alloc ().buffer (serverBoundPartialPacket .readableBytes () + in .readableBytes ());
66+ bb .writeBytes (serverBoundPartialPacket );
67+ serverBoundPartialPacket .release ();
68+ serverBoundPartialPacket = Unpooled .EMPTY_BUFFER ;
69+ bb .writeBytes (in );
70+ int readerIndex = 0 ;
71+ try {
72+ while (bb .isReadable ()) {
73+ readerIndex = bb .readerIndex ();
74+ ServerboundPackets1_5_2 pkt = ServerboundPackets1_5_2 .getPacket (bb .readUnsignedByte ());
75+ pkt .getPacketReader ().accept (null , bb );
76+ int len = bb .readerIndex () - readerIndex ;
77+ ByteBuf packet = ctx .alloc ().buffer (len );
78+ bb .readerIndex (readerIndex );
79+ bb .readBytes (packet , len );
80+ encodeOld (ctx , packet , out );
81+ }
82+ } catch (Exception e ) {
83+ bb .readerIndex (readerIndex );
84+ if (bb .readableBytes () > 65535 ) {
85+ ctx .close ();
86+ out .add (Unpooled .EMPTY_BUFFER );
87+ return ;
88+ }
89+ serverBoundPartialPacket = ctx .alloc ().buffer (bb .readableBytes ());
90+ serverBoundPartialPacket .writeBytes (bb );
91+ }
92+ }
93+ if (out .isEmpty ()) {
94+ out .add (Unpooled .EMPTY_BUFFER );
95+ }
96+ }
97+
98+ public void encodeOld (ChannelHandlerContext ctx , ByteBuf in , List <Object > out ) {
99+ if (handshakeState == 0 ) {
100+ handshakeState = 1 ;
101+ if (in .readableBytes () >= 2 && in .getUnsignedByte (0 ) == 2 ) {
102+ in .setByte (1 , in .getUnsignedByte (1 ) + 8 );
103+ }
104+ }
105+ if (in .readableBytes () >= 1 && in .getUnsignedByte (0 ) == 0xFD ) {
106+ return ;
107+ }
108+ if (in .readableBytes () >= 3 && in .getUnsignedByte (0 ) == 250 ) {
109+ in .skipBytes (1 );
110+ String tag ;
111+ byte [] msg ;
112+ try {
113+ tag = Types1_6_4 .STRING .read (in );
114+ if (tag .equals ("EAG|Skins-1.8" )) {
115+ msg = new byte [in .readShort ()];
116+ in .readBytes (msg );
117+ if (msg .length == 0 ) {
118+ throw new IOException ("Zero-length packet recieved" );
119+ }
120+ final int packetId = msg [0 ] & 0xFF ;
121+ switch (packetId ) {
122+ case 3 : {
123+ if (msg .length != 17 ) {
124+ throw new IOException ("Invalid length " + msg .length + " for skin request packet" );
125+ }
126+ final UUID searchUUID = SkinPackets .bytesToUUID (msg , 1 );
127+ if (uuidStringMap .containsKey (searchUUID )) {
128+ // skinsBeingFetched.add(searchUUID);
129+ String name = uuidStringMap .get (searchUUID );
130+ ByteBuf bb = ctx .alloc ().buffer ();
131+ bb .writeByte ((byte ) 250 );
132+ Types1_6_4 .STRING .write (bb , "EAG|FetchSkin" ); // todo: get to work
133+ bb .writeByte ((byte ) 0 );
134+ bb .writeByte ((byte ) 0 );
135+ bb .writeBytes (name .getBytes (StandardCharsets .UTF_8 ));
136+ out .add (new BinaryWebSocketFrame (bb ));
137+ }
138+ break ;
139+ }
140+ case 6 : {
141+ break ;
142+ }
143+ default : {
144+ throw new IOException ("Unknown packet type " + packetId );
145+ }
146+ }
147+ return ;
148+ }
149+ } catch (Exception ignored ) {
150+ }
151+ in .resetReaderIndex ();
152+ }
153+ out .add (new BinaryWebSocketFrame (in .retain ()));
154+ }
155+
156+ @ Override
157+ public void decode (ChannelHandlerContext ctx , BinaryWebSocketFrame in , List <Object > out ) {
158+ if (version .isNewerThan (VersionEnum .r1_6_4 )) {
159+ if (handshakeState == 0 ) {
160+ out .add (Unpooled .EMPTY_BUFFER );
161+ } else if (handshakeState == 1 ) {
162+ handshakeState = 2 ;
163+ ConnectionHandshake .attemptHandshake2 (ctx .channel (), ByteBufUtil .getBytes (in .content ()), (ProxyConnection ) proxyConnection , password );
164+ out .add (Unpooled .EMPTY_BUFFER );
165+ } else if (handshakeState == 2 ) {
166+ handshakeState = 3 ;
167+ ConnectionHandshake .attemptHandshake3 (ctx .channel (), ByteBufUtil .getBytes (in .content ()), (ProxyConnection ) proxyConnection );
168+ ByteBuf bb = ctx .alloc ().buffer ();
169+ PacketTypes .writeVarInt (bb , MCPackets .S2C_LOGIN_SUCCESS .getId (version .getVersion ()));
170+ PacketTypes .writeString (bb , ((ProxyConnection ) proxyConnection ).getGameProfile ().getId ().toString ());
171+ PacketTypes .writeString (bb , ((ProxyConnection ) proxyConnection ).getGameProfile ().getName ());
172+ out .add (bb );
173+ } else if (handshakeState == 3 ) {
174+ handshakeState = 4 ;
175+ ConnectionHandshake .attemptHandshake4 (ctx .channel (), ByteBufUtil .getBytes (in .content ()), (ProxyConnection ) proxyConnection );
176+ out .add (Unpooled .EMPTY_BUFFER );
177+ } else {
178+ if (in .content ().getByte (0 ) == MCPackets .S2C_LOGIN_SUCCESS .getId (version .getVersion ()) && in .content ().getByte (1 ) == 0 && in .content ().getByte (2 ) == 2 ) {
179+ out .add (Unpooled .EMPTY_BUFFER );
180+ return ;
181+ }
182+ if (in .content ().getByte (0 ) == 0 ) {
183+ in .content ().skipBytes (1 );
184+ PacketTypes .readVarInt (in .content ());
185+ if (in .content ().readableBytes () > 0 ) {
186+ in .content ().setByte (0 , 0x40 );
187+ }
188+ in .content ().resetReaderIndex ();
189+ }
190+ out .add (in .content ().retain ());
191+ }
192+ } else {
193+ ByteBuf bb = ctx .alloc ().buffer (clientBoundPartialPacket .readableBytes () + in .content ().readableBytes ());
194+ bb .writeBytes (clientBoundPartialPacket );
195+ clientBoundPartialPacket .release ();
196+ clientBoundPartialPacket = Unpooled .EMPTY_BUFFER ;
197+ bb .writeBytes (in .content ());
198+ int readerIndex = 0 ;
199+ try {
200+ while (bb .isReadable ()) {
201+ readerIndex = bb .readerIndex ();
202+ ClientboundPackets1_5_2 pkt = ClientboundPackets1_5_2 .getPacket (bb .readUnsignedByte ());
203+ pkt .getPacketReader ().accept (null , bb );
204+ int len = bb .readerIndex () - readerIndex ;
205+ ByteBuf packet = ctx .alloc ().buffer (len );
206+ bb .readerIndex (readerIndex );
207+ bb .readBytes (packet , len );
208+ decodeOld (ctx , packet , out );
209+ }
210+ } catch (Exception e ) {
211+ bb .readerIndex (readerIndex );
212+ if (bb .readableBytes () > 65535 ) {
213+ ctx .close ();
214+ out .add (Unpooled .EMPTY_BUFFER );
215+ return ;
216+ }
217+ clientBoundPartialPacket = ctx .alloc ().buffer (bb .readableBytes ());
218+ clientBoundPartialPacket .writeBytes (bb );
219+ }
220+ }
221+ if (out .isEmpty ()) {
222+ out .add (Unpooled .EMPTY_BUFFER );
223+ }
224+ }
225+ public void decodeOld (ChannelHandlerContext ctx , ByteBuf in , List <Object > out ) {
226+ if (in .getUnsignedByte (0 ) == 0x14 ) {
227+ in .skipBytes (5 );
228+ try {
229+ String name = Types1_6_4 .STRING .read (in );
230+ UUID uuid = UUID .nameUUIDFromBytes (("OfflinePlayer:" + name ).getBytes (StandardCharsets .UTF_8 ));
231+ uuidStringMap .put (uuid , name );
232+ } catch (Exception ignored ) {
233+ }
234+ in .resetReaderIndex ();
235+ }
236+ if (in .getUnsignedByte (0 ) == 0xFD ) {
237+ in .writerIndex (0 );
238+ in .writeByte ((byte ) 0xCD );
239+ in .writeByte ((byte ) 0x00 );
240+ ctx .writeAndFlush (new BinaryWebSocketFrame (in .retain ()));
241+ return ;
242+ }
243+ if (!skinsBeingFetched .isEmpty () && in .readableBytes () >= 3 && in .getUnsignedByte (0 ) == 250 ) {
244+ in .skipBytes (1 );
245+ String tag ;
246+ byte [] msg ;
247+ try {
248+ tag = Types1_6_4 .STRING .read (in );
249+ // System.out.println(tag);
250+ if (tag .equals ("EAG|UserSkin" )) {
251+ msg = new byte [in .readShort ()];
252+ in .readBytes (msg );
253+ System .out .println (msg .length );
254+ byte [] res = new byte [msg .length - 1 ];
255+ System .arraycopy (msg , 1 , res , 0 , res .length );
256+ if (res .length == 8192 ) {
257+ final int [] tmp1 = new int [2048 ];
258+ final int [] tmp2 = new int [4096 ];
259+ for (int i = 0 ; i < tmp1 .length ; ++i ) {
260+ tmp1 [i ] = Ints .fromBytes (res [i * 4 + 3 ], res [i * 4 ], res [i * 4 + 1 ], res [i * 4 + 2 ]);
261+ }
262+ SkinConverter .convert64x32to64x64 (tmp1 , tmp2 );
263+ res = new byte [16384 ];
264+ for (int i = 0 ; i < tmp2 .length ; ++i ) {
265+ System .arraycopy (Ints .toByteArray (tmp2 [i ]), 0 , res , i * 4 , 4 );
266+ }
267+ } else {
268+ for (int j = 0 ; j < res .length ; j += 4 ) {
269+ final byte tmp3 = res [j + 3 ];
270+ res [j + 3 ] = res [j + 2 ];
271+ res [j + 2 ] = res [j + 1 ];
272+ res [j + 1 ] = res [j ];
273+ res [j ] = tmp3 ;
274+ }
275+ }
276+ in .writerIndex (1 );
277+ Types1_6_4 .STRING .write (in , "EAG|Skins-1.8" );
278+ byte [] data = SkinPackets .makeCustomResponse (skinsBeingFetched .remove (0 ), 0 , res );
279+ in .writeShort (data .length );
280+ in .writeBytes (data );
281+ }
282+ } catch (Exception ignored ) {
283+ }
284+ in .resetReaderIndex ();
285+ }
286+ if (in .getByte (0 ) == (byte ) 0x83 && in .getShort (1 ) != 358 ) {
287+ return ;
288+ }
289+ out .add (in .retain ());
290+ }
291+ }
0 commit comments