· 8 years ago · Dec 07, 2017, 09:22 PM
1package fr.adamaq01.altproxy.network.old;
2
3import fr.adamaq01.altproxy.AltProxy;
4import fr.adamaq01.altproxy.io.bytebuf.ByteBufInput;
5import fr.adamaq01.altproxy.io.bytebuf.ByteBufOutput;
6import fr.adamaq01.altproxy.minecraft.SubProtocol;
7import fr.adamaq01.altproxy.minecraft.old.AltClient;
8import fr.adamaq01.altproxy.utils.Util;
9import io.netty.buffer.ByteBuf;
10import io.netty.buffer.Unpooled;
11import io.netty.channel.Channel;
12import io.netty.channel.ChannelFutureListener;
13import io.netty.channel.ChannelHandlerContext;
14import io.netty.handler.codec.MessageToMessageDecoder;
15import net.md_5.bungee.jni.cipher.BungeeCipher;
16import net.md_5.bungee.jni.cipher.JavaCipher;
17
18import javax.crypto.Cipher;
19import javax.crypto.SecretKey;
20import javax.crypto.spec.SecretKeySpec;
21import java.io.IOException;
22import java.security.KeyPair;
23import java.security.KeyPairGenerator;
24import java.util.List;
25
26/**
27 * Created by Adamaq01 on 03/12/2017.
28 */
29public class HandshakeHandler extends MessageToMessageDecoder<ByteBuf> {
30
31 private UpstreamHandler upstreamHandler;
32
33 private SubProtocol protocolMode = SubProtocol.HANDSHAKE;
34
35 private boolean downstreamInitialized = false;
36
37 private AltProxy altProxy;
38
39 private String response;
40
41 public HandshakeHandler(AltProxy altProxy) {
42 this.altProxy = altProxy;
43
44 this.response = "{\"version\":{\"name\":\"" + "1.12.2" + "\",\"protocol\":" + "%protocol%" + "},\"players\":{\"max\":" + "150" + ",\"online\":" + "1" + ", \"sample\":[{\"name\":\"" + "Adamaq01" + "\",\"id\":\"00000000-0000-0000-0000-000000000000\"}]},\"description\":\"" + "Hello les amis" + "\",\"favicon\":\"data:image/png;base64," + "" + "\",\"modinfo\":{\"type\":\"FML\",\"modList\":[]}}";
45 }
46
47 @Override
48 public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
49 super.handlerAdded(ctx);
50 System.out.println("Added a handler!");
51 }
52
53 @Override
54 protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf msg, List<Object> out) throws Exception {
55 ByteBuf copy = msg.copy();
56
57 ByteBufInput input = new ByteBufInput(copy);
58
59 input.readVarInt();
60
61 int packetId = input.readVarInt();
62
63 System.out.println("Received packet " + packetId);
64
65 if (packetId == 0) {
66
67 int clientProtocol = -1;
68
69 if (protocolMode == SubProtocol.HANDSHAKE) {
70 clientProtocol = input.readVarInt();
71 input.readString();
72 input.readUnsignedShort();
73 protocolMode = SubProtocol.valueOf((byte) input.readVarInt());
74 }
75
76 if (protocolMode == SubProtocol.STATUS) {
77 ByteBufOutput responseOutput = new ByteBufOutput(Unpooled.buffer());
78 String response = this.response.replace("%protocol%", String.valueOf(clientProtocol));
79 responseOutput.writeVarInt(3 + response.length()); // Size
80 responseOutput.writeVarInt(0); // Packet id
81 responseOutput.writeString(response); // Data as json string
82 channelHandlerContext.writeAndFlush(responseOutput.get());
83
84 // Sending Pong instant because otherwise the pong will not receive properly!
85 ByteBufOutput pongOutput = new ByteBufOutput(Unpooled.buffer());
86 pongOutput.writeVarInt(9);
87 pongOutput.writeVarInt(1);
88 pongOutput.writeLong(0);
89 channelHandlerContext.writeAndFlush(pongOutput.get());
90
91 channelHandlerContext.close();
92 }
93
94 if (protocolMode == SubProtocol.LOGIN) {
95 if (msg.readableBytes() == 0) {
96 upstreamHandler.connectDownstream(Util.parseServerAddress("play.epicube.fr"), copy);
97
98 downstreamInitialized = true;
99
100 out.add(copy.retain());
101
102 return;
103 }
104
105 String name = input.readString();
106
107 //TODO: Improve
108 /*if (Comix.getInstance().getComixConfig().isMaintenance()) {
109 if (Comix.getInstance().isWhitelistEnabled()) {
110 if (!Comix.getInstance().isWhitelisted(name)) {
111 kick(channelHandlerContext, Comix.getInstance().getWhitelistKickMessage());
112 }
113 } else {
114 kick(channelHandlerContext, Comix.getInstance().getComixConfig().getMaintenanceKickMessage());
115 }
116
117 channelHandlerContext.close();
118 return;
119 } else if(Comix.getInstance().isWhitelistEnabled() && !Comix.getInstance().isWhitelisted(name)) {
120 kick(channelHandlerContext, Comix.getInstance().getWhitelistKickMessage());
121
122 channelHandlerContext.close();
123 return;
124 }*/
125
126 if (!downstreamInitialized) {
127 upstreamHandler.connectDownstream(Util.parseServerAddress("play.epicube.fr"), copy);
128 } else {
129 upstreamHandler.addInitialPacket(copy);
130 }
131
132 AltClient altClient = new AltClient(name, upstreamHandler.getDownstreamHandler(), upstreamHandler);
133 altProxy.addClient(altClient);
134 upstreamHandler.setClient(altClient);
135
136 protocolMode = SubProtocol.PLAY;
137
138 // channelHandlerContext.channel().pipeline().remove(this);
139
140 System.out.println("Player logged in " + name);
141
142 // Comix.getLogger().log(Level.INFO, "Handshake", "Player logged in: " + name);
143
144 out.add(copy.retain());
145 }
146 } else {
147 if (packetId == 1) {
148 System.out.println("Encryption Response");
149 int sharedSecretLength = input.readVarInt();
150 byte[] sharedSecret = input.readBytes(sharedSecretLength);
151 int verifiedTokenLength = input.readVarInt();
152 byte[] verifiedToken = input.readBytes(verifiedTokenLength);
153 System.out.println("Shared secret length: " + sharedSecretLength);
154 System.out.println("Shared secret: " + sharedSecret);
155 System.out.println("Verified token length: " + verifiedTokenLength);
156 System.out.println("Verified token: " + verifiedToken);
157
158 System.out.println("Added !");
159 KeyPair keys;
160
161 KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
162 generator.initialize(1024);
163 keys = generator.generateKeyPair();
164
165 Cipher cipher = Cipher.getInstance("RSA");
166 cipher.init(Cipher.DECRYPT_MODE, keys.getPrivate());
167
168 SecretKey sharedKey = new SecretKeySpec(cipher.doFinal(sharedSecret), "AES");
169 BungeeCipher decrypt = new JavaCipher();
170 decrypt.init(false, sharedKey);
171
172 channelHandlerContext.channel().pipeline().remove(this);
173 this.upstreamHandler.getUpstreamChannel().pipeline().addBefore("upstreamHandler", "cipherDecoder", new CipherDecoder(decrypt));
174 }
175 out.add(copy.retain());
176 }
177 }
178
179 @Override
180 public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
181 Channel ch = ctx.channel();
182 if (ch.isActive()) {
183 ch.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
184 }
185 }
186
187 private void kick(ChannelHandlerContext channelHandlerContext, String message) throws IOException {
188 ByteBufOutput msg = new ByteBufOutput(Unpooled.buffer());
189 msg.writeVarInt(2 + message.length());
190 msg.writeVarInt(0);
191 msg.writeString(message);
192 channelHandlerContext.writeAndFlush(msg.get());
193 }
194
195 public void setUpstreamHandler(UpstreamHandler upstreamHandler) {
196 this.upstreamHandler = upstreamHandler;
197 }
198}