· 9 years ago · Jan 06, 2017, 03:46 PM
1package net.bartzz.lightlogin.nms;
2
3import com.google.common.base.Charsets;
4import com.mojang.authlib.GameProfile;
5import com.mojang.authlib.exceptions.AuthenticationUnavailableException;
6import io.netty.channel.ChannelFuture;
7import io.netty.channel.ChannelFutureListener;
8import io.netty.util.concurrent.GenericFutureListener;
9import net.minecraft.server.v1_11_R1.*;
10import org.apache.commons.lang3.Validate;
11import org.apache.logging.log4j.LogManager;
12import org.apache.logging.log4j.Logger;
13import org.bukkit.craftbukkit.v1_11_R1.CraftServer;
14import org.bukkit.craftbukkit.v1_11_R1.util.Waitable;
15import org.bukkit.event.player.AsyncPlayerPreLoginEvent;
16import org.bukkit.event.player.PlayerPreLoginEvent;
17
18import javax.annotation.Nullable;
19import javax.crypto.SecretKey;
20import java.math.BigInteger;
21import java.net.InetAddress;
22import java.net.InetSocketAddress;
23import java.net.SocketAddress;
24import java.security.PrivateKey;
25import java.util.Arrays;
26import java.util.Random;
27import java.util.UUID;
28import java.util.concurrent.atomic.AtomicInteger;
29import java.util.logging.Level;
30
31public class LightLoginListener extends LoginListener
32{
33 private static final AtomicInteger b = new AtomicInteger(0);
34 private static final Logger c = LogManager.getLogger();
35 private static final Random random = new Random();
36 private final byte[] e = new byte[4];
37 private final MinecraftServer server;
38 public final NetworkManager networkManager;
39 private EnumProtocolState g;
40 private int h;
41 private GameProfile i;
42 private final String j;
43 private SecretKey loginKey;
44 private EntityPlayer l;
45 public String hostname = "";
46
47 public LightLoginListener(MinecraftServer minecraftserver, NetworkManager networkmanager)
48 {
49 super(minecraftserver, networkmanager);
50 this.g = EnumProtocolState.HELLO;
51 this.j = "";
52 this.server = minecraftserver;
53 this.networkManager = networkmanager;
54 random.nextBytes(this.e);
55 }
56
57 public void F_()
58 {
59 if (this.g == EnumProtocolState.READY_TO_ACCEPT)
60 {
61 this.b();
62 }
63 else if (this.g == EnumProtocolState.DELAY_ACCEPT)
64 {
65 EntityPlayer entityplayer = this.server.getPlayerList().a(this.i.getId());
66 if (entityplayer == null)
67 {
68 this.g = EnumProtocolState.READY_TO_ACCEPT;
69 this.server.getPlayerList().a(this.networkManager, this.l);
70 this.l = null;
71 }
72 }
73
74 if (this.h++ == 600)
75 {
76 this.disconnect("Took too long to log in");
77 }
78
79 }
80
81 public void disconnect(String s)
82 {
83 try
84 {
85 c.info("Disconnecting {}: {}", new Object[]{ this.d(), s });
86 ChatComponentText exception = new ChatComponentText(s);
87 this.networkManager.sendPacket(new PacketLoginOutDisconnect(exception));
88 this.networkManager.close(exception);
89 } catch (Exception var3)
90 {
91 c.error("Error whilst disconnecting player", var3);
92 }
93
94 }
95
96 public void b()
97 {
98 if (!this.i.isComplete())
99 {
100 this.i = this.a(this.i);
101 }
102
103 EntityPlayer s = this.server.getPlayerList().attemptLogin(this, this.i, this.hostname);
104 if (s != null)
105 {
106 this.g = EnumProtocolState.ACCEPTED;
107 if (this.server.aG() >= 0 && !this.networkManager.isLocal())
108 {
109 this.networkManager.sendPacket(new PacketLoginOutSetCompression(this.server.aG()), new ChannelFutureListener()
110 {
111 public void a(ChannelFuture channelfuture) throws Exception
112 {
113 networkManager.setCompressionLevel(server.aG());
114 }
115
116 public void operationComplete(ChannelFuture future) throws Exception
117 {
118 this.a(future);
119 }
120 }, new GenericFutureListener[0]);
121 }
122
123 this.networkManager.sendPacket(new PacketLoginOutSuccess(this.i));
124 EntityPlayer entityplayer = this.server.getPlayerList().a(this.i.getId());
125 if (entityplayer != null)
126 {
127 this.g = EnumProtocolState.DELAY_ACCEPT;
128 this.l = this.server.getPlayerList().processLogin(this.i, s);
129 }
130 else
131 {
132 this.server.getPlayerList().a(this.networkManager, this.server.getPlayerList().processLogin(this.i, s));
133 }
134 }
135
136 }
137
138 public void a(IChatBaseComponent ichatbasecomponent)
139 {
140 c.info("{} lost connection: {}", new Object[]{ this.d(), ichatbasecomponent.toPlainText() });
141 }
142
143 public String d()
144 {
145 return this.i != null ? this.i + " (" + this.networkManager.getSocketAddress() + ")" : String.valueOf(this.networkManager.getSocketAddress());
146 }
147
148 public void a(PacketLoginInStart packetlogininstart)
149 {
150 Validate.validState(this.g == EnumProtocolState.HELLO, "Unexpected hello packet", new Object[0]);
151 this.i = packetlogininstart.a();
152 if (this.server.getOnlineMode() && !this.networkManager.isLocal())
153 {
154 this.g = EnumProtocolState.KEY;
155 this.networkManager.sendPacket(new PacketLoginOutEncryptionBegin("", this.server.O().getPublic(), this.e));
156 }
157 else
158 {
159 this.g = EnumProtocolState.READY_TO_ACCEPT;
160 }
161
162 }
163
164 public void a(PacketLoginInEncryptionBegin packetlogininencryptionbegin)
165 {
166 Validate.validState(this.g == EnumProtocolState.KEY, "Unexpected key packet", new Object[0]);
167 PrivateKey privatekey = this.server.O().getPrivate();
168 if (!Arrays.equals(this.e, packetlogininencryptionbegin.b(privatekey)))
169 {
170 throw new IllegalStateException("Invalid nonce!");
171 }
172 else
173 {
174 this.loginKey = packetlogininencryptionbegin.a(privatekey);
175 this.g = EnumProtocolState.AUTHENTICATING;
176 this.networkManager.a(this.loginKey);
177 (new Thread("User Authenticator #" + b.incrementAndGet())
178 {
179 public void run()
180 {
181 GameProfile gameprofile = i;
182
183 try
184 {
185 String exception = (new BigInteger(MinecraftEncryption.a("", server.O().getPublic(), loginKey))).toString(16);
186 i = server.az().hasJoinedServer(new GameProfile((UUID) null, gameprofile.getName()), exception, this.a());
187 if (i != null)
188 {
189 if (!networkManager.isConnected())
190 {
191 return;
192 }
193
194 String playerName = i.getName();
195 InetAddress address = ((InetSocketAddress) networkManager.getSocketAddress()).getAddress();
196 UUID uniqueId = i.getId();
197 final CraftServer server = LightLoginListener.this.server.server;
198 AsyncPlayerPreLoginEvent asyncEvent = new AsyncPlayerPreLoginEvent(playerName, address, uniqueId);
199 server.getPluginManager().callEvent(asyncEvent);
200 if (PlayerPreLoginEvent.getHandlerList().getRegisteredListeners().length != 0)
201 {
202 final PlayerPreLoginEvent event = new PlayerPreLoginEvent(playerName, address, uniqueId);
203 if (asyncEvent.getResult() != PlayerPreLoginEvent.Result.ALLOWED)
204 {
205 event.disallow(asyncEvent.getResult(), asyncEvent.getKickMessage());
206 }
207
208 Waitable waitable = new Waitable()
209 {
210 protected PlayerPreLoginEvent.Result evaluate()
211 {
212 server.getPluginManager().callEvent(event);
213 return event.getResult();
214 }
215 };
216
217 LightLoginListener.this.server.processQueue.add(waitable);
218 if (waitable.get() != PlayerPreLoginEvent.Result.ALLOWED)
219 {
220 disconnect(event.getKickMessage());
221 return;
222 }
223 }
224 else if (asyncEvent.getLoginResult() != org.bukkit.event.player.AsyncPlayerPreLoginEvent.Result.ALLOWED)
225 {
226 disconnect(asyncEvent.getKickMessage());
227 return;
228 }
229
230 c.info("UUID of player {} is {}", new Object[]{ i.getName(), i.getId() });
231 g = EnumProtocolState.READY_TO_ACCEPT;
232 }
233 else if (server.R())
234 {
235 c.warn("Failed to verify username but will let them in anyway!");
236 i = LightLoginListener.this.a(gameprofile);
237 g = EnumProtocolState.READY_TO_ACCEPT;
238 }
239 else
240 {
241 disconnect("Failed to verify username!");
242 c.error("Username \'{}\' tried to join with an invalid session", new Object[]{ gameprofile.getName() });
243 }
244 } catch (AuthenticationUnavailableException var10)
245 {
246 if (server.R())
247 {
248 LightLoginListener.this.c.warn("Authentication servers are down but will let them in anyway!");
249 i = LightLoginListener.this.a(gameprofile);
250 g = EnumProtocolState.READY_TO_ACCEPT;
251 }
252 else
253 {
254 disconnect("Authentication servers are down. Please try again later, sorry!");
255 c.error("Couldn\'t verify username because servers are unavailable");
256 }
257 } catch (Exception var11)
258 {
259 disconnect("Failed to verify username!");
260 server.server.getLogger().log(Level.WARNING, "Exception verifying " + gameprofile.getName(), var11);
261 }
262
263 }
264
265 @Nullable
266 private InetAddress a()
267 {
268 SocketAddress socketaddress = networkManager.getSocketAddress();
269 return server.ac() && socketaddress instanceof InetSocketAddress ? ((InetSocketAddress) socketaddress).getAddress() : null;
270 }
271 }).start();
272 }
273 }
274
275 protected GameProfile a(GameProfile gameprofile)
276 {
277 UUID uuid = UUID.nameUUIDFromBytes(("OfflinePlayer:" + gameprofile.getName()).getBytes(Charsets.UTF_8));
278 return new GameProfile(uuid, gameprofile.getName());
279 }
280
281 static enum EnumProtocolState
282 {
283 HELLO,
284 KEY,
285 AUTHENTICATING,
286 READY_TO_ACCEPT,
287 DELAY_ACCEPT,
288 ACCEPTED;
289 }
290}