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